Class: Bldr::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/bldr/node.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value = nil, opts = {}, &block) ⇒ Node

Initialize a new Node instance.

Examples:

Building a simple node

node = Node.new do
  Node.new(:person => Person.new("alex")) do
    attributes(:name)
  end
end
node.to_json # => {"person": {"name": "alex"}}


20
21
22
23
24
25
26
27
28
29
30
# File 'lib/bldr/node.rb', line 20

def initialize(value = nil, opts = {}, &block)
  @current_object = value
  @opts           = opts
  @parent         = opts[:parent]
  @views          = opts[:views]
  @locals         = opts[:locals]
  # Storage hash for all descendant nodes
  @result  = {}

  instance_eval(&block) if block_given?
end

Instance Attribute Details

#current_objectObject (readonly)

Returns the value of attribute current_object.



6
7
8
# File 'lib/bldr/node.rb', line 6

def current_object
  @current_object
end

#localsObject (readonly)

Returns the value of attribute locals.



6
7
8
# File 'lib/bldr/node.rb', line 6

def locals
  @locals
end

#optsObject (readonly)

Returns the value of attribute opts.



6
7
8
# File 'lib/bldr/node.rb', line 6

def opts
  @opts
end

#parentObject (readonly)

Returns the value of attribute parent.



6
7
8
# File 'lib/bldr/node.rb', line 6

def parent
  @parent
end

#resultObject (readonly)

Returns the value of attribute result.



6
7
8
# File 'lib/bldr/node.rb', line 6

def result
  @result
end

#viewsObject (readonly)

Returns the value of attribute views.



6
7
8
# File 'lib/bldr/node.rb', line 6

def views
  @views
end

Instance Method Details

#attribute(*args, &block) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/bldr/node.rb', line 199

def attribute(*args,&block)
  if block_given?
    raise(ArgumentError, "You may only pass one argument to #attribute when using the block syntax.") if args.size > 1
    raise(ArgumentError, "You cannot use a block of arity > 0 if current_object is not present.") if block.arity > 0 and current_object.nil?
    merge_result!(args.first, (block.arity == 1) ? block.call(current_object) : current_object.instance_eval(&block))
  else
    case args.size
    when 1 # inferred object
      raise(ArgumentError, "#attribute can't be used when there is no current_object.") if current_object.nil?
      if args[0].is_a?(Hash)
        merge_result!(args[0].keys.first, current_object.send(args[0].values.first))
      else
        merge_result!(args[0], current_object.send(args[0]))
      end
    when 2 # static property
      merge_result!(args[0], args[1])
    else
      raise(ArgumentError, "You cannot pass more than two arguments to #attribute.")
    end
  end
  self
end

#attributes(*args, &block) ⇒ Nil

Add attributes to the result hash in a variety of ways

Examples:

Simple list of attributes

object :person => dude do
  attributes :name, :age
end

Attribute aliasing

object :person => dude do
  attributes :surname => :last_name
end

Dynamic attributes (explicit object context)

object :person => employee do
  collection :colleagues => employee.colleagues do |colleague|
    attribute :isBoss do |colleague|
      employee.works_with?(colleague) && colleague.admin?
    end
  end
end

Dynamic attributes (implicit object context)

object :person => dude do
  collection :colleagues => employee.colleagues do |colleague|
    attribute :rank do
      # method called on colleague
      if admin? && superior_to?(employee)
        "High Up"
      end
    end
  end
end


184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/bldr/node.rb', line 184

def attributes(*args, &block)
  if current_object.nil?
    raise(ArgumentError, "No current_object to apply #attributes to.")
  end

  args.each do |arg|
    if arg.is_a?(Hash)
      merge_result!(arg.keys.first, current_object.send(arg.values.first))
    else
      merge_result!(arg, current_object.send(arg))
    end
  end
  self
end

#collection(items, &block) ⇒ Bldr::Node

Build a collection of objects, either passing each object into the block provided, or rendering the collection “pass-through”, i.e. exactly as it appears.

Examples:

object :person => person do
  attributes :id, :name, :age

  collection :friends => person.friends do
    attributes :name, :age, :friend_count
  end
end

“Pass-through” collections

object :person => person do
  collection :hobbies => hobbies
end


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/bldr/node.rb', line 118

def collection(items, &block)

  # Does this collection live in a key, or is it top-level?
  if keyed_object?(items)
    key = items.keys.first
    values = items.values.to_a.first
  else
    key = nil
    values = items
  end

  vals = if values
    if block_given?
      values.map do |item|
        Node.new(item, opts.merge(:parent => self), &block).result
      end
    else
      values
    end
  else
    []
  end

  if keyed_object?(items)
    merge_result! key, vals
  else
    @result = massage_value(vals)
  end
    
  self
end

#object(base = nil, &block) ⇒ Bldr::Node

Create and render a node.

Examples:

A keyed object

get '/users/:id' do
  user = User.find(params['id'])

  bldr :'users/show.json', :locals => {:user => user}
end

# views/users/show.json.bldr
object :user => user do
  attributes :name, :email

  attribute(:id) { |person| person.id.to_s }
end

Root-level object with no key

get '/' do
  url = "http://google.com"

  bldr :'template.json', :locals => {:url => url}
end

# views/template.json.bldr
object do
  attributes(:url) { url }
end

“Pass-through” objects

object :person => person do
  object :hobbies => hobbies
end


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/bldr/node.rb', line 70

def object(base = nil, &block)
  if block_given?
    if keyed_object?(base)
      key   = base.keys.first
      value = base.values.first
    else
      key = base
      value = nil
    end

    # Short circuit here if the object passed in pointed
    # at a nil value. There's some debate about how this
    # should behave by default -- should it build the keyspace,
    # pointing a null value, or should it leave the key out.
    # With this implementation, it leaves the keyspace out.
    return nil if value.nil? and keyed_object?(base)

    node  = Node.new(value, opts.merge(:parent => self), &block)
    merge_result!(key, node.result)
  else
    merge_result!(nil, base)
  end

  self
end

#template(template, options = {}) ⇒ Bldr::Node

Render a template inline within a view

Examples:

Simple render

object :person => dude do
  template "path/to/template"
end

Using locals

object :person => dude do
  template "path/to/template", :locals => {:foo => 'bar'}
end


235
236
237
238
239
240
241
242
243
# File 'lib/bldr/node.rb', line 235

def template(template, options={})
  locals = options[:locals] || options['locals']

  if tpl = Bldr::Template.new(find_template(template)).render(self, locals)
    merge_result! nil, tpl.result
  end

  self
end