jbuilder 1.5.3 → 2.11.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +108 -0
  3. data/.gitignore +4 -1
  4. data/Appraisals +25 -0
  5. data/CONTRIBUTING.md +106 -0
  6. data/Gemfile +4 -5
  7. data/MIT-LICENSE +2 -2
  8. data/README.md +182 -40
  9. data/Rakefile +15 -10
  10. data/gemfiles/rails_5_0.gemfile +10 -0
  11. data/gemfiles/rails_5_1.gemfile +10 -0
  12. data/gemfiles/rails_5_2.gemfile +10 -0
  13. data/gemfiles/rails_6_0.gemfile +10 -0
  14. data/gemfiles/rails_6_1.gemfile +10 -0
  15. data/gemfiles/rails_head.gemfile +10 -0
  16. data/jbuilder.gemspec +25 -8
  17. data/lib/generators/rails/jbuilder_generator.rb +13 -2
  18. data/lib/generators/rails/scaffold_controller_generator.rb +9 -3
  19. data/lib/generators/rails/templates/api_controller.rb +63 -0
  20. data/lib/generators/rails/templates/controller.rb +18 -22
  21. data/lib/generators/rails/templates/index.json.jbuilder +1 -4
  22. data/lib/generators/rails/templates/partial.json.jbuilder +16 -0
  23. data/lib/generators/rails/templates/show.json.jbuilder +1 -1
  24. data/lib/jbuilder/blank.rb +11 -0
  25. data/lib/jbuilder/collection_renderer.rb +109 -0
  26. data/lib/jbuilder/dependency_tracker.rb +61 -0
  27. data/lib/jbuilder/errors.rb +24 -0
  28. data/lib/jbuilder/jbuilder.rb +7 -0
  29. data/lib/jbuilder/jbuilder_template.rb +228 -67
  30. data/lib/jbuilder/key_formatter.rb +34 -0
  31. data/lib/jbuilder/railtie.rb +31 -6
  32. data/lib/jbuilder.rb +144 -137
  33. data/test/jbuilder_dependency_tracker_test.rb +72 -0
  34. data/test/jbuilder_generator_test.rb +31 -4
  35. data/test/jbuilder_template_test.rb +319 -163
  36. data/test/jbuilder_test.rb +613 -298
  37. data/test/scaffold_api_controller_generator_test.rb +70 -0
  38. data/test/scaffold_controller_generator_test.rb +62 -19
  39. data/test/test_helper.rb +36 -0
  40. metadata +47 -22
  41. data/.travis.yml +0 -38
  42. data/Gemfile.old +0 -7
@@ -1,295 +1,356 @@
1
- require 'test/unit'
2
- require 'active_support/test_case'
1
+ require 'test_helper'
3
2
  require 'active_support/inflector'
4
3
  require 'jbuilder'
5
4
 
6
- Comment = Struct.new(:content, :id)
7
-
8
- unless JbuilderProxy.method_defined? :instance_eval
9
- # Faking Object#instance_eval for 1.8 and some newer JRubies
10
- class JbuilderProxy
11
- def instance_eval(code)
12
- eval code
13
- end
14
- end
5
+ def jbuild(*args, &block)
6
+ Jbuilder.new(*args, &block).attributes!
15
7
  end
16
8
 
9
+ Comment = Struct.new(:content, :id)
10
+
17
11
  class NonEnumerable
18
12
  def initialize(collection)
19
13
  @collection = collection
20
14
  end
21
15
 
22
- def map(&block)
23
- @collection.map(&block)
16
+ delegate :map, :count, to: :@collection
17
+ end
18
+
19
+ class VeryBasicWrapper < BasicObject
20
+ def initialize(thing)
21
+ @thing = thing
22
+ end
23
+
24
+ def method_missing(name, *args, &block)
25
+ @thing.send name, *args, &block
26
+ end
27
+ end
28
+
29
+ # This is not Struct, because structs are Enumerable
30
+ class Person
31
+ attr_reader :name, :age
32
+
33
+ def initialize(name, age)
34
+ @name, @age = name, age
35
+ end
36
+ end
37
+
38
+ class RelationMock
39
+ include Enumerable
40
+
41
+ def each(&block)
42
+ [Person.new('Bob', 30), Person.new('Frank', 50)].each(&block)
43
+ end
44
+
45
+ def empty?
46
+ false
24
47
  end
25
48
  end
26
49
 
50
+
27
51
  class JbuilderTest < ActiveSupport::TestCase
52
+ teardown do
53
+ Jbuilder.send :class_variable_set, '@@key_formatter', nil
54
+ end
55
+
28
56
  test 'single key' do
29
- json = Jbuilder.encode do |json|
57
+ result = jbuild do |json|
30
58
  json.content 'hello'
31
59
  end
32
60
 
33
- assert_equal 'hello', MultiJson.load(json)['content']
61
+ assert_equal 'hello', result['content']
34
62
  end
35
63
 
36
64
  test 'single key with false value' do
37
- json = Jbuilder.encode do |json|
65
+ result = jbuild do |json|
38
66
  json.content false
39
67
  end
40
68
 
41
- assert_equal false, MultiJson.load(json)['content']
69
+ assert_equal false, result['content']
42
70
  end
43
71
 
44
72
  test 'single key with nil value' do
45
- json = Jbuilder.encode do |json|
73
+ result = jbuild do |json|
46
74
  json.content nil
47
75
  end
48
76
 
49
- assert MultiJson.load(json).has_key?('content')
50
- assert_equal nil, MultiJson.load(json)['content']
77
+ assert result.has_key?('content')
78
+ assert_nil result['content']
51
79
  end
52
80
 
53
81
  test 'multiple keys' do
54
- json = Jbuilder.encode do |json|
82
+ result = jbuild do |json|
55
83
  json.title 'hello'
