Skip to content

Commit

Permalink
[engine,builder] collection method now accepts rootname options
Browse files Browse the repository at this point in the history
  • Loading branch information
nesquena committed Feb 12, 2012
1 parent fedebf4 commit af5594a
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 26 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -6,7 +6,9 @@
* Alias to\_msgpack to to\_mpac
* Cache template sources for faster partial lookups (thanks cj)
* Adds BSON format support (thanks Antiarchitect)
* Use Rails template lookup mechanism to find templates (in Rails 3)
* Use template lookup mechanism to find templates in Rails 3 (thanks blakewatters)
* Adds a 'object_root' option to collection (thanks blakewatters)
* Adds a 'root_name' option to collection

## 0.5.4

Expand Down
9 changes: 8 additions & 1 deletion README.md
Expand Up @@ -216,13 +216,20 @@ collection @users
# => [ { "user" : { ... } } ]
```

or even specify a root node label for the collection:
or specify a root node label for the collection:

```ruby
collection @users => :people
# => { "people" : [ { "person" : { ... } } ] }
```

or even specify both the child and root labels for a collection:

```ruby
collection @users, :root_name => "people", :object_root => "user"
# => { "people" : [ { "user" : { ... } } ] }
```

and this will be used as the default data for the rendering.

There can also be odd cases where the root-level of the response doesn't map directly to any object:
Expand Down
19 changes: 10 additions & 9 deletions lib/rabl/builder.rb
Expand Up @@ -3,25 +3,26 @@ class Builder
include Rabl::Partials

# Constructs a new rabl hash based on given object and options
# options = { :format => "json", :attributes, :root => true,
# :child_root => true, :node, :child, :glue, :extends }
# options = { :format => "json", :root => true, :child_root => true,
# :attributes, :node, :child, :glue, :extends }
#
def initialize(options={}, &block)
@options = options
@_scope = options[:scope]
end

# Given an object and options, returns the hash representation
# build(@user, :format => "json", :attributes => { ... })
def build(data, options={})
@_data = data
@_object = data_object(data)
# build(@user, :format => "json", :attributes => { ... }, :root_name => "user")
def build(object, options={})
@_object = object
compile_hash(options)
end

protected

# Returns a hash representation of the data object
# compile_hash(:root => true)
# compile_hash(:root_name => false)
# compile_hash(:root_name => "user")
def compile_hash(options={})
@_result = {}
# Extends
Expand All @@ -46,8 +47,8 @@ def compile_hash(options={})
end if @options.has_key?(:glue)

# Wrap result in root
if @options[:root] || options[:root]
@_root_name ||= data_name(@_data)
if options[:root_name].present?
@_root_name = options[:root_name]
else # no root
@_root_name = nil
end
Expand Down
22 changes: 12 additions & 10 deletions lib/rabl/engine.rb
Expand Up @@ -31,17 +31,15 @@ def render(scope, locals, &block)
# to_hash(:root => true, :child_root => true)
def to_hash(options={})
options = @_options.merge(options)
data = data_object(@_data)
data, root_name = data_object(@_data), data_name(@_data)
builder = Rabl::Builder.new(options)
if is_object?(data) || !data # object @user
builder.build(@_data, options)
options[:root_name] = root_name if options[:root]
builder.build(data, options)
elsif is_collection?(data) # collection @users
if options[:root] # only calculate root name if needed
object_name = data_name(@_data).to_s.singularize # @users => :users
data.map { |object| builder.build({ object => object_name }, options) }
else # skip root name
data.map { |object| builder.build(object, options) }
end
options[:root_name] = object_root_name if object_root_name
options[:root_name] ||= root_name.to_s.singularize if options[:root]
data.map { |object| builder.build(object, options) }
end
end

Expand Down Expand Up @@ -99,8 +97,12 @@ def object(data)
# Sets the object as a collection casted to a simple array
# collection @users
# collection @users => :people
def collection(data)
@_collection_name = data.values.first if data.respond_to?(:each_pair)
# collection @users, :root => :person
# collection @users, :object_root => :person
def collection(data, options={})
@_collection_name = options[:root] if options[:root]
@_collection_name ||= data.values.first if data.respond_to?(:each_pair)
@_object_root_name = options[:object_root] if options[:object_root]
self.object(data_object(data).to_a) if data
end

Expand Down
4 changes: 2 additions & 2 deletions test/builder_test.rb
Expand Up @@ -28,7 +28,7 @@

setup { builder({ :attributes => { :name => :name } }) }
asserts "that the object is set properly" do
topic.build(User.new, :root => true)
topic.build(User.new, :root_name => "user")
end.equivalent_to({ "user" => { :name => "rabl" } })

end
Expand All @@ -37,7 +37,7 @@

setup { builder({ :attributes => { :name => :name } }) }
asserts "that the object is set properly" do
topic.build({ User.new => "person" }, :root => true)
topic.build(User.new, :root_name => "person")
end.equivalent_to({ "person" => { :name => "rabl" } })

end
Expand Down
23 changes: 20 additions & 3 deletions test/engine_test.rb
Expand Up @@ -263,15 +263,32 @@
template.render(scope)
end.equals "[{},{}]"

asserts "that it sets root node for objects" do
asserts "that it sets root node for objects using hash" do
template = rabl %{
collection @users => :person
collection @users => :people
}
scope = Object.new
scope.instance_variable_set :@users, [User.new, User.new]
template.render(scope)
end.equals "{\"person\":[{},{}]}"
end.equals "{\"people\":[{},{}]}"

asserts "that it sets root node for objects using root option" do
template = rabl %{
collection @users, :root => :people
}
scope = Object.new
scope.instance_variable_set :@users, [User.new, User.new]
template.render(scope)
end.equals "{\"people\":[{},{}]}"

asserts "that it sets root node for objects using object_root option" do
template = rabl %{
collection @users, :root => :humans, :object_root => :person
}
scope = Object.new
scope.instance_variable_set :@users, [User.new, User.new]
template.render(scope)
end.equals %Q^{"humans":[{"person":{}},{"person":{}}]}^
end

context "#attribute" do
Expand Down

0 comments on commit af5594a

Please sign in to comment.