jbuilder 2.0.6 → 2.11.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) 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 -12
  7. data/MIT-LICENSE +1 -1
  8. data/README.md +171 -45
  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 +20 -6
  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 +16 -20
  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 +1 -1
  27. data/lib/jbuilder/errors.rb +24 -0
  28. data/lib/jbuilder/jbuilder.rb +7 -0
  29. data/lib/jbuilder/jbuilder_template.rb +213 -65
  30. data/lib/jbuilder/key_formatter.rb +34 -0
  31. data/lib/jbuilder/railtie.rb +31 -6
  32. data/lib/jbuilder.rb +148 -114
  33. data/test/jbuilder_dependency_tracker_test.rb +3 -4
  34. data/test/jbuilder_generator_test.rb +31 -4
  35. data/test/jbuilder_template_test.rb +313 -195
  36. data/test/jbuilder_test.rb +615 -219
  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 +38 -23
  41. data/.travis.yml +0 -21
  42. data/CHANGELOG.md +0 -89
  43. data/Gemfile.old +0 -14
@@ -1,8 +1,11 @@
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
 
5
+ def jbuild(*args, &block)
6
+ Jbuilder.new(*args, &block).attributes!
7
+ end
8
+
6
9
  Comment = Struct.new(:content, :id)
7
10
 
8
11
  class NonEnumerable
@@ -10,223 +13,344 @@ class NonEnumerable
10
13
  @collection = collection
11
14
  end
12
15
 
13
- def map(&block)
14
- @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
15
26
  end
16
27
  end
17
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
47
+ end
48
+ end
49
+
50
+
18
51
  class JbuilderTest < ActiveSupport::TestCase
52
+ teardown do
53
+ Jbuilder.send :class_variable_set, '@@key_formatter', nil
54
+ end
55
+
19
56
  test 'single key' do
20
- json = Jbuilder.encode do |json|
57
+ result = jbuild do |json|
21
58
  json.content 'hello'
22
59
  end
23
60
 
24
- assert_equal 'hello', MultiJson.load(json)['content']
61
+ assert_equal 'hello', result['content']
25
62
  end
26
63
 
27
64
  test 'single key with false value' do
28
- json = Jbuilder.encode do |json|
65
+ result = jbuild do |json|
29
66
  json.content false
30
67
  end
31
68
 
32
- assert_equal false, MultiJson.load(json)['content']
69
+ assert_equal false, result['content']
33
70
  end
34
71
 
35
72
  test 'single key with nil value' do
36
- json = Jbuilder.encode do |json|
73
+ result = jbuild do |json|
37
74
  json.content nil
38
75
  end
39
76
 
40
- assert MultiJson.load(json).has_key?('content')
41
- assert_equal nil, MultiJson.load(json)['content']
77
+ assert result.has_key?('content')
78
+ assert_nil result['content']
42
79
  end
43
80
 
44
81
  test 'multiple keys' do
45
- json = Jbuilder.encode do |json|
82
+ result = jbuild do |json|
46
83
  json.title 'hello'
47
84
  json.content 'world'
48
85
  end
49
86
 
50
- parsed = MultiJson.load(json)
51
- assert_equal 'hello', parsed['title']
52
- assert_equal 'world', parsed['content']
87
+ assert_equal 'hello', result['title']
88
+ assert_equal 'world', result['content']
53
89
  end
54
90
 
55
91
  test 'extracting from object' do
56
92
  person = Struct.new(:name, :age).new('David', 32)
57
93
 
58
- json = Jbuilder.encode do |json|
94
+ result = jbuild do |json|
59
95
  json.extract! person, :name, :age
60
96
  end
61
97
 
62
- parsed = MultiJson.load(json)
63
- assert_equal 'David', parsed['name']
64
- assert_equal 32, parsed['age']
98
+ assert_equal 'David', result['name']
99
+ assert_equal 32, result['age']
65
100
  end
66
101
 
67
- test 'extracting from object using call style for 1.9' do
102
+ test 'extracting from object using call style' do
68
103
  person = Struct.new(:name, :age).new('David', 32)
69
104
 
