From 3c0c882f23e892dbe51be625bb71adc42febae09 Mon Sep 17 00:00:00 2001 From: Jack Grzechowiak Date: Wed, 8 Apr 2020 20:43:49 -0400 Subject: [PATCH] Fix for key_format! when using nested hashes Converts the keys of all hashes within arrays and ones being merged in to follow the specified key format. Fixes #473 --- lib/jbuilder.rb | 20 ++++++++++++----- test/jbuilder_test.rb | 52 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 0edab64f..ee128db5 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -43,11 +43,11 @@ def set!(key, value = BLANK, *args, &block) # json.age 32 # json.person another_jbuilder # { "age": 32, "person": { ... } - value.attributes! + _format_keys(value.attributes!) else # json.age 32 # { "age": 32 } - value + _format_keys(value) end elsif _is_collection?(value) # json.comments @post.comments, :content, :created_at @@ -272,11 +272,11 @@ def _merge_values(current_value, updates) if _blank?(updates) current_value elsif _blank?(current_value) || updates.nil? || current_value.empty? && ::Array === updates - updates + _format_keys(updates) elsif ::Array === current_value && ::Array === updates - current_value + updates + current_value + _format_keys(updates) elsif ::Hash === current_value && ::Hash === updates - current_value.deep_merge(updates) + current_value.deep_merge(_format_keys(updates)) else raise MergeError.build(current_value, updates) end @@ -286,6 +286,16 @@ def _key(key) @key_formatter ? @key_formatter.format(key) : key.to_s end + def _format_keys(hash_or_array) + if ::Array === hash_or_array + hash_or_array.map { |value| _format_keys(value) } + elsif ::Hash === hash_or_array + ::Hash[hash_or_array.collect { |k, v| [_key(k), _format_keys(v)] }] + else + hash_or_array + end + end + def _set_value(key, value) raise NullError.build(key) if @attributes.nil? raise ArrayError.build(key) if ::Array === @attributes diff --git a/test/jbuilder_test.rb b/test/jbuilder_test.rb index 18766a1d..c0eb8476 100644 --- a/test/jbuilder_test.rb +++ b/test/jbuilder_test.rb @@ -581,6 +581,58 @@ class JbuilderTest < ActiveSupport::TestCase assert_equal ['oats and friends'], result.keys end + test 'key_format! with merge!' do + hash = { camel_style: 'for JS' } + result = jbuild do |json| + json.key_format! camelize: :lower + json.merge! hash + end + + assert_equal ['camelStyle'], result.keys + end + + test 'key_format! with merge! deep' do + hash = { camel_style: { sub_attr: 'for JS' } } + result = jbuild do |json| + json.key_format! camelize: :lower + json.merge! hash + end + + assert_equal ['subAttr'], result['camelStyle'].keys + end + + test 'key_format! with set! array of hashes' do + names = [{ first_name: 'camel', last_name: 'case' }] + result = jbuild do |json| + json.key_format! camelize: :lower + json.set! :names, names + end + + assert_equal %w[firstName lastName], result['names'][0].keys + end + + test 'key_format! with array! of hashes' do + names = [{ first_name: 'camel', last_name: 'case' }] + result = jbuild do |json| + json.key_format! camelize: :lower + json.array! names + end + + assert_equal %w[firstName lastName], result[0].keys + end + + test 'key_format! with merge! array of hashes' do + names = [{ first_name: 'camel', last_name: 'case' }] + new_names = [{ first_name: 'snake', last_name: 'case' }] + result = jbuild do |json| + json.key_format! camelize: :lower + json.array! names + json.merge! new_names + end + + assert_equal %w[firstName lastName], result[1].keys + end + test 'default key_format!' do Jbuilder.key_format camelize: :lower result = jbuild{ |json| json.camel_style 'for JS' }