jbuilder 2.11.1 → 2.11.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e3eebf3fe3849616361ae7df9556f466eaf84da813756b8690dfbd5c28d41a1
4
- data.tar.gz: 011c0162b09a94f229673e88bab0d0d466d9552a004afb426f817a02c3af8943
3
+ metadata.gz: '039b14d174dd7bfb3a5e00d5a315aee89f1efd46a570244191ab985bb44fc328'
4
+ data.tar.gz: 4eda58d10150903687b7940b858fa02c6f0a2cbca8858cd2ae9866c5be5a4b62
5
5
  SHA512:
6
- metadata.gz: 29968e2f35da52dc00db229d0085d77a7d390417bbe3011b005824ff45a1291bca0f45c59d4f40263a3ac236e31ea3fdd0cd78ba01ddef4e51414aea4ac34704
7
- data.tar.gz: '09df7fb01ce2d128b0f45116cc4f2ccb01469031a51b598f6c17c16f58ddbd0c3059095a1a6761a2f26e328b3960def55752d6ed36cca0e2952e393d712e48b3'
6
+ metadata.gz: 1d20f2794455635cbb3272bd4b6e8f91781e2c55aa40c7228d5347b4b6ad049cd3cc22ebc9ef708b8bbe4a05811774de07770b175035342123458a4637b9240f
7
+ data.tar.gz: 383aca1c7489eda135339e4538fa8a9dec80900c7c8bab786729a7c323d63f3a75657889ee6dad6bf91b769ced3eb507e41ef7daa15faa8bb3c5d0261c0c0394
@@ -1,9 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ 2.11.2
4
+ ------
5
+
6
+ * [Improve key formatting for nested hashes and disable by default](https://github.com/rails/jbuilder/pull/497)
7
+
3
8
  2.11.1
4
9
  ------
5
10
 
6
- * Use symbols instead of strings for before_action fitlers [DHH]
11
+ * Use symbols instead of strings for before_action filters [DHH]
7
12
  * Slim down comments in generated scaffold code [DHH]
8
13
 
9
14
  2.11.0
data/README.md CHANGED
@@ -274,6 +274,25 @@ environment.rb for example):
274
274
  Jbuilder.key_format camelize: :lower
