Class: Bldr::Node

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

Constant Summary collapse

PROTECTED_IVARS =
[:@current_object, :@result, :@parent, :@opts, :@views, :@locals]

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"}}

Parameters:

  • value (Object) (defaults to: nil)

    an object to serialize.

  • opts (Hash) (defaults to: {})
  • [Object] (Hash)

    a customizable set of options



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/bldr/node.rb', line 24

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         = {}

  copy_instance_variables_from(opts[:parent]) if opts[:parent]

  if block_given?
    if value && block.arity > 0
      instance_exec(value, &block)
    else
      instance_eval(&block)
    end
  end
end

Instance Attribute Details

#current_objectObject (readonly)

Returns the value of attribute current_object.



8
9
10
# File 'lib/bldr/node.rb', line 8

def current_object
  @current_object
end

#localsObject (readonly)

Returns the value of attribute locals.



8
9
10
# File 'lib/bldr/node.rb', line 8

def locals
  @locals
end

#optsObject (readonly)

Returns the value of attribute opts.



8
9
10
# File 'lib/bldr/node.rb', line 8

def opts
  @opts
end

#parentObject (readonly)

Returns the value of attribute parent.



8
9
10
# File 'lib/bldr/node.rb', line 8

def parent
  @parent
end

#resultObject (readonly)

Returns the value of attribute result.



8
9
10
# File 'lib/bldr/node.rb', line 8

def result
  @result
end

#viewsObject (readonly)

Returns the value of attribute views.



8
9
10
# File 'lib/bldr/node.rb', line 8

def views
  @views
end

Instance Method Details

#attribute(*args, &block) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/bldr/node.rb', line 216

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?
    if block.arity > 0
      merge_result! args.first, block.call(@current_object)
    else
      merge_result! args.first, block.call
    end
  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

Returns:

  • (Nil)


201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/bldr/node.rb', line 201

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

Parameters:

  • items (Array, Hash)

    Either an array of items, or a hash. If an array is passed in, the objects will be rendered at the “top level”, i.e. without a key pointing to them.

Returns:



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/bldr/node.rb', line 135

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

Parameters:

  • hash (Hash, Nil)

    a key/value pair indicating the output key name and the object to serialize.

  • block (Proc)

    the code block to evaluate

Returns:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/bldr/node.rb', line 87

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

Returns:



256
257
258
259
260
261
262
263
264
# File 'lib/bldr/node.rb', line 256

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