70
- json = Jbuilder.encode do |json|
105
+ result = jbuild do |json|
71
106
  json.(person, :name, :age)
72
107
  end
73
108
 
74
- parsed = MultiJson.load(json)
75
- assert_equal 'David', parsed['name']
76
- assert_equal 32, parsed['age']
109
+ assert_equal 'David', result['name']
110
+ assert_equal 32, result['age']
77
111
  end
78
112
 
79
113
  test 'extracting from hash' do
80
114
  person = {:name => 'Jim', :age => 34}
81
115
 
82
- json = Jbuilder.encode do |json|
116
+ result = jbuild do |json|
83
117
  json.extract! person, :name, :age
84
118
  end
85
119
 
86
- parsed = MultiJson.load(json)
87
- assert_equal 'Jim', parsed['name']
88
- assert_equal 34, parsed['age']
120
+ assert_equal 'Jim', result['name']
121
+ assert_equal 34, result['age']
89
122
  end
90
123
 
91
124
  test 'nesting single child with block' do
92
- json = Jbuilder.encode do |json|
125
+ result = jbuild do |json|
93
126
  json.author do
94
127
  json.name 'David'
95
128
  json.age 32
96
129
  end
97
130
  end
98
131
 
99
- parsed = MultiJson.load(json)
100
- assert_equal 'David', parsed['author']['name']
101
- 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
102
230
  end
103
231
 
104
232
  test 'nesting multiple children with block' do
105
- json = Jbuilder.encode do |json|
233
+ result = jbuild do |json|
106
234
  json.comments do
107
235
  json.child! { json.content 'hello' }
108
236
  json.child! { json.content 'world' }
109
237
  end
110
238
  end
111
239
 
112
- parsed = MultiJson.load(json)
113
- assert_equal 'hello', parsed['comments'].first['content']
114
- assert_equal 'world', parsed['comments'].second['content']
240
+ assert_equal 'hello', result['comments'].first['content']
241
+ assert_equal 'world', result['comments'].second['content']
115
242
  end
116
243
 
117
244
  test 'nesting single child with inline extract' do
118
- person = Class.new do
119
- attr_reader :name, :age
120
-
121
- def initialize(name, age)
122
- @name, @age = name, age
123
- end
124
- end.new('David', 32)
245
+ person = Person.new('David', 32)
125
246
 
126
- json = Jbuilder.encode do |json|
247
+ result = jbuild do |json|
127
248
  json.author person, :name, :age
128
249
  end
129
250
 
130
- parsed = MultiJson.load(json)
131
- assert_equal 'David', parsed['author']['name']
132
- assert_equal 32, parsed['author']['age']
251
+ assert_equal 'David', result['author']['name']
252
+ assert_equal 32, result['author']['age']
133
253
  end
134
254
 
135
255
  test 'nesting multiple children from array' do
136
256
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
137
257
 
138
- json = Jbuilder.encode do |json|
258
+ result = jbuild do |json|
139
259
  json.comments comments, :content
140
260
  end
141
261
 
142
- parsed = MultiJson.load(json)
143
- assert_equal ['content'], parsed['comments'].first.keys
144
- assert_equal 'hello', parsed['comments'].first['content']
145
- 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']
146
265
  end
147
266
 
148
267
  test 'nesting multiple children from array when child array is empty' do
149
268
  comments = []
150
269
 
151
- json = Jbuilder.encode do |json|
270
+ result = jbuild do |json|
152
271
  json.name 'Parent'
153
272
  json.comments comments, :content
154
273
  end
155
274
 
156
- parsed = MultiJson.load(json)
157
- assert_equal 'Parent', parsed['name']
158
- assert_equal [], parsed['comments']
275
+ assert_equal 'Parent', result['name']
276
+ assert_equal [], result['comments']
159
277
  end
160
278
 
161
279
  test 'nesting multiple children from array with inline loop' do
162
280
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
163
281
 
164
- json = Jbuilder.encode do |json|
282
+ result = jbuild do |json|
165
283
  json.comments comments do |comment|
166
284
  json.content comment.content
167
285
  end
168
286
  end
169
287
 
