Skip to content

Commit

Permalink
Merge pull request rails#23 from bigjason/nestable-jbuilder
Browse files Browse the repository at this point in the history
Allow nesting of Jbuilder objects
  • Loading branch information
dhh committed Aug 8, 2012
2 parents 83470d5 + 325c3e4 commit fcebaad
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,34 @@ end
# => [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ]
```

Jbuilder objects can be directly nested inside each other. Useful for composing objects.

``` ruby
class Person
# ... Class Definition ... #
def to_builder
person = Jbuilder.new
person.(self, :name, :age)
person
end
end

class Company
# ... Class Definition ... #
def to_builder
company = Jbuilder.new
company.name name
company.president president.to_builder
company
end
end

company = Company.new("Doodle Corp", Person.new("John Stobs", 58))
company.to_builder.target!

# => {"name":"Doodle Corp","president":{"name":"John Stobs","age":58}}
```

You can either use Jbuilder stand-alone or directly as an ActionView template language. When required in Rails, you can create views ala show.json.jbuilder (the json is already yielded):

``` ruby
Expand Down
10 changes: 9 additions & 1 deletion lib/jbuilder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def self.encode

define_method(:__class__, find_hidden_method(:class))
define_method(:_tap, find_hidden_method(:tap))
define_method(:_is_a?, find_hidden_method(:is_a?))
reveal(:respond_to?)

def initialize(key_format = @@key_format.clone)
@attributes = ActiveSupport::OrderedHash.new
Expand Down Expand Up @@ -178,6 +180,12 @@ def target!
private
def method_missing(method, *args)
case
# json.age 32
# json.person another_jbuilder
# { "age": 32, "person": { ... }
when args.one? && args.first.respond_to?(:_is_a?) && args.first._is_a?(Jbuilder)
set! method, args.first.attributes!

# json.comments @post.comments { |json, comment| ... }
# { "comments": [ { ... }, { ... } ] }
when args.one? && block_given?
Expand All @@ -192,7 +200,7 @@ def method_missing(method, *args)
# { "comments": ... }
when args.empty? && block_given?
_yield_nesting(method) { |jbuilder| yield jbuilder }

# json.comments(@post.comments, :content, :created_at)
# { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
when args.many? && args.first.is_a?(Enumerable)
Expand Down
14 changes: 13 additions & 1 deletion test/jbuilder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,19 @@ def initialize(name, age)

assert_equal "david", JSON.parse(json)["comments"].first["authors"].first["name"]
end


test "nested jbuilder objects" do
to_nest = Jbuilder.new
to_nest.nested_value "Nested Test"
json = Jbuilder.encode do |json|
json.value "Test"
json.nested to_nest
end
parsed = JSON.parse(json)
assert_equal "Test", parsed['value']
assert_equal "Nested Test", parsed["nested"]["nested_value"]
end

test "top-level array" do
comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]

Expand Down

0 comments on commit fcebaad

Please sign in to comment.