56
84
  json.content 'world'
57
85
  end
58
86
 
59
- parsed = MultiJson.load(json)
60
- assert_equal 'hello', parsed['title']
61
- assert_equal 'world', parsed['content']
87
+ assert_equal 'hello', result['title']
88
+ assert_equal 'world', result['content']
62
89
  end
63
90
 
64
91
  test 'extracting from object' do
65
92
  person = Struct.new(:name, :age).new('David', 32)
66
93
 
67
- json = Jbuilder.encode do |json|
94
+ result = jbuild do |json|
68
95
  json.extract! person, :name, :age
69
96
  end
70
97
 
71
- parsed = MultiJson.load(json)
72
- assert_equal 'David', parsed['name']
73
- assert_equal 32, parsed['age']
74
- end
75
-
76
- test 'extracting from object using private method' do
77
- person = Struct.new(:name) do
78
- private
79
- def age
80
- 32
81
- end
82
- end.new('David')
83
-
84
- message = 'Private method :age was used to extract value. This will be' +
85
- ' an error in future versions of Jbuilder'
86
-
87
- ::ActiveSupport::Deprecation.expects(:warn).with(message)
88
- json = Jbuilder.encode do |json|
89
- json.extract! person, :name, :age
90
- end
98
+ assert_equal 'David', result['name']
99
+ assert_equal 32, result['age']
91
100
  end
92
101
 
93
- test 'extracting from object using call style for 1.9' do
102
+ test 'extracting from object using call style' do
94
103
  person = Struct.new(:name, :age).new('David', 32)
95
104
 
96
- json = Jbuilder.encode do |json|
97
- if ::RUBY_VERSION > '1.9'
98
- instance_eval 'json.(person, :name, :age)'
99
- else
100
- instance_eval 'json.call(person, :name, :age)'
101
- end
105
+ result = jbuild do |json|
106
+ json.(person, :name, :age)
102
107
  end
103
108
 
104
- parsed = MultiJson.load(json)
105
- assert_equal 'David', parsed['name']
106
- assert_equal 32, parsed['age']
109
+ assert_equal 'David', result['name']
110
+ assert_equal 32, result['age']
107
111
  end
108
112
 
109
113
  test 'extracting from hash' do
110
114
  person = {:name => 'Jim', :age => 34}
111
115
 
112
- json = Jbuilder.encode do |json|
116
+ result = jbuild do |json|
113
117
  json.extract! person, :name, :age
114
118
  end
115
119
 
116
- parsed = MultiJson.load(json)
117
- assert_equal 'Jim', parsed['name']
118
- assert_equal 34, parsed['age']
120
+ assert_equal 'Jim', result['name']
121
+ assert_equal 34, result['age']
119
122
  end
120
123
 
121
124
  test 'nesting single child with block' do
122
- json = Jbuilder.encode do |json|
125
+ result = jbuild do |json|
123
126
  json.author do
124
127
  json.name 'David'
125
128
  json.age 32
126
129
  end
127
130
  end
128
131
 
129
- parsed = MultiJson.load(json)
130
- assert_equal 'David', parsed['author']['name']
131
- assert_equal 32, parsed['author']['age']
132
+ assert_equal 'David', result['author']['name']
133
+ assert_equal 32, result['author']['age']
134
+ end
135
+
136
+ test 'empty block handling' do
137
+ result = jbuild do |json|
138
+ json.foo 'bar'
139
+ json.author do
140
+ end
141
+ end
142
+
143
+ assert_equal 'bar', result['foo']
144
+ assert !result.key?('author')
145
+ end
146
+
147
+ test 'blocks are additive' do
148
+ result = jbuild do |json|
149
+ json.author do
150
+ json.name 'David'
151
+ end
152
+
153
+ json.author do
154
+ json.age 32
155
+ end
156
+ end
157
+
158
+ assert_equal 'David', result['author']['name']
159
+ assert_equal 32, result['author']['age']
160
+ end
161
+
162
+ test 'nested blocks are additive' do
163
+ result = jbuild do |json|
164
+ json.author do
165
+ json.name do
166
+ json.first 'David'
167
+ end
168
+ end
169
+
170
+ json.author do
171
+ json.name do
172
+ json.last 'Heinemeier Hansson'
173
+ end
174
+ end
175
+ end
176
+
177
+ assert_equal 'David', result['author']['name']['first']
178
+ assert_equal 'Heinemeier Hansson', result['author']['name']['last']
179
+ end
180
+
181
+ test 'support merge! method' do
182
+ result = jbuild do |json|
183
+ json.merge! 'foo' => 'bar'
184
+ end
185
+
186
+ assert_equal 'bar', result['foo']
187
+ end
188
+
189
+ test 'support merge! method in a block' do
190
+ result = jbuild do |json|
191
+ json.author do
192
+ json.merge! 'name' => 'Pavel'
193
+ end
194
+ end
195
+
196
+ assert_equal 'Pavel', result['author']['name']
197
+ end
198
+
199
+ test 'support merge! method with Jbuilder instance' do
200
+ obj = jbuild do |json|
201
+ json.foo 'bar'
202
+ end
203
+
204
+ result = jbuild do |json|
205
+ json.merge! obj
206
+ end
207
+
208
+ assert_equal 'bar', result['foo']
209
+ end
210
+
211
+ test 'blocks are additive via extract syntax' do
212
+ person = Person.new('Pavel', 27)
213
+
214
+ result = jbuild do |json|
215
+ json.author person, :age
216
+ json.author person, :name
217
+ end
218
+
219
+ assert_equal 'Pavel', result['author']['name']
220
+ assert_equal 27, result['author']['age']
221
+ end
222
+
223
+ test 'arrays are additive' do
224
+ result = jbuild do |json|
225
+ json.array! %w[foo]
226
+ json.array! %w[bar]
227
+ end
228
+
229
+ assert_equal %w[foo bar], result
132
230
  end