170
- parsed = MultiJson.load(json)
171
- assert_equal ['content'], parsed['comments'].first.keys
172
- assert_equal 'hello', parsed['comments'].first['content']
173
- 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']
174
291
  end
175
292
 
176
293
  test 'handles nil-collections as empty arrays' do
177
- json = Jbuilder.encode do |json|
294
+ result = jbuild do |json|
178
295
  json.comments nil do |comment|
179
296
  json.content comment.content
180
297
  end
181
298
  end
182
299
 
183
- assert_equal [], MultiJson.load(json)['comments']
300
+ assert_equal [], result['comments']
184
301
  end
185
302
 
186
303
  test 'nesting multiple children from a non-Enumerable that responds to #map' do
187
304
  comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
188
305
 
189
- json = Jbuilder.encode do |json|
306
+ result = jbuild do |json|
190
307
  json.comments comments, :content
191
308
  end
192
309
 
193
- parsed = MultiJson.load(json)
194
- assert_equal ['content'], parsed['comments'].first.keys
195
- assert_equal 'hello', parsed['comments'].first['content']
196
- 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']
197
313
  end
198
314
 
199
- 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
200
316
  comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
201
317
 
202
- json = Jbuilder.encode do |json|
318
+ result = jbuild do |json|
203
319
  json.comments comments do |comment|
204
320
  json.content comment.content
205
321
  end
206
322
  end
207
323
 
208
- parsed = MultiJson.load(json)
209
- assert_equal ['content'], parsed['comments'].first.keys
210
- assert_equal 'hello', parsed['comments'].first['content']
211
- 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']
327
+ end
328
+
329
+ test 'array! casts array-like objects to array before merging' do
330
+ wrapped_array = VeryBasicWrapper.new(%w[foo bar])
331
+
332
+ result = jbuild do |json|
333
+ json.array! wrapped_array
334
+ end
335
+
336
+ assert_equal %w[foo bar], result
212
337
  end
213
338
 
214
339
  test 'nesting multiple children from array with inline loop on root' do
215
340
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
216
341
 
217
- json = Jbuilder.encode do |json|
342
+ result = jbuild do |json|
218
343
  json.call(comments) do |comment|
219
344
  json.content comment.content
220
345
  end
221
346
  end
222
347
 
223
- parsed = MultiJson.load(json)
224
- assert_equal 'hello', parsed.first['content']
225
- assert_equal 'world', parsed.second['content']
348
+ assert_equal 'hello', result.first['content']
349
+ assert_equal 'world', result.second['content']
226
350
  end
227
351
 
228
352
  test 'array nested inside nested hash' do
229
- json = Jbuilder.encode do |json|
353
+ result = jbuild do |json|
230
354
  json.author do
231
355
  json.name 'David'
232
356
  json.age 32
@@ -238,13 +362,12 @@ class JbuilderTest < ActiveSupport::TestCase
238
362
  end
239
363
  end
240
364
 
241
- parsed = MultiJson.load(json)
242
- assert_equal 'hello', parsed['author']['comments'].first['content']
243
- 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']
244
367
  end
245
368
 
246
369
  test 'array nested inside array' do
247
- json = Jbuilder.encode do |json|
370
+ result = jbuild do |json|
248
371
  json.comments do
249
372
  json.child! do
250
373
  json.authors do
@@ -256,12 +379,13 @@ class JbuilderTest < ActiveSupport::TestCase
256
379
  end
257
380
  end
258
381
 
259
- assert_equal 'david', MultiJson.load(json)['comments'].first['authors'].first['name']
382
+ assert_equal 'david', result['comments'].first['authors'].first['name']
260
383
  end
261
384
 
262
385
  test 'directly set an array nested in another array' do
263
386
  data = [ { :department => 'QA', :not_in_json => 'hello', :names => ['John', 'David'] } ]
264
- json = Jbuilder.encode do |json|
387
+
388
+ result = jbuild do |json|
265
389
  json.array! data do |object|
266
390
  json.department object[:department]
267
391
  json.names do
@@ -270,276 +394,548 @@ class JbuilderTest < ActiveSupport::TestCase
270
394
  end
271
395
  end
272
396
 
