jbuilder 2.13.0 → 2.15.1

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/lib/jbuilder.rb CHANGED
@@ -1,75 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'jbuilder/jbuilder'
3
5
  require 'jbuilder/blank'
4
6
  require 'jbuilder/key_formatter'
5
7
  require 'jbuilder/errors'
6
- require 'jbuilder/version'
7
8
  require 'json'
8
9
  require 'active_support/core_ext/hash/deep_merge'
10
+ require 'active_support/core_ext/object/blank'
9
11
 
10
12
  class Jbuilder
11
13
  @@key_formatter = nil
12
14
  @@ignore_nil = false
13
15
  @@deep_format_keys = false
14
16
 
15
- def initialize(options = {})
17
+ def initialize(
18
+ key_formatter: @@key_formatter,
19
+ ignore_nil: @@ignore_nil,
20
+ deep_format_keys: @@deep_format_keys,
21
+ &block
22
+ )
16
23
  @attributes = {}
24
+ @key_formatter = key_formatter
25
+ @ignore_nil = ignore_nil
26
+ @deep_format_keys = deep_format_keys
17
27
 
18
- @key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
19
- @ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
20
- @deep_format_keys = options.fetch(:deep_format_keys, @@deep_format_keys)
21
-
22
- yield self if ::Kernel.block_given?
28
+ yield self if block
23
29
  end
24
30
 
25
31
  # Yields a builder and automatically turns the result into a JSON string
26
- def self.encode(*args, &block)
27
- new(*args, &block).target!
32
+ def self.encode(...)
33
+ new(...).target!
28
34
  end
29
35
 
30
- BLANK = Blank.new
36
+ BLANK = Blank.new.freeze
37
+ EMPTY_ARRAY = [].freeze
38
+ private_constant :BLANK, :EMPTY_ARRAY
31
39
 
32
40
  def set!(key, value = BLANK, *args, &block)
33
- result = if ::Kernel.block_given?
34
- if !_blank?(value)
35
- # json.comments @post.comments { |comment| ... }
36
- # { "comments": [ { ... }, { ... } ] }
37
- _scope{ array! value, &block }
38
- else
39
- # json.comments { ... }
40
- # { "comments": ... }
41
- _merge_block(key){ yield self }
42
- end
43
- elsif args.empty?
44
- if ::Jbuilder === value
45
- # json.age 32
46
- # json.person another_jbuilder
47
- # { "age": 32, "person": { ... }
48
- _format_keys(value.attributes!)
49
- else
50
- # json.age 32
51
- # { "age": 32 }
52
- _format_keys(value)
53
- end
54
- elsif _is_collection?(value)
55
- # json.comments @post.comments, :content, :created_at
56
- # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
57
- _scope{ array! value, *args }
58
- else
59
- # json.author @post.creator, :name, :email_address
60
- # { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
61
- _merge_block(key){ extract! value, *args }
62
- end
63
-
64
- _set_value key, result
65
- end
66
-
67
- def method_missing(*args, &block)
68
- if ::Kernel.block_given?
69
- set!(*args, &block)
70
- else
71
- set!(*args)
72
- end
41
+ _set(key, value, args, &block)
73
42
  end
74
43
 
75
44
  # Specifies formatting to be applied to the key. Passing in a name of a function
@@ -100,13 +69,13 @@ class Jbuilder
100
69
  #
101
70
  # { "_first_name": "David" }
102
71
  #
103
- def key_format!(*args)
104
- @key_formatter = KeyFormatter.new(*args)
72
+ def key_format!(...)
73
+ @key_formatter = KeyFormatter.new(...)
105
74
  end
106
75
 
107
76
  # Same as the instance method key_format! except sets the default.
108
- def self.key_format(*args)
109
- @@key_formatter = KeyFormatter.new(*args)
77
+ def self.key_format(...)
78
+ @@key_formatter = KeyFormatter.new(...)
110
79
  end
111
80
 
112
81
  # If you want to skip adding nil values to your JSON hash. This is useful
@@ -209,18 +178,8 @@ class Jbuilder
209
178
  # json.array! [1, 2, 3]
210
179
  #
211
180
  # [1,2,3]