133
231
 
134
232
  test 'nesting multiple children with block' do
135
- json = Jbuilder.encode do |json|
233
+ result = jbuild do |json|
136
234
  json.comments do
137
235
  json.child! { json.content 'hello' }
138
236
  json.child! { json.content 'world' }
139
237
  end
140
238
  end
141
239
 
142
- parsed = MultiJson.load(json)
143
- assert_equal 'hello', parsed['comments'].first['content']
144
- assert_equal 'world', parsed['comments'].second['content']
240
+ assert_equal 'hello', result['comments'].first['content']
241
+ assert_equal 'world', result['comments'].second['content']
145
242
  end
146
243
 
147
244
  test 'nesting single child with inline extract' do
148
- person = Class.new do
149
- attr_reader :name, :age
150
-
151
- def initialize(name, age)
152
- @name, @age = name, age
153
- end
154
- end.new('David', 32)
245
+ person = Person.new('David', 32)
155
246
 
156
- json = Jbuilder.encode do |json|
247
+ result = jbuild do |json|
157
248
  json.author person, :name, :age
158
249
  end
159
250
 
160
- parsed = MultiJson.load(json)
161
- assert_equal 'David', parsed['author']['name']
162
- assert_equal 32, parsed['author']['age']
251
+ assert_equal 'David', result['author']['name']
252
+ assert_equal 32, result['author']['age']
163
253
  end
164
254
 
165
255
  test 'nesting multiple children from array' do
166
256
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
167
257
 
168
- json = Jbuilder.encode do |json|
258
+ result = jbuild do |json|
169
259
  json.comments comments, :content
170
260
  end
171
261
 
172
- parsed = MultiJson.load(json)
173
- assert_equal ['content'], parsed['comments'].first.keys
174
- assert_equal 'hello', parsed['comments'].first['content']
175
- assert_equal 'world', parsed['comments'].second['content']
262
+ assert_equal ['content'], result['comments'].first.keys
263
+ assert_equal 'hello', result['comments'].first['content']
264
+ assert_equal 'world', result['comments'].second['content']
176
265
  end
177
266
 
178
267
  test 'nesting multiple children from array when child array is empty' do
179
268
  comments = []
180
269
 
181
- json = Jbuilder.encode do |json|
270
+ result = jbuild do |json|
182
271
  json.name 'Parent'
183
272
  json.comments comments, :content
184
273
  end
185
274
 
186
- parsed = MultiJson.load(json)
187
- assert_equal 'Parent', parsed['name']
188
- assert_equal [], parsed['comments']
275
+ assert_equal 'Parent', result['name']
276
+ assert_equal [], result['comments']
189
277
  end
190
278
 
191
279
  test 'nesting multiple children from array with inline loop' do
192
280
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
193
281
 
194
- json = Jbuilder.encode do |json|
282
+ result = jbuild do |json|
195
283
  json.comments comments do |comment|
196
284
  json.content comment.content
197
285
  end
198
286
  end
199
287
 
200
- parsed = MultiJson.load(json)
201
- assert_equal ['content'], parsed['comments'].first.keys
202
- assert_equal 'hello', parsed['comments'].first['content']
203
- assert_equal 'world', parsed['comments'].second['content']
288
+ assert_equal ['content'], result['comments'].first.keys
289
+ assert_equal 'hello', result['comments'].first['content']
290
+ assert_equal 'world', result['comments'].second['content']
204
291
  end
205
292
 
206
293
  test 'handles nil-collections as empty arrays' do
207
- json = Jbuilder.encode do |json|
294
+ result = jbuild do |json|
208
295
  json.comments nil do |comment|
209
296
  json.content comment.content
210
297
  end
211
298
  end
212
299
 
213
- assert_equal [], MultiJson.load(json)['comments']
300
+ assert_equal [], result['comments']
214
301
  end
215
302
 
216
303
  test 'nesting multiple children from a non-Enumerable that responds to #map' do
217
304
  comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
218
305
 
219
- json = Jbuilder.encode do |json|
306
+ result = jbuild do |json|
220
307
  json.comments comments, :content
221
308
  end
222
309
 
223
- parsed = MultiJson.load(json)
224
- assert_equal ['content'], parsed['comments'].first.keys
225
- assert_equal 'hello', parsed['comments'].first['content']
226
- assert_equal 'world', parsed['comments'].second['content']
310
+ assert_equal ['content'], result['comments'].first.keys
311
+ assert_equal 'hello', result['comments'].first['content']
312
+ assert_equal 'world', result['comments'].second['content']
227
313
  end
228
314
 
229
- test 'nesting multiple chilren from a non-Enumerable that responds to #map with inline loop' do
315
+ test 'nesting multiple children from a non-Enumerable that responds to #map with inline loop' do
230
316
  comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
231
317
 
232
- json = Jbuilder.encode do |json|
318
+ result = jbuild do |json|
233
319
  json.comments comments do |comment|
234
320
  json.content comment.content
235
321
  end
236
322
  end
237
323
 
238
- parsed = MultiJson.load(json)
239
- assert_equal ['content'], parsed['comments'].first.keys
240
- assert_equal 'hello', parsed['comments'].first['content']
241
- assert_equal 'world', parsed['comments'].second['content']
324
+ assert_equal ['content'], result['comments'].first.keys
325
+ assert_equal 'hello', result['comments'].first['content']
326
+ assert_equal 'world', result['comments'].second['content']
242
327
  end
243
328
 