273
- assert_equal 'David', MultiJson.load(json)[0]['names'].last
274
- assert_not_equal 'hello', MultiJson.load(json)[0]['not_in_json']
397
+ assert_equal 'David', result[0]['names'].last
398
+ assert !result[0].key?('not_in_json')
275
399
  end
276
400
 
277
401
  test 'nested jbuilder objects' do
278
- to_nest = Jbuilder.new
279
- to_nest.nested_value 'Nested Test'
280
- json = Jbuilder.encode do |json|
402
+ to_nest = Jbuilder.new{ |json| json.nested_value 'Nested Test' }
403
+
404
+ result = jbuild do |json|
281
405
  json.value 'Test'
282
406
  json.nested to_nest
283
407
  end
284
408
 
285
- result = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
286
- assert_equal result, MultiJson.load(json)
409
+ expected = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
410
+ assert_equal expected, result
287
411
  end
288
412
 
289
413
  test 'nested jbuilder object via set!' do
290
- to_nest = Jbuilder.new
291
- to_nest.nested_value 'Nested Test'
292
- json = Jbuilder.encode do |json|
414
+ to_nest = Jbuilder.new{ |json| json.nested_value 'Nested Test' }
415
+
416
+ result = jbuild do |json|
293
417
  json.value 'Test'
294
418
  json.set! :nested, to_nest
295
419
  end
296
420
 
297
- result = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
298
- assert_equal result, MultiJson.load(json)
421
+ expected = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
422
+ assert_equal expected, result
299
423
  end
300
424
 
301
425
  test 'top-level array' do
302
426
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
303
427
 
304
- json = Jbuilder.encode do |json|
305
- json.array!(comments) do |comment|
428
+ result = jbuild do |json|
429
+ json.array! comments do |comment|
430
+ json.content comment.content
431
+ end
432
+ end
433
+
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
306
443
  json.content comment.content
307
444
  end
308
445
  end
309
446
 
310
- parsed = MultiJson.load(json)
311
- assert_equal 'hello', parsed.first['content']
312
- assert_equal 'world', parsed.second['content']
447
+ assert_equal 2, result.length
448
+ assert_equal 'hello', result.first['content']
449
+ assert_equal 'world', result.second['content']
313
450
  end
314
451
 
315
452
  test 'extract attributes directly from array' do
316
453
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
317
454
 
318
- json = Jbuilder.encode do |json|
455
+ result = jbuild do |json|
319
456
  json.array! comments, :content, :id
320
457
  end
321
458
 
322
- parsed = MultiJson.load(json)
323
- assert_equal 'hello', parsed.first['content']
324
- assert_equal 1, parsed.first['id']
325
- assert_equal 'world', parsed.second['content']
326
- 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']
327
463
  end
328
464
 
329
465
  test 'empty top-level array' do
330
466
  comments = []
331
467
 
332
- json = Jbuilder.encode do |json|
333
- json.array!(comments) do |comment|
468
+ result = jbuild do |json|
469
+ json.array! comments do |comment|
334
470
  json.content comment.content
335
471
  end
336
472
  end
337
473
 
338
- assert_equal [], MultiJson.load(json)
474
+ assert_equal [], result
339
475
  end
340
476
 
341
477
  test 'dynamically set a key/value' do
342
- json = Jbuilder.encode do |json|
478
+ result = jbuild do |json|
343
479
  json.set! :each, 'stuff'
344
480
  end
345
481
 
346
- assert_equal 'stuff', MultiJson.load(json)['each']
482
+ assert_equal 'stuff', result['each']
347
483
  end
348
484
 
349
485
  test 'dynamically set a key/nested child with block' do
350
- json = Jbuilder.encode do |json|
351
- json.set!(:author) do
486
+ result = jbuild do |json|
487
+ json.set! :author do
352
488
  json.name 'David'
353
489
  json.age 32
354
490
  end
355
491
  end
356
492
 
357
- parsed = MultiJson.load(json)
358
- assert_equal 'David', parsed['author']['name']
359
- assert_equal 32, parsed['author']['age']
493
+ assert_equal 'David', result['author']['name']
494
+ assert_equal 32, result['author']['age']
360
495
  end