212
- def array!(collection = [], *attributes, &block)
213
- array = if collection.nil?
214
- []
215
- elsif ::Kernel.block_given?
216
- _map_collection(collection, &block)
217
- elsif attributes.any?
218
- _map_collection(collection) { |element| extract! element, *attributes }
219
- else
220
- _format_keys(collection.to_a)
221
- end
222
-
223
- @attributes = _merge_values(@attributes, array)
181
+ def array!(collection = EMPTY_ARRAY, *attributes, &block)
182
+ _array collection, attributes, &block
224
183
  end
225
184
 
226
185
  # Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
@@ -241,18 +200,14 @@ class Jbuilder
241
200
  #
242
201
  # json.(@person, :name, :age)
243
202
  def extract!(object, *attributes)
244
- if ::Hash === object
245
- _extract_hash_values(object, attributes)
246
- else
247
- _extract_method_values(object, attributes)
248
- end
203
+ _extract object, attributes
249
204
  end
250
205
 
251
206
  def call(object, *attributes, &block)
252
- if ::Kernel.block_given?
253
- array! object, &block
207
+ if block
208
+ _array object, &block
254
209
  else
255
- extract! object, *attributes
210
+ _extract object, attributes
256
211
  end
257
212
  end
258
213
 
@@ -279,8 +234,68 @@ class Jbuilder
279
234
  @attributes.to_json
280
235
  end
281
236
 
237
+ alias_method :method_missing, :set!
238
+ private :method_missing
239
+
282
240
  private
283
241
 
242
+ def _set(key, value = BLANK, attributes = nil, &block)
243
+ result = if block
244
+ if _blank?(value)
245
+ # json.comments { ... }
246
+ # { "comments": ... }
247
+ _merge_block key, &block
248
+ else
249
+ # json.comments @post.comments { |comment| ... }
250
+ # { "comments": [ { ... }, { ... } ] }
251
+ _scope { _array value, &block }
252
+ end
253
+ elsif attributes.empty?
254
+ if ::Jbuilder === value
255
+ # json.age 32
256
+ # json.person another_jbuilder
257
+ # { "age": 32, "person": { ... }
258
+ _format_keys(value.attributes!)
259
+ else
260
+ # json.age 32
261
+ # { "age": 32 }
262
+ _format_keys(value)
263
+ end
264
+ elsif _is_collection?(value)
265
+ # json.comments @post.comments, :content, :created_at
266
+ # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
267
+ _scope { _array value, attributes }
268
+ else
269
+ # json.author @post.creator, :name, :email_address
270
+ # { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
271
+ _merge_block(key) { _extract value, attributes }
272
+ end
273
+
274
+ _set_value key, result
275
+ end
276
+
277
+ def _array(collection = EMPTY_ARRAY, attributes = nil, &block)
278
+ array = if collection.nil?
279
+ EMPTY_ARRAY
280
+ elsif block
281
+ _map_collection(collection, &block)
282
+ elsif attributes.present?
283
+ _map_collection(collection) { |element| _extract element, attributes }
284
+ else
285
+ _format_keys(collection.to_a)
286
+ end
287
+
288
+ @attributes = _merge_values(@attributes, array)
289
+ end
290
+
291
+ def _extract(object, attributes)
292
+ if ::Hash === object
293
+ _extract_hash_values(object, attributes)
294
+ else
295
+ _extract_method_values(object, attributes)
296
+ end
297
+ end
298
+
284
299
  def _extract_hash_values(object, attributes)
285
300
  attributes.each{ |key| _set_value key, _format_keys(object.fetch(key)) }
286
301
  end
@@ -311,7 +326,13 @@ class Jbuilder
311
326
  end
312
327
 
313
328
  def _key(key)
314
- @key_formatter ? @key_formatter.format(key) : key.to_s
329
+ if @key_formatter
330
+ @key_formatter.format(key)
331
+ elsif key.is_a?(::Symbol)
332
+ key.name
333
+ else
334
+ key.to_s
335
+ end
315
336
  end
316
337
 
317
338
  def _format_keys(hash_or_array)
@@ -335,9 +356,11 @@ class Jbuilder
335
356
  end
