jbuilder 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -3
- data/Rakefile +10 -0
- data/jbuilder.gemspec +1 -2
- data/lib/jbuilder.rb +50 -67
- data/lib/jbuilder_template.rb +1 -11
- data/test/jbuilder_template_test.rb +38 -21
- data/test/jbuilder_test.rb +84 -67
- metadata +6 -26
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
jbuilder (0.
|
4
|
+
jbuilder (0.6.0)
|
5
5
|
activesupport (>= 3.0.0)
|
6
|
-
blankslate (>= 2.1.2.4)
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: http://rubygems.org/
|
@@ -24,7 +23,6 @@ GEM
|
|
24
23
|
activesupport (3.2.8)
|
25
24
|
i18n (~> 0.6)
|
26
25
|
multi_json (~> 1.0)
|
27
|
-
blankslate (2.1.2.4)
|
28
26
|
builder (3.0.0)
|
29
27
|
erubis (2.7.0)
|
30
28
|
hike (1.2.1)
|
@@ -36,6 +34,7 @@ GEM
|
|
36
34
|
rack (>= 0.4)
|
37
35
|
rack-test (0.6.1)
|
38
36
|
rack (>= 1.0)
|
37
|
+
rake (0.9.2.2)
|
39
38
|
sprockets (2.1.3)
|
40
39
|
hike (~> 1.2)
|
41
40
|
rack (~> 1.0)
|
@@ -48,3 +47,4 @@ PLATFORMS
|
|
48
47
|
DEPENDENCIES
|
49
48
|
actionpack
|
50
49
|
jbuilder!
|
50
|
+
rake
|
data/Rakefile
ADDED
data/jbuilder.gemspec
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'jbuilder'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '0.6.0'
|
4
4
|
s.author = 'David Heinemeier Hansson'
|
5
5
|
s.email = 'david@37signals.com'
|
6
6
|
s.summary = 'Create JSON structures via a Builder-style DSL'
|
7
7
|
|
8
8
|
s.add_dependency 'activesupport', '>= 3.0.0'
|
9
|
-
s.add_dependency 'blankslate', '>= 2.1.2.4'
|
10
9
|
|
11
10
|
s.files = Dir["#{File.dirname(__FILE__)}/**/*"]
|
12
11
|
end
|
data/lib/jbuilder.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/basic_object'
|
2
2
|
require 'active_support/ordered_hash'
|
3
3
|
require 'active_support/core_ext/array/access'
|
4
4
|
require 'active_support/core_ext/enumerable'
|
5
5
|
require 'active_support/json'
|
6
6
|
require 'multi_json'
|
7
|
-
|
7
|
+
|
8
|
+
class Jbuilder < ActiveSupport::BasicObject
|
8
9
|
class KeyFormatter
|
9
10
|
def initialize(*args)
|
10
11
|
@format = {}
|
@@ -34,20 +35,18 @@ class Jbuilder < BlankSlate
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
37
|
-
|
38
|
+
|
38
39
|
# Yields a builder and automatically turns the result into a JSON string
|
39
|
-
def self.encode
|
40
|
-
|
40
|
+
def self.encode(*args)
|
41
|
+
jbuilder = new(*args)
|
42
|
+
yield jbuilder
|
43
|
+
jbuilder.target!
|
41
44
|
end
|
42
45
|
|
43
46
|
@@key_formatter = KeyFormatter.new
|
44
47
|
|
45
|
-
define_method(:__class__, find_hidden_method(:class))
|
46
|
-
define_method(:_tap, find_hidden_method(:tap))
|
47
|
-
reveal(:respond_to?)
|
48
|
-
|
49
48
|
def initialize(key_formatter = @@key_formatter.clone)
|
50
|
-
@attributes = ActiveSupport::OrderedHash.new
|
49
|
+
@attributes = ::ActiveSupport::OrderedHash.new
|
51
50
|
@key_formatter = key_formatter
|
52
51
|
end
|
53
52
|
|
@@ -68,8 +67,8 @@ class Jbuilder < BlankSlate
|
|
68
67
|
#
|
69
68
|
# { "author": { "name": "David", "age": 32 } }
|
70
69
|
def set!(key, value = nil)
|
71
|
-
if block_given?
|
72
|
-
|
70
|
+
if ::Kernel::block_given?
|
71
|
+
_set_value(key, _with_attributes { yield self })
|
73
72
|
else
|
74
73
|
_set_value(key, value)
|
75
74
|
end
|
@@ -106,7 +105,7 @@ class Jbuilder < BlankSlate
|
|
106
105
|
def key_format!(*args)
|
107
106
|
@key_formatter = KeyFormatter.new(*args)
|
108
107
|
end
|
109
|
-
|
108
|
+
|
110
109
|
# Same as the instance method key_format! except sets the default.
|
111
110
|
def self.key_format(*args)
|
112
111
|
@@key_formatter = KeyFormatter.new(*args)
|
@@ -127,13 +126,13 @@ class Jbuilder < BlankSlate
|
|
127
126
|
#
|
128
127
|
# json.comments(@post.comments) do |json, comment|
|
129
128
|
# json.content comment.formatted_content
|
130
|
-
# end
|
129
|
+
# end
|
131
130
|
def child!
|
132
|
-
@attributes = [] unless @attributes.is_a? Array
|
133
|
-
@attributes <<
|
131
|
+
@attributes = [] unless @attributes.is_a? ::Array
|
132
|
+
@attributes << _with_attributes { yield self }
|
134
133
|
end
|
135
134
|
|
136
|
-
# Turns the current element into an array and iterates over the passed collection, adding each iteration as
|
135
|
+
# Turns the current element into an array and iterates over the passed collection, adding each iteration as
|
137
136
|
# an element of the resulting array.
|
138
137
|
#
|
139
138
|
# Example:
|
@@ -154,14 +153,11 @@ class Jbuilder < BlankSlate
|
|
154
153
|
# json.people(@people) do |json, person|
|
155
154
|
# json.name person.name
|
156
155
|
# json.age calculate_age(person.birthday)
|
157
|
-
# end
|
156
|
+
# end
|
158
157
|
#
|
159
158
|
# { "people": [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ] }
|
160
159
|
def array!(collection)
|
161
|
-
@attributes =
|
162
|
-
collection.each do |element| #[] and return if collection.empty?
|
163
|
-
@attributes << _new_instance._tap { |jbuilder| yield jbuilder, element }.attributes!
|
164
|
-
end
|
160
|
+
@attributes = _map_collection(collection) { |element| yield self, element }
|
165
161
|
end
|
166
162
|
|
167
163
|
# Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
|
@@ -182,20 +178,18 @@ class Jbuilder < BlankSlate
|
|
182
178
|
#
|
183
179
|
# json.(@person, :name, :age)
|
184
180
|
def extract!(object, *attributes)
|
185
|
-
if object.is_a?(Hash)
|
181
|
+
if object.is_a?(::Hash)
|
186
182
|
attributes.each {|attribute| _set_value attribute, object.send(:fetch, attribute)}
|
187
183
|
else
|
188
184
|
attributes.each {|attribute| _set_value attribute, object.send(attribute)}
|
189
185
|
end
|
190
186
|
end
|
191
187
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
extract!(object, *attributes)
|
198
|
-
end
|
188
|
+
def call(object = nil, *attributes)
|
189
|
+
if attributes.empty?
|
190
|
+
array!(object) { |_, element| yield self, element }
|
191
|
+
else
|
192
|
+
extract!(object, *attributes)
|
199
193
|
end
|
200
194
|
end
|
201
195
|
|
@@ -203,10 +197,10 @@ class Jbuilder < BlankSlate
|
|
203
197
|
def attributes!
|
204
198
|
@attributes
|
205
199
|
end
|
206
|
-
|
200
|
+
|
207
201
|
# Encodes the current builder as JSON.
|
208
202
|
def target!
|
209
|
-
MultiJson.encode @attributes
|
203
|
+
::MultiJson.encode @attributes
|
210
204
|
end
|
211
205
|
|
212
206
|
|
@@ -218,71 +212,60 @@ class Jbuilder < BlankSlate
|
|
218
212
|
|
219
213
|
private
|
220
214
|
def method_missing(method, value = nil, *args)
|
221
|
-
if block_given?
|
215
|
+
result = if ::Kernel.block_given?
|
222
216
|
if value
|
223
217
|
# json.comments @post.comments { |json, comment| ... }
|
224
218
|
# { "comments": [ { ... }, { ... } ] }
|
225
|
-
|
219
|
+
_map_collection(value) { |element| yield self, element }
|
226
220
|
else
|
227
221
|
# json.comments { |json| ... }
|
228
222
|
# { "comments": ... }
|
229
|
-
|
223
|
+
_with_attributes { yield self }
|
230
224
|
end
|
231
225
|
else
|
232
226
|
if args.empty?
|
233
|
-
if Jbuilder === value
|
227
|
+
if ::Jbuilder === value
|
234
228
|
# json.age 32
|
235
229
|
# json.person another_jbuilder
|
236
230
|
# { "age": 32, "person": { ... }
|
237
|
-
|
231
|
+
value.attributes!
|
238
232
|
else
|
239
233
|
# json.age 32
|
240
234
|
# { "age": 32 }
|
241
|
-
|
235
|
+
value
|
242
236
|
end
|
243
237
|
else
|
244
238
|
if value.respond_to?(:each)
|
245
239
|
# json.comments(@post.comments, :content, :created_at)
|
246
240
|
# { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
|
247
|
-
|
241
|
+
_map_collection(value) do |element|
|
242
|
+
args.each do |attribute|
|
243
|
+
_set_value attribute, element.send(attribute)
|
244
|
+
end
|
245
|
+
end
|
248
246
|
else
|
249
247
|
# json.author @post.creator, :name, :email_address
|
250
248
|
# { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
|
251
|
-
|
249
|
+
_with_attributes { extract! value, *args }
|
252
250
|
end
|
253
251
|
end
|
254
252
|
end
|
253
|
+
_set_value method, result
|
255
254
|
end
|
256
255
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
end
|
261
|
-
|
262
|
-
def _yield_nesting(container)
|
263
|
-
_set_value container, _new_instance._tap { |jbuilder| yield jbuilder }.attributes!
|
264
|
-
end
|
265
|
-
|
266
|
-
def _inline_nesting(container, collection, attributes)
|
267
|
-
_yield_nesting(container) do |parent|
|
268
|
-
parent.array!(collection) do |child, element|
|
269
|
-
attributes.each do |attribute|
|
270
|
-
child._set_value attribute, element.send(attribute)
|
271
|
-
end
|
272
|
-
end
|
256
|
+
def _map_collection(collection)
|
257
|
+
collection.each.map do |element|
|
258
|
+
_with_attributes { yield element }
|
273
259
|
end
|
274
260
|
end
|
275
|
-
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
def _inline_extract(container, record, attributes)
|
285
|
-
_yield_nesting(container) { |parent| parent.extract! record, *attributes }
|
261
|
+
|
262
|
+
def _with_attributes
|
263
|
+
parent_attributes, parent_formatter = @attributes, @key_formatter
|
264
|
+
@attributes = ::ActiveSupport::OrderedHash.new
|
265
|
+
yield
|
266
|
+
@attributes
|
267
|
+
ensure
|
268
|
+
@attributes, @key_formatter = parent_attributes, parent_formatter
|
286
269
|
end
|
287
270
|
end
|
288
271
|
|
data/lib/jbuilder_template.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
1
|
class JbuilderTemplate < Jbuilder
|
2
|
-
def self.encode(context)
|
3
|
-
new(context)._tap { |jbuilder| yield jbuilder }.target!
|
4
|
-
end
|
5
|
-
|
6
2
|
def initialize(context, *args)
|
7
3
|
@context = context
|
8
4
|
super(*args)
|
@@ -10,7 +6,7 @@ class JbuilderTemplate < Jbuilder
|
|
10
6
|
|
11
7
|
def partial!(options, locals = {})
|
12
8
|
case options
|
13
|
-
when Hash
|
9
|
+
when ::Hash
|
14
10
|
options[:locals] ||= {}
|
15
11
|
options[:locals].merge!(:json => self)
|
16
12
|
@context.render(options)
|
@@ -18,11 +14,6 @@ class JbuilderTemplate < Jbuilder
|
|
18
14
|
@context.render(options, locals.merge(:json => self))
|
19
15
|
end
|
20
16
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
def _new_instance
|
24
|
-
__class__.new(@context, @key_formatter)
|
25
|
-
end
|
26
17
|
end
|
27
18
|
|
28
19
|
class JbuilderHandler
|
@@ -30,7 +21,6 @@ class JbuilderHandler
|
|
30
21
|
self.default_format = Mime::JSON
|
31
22
|
|
32
23
|
def self.call(template)
|
33
|
-
|
34
24
|
# this juggling is required to keep line numbers right in the error
|
35
25
|
%{__already_defined = defined?(json); json||=JbuilderTemplate.new(self); #{template.source}
|
36
26
|
json.target! unless __already_defined}
|
@@ -1,39 +1,56 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
require 'active_support/test_case'
|
3
|
-
require 'active_support/inflector'
|
4
|
-
require 'action_dispatch'
|
5
2
|
require 'action_view'
|
3
|
+
require 'action_view/testing/resolvers'
|
6
4
|
|
7
5
|
require 'jbuilder'
|
8
|
-
require 'jbuilder_template'
|
9
6
|
|
10
|
-
class JbuilderTemplateTest <
|
7
|
+
class JbuilderTemplateTest < ActionView::TestCase
|
8
|
+
def partials
|
9
|
+
{ "_partial.json.jbuilder" => 'json.content "hello"' }
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_jbuilder(source)
|
13
|
+
@rendered = []
|
14
|
+
lookup_context.view_paths = [ActionView::FixtureResolver.new(partials.merge("test.json.jbuilder" => source))]
|
15
|
+
ActionView::Template.new(source, "test", JbuilderHandler, :virtual_path => "test").render(self, {}).strip
|
16
|
+
end
|
17
|
+
|
11
18
|
test "rendering" do
|
12
|
-
json =
|
19
|
+
json = render_jbuilder <<-JBUILDER
|
13
20
|
json.content "hello"
|
14
|
-
|
15
|
-
|
16
|
-
assert_equal "hello",
|
21
|
+
JBUILDER
|
22
|
+
|
23
|
+
assert_equal "hello", MultiJson.load(json)["content"]
|
17
24
|
end
|
18
25
|
|
19
26
|
test "key_format! with parameter" do
|
20
|
-
json =
|
21
|
-
|
22
|
-
|
27
|
+
json = render_jbuilder <<-JBUILDER
|
28
|
+
json.key_format! :camelize => [:lower]
|
29
|
+
json.camel_style "for JS"
|
30
|
+
JBUILDER
|
23
31
|
|
24
|
-
assert_equal ['camelStyle'], json.
|
32
|
+
assert_equal ['camelStyle'], MultiJson.load(json).keys
|
25
33
|
end
|
26
34
|
|
27
35
|
test "key_format! propagates to child elements" do
|
28
|
-
json =
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
json = render_jbuilder <<-JBUILDER
|
37
|
+
json.key_format! :upcase
|
38
|
+
json.level1 "one"
|
39
|
+
json.level2 do |json|
|
40
|
+
json.value "two"
|
41
|
+
end
|
42
|
+
JBUILDER
|
43
|
+
|
44
|
+
result = MultiJson.load(json)
|
36
45
|
assert_equal "one", result["LEVEL1"]
|
37
46
|
assert_equal "two", result["LEVEL2"]["VALUE"]
|
38
47
|
end
|
48
|
+
|
49
|
+
test "partial! renders partial" do
|
50
|
+
json = render_jbuilder <<-JBUILDER
|
51
|
+
json.partial! 'partial'
|
52
|
+
JBUILDER
|
53
|
+
|
54
|
+
assert_equal "hello", MultiJson.load(json)["content"]
|
55
|
+
end
|
39
56
|
end
|
data/test/jbuilder_test.rb
CHANGED
@@ -9,8 +9,8 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
9
9
|
json = Jbuilder.encode do |json|
|
10
10
|
json.content "hello"
|
11
11
|
end
|
12
|
-
|
13
|
-
assert_equal "hello",
|
12
|
+
|
13
|
+
assert_equal "hello", MultiJson.load(json)["content"]
|
14
14
|
end
|
15
15
|
|
16
16
|
test "single key with false value" do
|
@@ -18,7 +18,7 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
18
18
|
json.content false
|
19
19
|
end
|
20
20
|
|
21
|
-
assert_equal false,
|
21
|
+
assert_equal false, MultiJson.load(json)["content"]
|
22
22
|
end
|
23
23
|
|
24
24
|
test "single key with nil value" do
|
@@ -26,8 +26,8 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
26
26
|
json.content nil
|
27
27
|
end
|
28
28
|
|
29
|
-
assert
|
30
|
-
assert_equal nil,
|
29
|
+
assert MultiJson.load(json).has_key?("content")
|
30
|
+
assert_equal nil, MultiJson.load(json)["content"]
|
31
31
|
end
|
32
32
|
|
33
33
|
test "multiple keys" do
|
@@ -35,34 +35,38 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
35
35
|
json.title "hello"
|
36
36
|
json.content "world"
|
37
37
|
end
|
38
|
-
|
39
|
-
|
38
|
+
|
39
|
+
MultiJson.load(json).tap do |parsed|
|
40
40
|
assert_equal "hello", parsed["title"]
|
41
41
|
assert_equal "world", parsed["content"]
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
test "extracting from object" do
|
46
46
|
person = Struct.new(:name, :age).new("David", 32)
|
47
|
-
|
47
|
+
|
48
48
|
json = Jbuilder.encode do |json|
|
49
49
|
json.extract! person, :name, :age
|
50
50
|
end
|
51
|
-
|
52
|
-
|
51
|
+
|
52
|
+
MultiJson.load(json).tap do |parsed|
|
53
53
|
assert_equal "David", parsed["name"]
|
54
54
|
assert_equal 32, parsed["age"]
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
test "extracting from object using call style for 1.9" do
|
59
59
|
person = Struct.new(:name, :age).new("David", 32)
|
60
|
-
|
60
|
+
|
61
61
|
json = Jbuilder.encode do |json|
|
62
|
-
|
62
|
+
if ::RUBY_VERSION > '1.9'
|
63
|
+
instance_eval "json.(person, :name, :age)"
|
64
|
+
else
|
65
|
+
instance_eval "json.call(person, :name, :age)"
|
66
|
+
end
|
63
67
|
end
|
64
|
-
|
65
|
-
|
68
|
+
|
69
|
+
MultiJson.load(json).tap do |parsed|
|
66
70
|
assert_equal "David", parsed["name"]
|
67
71
|
assert_equal 32, parsed["age"]
|
68
72
|
end
|
@@ -75,7 +79,7 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
75
79
|
json.extract! person, :name, :age
|
76
80
|
end
|
77
81
|
|
78
|
-
|
82
|
+
MultiJson.load(json).tap do |parsed|
|
79
83
|
assert_equal "Jim", parsed["name"]
|
80
84
|
assert_equal 34, parsed["age"]
|
81
85
|
end
|
@@ -88,13 +92,13 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
88
92
|
json.age 32
|
89
93
|
end
|
90
94
|
end
|
91
|
-
|
92
|
-
|
95
|
+
|
96
|
+
MultiJson.load(json).tap do |parsed|
|
93
97
|
assert_equal "David", parsed["author"]["name"]
|
94
98
|
assert_equal 32, parsed["author"]["age"]
|
95
99
|
end
|
96
100
|
end
|
97
|
-
|
101
|
+
|
98
102
|
test "nesting multiple children with block" do
|
99
103
|
json = Jbuilder.encode do |json|
|
100
104
|
json.comments do |json|
|
@@ -103,69 +107,69 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
103
107
|
end
|
104
108
|
end
|
105
109
|
|
106
|
-
|
110
|
+
MultiJson.load(json).tap do |parsed|
|
107
111
|
assert_equal "hello", parsed["comments"].first["content"]
|
108
112
|
assert_equal "world", parsed["comments"].second["content"]
|
109
113
|
end
|
110
114
|
end
|
111
|
-
|
115
|
+
|
112
116
|
test "nesting single child with inline extract" do
|
113
117
|
person = Class.new do
|
114
118
|
attr_reader :name, :age
|
115
|
-
|
119
|
+
|
116
120
|
def initialize(name, age)
|
117
121
|
@name, @age = name, age
|
118
122
|
end
|
119
123
|
end.new("David", 32)
|
120
|
-
|
124
|
+
|
121
125
|
json = Jbuilder.encode do |json|
|
122
126
|
json.author person, :name, :age
|
123
127
|
end
|
124
|
-
|
125
|
-
|
128
|
+
|
129
|
+
MultiJson.load(json).tap do |parsed|
|
126
130
|
assert_equal "David", parsed["author"]["name"]
|
127
131
|
assert_equal 32, parsed["author"]["age"]
|
128
132
|
end
|
129
133
|
end
|
130
|
-
|
134
|
+
|
131
135
|
test "nesting multiple children from array" do
|
132
136
|
comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
|
133
|
-
|
137
|
+
|
134
138
|
json = Jbuilder.encode do |json|
|
135
139
|
json.comments comments, :content
|
136
140
|
end
|
137
|
-
|
138
|
-
|
141
|
+
|
142
|
+
MultiJson.load(json).tap do |parsed|
|
139
143
|
assert_equal ["content"], parsed["comments"].first.keys
|
140
144
|
assert_equal "hello", parsed["comments"].first["content"]
|
141
145
|
assert_equal "world", parsed["comments"].second["content"]
|
142
146
|
end
|
143
147
|
end
|
144
|
-
|
148
|
+
|
145
149
|
test "nesting multiple children from array when child array is empty" do
|
146
150
|
comments = []
|
147
|
-
|
151
|
+
|
148
152
|
json = Jbuilder.encode do |json|
|
149
153
|
json.name "Parent"
|
150
154
|
json.comments comments, :content
|
151
155
|
end
|
152
|
-
|
153
|
-
|
156
|
+
|
157
|
+
MultiJson.load(json).tap do |parsed|
|
154
158
|
assert_equal "Parent", parsed["name"]
|
155
159
|
assert_equal [], parsed["comments"]
|
156
160
|
end
|
157
161
|
end
|
158
|
-
|
162
|
+
|
159
163
|
test "nesting multiple children from array with inline loop" do
|
160
164
|
comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
|
161
|
-
|
165
|
+
|
162
166
|
json = Jbuilder.encode do |json|
|
163
167
|
json.comments comments do |json, comment|
|
164
168
|
json.content comment.content
|
165
169
|
end
|
166
170
|
end
|
167
|
-
|
168
|
-
|
171
|
+
|
172
|
+
MultiJson.load(json).tap do |parsed|
|
169
173
|
assert_equal ["content"], parsed["comments"].first.keys
|
170
174
|
assert_equal "hello", parsed["comments"].first["content"]
|
171
175
|
assert_equal "world", parsed["comments"].second["content"]
|
@@ -174,42 +178,42 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
174
178
|
|
175
179
|
test "nesting multiple children from array with inline loop on root" do
|
176
180
|
comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
|
177
|
-
|
181
|
+
|
178
182
|
json = Jbuilder.encode do |json|
|
179
|
-
json.(comments) do |json, comment|
|
183
|
+
json.call(comments) do |json, comment|
|
180
184
|
json.content comment.content
|
181
185
|
end
|
182
186
|
end
|
183
|
-
|
184
|
-
|
187
|
+
|
188
|
+
MultiJson.load(json).tap do |parsed|
|
185
189
|
assert_equal "hello", parsed.first["content"]
|
186
190
|
assert_equal "world", parsed.second["content"]
|
187
191
|
end
|
188
192
|
end
|
189
|
-
|
193
|
+
|
190
194
|
test "array nested inside nested hash" do
|
191
195
|
json = Jbuilder.encode do |json|
|
192
196
|
json.author do |json|
|
193
197
|
json.name "David"
|
194
198
|
json.age 32
|
195
|
-
|
199
|
+
|
196
200
|
json.comments do |json|
|
197
201
|
json.child! { |json| json.content "hello" }
|
198
202
|
json.child! { |json| json.content "world" }
|
199
203
|
end
|
200
204
|
end
|
201
205
|
end
|
202
|
-
|
203
|
-
|
206
|
+
|
207
|
+
MultiJson.load(json).tap do |parsed|
|
204
208
|
assert_equal "hello", parsed["author"]["comments"].first["content"]
|
205
209
|
assert_equal "world", parsed["author"]["comments"].second["content"]
|
206
210
|
end
|
207
211
|
end
|
208
|
-
|
212
|
+
|
209
213
|
test "array nested inside array" do
|
210
214
|
json = Jbuilder.encode do |json|
|
211
215
|
json.comments do |json|
|
212
|
-
json.child! do |json|
|
216
|
+
json.child! do |json|
|
213
217
|
json.authors do |json|
|
214
218
|
json.child! do |json|
|
215
219
|
json.name "david"
|
@@ -218,8 +222,8 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
218
222
|
end
|
219
223
|
end
|
220
224
|
end
|
221
|
-
|
222
|
-
assert_equal "david",
|
225
|
+
|
226
|
+
assert_equal "david", MultiJson.load(json)["comments"].first["authors"].first["name"]
|
223
227
|
end
|
224
228
|
|
225
229
|
test "nested jbuilder objects" do
|
@@ -229,7 +233,7 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
229
233
|
json.value "Test"
|
230
234
|
json.nested to_nest
|
231
235
|
end
|
232
|
-
parsed =
|
236
|
+
parsed = MultiJson.load(json)
|
233
237
|
assert_equal "Test", parsed['value']
|
234
238
|
assert_equal "Nested Test", parsed["nested"]["nested_value"]
|
235
239
|
end
|
@@ -242,31 +246,31 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
242
246
|
json.content comment.content
|
243
247
|
end
|
244
248
|
end
|
245
|
-
|
246
|
-
|
249
|
+
|
250
|
+
MultiJson.load(json).tap do |parsed|
|
247
251
|
assert_equal "hello", parsed.first["content"]
|
248
252
|
assert_equal "world", parsed.second["content"]
|
249
253
|
end
|
250
|
-
end
|
251
|
-
|
254
|
+
end
|
255
|
+
|
252
256
|
test "empty top-level array" do
|
253
257
|
comments = []
|
254
|
-
|
258
|
+
|
255
259
|
json = Jbuilder.encode do |json|
|
256
260
|
json.array!(comments) do |json, comment|
|
257
261
|
json.content comment.content
|
258
262
|
end
|
259
263
|
end
|
260
|
-
|
261
|
-
assert_equal [],
|
264
|
+
|
265
|
+
assert_equal [], MultiJson.load(json)
|
262
266
|
end
|
263
|
-
|
267
|
+
|
264
268
|
test "dynamically set a key/value" do
|
265
269
|
json = Jbuilder.encode do |json|
|
266
270
|
json.set!(:each, "stuff")
|
267
271
|
end
|
268
|
-
|
269
|
-
assert_equal "stuff",
|
272
|
+
|
273
|
+
assert_equal "stuff", MultiJson.load(json)["each"]
|
270
274
|
end
|
271
275
|
|
272
276
|
test "dynamically set a key/nested child with block" do
|
@@ -276,8 +280,8 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
276
280
|
json.age 32
|
277
281
|
end
|
278
282
|
end
|
279
|
-
|
280
|
-
|
283
|
+
|
284
|
+
MultiJson.load(json).tap do |parsed|
|
281
285
|
assert_equal "David", parsed["author"]["name"]
|
282
286
|
assert_equal 32, parsed["author"]["age"]
|
283
287
|
end
|
@@ -304,7 +308,7 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
304
308
|
json.relations RelationMock.new, :name, :age
|
305
309
|
end
|
306
310
|
|
307
|
-
parsed =
|
311
|
+
parsed = MultiJson.load(result)
|
308
312
|
assert_equal 2, parsed["relations"].length
|
309
313
|
assert_equal "Bob", parsed["relations"][0]["name"]
|
310
314
|
assert_equal 50, parsed["relations"][1]["age"]
|
@@ -339,6 +343,19 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
339
343
|
assert_equal "two", result["LEVEL2"]["VALUE"]
|
340
344
|
end
|
341
345
|
|
346
|
+
test "key_format! resets after child element" do
|
347
|
+
json = Jbuilder.new
|
348
|
+
json.level2 do |json|
|
349
|
+
json.key_format! :upcase
|
350
|
+
json.value "two"
|
351
|
+
end
|
352
|
+
json.level1 "one"
|
353
|
+
|
354
|
+
result = json.attributes!
|
355
|
+
assert_equal "two", result["level2"]["VALUE"]
|
356
|
+
assert_equal "one", result["level1"]
|
357
|
+
end
|
358
|
+
|
342
359
|
test "key_format! with no parameter" do
|
343
360
|
json = Jbuilder.new
|
344
361
|
json.key_format! :upcase
|
@@ -357,7 +374,7 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
357
374
|
|
358
375
|
test "key_format! with lambda/proc" do
|
359
376
|
json = Jbuilder.new
|
360
|
-
json.key_format!
|
377
|
+
json.key_format! lambda { |key| key + " and friends" }
|
361
378
|
json.oats ""
|
362
379
|
|
363
380
|
assert_equal ["oats and friends"], json.attributes!.keys
|
@@ -369,13 +386,13 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
369
386
|
json.camel_style "for JS"
|
370
387
|
|
371
388
|
assert_equal ['camelStyle'], json.attributes!.keys
|
372
|
-
Jbuilder.class_variable_set
|
389
|
+
Jbuilder.send(:class_variable_set, "@@key_formatter", Jbuilder::KeyFormatter.new)
|
373
390
|
end
|
374
391
|
|
375
392
|
test "don't use default key formatter directly" do
|
376
393
|
json = Jbuilder.new
|
377
394
|
json.key "value"
|
378
395
|
|
379
|
-
assert_equal [], Jbuilder.class_variable_get
|
396
|
+
assert_equal [], Jbuilder.send(:class_variable_get, "@@key_formatter").instance_variable_get("@cache").keys
|
380
397
|
end
|
381
398
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jbuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &2152682460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,28 +21,7 @@ dependencies:
|
|
21
21
|
version: 3.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 3.0.0
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: blankslate
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 2.1.2.4
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 2.1.2.4
|
24
|
+
version_requirements: *2152682460
|
46
25
|
description:
|
47
26
|
email: david@37signals.com
|
48
27
|
executables: []
|
@@ -55,6 +34,7 @@ files:
|
|
55
34
|
- ./lib/jbuilder.rb
|
56
35
|
- ./lib/jbuilder_template.rb
|
57
36
|
- ./MIT-LICENSE
|
37
|
+
- ./Rakefile
|
58
38
|
- ./README.md
|
59
39
|
- ./test/jbuilder_template_test.rb
|
60
40
|
- ./test/jbuilder_test.rb
|
@@ -78,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
58
|
version: '0'
|
79
59
|
requirements: []
|
80
60
|
rubyforge_project:
|
81
|
-
rubygems_version: 1.8.
|
61
|
+
rubygems_version: 1.8.7
|
82
62
|
signing_key:
|
83
63
|
specification_version: 3
|
84
64
|
summary: Create JSON structures via a Builder-style DSL
|