361
496
 
362
497
  test 'dynamically sets a collection' do
363
498
  comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
364
499
 
365
- json = Jbuilder.encode do |json|
500
+ result = jbuild do |json|
366
501
  json.set! :comments, comments, :content
367
502
  end
368
503
 
369
- parsed = MultiJson.load(json)
370
- assert_equal ['content'], parsed['comments'].first.keys
371
- assert_equal 'hello', parsed['comments'].first['content']
372
- 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']
373
507
  end
374
508
 
375
509
  test 'query like object' do
376
- class Person
377
- attr_reader :name, :age
378
-
379
- def initialize(name, age)
380
- @name, @age = name, age
381
- end
382
- end
383
- class RelationMock
384
- include Enumerable
385
-
386
- def each(&block)
387
- [Person.new('Bob', 30), Person.new('Frank', 50)].each(&block)
388
- end
389
- def empty?
390
- false
391
- end
392
- end
393
-
394
- result = Jbuilder.encode do |json|
510
+ result = jbuild do |json|
395
511
  json.relations RelationMock.new, :name, :age
396
512
  end
397
513
 
398
- parsed = MultiJson.load(result)
399
- assert_equal 2, parsed['relations'].length
400
- assert_equal 'Bob', parsed['relations'][0]['name']
401
- 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']
402
517
  end
403
518
 
404
519
  test 'initialize via options hash' do
405
- jbuilder = Jbuilder.new(:key_formatter => 1, :ignore_nil => 2)
520
+ jbuilder = Jbuilder.new(key_formatter: 1, ignore_nil: 2)
406
521
  assert_equal 1, jbuilder.instance_eval{ @key_formatter }
407
522
  assert_equal 2, jbuilder.instance_eval{ @ignore_nil }
408
523
  end
409
524
 
410
525
  test 'key_format! with parameter' do
411
- json = Jbuilder.new
412
- json.key_format! :camelize => [:lower]
413
- json.camel_style 'for JS'
526
+ result = jbuild do |json|
527
+ json.key_format! camelize: [:lower]
528
+ json.camel_style 'for JS'
529
+ end
414
530
 
415
- assert_equal ['camelStyle'], json.attributes!.keys
531
+ assert_equal ['camelStyle'], result.keys
416
532
  end
417
533
 
418
534
  test 'key_format! with parameter not as an array' do
419
- json = Jbuilder.new
420
- json.key_format! :camelize => :lower
421
- json.camel_style 'for JS'
535
+ result = jbuild do |json|
536
+ json.key_format! :camelize => :lower
537
+ json.camel_style 'for JS'
538
+ end
422
539
 
423
- assert_equal ['camelStyle'], json.attributes!.keys
540
+ assert_equal ['camelStyle'], result.keys
424
541
  end
425
542
 
426
543
  test 'key_format! propagates to child elements' do
427
- json = Jbuilder.new
428
- json.key_format! :upcase
429
- json.level1 'one'
430
- json.level2 do
431
- 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
432
550
  end
433
551
 
434
- result = json.attributes!
435
552
  assert_equal 'one', result['LEVEL1']
436
553
  assert_equal 'two', result['LEVEL2']['VALUE']
437
554
  end
438
555
 
439
556
  test 'key_format! resets after child element' do
440
- json = Jbuilder.new
441
- json.level2 do
442
- json.key_format! :upcase
443
- 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'
444
563
  end
445
- json.level1 'one'
446
564
 
447
- result = json.attributes!
448
565
  assert_equal 'two', result['level2']['VALUE']
449
566
  assert_equal 'one', result['level1']
450
567
  end
451
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
+
452
599
  test 'key_format! with no parameter' do
453
- json = Jbuilder.new
454
- json.key_format! :upcase
455
- json.lower 'Value'
600
+ result = jbuild do |json|
601
+ json.key_format! :upcase
602
+ json.lower 'Value'
603
+ end
456
604
 
457
- assert_equal ['LOWER'], json.attributes!.keys
605
+ assert_equal ['LOWER'], result.keys
458
606
  end
459
607
 
460
608
  test 'key_format! with multiple steps' do