244
- test 'nesting multiple children from array with inline loop with old api' do
245
- comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
329
+ test 'array! casts array-like objects to array before merging' do
330
+ wrapped_array = VeryBasicWrapper.new(%w[foo bar])
246
331
 
247
- json = Jbuilder.encode do |json|
248
- ::ActiveSupport::Deprecation.silence do
249
- json.comments comments do |json, comment|
250
- json.content comment.content
251
- end
252
- end
332
+ result = jbuild do |json|
333
+ json.array! wrapped_array
253
334
  end
254
335
 
255
- parsed = MultiJson.load(json)
256
- assert_equal ['content'], parsed['comments'].first.keys
257
- assert_equal 'hello', parsed['comments'].first['content']
258
- assert_equal 'world', parsed['comments'].second['content']
336
+ assert_equal %w[foo bar], result
259
337
  end
260
338
 
261
339
  test 'nesting multiple children from array with inline loop on root' do
262
340
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
263
341
 
264
- json = Jbuilder.encode do |json|
342
+ result = jbuild do |json|
265
343
  json.call(comments) do |comment|
266
344
  json.content comment.content
267
345
  end
268
346
  end
269
347
 
270
- parsed = MultiJson.load(json)
271
- assert_equal 'hello', parsed.first['content']
272
- assert_equal 'world', parsed.second['content']
273
- end
274
-
275
- test 'nesting multiple children from array with inline loop on root with old api' do
276
- comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
277
-
278
- json = Jbuilder.encode do |json|
279
- ::ActiveSupport::Deprecation.silence do
280
- json.call(comments) do |json, comment|
281
- json.content comment.content
282
- end
283
- end
284
- end
285
-
286
- parsed = MultiJson.load(json)
287
- assert_equal 'hello', parsed.first['content']
288
- assert_equal 'world', parsed.second['content']
348
+ assert_equal 'hello', result.first['content']
349
+ assert_equal 'world', result.second['content']
289
350
  end
290
351
 
291
352
  test 'array nested inside nested hash' do
292
- json = Jbuilder.encode do |json|
353
+ result = jbuild do |json|
293
354
  json.author do
294
355
  json.name 'David'
295
356
  json.age 32
@@ -301,13 +362,12 @@ class JbuilderTest < ActiveSupport::TestCase
301
362
  end
302
363
  end
303
364
 
304
- parsed = MultiJson.load(json)
305
- assert_equal 'hello', parsed['author']['comments'].first['content']
306
- assert_equal 'world', parsed['author']['comments'].second['content']
365
+ assert_equal 'hello', result['author']['comments'].first['content']
366
+ assert_equal 'world', result['author']['comments'].second['content']
307
367
  end
308
368
 
309
369
  test 'array nested inside array' do
310
- json = Jbuilder.encode do |json|
370
+ result = jbuild do |json|
311
371
  json.comments do
312
372
  json.child! do
313
373
  json.authors do
@@ -319,12 +379,13 @@ class JbuilderTest < ActiveSupport::TestCase
319
379
  end
320
380
  end
321
381
 
322
- assert_equal 'david', MultiJson.load(json)['comments'].first['authors'].first['name']
382
+ assert_equal 'david', result['comments'].first['authors'].first['name']
323
383
  end
324
384
 
325
385
  test 'directly set an array nested in another array' do
326
386
  data = [ { :department => 'QA', :not_in_json => 'hello', :names => ['John', 'David'] } ]
327
- json = Jbuilder.encode do |json|
387
+
388
+ result = jbuild do |json|
328
389
  json.array! data do |object|
329
390
  json.department object[:department]
330
391
  json.names do
@@ -333,294 +394,548 @@ class JbuilderTest < ActiveSupport::TestCase
333
394
  end
334
395
  end
335
396
 
336
- assert_equal 'David', MultiJson.load(json)[0]['names'].last
337
- assert_not_equal 'hello', MultiJson.load(json)[0]['not_in_json']
338
- end
339
-
340
- test 'directly set an array nested in another array with old api' do
341
- data = [ { :department => 'QA', :not_in_json => 'hello', :names => ['John', 'David'] } ]
342
- json = Jbuilder.encode do |json|
343
- ::ActiveSupport::Deprecation.silence do
344
- json.array! data do |json, object|
345
- json.department object[:department]
346
- json.names do
347
- json.array! object[:names]
348
- end
349
- end
350
- end
351
- end
352
-
353
- parsed = MultiJson.load(json)
354
- assert_equal 'David', parsed.first['names'].last
355
- assert_not_equal 'hello', parsed.first['not_in_json']
397
+ assert_equal 'David', result[0]['names'].last
398
+ assert !result[0].key?('not_in_json')
356
399
  end
357
400
 
358
401
  test 'nested jbuilder objects' do
359
- to_nest = Jbuilder.new
360
- to_nest.nested_value 'Nested Test'
361
- json = Jbuilder.encode do |json|
402
+ to_nest = Jbuilder.new{ |json| json.nested_value 'Nested Test' }
403
+
404
+ result = jbuild do |json|
362
405
  json.value 'Test'
363
406
  json.nested to_nest
364
407
  end
365
408
 
366
- result = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
367
- assert_equal result, MultiJson.load(json)
409
+ expected = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
410
+ assert_equal expected, result
368
411
  end
369
412
 
370
413
  test 'nested jbuilder object via set!' do
371
- to_nest = Jbuilder.new
372
- to_nest.nested_value 'Nested Test'
373
- json = Jbuilder.encode do |json|
414
+ to_nest = Jbuilder.new{ |json| json.nested_value 'Nested Test' }
415
+
416
+ result = jbuild do |json|
374
417
  json.value 'Test'
375
418
  json.set! :nested, to_nest
376
419
  end
377
420
 
378
- result = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
379
- assert_equal result, MultiJson.load(json)
421
+ expected = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
422
+ assert_equal expected, result
380
423
  end