336
357
 
337
358
  def _map_collection(collection)
338
- collection.map do |element|
359
+ collection = collection.map do |element|
339
360
  _scope{ yield element }
340
- end - [BLANK]
361
+ end
362
+ collection.delete(BLANK)
363
+ collection
341
364
  end
342
365
 
343
366
  def _scope
@@ -350,16 +373,12 @@ class Jbuilder
350
373
  end
351
374
 
352
375
  def _is_collection?(object)
353
- _object_respond_to?(object, :map, :count) && !(::Struct === object)
376
+ object.respond_to?(:map) && object.respond_to?(:count) && !(::Struct === object)
354
377
  end
355
378
 
356
379
  def _blank?(value=@attributes)
357
380
  BLANK == value
358
381
  end
359
-
360
- def _object_respond_to?(object, *methods)
361
- methods.all?{ |m| object.respond_to?(m) }
362
- end
363
382
  end
364
383
 
365
384
  require 'jbuilder/railtie' if defined?(Rails)
@@ -56,15 +56,13 @@ class JbuilderGeneratorTest < Rails::Generators::TestCase
56
56
  end
57
57
  end
58
58
 
59
- if Rails::VERSION::MAJOR >= 6
60
- test 'handles virtual attributes' do
61
- run_generator %w(Message content:rich_text video:attachment photos:attachments)
59
+ test 'handles virtual attributes' do
60
+ run_generator %w(Message content:rich_text video:attachment photos:attachments)
62
61
 
63
- assert_file 'app/views/messages/_message.json.jbuilder' do |content|
64
- assert_match %r{json\.content message\.content\.to_s}, content
65
- assert_match %r{json\.video url_for\(message\.video\)}, content
66
- assert_match %r{json\.photos do\n json\.array!\(message\.photos\) do \|photo\|\n json\.id photo\.id\n json\.url url_for\(photo\)\n end\nend}, content
67
- end
62
+ assert_file 'app/views/messages/_message.json.jbuilder' do |content|
63
+ assert_match %r{json\.content message\.content\.to_s}, content
64
+ assert_match %r{json\.video url_for\(message\.video\)}, content
65
+ assert_match %r{json\.photos do\n json\.array!\(message\.photos\) do \|photo\|\n json\.id photo\.id\n json\.url url_for\(photo\)\n end\nend}, content
68
66
  end
69
67
  end
70
68
  end
@@ -4,6 +4,7 @@ require "action_view/testing/resolvers"
4
4
  class JbuilderTemplateTest < ActiveSupport::TestCase
5
5
  POST_PARTIAL = <<-JBUILDER
6
6
  json.extract! post, :id, :body
7
+ json.title post.title if local_assigns.fetch(:include_title, false)
7
8
  json.author do
8
9
  first_name, last_name = post.author_name.split(nil, 2)
9
10
  json.first_name first_name
@@ -17,6 +18,7 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
17
18
 
18
19
  RACER_PARTIAL = <<-JBUILDER
19
20
  json.extract! racer, :id, :name
21
+ json.highlighted local_assigns.fetch(:highlighted, false)
20
22
  JBUILDER
21
23
 
22
24
  PARTIALS = {
@@ -30,7 +32,7 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
30
32
  }
31
33
 
32
34
  AUTHORS = [ "David Heinemeier Hansson", "Pavel Pravosud" ].cycle
33
- POSTS = (1..10).collect { |i| Post.new(i, "Post ##{i}", AUTHORS.next) }
35
+ POSTS = (1..10).collect { |i| Post.new(i, "Title #{i}", "Post ##{i}", AUTHORS.next) }
34
36
 
35
37
  setup { Rails.cache.clear }
36
38
 
@@ -39,6 +41,11 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
39
41
  assert_equal "hello", result["content"]
40
42
  end
41
43
 
44
+ test "method_missing can be used as a key" do
45
+ result = render('json.method_missing "hello"')
46
+ assert_equal({ "method_missing" => "hello" }, result)
47
+ end
48
+
42
49
  test "partial by name with top-level locals" do
43
50
  result = render('json.partial! "partial", content: "hello"')