275
275
  ```
276
276
 
277
+ By default, key format is not applied to keys of hashes that are
278
+ passed to methods like `set!`, `array!` or `merge!`. You can opt into
279
+ deeply transforming these as well:
280
+
281
+ ``` ruby
282
+ json.key_format! camelize: :lower
283
+ json.deep_format_keys!
284
+ json.settings([{some_value: "abc"}])
285
+
286
+ # => { "settings": [{ "someValue": "abc" }]}
287
+ ```
288
+
289
+ You can set this globally with the class method `deep_format_keys` (from inside your
290
+ environment.rb for example):
291
+
292
+ ``` ruby
293
+ Jbuilder.deep_format_keys true
294
+ ```
295
+
277
296
  ## Contributing to Jbuilder
278
297
 
279
298
  Jbuilder is the work of many contributors. You're encouraged to submit pull requests, propose
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '2.11.1'
3
+ s.version = '2.11.2'
4
4
  s.authors = 'David Heinemeier Hansson'
5
5
  s.email = 'david@basecamp.com'
6
6
  s.summary = 'Create JSON structures via a Builder-style DSL'
@@ -9,12 +9,14 @@ require 'active_support/core_ext/hash/deep_merge'
9
9
  class Jbuilder
10
10
  @@key_formatter = nil
11
11
  @@ignore_nil = false
12
+ @@deep_format_keys = false
12
13
 
13
14
  def initialize(options = {})
14
15
  @attributes = {}
15
16
 
16
17
  @key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
17
18
  @ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
19
+ @deep_format_keys = options.fetch(:deep_format_keys, @@deep_format_keys)
18
20
 
19
21
  yield self if ::Kernel.block_given?
20
22
  end
@@ -131,6 +133,31 @@ class Jbuilder
131
133
  @@ignore_nil = value
132
134
  end
133
135
 
136
+ # Deeply apply key format to nested hashes and arrays passed to
137
+ # methods like set!, merge! or array!.
138
+ #
139
+ # Example:
140
+ #
141
+ # json.key_format! camelize: :lower
142
+ # json.settings({some_value: "abc"})
143
+ #
144
+ # { "settings": { "some_value": "abc" }}
145
+ #
146
+ # json.key_format! camelize: :lower
147
+ # json.deep_format_keys!
148
+ # json.settings({some_value: "abc"})
149
+ #
150
+ # { "settings": { "someValue": "abc" }}
151
+ #
152
+ def deep_format_keys!(value = true)
153
+ @deep_format_keys = value
154
+ end
155
+
156
+ # Same as instance method deep_format_keys! except sets the default.
157
+ def self.deep_format_keys(value = true)
158
+ @@deep_format_keys = value
159
+ end
160
+
134
161
  # Turns the current element into an array and yields a builder to add a hash.
135
162
  #
136
163
  # Example:
@@ -190,10 +217,10 @@ class Jbuilder
190
217
  elsif attributes.any?
191
218
  _map_collection(collection) { |element| extract! element, *attributes }
192
219
  else
193
- collection.to_a
220
+ _format_keys(collection.to_a)
194
221
  end
195
222
 
196
- merge! array
223
+ @attributes = _merge_values(@attributes, array)
197
224
  end
198
225
 
199
226
  # Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
@@ -244,7 +271,7 @@ class Jbuilder
244
271
  # Merges hash, array, or Jbuilder instance into current builder.
245
272
  def merge!(object)
246
273
  hash_or_array = ::Jbuilder === object ? object.attributes! : object
247
- @attributes = _merge_values(@attributes, hash_or_array)
274
+ @attributes = _merge_values(@attributes, _format_keys(hash_or_array))
248
275
  end
249
276
 
250
277
  # Encodes the current builder as JSON.
@@ -255,11 +282,11 @@ class Jbuilder
255
282
  private
256
283
 
257
284
  def _extract_hash_values(object, attributes)
258
- attributes.each{ |key| _set_value key, object.fetch(key) }
285
+ attributes.each{ |key| _set_value key, _format_keys(object.fetch(key)) }
259
286
  end
260
287
 
261
288
  def _extract_method_values(object, attributes)
262
- attributes.each{ |key| _set_value key, object.public_send(key) }
289
+ attributes.each{ |key| _set_value key, _format_keys(object.public_send(key)) }
263
290
  end
264
291
 
265
292
  def _merge_block(key)
@@ -273,11 +300,11 @@ class Jbuilder
273
300
  if _blank?(updates)
274
301
  current_value
275
302
  elsif _blank?(current_value) || updates.nil? || current_value.empty? && ::Array === updates
276
- _format_keys(updates)
303
+ updates
277
304
  elsif ::Array === current_value && ::Array === updates
278
- current_value + _format_keys(updates)
305
+ current_value + updates
279
306
  elsif ::Hash === current_value && ::Hash === updates
280
- current_value.deep_merge(_format_keys(updates))
307
+ current_value.deep_merge(updates)
281
308
  else
282
309
  raise MergeError.build(current_value, updates)
283
310
  end
@@ -288,6 +315,8 @@ class Jbuilder
288
315
  end
289
316
 
290
317
  def _format_keys(hash_or_array)
318
+ return hash_or_array unless @deep_format_keys
319
+
291
320
  if ::Array === hash_or_array
292
321
  hash_or_array.map { |value| _format_keys(value) }
293
322
  elsif ::Hash === hash_or_array
@@ -312,12 +341,12 @@ class Jbuilder
312
341
  end
313
342
 
314
343
  def _scope
315
- parent_attributes, parent_formatter = @attributes, @key_formatter
344
+ parent_attributes, parent_formatter, parent_deep_format_keys = @attributes, @key_formatter, @deep_format_keys
316
345
  @attributes = BLANK
317
346
  yield
318
347
  @attributes
319
348
  ensure
320
- @attributes, @key_formatter = parent_attributes, parent_formatter
349
+ @attributes, @key_formatter, @deep_format_keys = parent_attributes, parent_formatter, parent_deep_format_keys
321
350
  end
322
351
 
323
352
  def _is_collection?(object)
@@ -566,6 +566,36 @@ class JbuilderTest < ActiveSupport::TestCase
566
566
  assert_equal 'one', result['level1']
567
567
  end
568
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
+
569
599
  test 'key_format! with no parameter' do
570
600
  result = jbuild do |json|
571
601
  json.key_format! :upcase
@@ -593,51 +623,121 @@ class JbuilderTest < ActiveSupport::TestCase
593
623
  assert_equal ['oats and friends'], result.keys
594
624
  end
595
625
 
596
- test 'key_format! with merge!' do
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
632
+
633
+ assert_equal %i[first_name last_name], result['allNames'].keys
634
+ end
635
+
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
597
681
  hash = { camel_style: 'for JS' }
598
682
  result = jbuild do |json|
599
683
  json.key_format! camelize: :lower
684
+ json.deep_format_keys!
600
685
  json.merge! hash
601
686
  end
602
687
 
603
688
  assert_equal ['camelStyle'], result.keys
604
689
  end
605
690
 
606
- test 'key_format! with merge! deep' do
691
+ test 'deep key_format! with merge! deep' do
607
692
  hash = { camel_style: { sub_attr: 'for JS' } }
608
693
  result = jbuild do |json|
609
694
  json.key_format! camelize: :lower
695
+ json.deep_format_keys!
610
696
  json.merge! hash
611
697
  end
612
698
 
613
699
  assert_equal ['subAttr'], result['camelStyle'].keys
614
700
  end
615
701
 
616
- test 'key_format! with set! array of hashes' do
702
+ test 'deep key_format! with set! array of hashes' do
617
703
  names = [{ first_name: 'camel', last_name: 'case' }]
618
704
  result = jbuild do |json|
619
705
  json.key_format! camelize: :lower
706
+ json.deep_format_keys!
620
707
  json.set! :names, names
621
708
  end
622
709
 
623
710
  assert_equal %w[firstName lastName], result['names'][0].keys
624
711
  end
625
712
 
626
- test 'key_format! with array! of hashes' do
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
627
725
  names = [{ first_name: 'camel', last_name: 'case' }]
628
726
  result = jbuild do |json|
629
727
  json.key_format! camelize: :lower
728
+ json.deep_format_keys!
630
729
  json.array! names
631
730
  end
632
731
 
633
732
  assert_equal %w[firstName lastName], result[0].keys
634
733
  end
635
734
 
636
- test 'key_format! with merge! array of hashes' do
735
+ test 'deep key_format! with merge! array of hashes' do
637
736
  names = [{ first_name: 'camel', last_name: 'case' }]
638
737
  new_names = [{ first_name: 'snake', last_name: 'case' }]
639
738
  result = jbuild do |json|
640
739
  json.key_format! camelize: :lower
740
+ json.deep_format_keys!
641
741
  json.array! names
642
742
  json.merge! new_names
643
743
  end
@@ -645,6 +745,39 @@ class JbuilderTest < ActiveSupport::TestCase
645
745
  assert_equal %w[firstName lastName], result[1].keys
646
746
  end
647
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
+
648
781
  test 'default key_format!' do
649
782
  Jbuilder.key_format camelize: :lower
650
783
  result = jbuild{ |json| json.camel_style 'for JS' }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.1
4
+ version: 2.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-24 00:00:00.000000000 Z
11
+ date: 2021-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport