Skip to content

Commit

Permalink
Make blocks and their extract! shortcut additive by default
Browse files Browse the repository at this point in the history
[Fixes #196]
  • Loading branch information
rwz committed Jun 9, 2014
1 parent f672a65 commit a493907
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 14 deletions.
51 changes: 39 additions & 12 deletions lib/jbuilder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def set!(key, value = BLANK, *args, &block)
else
# json.comments { ... }
# { "comments": ... }
_scope{ yield self }
_merge_block(key){ yield self }
end
elsif args.empty?
if ::Jbuilder === value
Expand All @@ -52,7 +52,7 @@ def set!(key, value = BLANK, *args, &block)
else
# json.author @post.creator, :name, :email_address
# { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
_scope{ extract! value, *args }
_merge_block(key){ extract! value, *args }
end

_set_value key, result
Expand Down Expand Up @@ -174,13 +174,15 @@ def child!
#
# [1,2,3]
def array!(collection = [], *attributes, &block)
@attributes = if block
array = if block
_map_collection(collection, &block)
elsif attributes.any?
_map_collection(collection) { |element| extract! element, *attributes }
else
collection
end

merge! array
end

# Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
Expand Down Expand Up @@ -230,12 +232,7 @@ def attributes!

# Merges hash or array into current builder.
def merge!(hash_or_array)
if ::Array === hash_or_array
@attributes = [] unless ::Array === @attributes
@attributes.concat hash_or_array
else
@attributes.update hash_or_array
end
@attributes = _merge_values(@attributes, hash_or_array)
end

# Encodes the current builder as JSON.
Expand All @@ -253,12 +250,29 @@ def _extract_method_values(object, *attributes)
attributes.each{ |key| _set_value key, object.public_send(key) }
end

def _merge_block(key, &block)
current_value = _read(key, {})
raise NullError.build(key) if current_value.nil?
value = _scope{ yield self }
value.nil? ? value : _merge_values(current_value, value)
end

def _read(key, default = nil)
@attributes.fetch(_key(key)){ default }
end

def _write(key, value)
@attributes[_key(key)] = value
end

def _key(key)
@key_formatter.format(key)
end

def _set_value(key, value)
raise NullError.build(key) if @attributes.nil?
return if @ignore_nil && value.nil?

key = @key_formatter.format(key)
@attributes[key] = value
_write key, value
end

def _map_collection(collection)
Expand All @@ -281,6 +295,19 @@ def _scope
def _mapable_arguments?(value, *args)
value.respond_to?(:map)
end

def _merge_values(attributes, hash_or_array)
attributes = attributes.dup

if ::Array === hash_or_array
attributes = [] unless ::Array === attributes
attributes.concat hash_or_array
else
attributes.update hash_or_array
end

attributes
end
end

require 'jbuilder/jbuilder_template' if defined?(ActionView::Template)
Expand Down
71 changes: 69 additions & 2 deletions test/jbuilder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,42 @@ class JbuilderTest < ActiveSupport::TestCase
assert_equal 32, result['author']['age']
end

test 'blocks are additive' do
result = jbuild do |json|
json.author do
json.name 'David'
end

json.author do
json.age 32
end
end

assert_equal 'David', result['author']['name']
assert_equal 32, result['author']['age']
end

test 'blocks are additive via extract syntax' do
person = Person.new('Pavel', 27)

result = jbuild do |json|
json.author person, :age
json.author person, :name
end

assert_equal 'Pavel', result['author']['name']
assert_equal 27, result['author']['age']
end

test 'arrays are additive' do
result = jbuild do |json|
json.array! %w[foo]
json.array! %w[bar]
end

assert_equal %w[foo bar], result
end

test 'nesting multiple children with block' do
result = jbuild do |json|
json.comments do
Expand Down Expand Up @@ -531,9 +567,40 @@ class JbuilderTest < ActiveSupport::TestCase
assert_nil result
end

test 'throws meaningfull error when on trying to add properties to null' do
test 'null! in a block' do
result = jbuild do |json|
json.author do
json.name 'David'
end

json.author do
json.null!
end
end

assert result.key?('author')
assert_nil result['author']
end

test 'throws NullError when trying to add properties to null' do
json = Jbuilder.new
json.null!
assert_raise(Jbuilder::NullError) { json.foo 'bar' }
assert_raise Jbuilder::NullError do
json.foo 'bar'
end
end

test 'throws NullError when trying to add properties to null using block syntax' do
assert_raise Jbuilder::NullError do
jbuild do |json|
json.author do
json.null!
end

json.author do
json.name "Pavel"
end
end
end
end
end

0 comments on commit a493907

Please sign in to comment.