44
51
  assert_equal "hello", result["content"]
@@ -49,6 +56,17 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
49
56
  assert_equal "hello", result["content"]
50
57
  end
51
58
 
59
+ test "partial by name with hash value omission (punning) as last statement [3.1+]" do
60
+ major, minor, _ = RUBY_VERSION.split(".").map(&:to_i)
61
+ return unless (major == 3 && minor >= 1) || major > 3
62
+
63
+ result = render(<<-JBUILDER)
64
+ content = "hello"
65
+ json.partial! "partial", content:
66
+ JBUILDER
67
+ assert_equal "hello", result["content"]
68
+ end
69
+
52
70
  test "partial by options containing nested locals" do
53
71
  result = render('json.partial! partial: "partial", locals: { content: "hello" }')
54
72
  assert_equal "hello", result["content"]
@@ -65,6 +83,13 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
65
83
  assert_equal "Chris Harris", result["name"]
66
84
  end
67
85
 
86
+ test "partial for Active Model preserves extra locals" do
87
+ result = render('json.partial! @racer, highlighted: true', racer: Racer.new(123, "Chris Harris"))
88
+ assert_equal 123, result["id"]
89
+ assert_equal "Chris Harris", result["name"]
90
+ assert_equal true, result["highlighted"]
91
+ end
92
+
68
93
  test "partial collection by name with symbol local" do
69
94
  result = render('json.partial! "post", collection: @posts, as: :post', posts: POSTS)
70
95
  assert_equal 10, result.count
@@ -125,6 +150,18 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
125
150
  assert_equal [], render('json.array! @posts, partial: "post", as: :post', posts: nil)
126
151
  end
127
152
 
153
+ test "single partial under key" do
154
+ result = render('json.post @post, partial: "post", as: :post', post: POSTS.first)
155
+ assert_equal "Post #1", result["post"]["body"]
156
+ assert_equal "Heinemeier Hansson", result["post"]["author"]["last_name"]
157
+ assert_equal "David", result["post"]["author"]["first_name"]
158
+ end
159
+
160
+ test 'single partial under key with local' do
161
+ result = render('json.post @post, partial: "post", as: :post, include_title: true', post: POSTS.first)
162
+ assert_equal "Title 1", result["post"]["title"]
163
+ end
164
+
128
165
  test "array of partials under key" do
129
166
  result = render('json.posts @posts, partial: "post", as: :post', posts: POSTS)
130
167
  assert_equal 10, result["posts"].count
@@ -133,13 +170,19 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
133
170
  assert_equal "Pavel", result["posts"][5]["author"]["first_name"]
134
171
  end
135
172
 
173
+ test "array of partials under key with local" do
174
+ result = render('json.posts @posts, partial: "post", as: :post, include_title: true', posts: POSTS)
175
+ assert_equal "Title 1", result["posts"][0]["title"]
176
+ assert_equal "Title 2", result["posts"][1]["title"]
177
+ end
178
+
136
179
  test "empty array of partials under key from nil collection" do
137
180
  Jbuilder::CollectionRenderer.expects(:new).never
138
181
  result = render('json.posts @posts, partial: "post", as: :post', posts: nil)
139
182
  assert_equal [], result["posts"]
140
183
  end
141
184
 
142
- test "empty array of partials under key from an empy collection" do
185
+ test "empty array of partials under key from an empty collection" do
143
186
  Jbuilder::CollectionRenderer.expects(:new).never
144
187
  result = render('json.posts @posts, partial: "post", as: :post', posts: [])
145
188
  assert_equal [], result["posts"]
@@ -306,99 +349,97 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
306
349
  assert_equal "David", result["firstName"]
307
350
  end
308
351
 
309
- if JbuilderTemplate::CollectionRenderer.supported?
310
- test "returns an empty array for an empty collection" do
311
- Jbuilder::CollectionRenderer.expects(:new).never
312
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: [])
352
+ test "returns an empty array for an empty collection" do
353
+ Jbuilder::CollectionRenderer.expects(:new).never
354
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: [])
313
355
 
314
- # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
315
- assert_equal [], result
316
- end
356
+ # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
357
+ assert_equal [], result
358
+ end
317
359
 