461
- json = Jbuilder.new
462
- json.key_format! :upcase, :pluralize
463
- json.pill ''
609
+ result = jbuild do |json|
610
+ json.key_format! :upcase, :pluralize
611
+ json.pill 'foo'
612
+ end
464
613
 
465
- assert_equal ['PILLs'], json.attributes!.keys
614
+ assert_equal ['PILLs'], result.keys
466
615
  end
467
616
 
468
617
  test 'key_format! with lambda/proc' do
469
- json = Jbuilder.new
470
- json.key_format! lambda { |key| key + ' and friends' }
471
- json.oats ''
618
+ result = jbuild do |json|
619
+ json.key_format! ->(key){ key + ' and friends' }
620
+ json.oats 'foo'
621
+ end
472
622
 
473
- assert_equal ['oats and friends'], json.attributes!.keys
623
+ assert_equal ['oats and friends'], result.keys
474
624
  end
475
625
 
476
- test 'default key_format!' do
477
- Jbuilder.key_format :camelize => :lower
478
- json = Jbuilder.new
479
- 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
480
632
 
481
- assert_equal ['camelStyle'], json.attributes!.keys
482
- Jbuilder.send(:class_variable_set, '@@key_formatter', Jbuilder::KeyFormatter.new)
633
+ assert_equal %i[first_name last_name], result['allNames'].keys
483
634
  end
484
635
 
485
- test 'do not use default key formatter directly' do
486
- json = Jbuilder.new
487
- 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
646
+
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
488
780
 
489
- assert_equal [], Jbuilder.send(:class_variable_get, '@@key_formatter').instance_variable_get('@cache').keys
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
490
793
  end
491
794
 
492
795
  test 'ignore_nil! without a parameter' do
493
- json = Jbuilder.new
494
- json.ignore_nil!
495
- json.test nil
796
+ result = jbuild do |json|
797
+ json.ignore_nil!
798
+ json.test nil
799
+ end
496
800
 
497
- assert_equal [], json.attributes!.keys
801
+ assert_empty result.keys
498
802
  end
499
803
 
500
804
  test 'ignore_nil! with parameter' do
501
- json = Jbuilder.new
502
- json.ignore_nil! true
503
- json.name 'Bob'
504
- json.dne nil
805
+ result = jbuild do |json|
806
+ json.ignore_nil! true
807
+ json.name 'Bob'
808
+ json.dne nil
809
+ end
505
810
 
506
- assert_equal ['name'], json.attributes!.keys
811
+ assert_equal ['name'], result.keys
507
812
 
508
- json = Jbuilder.new
509
- json.ignore_nil! false
510
- json.name 'Bob'
511
- json.dne nil
813
+ result = jbuild do |json|
814
+ json.ignore_nil! false
815
+ json.name 'Bob'
816
+ json.dne nil
817
+ end
512
818
 
513
- assert_equal ['name', 'dne'], json.attributes!.keys
819
+ assert_equal ['name', 'dne'], result.keys
514
820
  end
515
821
 
516
822
  test 'default ignore_nil!' do
517
823
  Jbuilder.ignore_nil
518
- json = Jbuilder.new
519
- json.name 'Bob'
520
- json.dne nil
521
824
 
522
- 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
523
831
  Jbuilder.send(:class_variable_set, '@@ignore_nil', false)
524
832
  end
525
833
 
526
834
  test 'nil!' do
527
- json = Jbuilder.new
528
- json.key 'value'
529
- json.nil!
530
- assert_nil json.attributes!
835
+ result = jbuild do |json|
836
+ json.key 'value'
837
+ json.nil!
838
+ end
839
+
840
+ assert_nil result
531
841
  end
532
842
 
533
843
  test 'null!' do
534
- json = Jbuilder.new
535
- json.key 'value'
536
- json.null!
537
- 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?
538
872
  end
539
873
 
540
- test 'throws meaningfull error when on trying to add properties to null' do
541
- json = Jbuilder.new
542
- json.null!
543
- assert_raise(Jbuilder::NullError) { json.foo 'bar' }
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
890
+ end
891
+
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
544
940
  end
545
941
  end