381
424
 
382
425
  test 'top-level array' do
383
426
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
384
427
 
385
- json = Jbuilder.encode do |json|
386
- json.array!(comments) do |comment|
428
+ result = jbuild do |json|
429
+ json.array! comments do |comment|
387
430
  json.content comment.content
388
431
  end
389
432
  end
390
433
 
391
- parsed = MultiJson.load(json)
392
- assert_equal 'hello', parsed.first['content']
393
- assert_equal 'world', parsed.second['content']
434
+ assert_equal 'hello', result.first['content']
435
+ assert_equal 'world', result.second['content']
436
+ end
437
+
438
+ test 'it allows using next in array block to skip value' do
439
+ comments = [ Comment.new('hello', 1), Comment.new('skip', 2), Comment.new('world', 3) ]
440
+ result = jbuild do |json|
441
+ json.array! comments do |comment|
442
+ next if comment.id == 2
443
+ json.content comment.content
444
+ end
445
+ end
446
+
447
+ assert_equal 2, result.length
448
+ assert_equal 'hello', result.first['content']
449
+ assert_equal 'world', result.second['content']
394
450
  end
395
451
 
396
452
  test 'extract attributes directly from array' do
397
453
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
398
454
 
399
- json = Jbuilder.encode do |json|
455
+ result = jbuild do |json|
400
456
  json.array! comments, :content, :id
401
457
  end
402
458
 
403
- parsed = MultiJson.load(json)
404
- assert_equal 'hello', parsed.first['content']
405
- assert_equal 1, parsed.first['id']
406
- assert_equal 'world', parsed.second['content']
407
- assert_equal 2, parsed.second['id']
459
+ assert_equal 'hello', result.first['content']
460
+ assert_equal 1, result.first['id']
461
+ assert_equal 'world', result.second['content']
462
+ assert_equal 2, result.second['id']
408
463
  end
409
464
 
410
465
  test 'empty top-level array' do
411
466
  comments = []
412
467
 
413
- json = Jbuilder.encode do |json|
414
- json.array!(comments) do |comment|
468
+ result = jbuild do |json|
469
+ json.array! comments do |comment|
415
470
  json.content comment.content
416
471
  end
417
472
  end
418
473
 
419
- assert_equal [], MultiJson.load(json)
474
+ assert_equal [], result
420
475
  end
421
476
 
422
477
  test 'dynamically set a key/value' do
423
- json = Jbuilder.encode do |json|
478
+ result = jbuild do |json|
424
479
  json.set! :each, 'stuff'
425
480
  end
426
481
 
427
- assert_equal 'stuff', MultiJson.load(json)['each']
482
+ assert_equal 'stuff', result['each']
428
483
  end
429
484
 
430
485
  test 'dynamically set a key/nested child with block' do
431
- json = Jbuilder.encode do |json|
432
- json.set!(:author) do
486
+ result = jbuild do |json|
487
+ json.set! :author do
433
488
  json.name 'David'
434
489
  json.age 32
435
490
  end
436
491
  end
437
492
 
438
- parsed = MultiJson.load(json)
439
- assert_equal 'David', parsed['author']['name']
440
- assert_equal 32, parsed['author']['age']
493
+ assert_equal 'David', result['author']['name']
494
+ assert_equal 32, result['author']['age']
441
495
  end
442
496
 
443
497
  test 'dynamically sets a collection' do
444
498
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
445
499
 
446
- json = Jbuilder.encode do |json|
500
+ result = jbuild do |json|
447
501
  json.set! :comments, comments, :content
448
502
  end
449
503
 
450
- parsed = MultiJson.load(json)
451
- assert_equal ['content'], parsed['comments'].first.keys
452
- assert_equal 'hello', parsed['comments'].first['content']
453
- assert_equal 'world', parsed['comments'].second['content']
504
+ assert_equal ['content'], result['comments'].first.keys
505
+ assert_equal 'hello', result['comments'].first['content']
506
+ assert_equal 'world', result['comments'].second['content']
454
507
  end
455
508
 
456
509
  test 'query like object' do
457
- class Person
458
- attr_reader :name, :age
459
-
460
- def initialize(name, age)
461
- @name, @age = name, age
462
- end
463
- end
464
- class RelationMock
465
- include Enumerable
466
-
467
- def each(&block)
468
- [Person.new('Bob', 30), Person.new('Frank', 50)].each(&block)
469
- end
470
- def empty?
471
- false
472
- end
473
- end
474
-
475
- result = Jbuilder.encode do |json|
510
+ result = jbuild do |json|
476
511
  json.relations RelationMock.new, :name, :age
477
512
  end
478
513
 
479
- parsed = MultiJson.load(result)
480
- assert_equal 2, parsed['relations'].length
481
- assert_equal 'Bob', parsed['relations'][0]['name']
482
- assert_equal 50, parsed['relations'][1]['age']
514
+ assert_equal 2, result['relations'].length
515
+ assert_equal 'Bob', result['relations'][0]['name']
516
+ assert_equal 50, result['relations'][1]['age']
483
517
  end
484
518
 
485
519
  test 'initialize via options hash' do
486
- jbuilder = Jbuilder.new(:key_formatter => 1, :ignore_nil => 2)
487
- assert_equal 1, jbuilder.instance_eval('@key_formatter')
488
- assert_equal 2, jbuilder.instance_eval('@ignore_nil')
520
+ jbuilder = Jbuilder.new(key_formatter: 1, ignore_nil: 2)
521
+ assert_equal 1, jbuilder.instance_eval{ @key_formatter }
522
+ assert_equal 2, jbuilder.instance_eval{ @ignore_nil }
489
523
  end
490
524
 