318
- test "works with an enumerable object" do
319
- enumerable_class = Class.new do
320
- include Enumerable
360
+ test "works with an enumerable object" do
361
+ enumerable_class = Class.new do
362
+ include Enumerable
321
363
 
322
- def each(&block)
323
- [].each(&block)
324
- end
364
+ def each(&block)
365
+ [].each(&block)
325
366
  end
367
+ end
326
368
 
327
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: enumerable_class.new)
369
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: enumerable_class.new)
328
370
 
329
- # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
330
- assert_equal [], result
331
- end
371
+ # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
372
+ assert_equal [], result
373
+ end
332
374
 
333
- test "supports the cached: true option" do
334
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
335
-
336
- assert_equal 10, result.count
337
- assert_equal "Post #5", result[4]["body"]
338
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
339
- assert_equal "Pavel", result[5]["author"]["first_name"]
340
-
341
- expected = {
342
- "id" => 1,
343
- "body" => "Post #1",
344
- "author" => {
345
- "first_name" => "David",
346
- "last_name" => "Heinemeier Hansson"
347
- }
375
+ test "supports the cached: true option" do
376
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
377
+
378
+ assert_equal 10, result.count
379
+ assert_equal "Post #5", result[4]["body"]
380
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
381
+ assert_equal "Pavel", result[5]["author"]["first_name"]
382
+
383
+ expected = {
384
+ "id" => 1,
385
+ "body" => "Post #1",
386
+ "author" => {
387
+ "first_name" => "David",
388
+ "last_name" => "Heinemeier Hansson"
348
389
  }
390
+ }
349
391
 
350
- assert_equal expected, Rails.cache.read("post-1")
392
+ assert_equal expected, Rails.cache.read("post-1")
351
393
 
352
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
394
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
353
395
 
354
- assert_equal 10, result.count
355
- assert_equal "Post #5", result[4]["body"]
356
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
357
- assert_equal "Pavel", result[5]["author"]["first_name"]
358
- end
396
+ assert_equal 10, result.count
397
+ assert_equal "Post #5", result[4]["body"]
398
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
399
+ assert_equal "Pavel", result[5]["author"]["first_name"]
400
+ end
359
401
 
360
- test "supports the cached: ->() {} option" do
361
- result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
362
-
363
- assert_equal 10, result.count
364
- assert_equal "Post #5", result[4]["body"]
365
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
366
- assert_equal "Pavel", result[5]["author"]["first_name"]
367
-
368
- expected = {
369
- "id" => 1,
370
- "body" => "Post #1",
371
- "author" => {
372
- "first_name" => "David",
373
- "last_name" => "Heinemeier Hansson"
374
- }
375
- }
402
+ test "supports the cached: ->() {} option" do
403
+ result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
376
404
 
377
- assert_equal expected, Rails.cache.read("post-1/foo")
405
+ assert_equal 10, result.count
406
+ assert_equal "Post #5", result[4]["body"]
407
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
408
+ assert_equal "Pavel", result[5]["author"]["first_name"]
378
409
 
379
- result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
410
+ expected = {
411
+ "id" => 1,
412
+ "body" => "Post #1",
413
+ "author" => {
414
+ "first_name" => "David",
415
+ "last_name" => "Heinemeier Hansson"
416
+ }
417
+ }
380
418
 
381
- assert_equal 10, result.count
382
- assert_equal "Post #5", result[4]["body"]
383
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
384
- assert_equal "Pavel", result[5]["author"]["first_name"]
385
- end
419
+ assert_equal expected, Rails.cache.read("post-1/foo")
386
420
 
387
- test "raises an error on a render call with the :layout option" do
388
- error = assert_raises NotImplementedError do
389
- render('json.array! @posts, partial: "post", as: :post, layout: "layout"', posts: POSTS)
390
- end
421
+ result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
391
422
 
392
- assert_equal "The `:layout' option is not supported in collection rendering.", error.message
423
+ assert_equal 10, result.count
424
+ assert_equal "Post #5", result[4]["body"]
425
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
426
+ assert_equal "Pavel", result[5]["author"]["first_name"]
427
+ end
428
+
429
+ test "raises an error on a render call with the :layout option" do
430
+ error = assert_raises NotImplementedError do
431
+ render('json.array! @posts, partial: "post", as: :post, layout: "layout"', posts: POSTS)
393
432
  end
394
433
 
395
- test "raises an error on a render call with the :spacer_template option" do
396
- error = assert_raises NotImplementedError do
397
- render('json.array! @posts, partial: "post", as: :post, spacer_template: "template"', posts: POSTS)
398
- end
434
+ assert_equal "The `:layout' option is not supported in collection rendering.", error.message
435
+ end
399
436
 
400
- assert_equal "The `:spacer_template' option is not supported in collection rendering.", error.message
437
+ test "raises an error on a render call with the :spacer_template option" do
438
+ error = assert_raises NotImplementedError do
439
+ render('json.array! @posts, partial: "post", as: :post, spacer_template: "template"', posts: POSTS)
401
440
  end
441
+
442
+ assert_equal "The `:spacer_template' option is not supported in collection rendering.", error.message
402
443
  end
403
444
 
404
445
  private
@@ -416,12 +457,7 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
416
457
  lookup_context = ActionView::LookupContext.new([ resolver ], {}, [""])
417
458
  controller = ActionView::TestCase::TestController.new
418
459
 
419
- # TODO: Use with_empty_template_cache unconditionally after dropping support for Rails <6.0.
420
- view = if ActionView::Base.respond_to?(:with_empty_template_cache)
421
- ActionView::Base.with_empty_template_cache.new(lookup_context, options.fetch(:assigns, {}), controller)
422
- else
423
- ActionView::Base.new(lookup_context, options.fetch(:assigns, {}), controller)
424
- end
460
+ view = ActionView::Base.with_empty_template_cache.new(lookup_context, options.fetch(:assigns, {}), controller)
425
461
 
426
462
  def view.view_cache_dependencies; []; end
427
463
  def view.combined_fragment_cache_key(key) [ key ] end
@@ -61,6 +61,14 @@ class JbuilderTest < ActiveSupport::TestCase
61
61
  assert_equal 'hello', result['content']
62
62
  end
63
63
 
64
+ test 'method_missing key' do
65
+ result = jbuild do |json|
66
+ json.method_missing 'hello'
67
+ end
68
+
69
+ assert_equal 'hello', result['method_missing']
70
+ end
71
+
64
72
  test 'single key with false value' do
65
73
  result = jbuild do |json|
66
74
  json.content false
@@ -784,12 +792,12 @@ class JbuilderTest < ActiveSupport::TestCase
784
792
  assert_equal ['camelStyle'], result.keys
785
793
  end
786
794
 
787
- test 'do not use default key formatter directly' do
795
+ test 'use default key formatter when configured' do
788
796
  Jbuilder.key_format
789
797
  jbuild{ |json| json.key 'value' }
790
798
  formatter = Jbuilder.send(:class_variable_get, '@@key_formatter')
791
799
  cache = formatter.instance_variable_get('@cache')
792
- assert_empty cache
800
+ assert_includes cache, :key
793
801
  end
794
802
 
795
803
  test 'ignore_nil! without a parameter' do
@@ -930,12 +938,17 @@ class JbuilderTest < ActiveSupport::TestCase
930
938
  end
931
939
  end
932
940
 
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"]
941
+ test "respects JSON encoding customizations" do
942
+ # Active Support overrides Time#as_json for custom formatting.
943
+ # Ensure we call #to_json on the final attributes instead of JSON.dump.
944
+ result = JSON.load(Jbuilder.encode { |json| json.time Time.parse("2018-05-13 11:51:00.485 -0400") })
945
+ assert_equal "2018-05-13T11:51:00.485-04:00", result["time"]
946
+ end
947
+
948
+ test "encode forwards options to new" do
949
+ Jbuilder.encode(key_formatter: 1, ignore_nil: 2) do |json|
950
+ assert_equal 1, json.instance_eval{ @key_formatter }
951
+ assert_equal 2, json.instance_eval{ @ignore_nil }
939
952
  end
940
953
  end
941
954
  end