491
525
  test 'key_format! with parameter' do
492
- json = Jbuilder.new
493
- json.key_format! :camelize => [:lower]
494
- json.camel_style 'for JS'
526
+ result = jbuild do |json|
527
+ json.key_format! camelize: [:lower]
528
+ json.camel_style 'for JS'
529
+ end
495
530
 
496
- assert_equal ['camelStyle'], json.attributes!.keys
531
+ assert_equal ['camelStyle'], result.keys
497
532
  end
498
533
 
499
534
  test 'key_format! with parameter not as an array' do
500
- json = Jbuilder.new
501
- json.key_format! :camelize => :lower
502
- json.camel_style 'for JS'
535
+ result = jbuild do |json|
536
+ json.key_format! :camelize => :lower
537
+ json.camel_style 'for JS'
538
+ end
503
539
 
504
- assert_equal ['camelStyle'], json.attributes!.keys
540
+ assert_equal ['camelStyle'], result.keys
505
541
  end
506
542
 
507
543
  test 'key_format! propagates to child elements' do
508
- json = Jbuilder.new
509
- json.key_format! :upcase
510
- json.level1 'one'
511
- json.level2 do
512
- json.value 'two'
544
+ result = jbuild do |json|
545
+ json.key_format! :upcase
546
+ json.level1 'one'
547
+ json.level2 do
548
+ json.value 'two'
549
+ end
513
550
  end
514
551
 
515
- result = json.attributes!
516
552
  assert_equal 'one', result['LEVEL1']
517
553
  assert_equal 'two', result['LEVEL2']['VALUE']
518
554
  end
519
555
 
520
556
  test 'key_format! resets after child element' do
521
- json = Jbuilder.new
522
- json.level2 do
523
- json.key_format! :upcase
524
- json.value 'two'
557
+ result = jbuild do |json|
558
+ json.level2 do
559
+ json.key_format! :upcase
560
+ json.value 'two'
561
+ end
562
+ json.level1 'one'
525
563
  end
526
- json.level1 'one'
527
564
 
528
- result = json.attributes!
529
565
  assert_equal 'two', result['level2']['VALUE']
530
566
  assert_equal 'one', result['level1']
531
567
  end
532
568
 
569
+ test 'key_format! can be changed in child elements' do
570
+ result = jbuild do |json|
571
+ json.key_format! camelize: :lower
572
+
573
+ json.level_one do
574
+ json.key_format! :upcase
575
+ json.value 'two'
576
+ end
577
+ end
578
+
579
+ assert_equal ['levelOne'], result.keys
580
+ assert_equal ['VALUE'], result['levelOne'].keys
581
+ end
582
+
583
+ test 'key_format! can be changed in array!' do
584
+ result = jbuild do |json|
585
+ json.key_format! camelize: :lower
586
+
587
+ json.level_one do
588
+ json.array! [{value: 'two'}] do |object|
589
+ json.key_format! :upcase
590
+ json.value object[:value]
591
+ end
592
+ end
593
+ end
594
+
595
+ assert_equal ['levelOne'], result.keys
596
+ assert_equal ['VALUE'], result['levelOne'][0].keys
597
+ end
598
+
533
599
  test 'key_format! with no parameter' do
534
- json = Jbuilder.new
535
- json.key_format! :upcase
536
- json.lower 'Value'
600
+ result = jbuild do |json|
601
+ json.key_format! :upcase
602
+ json.lower 'Value'
603
+ end
537
604
 
538
- assert_equal ['LOWER'], json.attributes!.keys
605
+ assert_equal ['LOWER'], result.keys
539
606
  end
540
607
 
541
608
  test 'key_format! with multiple steps' do
542
- json = Jbuilder.new
543
- json.key_format! :upcase, :pluralize
544
- json.pill ''
609
+ result = jbuild do |json|
610
+ json.key_format! :upcase, :pluralize
611
+ json.pill 'foo'
612
+ end
545
613
 
546
- assert_equal ['PILLs'], json.attributes!.keys
614
+ assert_equal ['PILLs'], result.keys
547
615
  end
548
616
 
549
617
  test 'key_format! with lambda/proc' do
550
- json = Jbuilder.new
551
- json.key_format! lambda { |key| key + ' and friends' }
552
- json.oats ''
618
+ result = jbuild do |json|
619
+ json.key_format! ->(key){ key + ' and friends' }
620
+ json.oats 'foo'
621
+ end
553
622
 
554
- assert_equal ['oats and friends'], json.attributes!.keys
623
+ assert_equal ['oats and friends'], result.keys
555
624
  end
556
625
 
557
- test 'default key_format!' do
558
- Jbuilder.key_format :camelize => :lower
559
- json = Jbuilder.new
560
- json.camel_style 'for JS'
626
+ test 'key_format! is not applied deeply by default' do
627
+ names = { first_name: 'camel', last_name: 'case' }
628
+ result = jbuild do |json|
629
+ json.key_format! camelize: :lower
630
+ json.set! :all_names, names
631
+ end
561
632
 
562
- assert_equal ['camelStyle'], json.attributes!.keys
563
- Jbuilder.send(:class_variable_set, '@@key_formatter', Jbuilder::KeyFormatter.new)
633
+ assert_equal %i[first_name last_name], result['allNames'].keys
564
634
  end
565
635
 
566
- test 'do not use default key formatter directly' do
567
- json = Jbuilder.new
568
- json.key 'value'
636
+ test 'applying key_format! deeply can be enabled per scope' do
637
+ names = { first_name: 'camel', last_name: 'case' }
638
+ result = jbuild do |json|
639
+ json.key_format! camelize: :lower
640
+ json.scope do
641
+ json.deep_format_keys!
642
+ json.set! :all_names, names
643
+ end
644
+ json.set! :all_names, names
645
+ end
569
646
 
570
- assert_equal [], Jbuilder.send(:class_variable_get, '@@key_formatter').instance_variable_get('@cache').keys
647
+ assert_equal %w[firstName lastName], result['scope']['allNames'].keys
648
+ assert_equal %i[first_name last_name], result['allNames'].keys
649
+ end
650
+
651
+ test 'applying key_format! deeply can be disabled per scope' do
652
+ names = { first_name: 'camel', last_name: 'case' }
653
+ result = jbuild do |json|
654
+ json.key_format! camelize: :lower
655
+ json.deep_format_keys!
656
+ json.set! :all_names, names
657
+ json.scope do
658
+ json.deep_format_keys! false
659
+ json.set! :all_names, names
660
+ end
661
+ end
662
+
663
+ assert_equal %w[firstName lastName], result['allNames'].keys
664
+ assert_equal %i[first_name last_name], result['scope']['allNames'].keys
665
+ end
666
+
667
+ test 'applying key_format! deeply can be enabled globally' do
668
+ names = { first_name: 'camel', last_name: 'case' }
669
+
670
+ Jbuilder.deep_format_keys true
671
+ result = jbuild do |json|
672
+ json.key_format! camelize: :lower
673
+ json.set! :all_names, names
674
+ end
675
+
676
+ assert_equal %w[firstName lastName], result['allNames'].keys
677
+ Jbuilder.send(:class_variable_set, '@@deep_format_keys', false)
678
+ end
679
+
680
+ test 'deep key_format! with merge!' do
681
+ hash = { camel_style: 'for JS' }
682
+ result = jbuild do |json|
683
+ json.key_format! camelize: :lower
684
+ json.deep_format_keys!
685
+ json.merge! hash
686
+ end
687
+
688
+ assert_equal ['camelStyle'], result.keys
689
+ end
690
+
691
+ test 'deep key_format! with merge! deep' do
692
+ hash = { camel_style: { sub_attr: 'for JS' } }
693
+ result = jbuild do |json|
694
+ json.key_format! camelize: :lower
695
+ json.deep_format_keys!
696
+ json.merge! hash
697
+ end
698
+
699
+ assert_equal ['subAttr'], result['camelStyle'].keys
700
+ end
701
+
702
+ test 'deep key_format! with set! array of hashes' do
703
+ names = [{ first_name: 'camel', last_name: 'case' }]
704
+ result = jbuild do |json|
705
+ json.key_format! camelize: :lower
706
+ json.deep_format_keys!
707
+ json.set! :names, names
708
+ end
709
+
710
+ assert_equal %w[firstName lastName], result['names'][0].keys
711
+ end
712
+
713
+ test 'deep key_format! with set! extracting hash from object' do
714
+ comment = Struct.new(:author).new({ first_name: 'camel', last_name: 'case' })
715
+ result = jbuild do |json|
716
+ json.key_format! camelize: :lower
717
+ json.deep_format_keys!
718
+ json.set! :comment, comment, :author
719
+ end
720
+
721
+ assert_equal %w[firstName lastName], result['comment']['author'].keys
722
+ end
723
+
724
+ test 'deep key_format! with array! of hashes' do
725
+ names = [{ first_name: 'camel', last_name: 'case' }]
726
+ result = jbuild do |json|
727
+ json.key_format! camelize: :lower
728
+ json.deep_format_keys!
729
+ json.array! names
730
+ end
731
+
732
+ assert_equal %w[firstName lastName], result[0].keys
733
+ end
734
+
735
+ test 'deep key_format! with merge! array of hashes' do
736
+ names = [{ first_name: 'camel', last_name: 'case' }]
737
+ new_names = [{ first_name: 'snake', last_name: 'case' }]
738
+ result = jbuild do |json|
739
+ json.key_format! camelize: :lower
740
+ json.deep_format_keys!
741
+ json.array! names
742
+ json.merge! new_names
743
+ end
744
+
745
+ assert_equal %w[firstName lastName], result[1].keys
746
+ end
747
+
748
+ test 'deep key_format! is applied to hash extracted from object' do
749
+ comment = Struct.new(:author).new({ first_name: 'camel', last_name: 'case' })
750
+ result = jbuild do |json|
751
+ json.key_format! camelize: :lower
752
+ json.deep_format_keys!
753
+ json.extract! comment, :author
754
+ end
755
+
756
+ assert_equal %w[firstName lastName], result['author'].keys
757
+ end
758
+
759
+ test 'deep key_format! is applied to hash extracted from hash' do
760
+ comment = {author: { first_name: 'camel', last_name: 'case' }}
761
+ result = jbuild do |json|
762
+ json.key_format! camelize: :lower
763
+ json.deep_format_keys!
764
+ json.extract! comment, :author
765
+ end
766
+
767
+ assert_equal %w[firstName lastName], result['author'].keys
768
+ end
769
+
770
+ test 'deep key_format! is applied to hash extracted directly from array' do
771
+ comments = [Struct.new(:author).new({ first_name: 'camel', last_name: 'case' })]
772
+ result = jbuild do |json|
773
+ json.key_format! camelize: :lower
774
+ json.deep_format_keys!
775
+ json.array! comments, :author
776
+ end
777
+
778
+ assert_equal %w[firstName lastName], result[0]['author'].keys
779
+ end
780
+
781
+ test 'default key_format!' do
782
+ Jbuilder.key_format camelize: :lower
783
+ result = jbuild{ |json| json.camel_style 'for JS' }
784
+ assert_equal ['camelStyle'], result.keys
785
+ end
786
+
787
+ test 'do not use default key formatter directly' do
788
+ Jbuilder.key_format
789
+ jbuild{ |json| json.key 'value' }
790
+ formatter = Jbuilder.send(:class_variable_get, '@@key_formatter')
791
+ cache = formatter.instance_variable_get('@cache')
792
+ assert_empty cache
571
793
  end
572
794
 
573
795
  test 'ignore_nil! without a parameter' do
574
- json = Jbuilder.new
575
- json.ignore_nil!
576
- json.test nil
796
+ result = jbuild do |json|
797
+ json.ignore_nil!
798
+ json.test nil
799
+ end
577
800
 
578
- assert_equal [], json.attributes!.keys
801
+ assert_empty result.keys
579
802
  end
580
803
 
581
804
  test 'ignore_nil! with parameter' do
582
- json = Jbuilder.new
583
- json.ignore_nil! true
584
- json.name 'Bob'
585
- json.dne nil
805
+ result = jbuild do |json|
806
+ json.ignore_nil! true
807
+ json.name 'Bob'
808
+ json.dne nil
809
+ end
586
810
 
587
- assert_equal ['name'], json.attributes!.keys
811
+ assert_equal ['name'], result.keys
588
812
 
589
- json = Jbuilder.new
590
- json.ignore_nil! false
591
- json.name 'Bob'
592
- json.dne nil
813
+ result = jbuild do |json|
814
+ json.ignore_nil! false
815
+ json.name 'Bob'
816
+ json.dne nil
817
+ end
593
818
 
594
- assert_equal ['name', 'dne'], json.attributes!.keys
819
+ assert_equal ['name', 'dne'], result.keys
595
820
  end
596
821
 
597
822
  test 'default ignore_nil!' do
598
823
  Jbuilder.ignore_nil
599
- json = Jbuilder.new
600
- json.name 'Bob'
601
- json.dne nil
602
824
 
603
- assert_equal ['name'], json.attributes!.keys
825
+ result = jbuild do |json|
826
+ json.name 'Bob'
827
+ json.dne nil
828
+ end
829
+
830
+ assert_equal ['name'], result.keys
604
831
  Jbuilder.send(:class_variable_set, '@@ignore_nil', false)
605
832
  end
606
833
 
607
834
  test 'nil!' do
608
- json = Jbuilder.new
609
- json.key 'value'
610
- json.nil!
611
- assert_nil json.attributes!
835
+ result = jbuild do |json|
836
+ json.key 'value'
837
+ json.nil!
838
+ end
839
+
840
+ assert_nil result
612
841
  end
613
842
 
614
843
  test 'null!' do
615
- json = Jbuilder.new
616
- json.key 'value'
617
- json.null!
618
- assert_nil json.attributes!
844
+ result = jbuild do |json|
845
+ json.key 'value'
846
+ json.null!
847
+ end
848
+
849
+ assert_nil result
850
+ end
851
+
852
+ test 'null! in a block' do
853
+ result = jbuild do |json|
854
+ json.author do
855
+ json.name 'David'
856
+ end
857
+
858
+ json.author do
859
+ json.null!
860
+ end
861
+ end
862
+
863
+ assert result.key?('author')
864
+ assert_nil result['author']
865
+ end
866
+
867
+ test 'empty attributes respond to empty?' do
868
+ attributes = Jbuilder.new.attributes!
869
+ assert attributes.empty?
870
+ assert attributes.blank?
871
+ assert !attributes.present?
872
+ end
873
+
874
+ test 'throws ArrayError when trying to add a key to an array' do
875
+ assert_raise Jbuilder::ArrayError do
876
+ jbuild do |json|
877
+ json.array! %w[foo bar]
878
+ json.fizz "buzz"
879
+ end
880
+ end
881
+ end
882
+
883
+ test 'throws NullError when trying to add properties to null' do
884
+ assert_raise Jbuilder::NullError do
885
+ jbuild do |json|
886
+ json.null!
887
+ json.foo 'bar'
888
+ end
889
+ end
619
890
  end
620
891
 
621
- test 'throws meaningfull error when on trying to add properties to null' do
622
- json = Jbuilder.new
623
- json.null!
624
- assert_raise(Jbuilder::NullError) { json.foo 'bar' }
892
+ test 'throws NullError when trying to add properties to null using block syntax' do
893
+ assert_raise Jbuilder::NullError do
894
+ jbuild do |json|
895
+ json.author do
896
+ json.null!
897
+ end
898
+
899
+ json.author do
900
+ json.name "Pavel"
901
+ end
902
+ end
903
+ end
904
+ end
905
+
906
+ test "throws MergeError when trying to merge array with non-empty hash" do
907
+ assert_raise Jbuilder::MergeError do
908
+ jbuild do |json|
909
+ json.name "Daniel"
910
+ json.merge! []
911
+ end
912
+ end
913
+ end
914
+
915
+ test "throws MergeError when trying to merge hash with array" do
916
+ assert_raise Jbuilder::MergeError do
917
+ jbuild do |json|
918
+ json.array!
919
+ json.merge!({})
920
+ end
921
+ end
922
+ end
923
+
924
+ test "throws MergeError when trying to merge invalid objects" do
925
+ assert_raise Jbuilder::MergeError do
926
+ jbuild do |json|
927
+ json.name "Daniel"
928
+ json.merge! "Nope"
929
+ end
930
+ end
931
+ end
932
+
933
+ if RUBY_VERSION >= "2.2.10"
934
+ test "respects JSON encoding customizations" do
935
+ # Active Support overrides Time#as_json for custom formatting.
936
+ # Ensure we call #to_json on the final attributes instead of JSON.dump.
937
+ result = JSON.load(Jbuilder.encode { |json| json.time Time.parse("2018-05-13 11:51:00.485 -0400") })
938
+ assert_equal "2018-05-13T11:51:00.485-04:00", result["time"]
939
+ end
625
940
  end
626
941
  end