From 690e6e991ed235e1b3e876609c3887949628ac5a Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 10:00:34 +0200 Subject: [PATCH 01/13] Avoid calls to method_missing by calling set! --- lib/jbuilder.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 3066dce5..bf6a99ab 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -157,9 +157,9 @@ def array!(collection) # json.(@person, :name, :age) def extract!(object, *attributes) p = if object.is_a?(Hash) - lambda{|attribute| __send__ attribute, object.send(:fetch, attribute)} + lambda{|attribute| set! attribute, object.send(:fetch, attribute)} else - lambda{|attribute| __send__ attribute, object.send(attribute)} + lambda{|attribute| set! attribute, object.send(attribute)} end attributes.each{|attribute| p.call(attribute)} @@ -233,13 +233,13 @@ def _yield_nesting(container) end def _inline_nesting(container, collection, attributes) - __send__(container) do |parent| + set!(container) do |parent| parent.array!(collection) and return if collection.empty? collection.each do |element| parent.child! do |child| attributes.each do |attribute| - child.__send__ attribute, element.send(attribute) + child.set! attribute, element.send(attribute) end end end @@ -247,7 +247,7 @@ def _inline_nesting(container, collection, attributes) end def _yield_iteration(container, collection) - __send__(container) do |parent| + set!(container) do |parent| parent.array!(collection) do |child, element| yield child, element end @@ -255,7 +255,7 @@ def _yield_iteration(container, collection) end def _inline_extract(container, record, attributes) - __send__(container) { |parent| parent.extract! record, *attributes } + set!(container) { |parent| parent.extract! record, *attributes } end # Format the key using the methods described in @key_format From e4b4ee982bd4a1903b91a331bcb07e9b0accb4a4 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 10:20:32 +0200 Subject: [PATCH 02/13] Refactor method_missing to use fewer comparisons. --- lib/jbuilder.rb | 64 +++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index bf6a99ab..67078691 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -189,37 +189,39 @@ def target! private def method_missing(method, *args) - case - # json.age 32 - # json.person another_jbuilder - # { "age": 32, "person": { ... } - when args.one? && args.first.respond_to?(:_is_a?) && args.first._is_a?(Jbuilder) - set! method, args.first.attributes! - - # json.comments @post.comments { |json, comment| ... } - # { "comments": [ { ... }, { ... } ] } - when args.one? && block_given? - _yield_iteration(method, args.first) { |child, element| yield child, element } - - # json.age 32 - # { "age": 32 } - when args.length == 1 - set! method, args.first - - # json.comments { |json| ... } - # { "comments": ... } - when args.empty? && block_given? - _yield_nesting(method) { |jbuilder| yield jbuilder } - - # json.comments(@post.comments, :content, :created_at) - # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] } - when args.many? && args.first.respond_to?(:each) - _inline_nesting method, args.first, args.from(1) - - # json.author @post.creator, :name, :email_address - # { "author": { "name": "David", "email_address": "david@loudthinking.com" } } - when args.many? - _inline_extract method, args.first, args.from(1) + if block_given? + if args.empty? + # json.comments { |json| ... } + # { "comments": ... } + _yield_nesting(method) { |jbuilder| yield jbuilder } + elsif args.one? + # json.comments @post.comments { |json, comment| ... } + # { "comments": [ { ... }, { ... } ] } + _yield_iteration(method, args.first) { |child, element| yield child, element } + end + else + if args.length == 1 + if args.first.respond_to?(:_is_a?) && args.first._is_a?(Jbuilder) + # json.age 32 + # json.person another_jbuilder + # { "age": 32, "person": { ... } + set! method, args.first.attributes! + else + # json.age 32 + # { "age": 32 } + set! method, args.first + end + elsif args.many? + if args.first.respond_to?(:each) + # json.comments(@post.comments, :content, :created_at) + # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] } + _inline_nesting method, args.first, args.from(1) + else + # json.author @post.creator, :name, :email_address + # { "author": { "name": "David", "email_address": "david@loudthinking.com" } } + _inline_extract method, args.first, args.from(1) + end + end end end From 05f47a736c3a7b52f0a22aaa13f6088ae971a303 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 10:37:08 +0200 Subject: [PATCH 03/13] Avoid many calls to Array#first. --- lib/jbuilder.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 67078691..29d155de 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -188,38 +188,38 @@ def target! private - def method_missing(method, *args) + def method_missing(method, value = nil, *args) if block_given? - if args.empty? + if value + # json.comments @post.comments { |json, comment| ... } + # { "comments": [ { ... }, { ... } ] } + _yield_iteration(method, value) { |child, element| yield child, element } + else # json.comments { |json| ... } # { "comments": ... } _yield_nesting(method) { |jbuilder| yield jbuilder } - elsif args.one? - # json.comments @post.comments { |json, comment| ... } - # { "comments": [ { ... }, { ... } ] } - _yield_iteration(method, args.first) { |child, element| yield child, element } end else - if args.length == 1 - if args.first.respond_to?(:_is_a?) && args.first._is_a?(Jbuilder) + if args.empty? + if value.respond_to?(:_is_a?) && value._is_a?(Jbuilder) # json.age 32 # json.person another_jbuilder # { "age": 32, "person": { ... } - set! method, args.first.attributes! + set! method, value.attributes! else # json.age 32 # { "age": 32 } - set! method, args.first + set! method, value end - elsif args.many? - if args.first.respond_to?(:each) + else + if value.respond_to?(:each) # json.comments(@post.comments, :content, :created_at) # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] } - _inline_nesting method, args.first, args.from(1) + _inline_nesting method, value, args else # json.author @post.creator, :name, :email_address # { "author": { "name": "David", "email_address": "david@loudthinking.com" } } - _inline_extract method, args.first, args.from(1) + _inline_extract method, value, args end end end From 28d7f1f651f33fe942820bd8f9e326be033921c7 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 10:50:58 +0200 Subject: [PATCH 04/13] Set value directly, avoiding calls to set! --- lib/jbuilder.rb | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 29d155de..e5cf55f9 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -42,7 +42,7 @@ def set!(key, value = nil) if block_given? _yield_nesting(key) { |jbuilder| yield jbuilder } else - @attributes[_format_key(key)] = value + _set_value(key, value) end end @@ -157,9 +157,9 @@ def array!(collection) # json.(@person, :name, :age) def extract!(object, *attributes) p = if object.is_a?(Hash) - lambda{|attribute| set! attribute, object.send(:fetch, attribute)} + lambda{|attribute| _set_value attribute, object.send(:fetch, attribute)} else - lambda{|attribute| set! attribute, object.send(attribute)} + lambda{|attribute| _set_value attribute, object.send(attribute)} end attributes.each{|attribute| p.call(attribute)} @@ -187,6 +187,12 @@ def target! end + protected + def _set_value(key, value) + @attributes[_format_key(key)] = value + end + + private def method_missing(method, value = nil, *args) if block_given? @@ -205,11 +211,11 @@ def method_missing(method, value = nil, *args) # json.age 32 # json.person another_jbuilder # { "age": 32, "person": { ... } - set! method, value.attributes! + _set_value method, value.attributes! else # json.age 32 # { "age": 32 } - set! method, value + _set_value method, value end else if value.respond_to?(:each) @@ -231,17 +237,17 @@ def _new_instance end def _yield_nesting(container) - set! container, _new_instance._tap { |jbuilder| yield jbuilder }.attributes! + _set_value container, _new_instance._tap { |jbuilder| yield jbuilder }.attributes! end def _inline_nesting(container, collection, attributes) - set!(container) do |parent| + _yield_nesting(container) do |parent| parent.array!(collection) and return if collection.empty? collection.each do |element| parent.child! do |child| attributes.each do |attribute| - child.set! attribute, element.send(attribute) + child._set_value attribute, element.send(attribute) end end end @@ -249,7 +255,7 @@ def _inline_nesting(container, collection, attributes) end def _yield_iteration(container, collection) - set!(container) do |parent| + _yield_nesting(container) do |parent| parent.array!(collection) do |child, element| yield child, element end @@ -257,7 +263,7 @@ def _yield_iteration(container, collection) end def _inline_extract(container, record, attributes) - set!(container) { |parent| parent.extract! record, *attributes } + _yield_nesting(container) { |parent| parent.extract! record, *attributes } end # Format the key using the methods described in @key_format From 8a4b02edac0cd31bedd313049c9b0ead8f5fa9be Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 11:14:16 +0200 Subject: [PATCH 05/13] Avoid creating lambda objects. --- lib/jbuilder.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index e5cf55f9..f3f4b5a1 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -156,13 +156,11 @@ def array!(collection) # # json.(@person, :name, :age) def extract!(object, *attributes) - p = if object.is_a?(Hash) - lambda{|attribute| _set_value attribute, object.send(:fetch, attribute)} + if object.is_a?(Hash) + attributes.each {|attribute| _set_value attribute, object.send(:fetch, attribute)} else - lambda{|attribute| _set_value attribute, object.send(attribute)} + attributes.each {|attribute| _set_value attribute, object.send(attribute)} end - - attributes.each{|attribute| p.call(attribute)} end if RUBY_VERSION > '1.9' From f074d6e22197d8750998b62a21917a0b1ff3f968 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 11:21:35 +0200 Subject: [PATCH 06/13] Avoid call to Enumerable#one? --- lib/jbuilder.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index f3f4b5a1..e767407e 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -164,12 +164,11 @@ def extract!(object, *attributes) end if RUBY_VERSION > '1.9' - def call(*args) - case - when args.one? - array!(args.first) { |json, element| yield json, element } - when args.many? - extract!(*args) + def call(object = nil, *attributes) + if attributes.empty? + array!(object) { |json, element| yield json, element } + else + extract!(object, *attributes) end end end From 7f24f1a35bc18ac2bf2b34371946f5d1394e9561 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 11:36:41 +0200 Subject: [PATCH 07/13] Key formatter should cache formatted keys. --- lib/jbuilder.rb | 62 +++++++++++++++++++++++-------------------- test/jbuilder_test.rb | 2 +- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index e767407e..b2924f76 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -5,21 +5,47 @@ require 'active_support/json' require 'multi_json' class Jbuilder < BlankSlate + class KeyFormatter + def initialize(*args) + @format = {} + @cache = {} + + options = args.extract_options! + args.each do |name| + @format[name] = [] + end + options.each do |name, paramaters| + @format[name] = paramaters + end + end + + def format(key) + @cache[key] ||= @format.inject(key.to_s) do |result, args| + func, args = args + if func.is_a? Proc + func.call(result, *args) + else + result.send(func, *args) + end + end + end + end + # Yields a builder and automatically turns the result into a JSON string def self.encode new._tap { |jbuilder| yield jbuilder }.target! end - @@key_format = {} + @@key_formatter = KeyFormatter.new define_method(:__class__, find_hidden_method(:class)) define_method(:_tap, find_hidden_method(:tap)) define_method(:_is_a?, find_hidden_method(:is_a?)) reveal(:respond_to?) - def initialize(key_format = @@key_format.clone) + def initialize(key_formatter = @@key_formatter) @attributes = ActiveSupport::OrderedHash.new - @key_format = key_format + @key_formatter = key_formatter end # Dynamically set a key value pair. @@ -75,12 +101,12 @@ def set!(key, value = nil) # { "_first_name": "David" } # def key_format!(*args) - __class__.extract_key_format(args, @key_format) + @key_formatter = KeyFormatter.new(*args) end # Same as the instance method key_format! except sets the default. def self.key_format(*args) - extract_key_format(args, @@key_format) + @@key_formatter = KeyFormatter.new(*args) end # Turns the current element into an array and yields a builder to add a hash. @@ -186,7 +212,7 @@ def target! protected def _set_value(key, value) - @attributes[_format_key(key)] = value + @attributes[@key_formatter.format(key)] = value end @@ -230,7 +256,7 @@ def method_missing(method, value = nil, *args) # Overwrite in subclasses if you need to add initialization values def _new_instance - __class__.new(@key_format) + __class__.new(@key_formatter) end def _yield_nesting(container) @@ -262,28 +288,6 @@ def _yield_iteration(container, collection) def _inline_extract(container, record, attributes) _yield_nesting(container) { |parent| parent.extract! record, *attributes } end - - # Format the key using the methods described in @key_format - def _format_key(key) - @key_format.inject(key.to_s) do |result, args| - func, args = args - if func.is_a? Proc - func.call(result, *args) - else - result.send(func, *args) - end - end - end - - def self.extract_key_format(args, target) - options = args.extract_options! - args.each do |name| - target[name] = [] - end - options.each do |name, paramaters| - target[name] = paramaters - end - end end require "jbuilder_template" if defined?(ActionView::Template) diff --git a/test/jbuilder_test.rb b/test/jbuilder_test.rb index b46e1d6c..679c4b82 100644 --- a/test/jbuilder_test.rb +++ b/test/jbuilder_test.rb @@ -369,6 +369,6 @@ def empty? json.camel_style "for JS" assert_equal ['camelStyle'], json.attributes!.keys - Jbuilder.class_variable_set("@@key_format", {}) + Jbuilder.class_variable_set("@@key_formatter", Jbuilder::KeyFormatter.new) end end From f8afe8a6ad7a05dea396485c1ad04fc9403ae4f0 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 11:39:57 +0200 Subject: [PATCH 08/13] Avoid calls to respond_to? when we really need Module#===. --- lib/jbuilder.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index b2924f76..f11f8fc5 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -40,7 +40,6 @@ def self.encode define_method(:__class__, find_hidden_method(:class)) define_method(:_tap, find_hidden_method(:tap)) - define_method(:_is_a?, find_hidden_method(:is_a?)) reveal(:respond_to?) def initialize(key_formatter = @@key_formatter) @@ -230,7 +229,7 @@ def method_missing(method, value = nil, *args) end else if args.empty? - if value.respond_to?(:_is_a?) && value._is_a?(Jbuilder) + if Jbuilder === value # json.age 32 # json.person another_jbuilder # { "age": 32, "person": { ... } From 39dca2f8bda4a69f830f4d0902a93d066555134a Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 12:11:28 +0200 Subject: [PATCH 09/13] Simplify inline_nesting. --- lib/jbuilder.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index f11f8fc5..4f226aa4 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -264,13 +264,9 @@ def _yield_nesting(container) def _inline_nesting(container, collection, attributes) _yield_nesting(container) do |parent| - parent.array!(collection) and return if collection.empty? - - collection.each do |element| - parent.child! do |child| - attributes.each do |attribute| - child._set_value attribute, element.send(attribute) - end + parent.array!(collection) do |child, element| + attributes.each do |attribute| + child._set_value attribute, element.send(attribute) end end end From 1bae9d1b882e93c4a8a0f93e74db03a34d0c1d4b Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 13:21:04 +0200 Subject: [PATCH 10/13] Simplify array! to avoid calls to child! --- lib/jbuilder.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 4f226aa4..9ae54d0c 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -154,12 +154,9 @@ def child! # # { "people": [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ] } def array!(collection) - @attributes = [] and return if collection.empty? - - collection.each do |element| - child! do |child| - yield child, element - end + @attributes = [] + collection.each do |element| #[] and return if collection.empty? + @attributes << _new_instance._tap { |jbuilder| yield jbuilder, element }.attributes! end end From d136416c9d3b4ac29cfe18c3689aaeb5a7314a4b Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 13:32:41 +0200 Subject: [PATCH 11/13] Clone default formatter for each root. --- lib/jbuilder.rb | 6 +++++- test/jbuilder_test.rb | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 9ae54d0c..6e10840a 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -19,6 +19,10 @@ def initialize(*args) end end + def initialize_copy(original) + @cache = {} + end + def format(key) @cache[key] ||= @format.inject(key.to_s) do |result, args| func, args = args @@ -42,7 +46,7 @@ def self.encode define_method(:_tap, find_hidden_method(:tap)) reveal(:respond_to?) - def initialize(key_formatter = @@key_formatter) + def initialize(key_formatter = @@key_formatter.clone) @attributes = ActiveSupport::OrderedHash.new @key_formatter = key_formatter end diff --git a/test/jbuilder_test.rb b/test/jbuilder_test.rb index 679c4b82..ecfb0557 100644 --- a/test/jbuilder_test.rb +++ b/test/jbuilder_test.rb @@ -371,4 +371,11 @@ def empty? assert_equal ['camelStyle'], json.attributes!.keys Jbuilder.class_variable_set("@@key_formatter", Jbuilder::KeyFormatter.new) end + + test "don't use default key formatter directly" do + json = Jbuilder.new + json.key "value" + + assert_equal [], Jbuilder.class_variable_get("@@key_formatter").instance_variable_get("@cache").keys + end end From 646c49bf2e0644153e6816ade4c0c76f3093c75b Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 16:40:44 +0200 Subject: [PATCH 12/13] Add basic test for JbuilderTemplate. Requires actionpack. --- Gemfile | 4 +++- Gemfile.lock | 36 +++++++++++++++++++++++++++++++--- test/jbuilder_template_test.rb | 18 +++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 test/jbuilder_template_test.rb diff --git a/Gemfile b/Gemfile index 857c670d..3b8dea8c 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ source "http://rubygems.org" -gemspec \ No newline at end of file +gemspec + +gem "actionpack" diff --git a/Gemfile.lock b/Gemfile.lock index 00ab1f83..22654f8a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,20 +1,50 @@ PATH remote: . specs: - jbuilder (0.3) + jbuilder (0.4.1) activesupport (>= 3.0.0) blankslate (>= 2.1.2.4) GEM remote: http://rubygems.org/ specs: - activesupport (3.1.3) + actionpack (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.0) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.1.3) + activemodel (3.2.8) + activesupport (= 3.2.8) + builder (~> 3.0.0) + activesupport (3.2.8) + i18n (~> 0.6) multi_json (~> 1.0) blankslate (2.1.2.4) - multi_json (1.0.4) + builder (3.0.0) + erubis (2.7.0) + hike (1.2.1) + i18n (0.6.1) + journey (1.0.4) + multi_json (1.3.6) + rack (1.4.1) + rack-cache (1.2) + rack (>= 0.4) + rack-test (0.6.1) + rack (>= 1.0) + sprockets (2.1.3) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + tilt (1.3.3) PLATFORMS ruby DEPENDENCIES + actionpack jbuilder! diff --git a/test/jbuilder_template_test.rb b/test/jbuilder_template_test.rb new file mode 100644 index 00000000..9bba39b6 --- /dev/null +++ b/test/jbuilder_template_test.rb @@ -0,0 +1,18 @@ +require 'test/unit' +require 'active_support/test_case' +require 'active_support/inflector' +require 'action_dispatch' +require 'action_view' + +require 'jbuilder' +require 'jbuilder_template' + +class JbuilderTemplateTest < ActiveSupport::TestCase + test "rendering" do + json = JbuilderTemplate.encode(binding) do |json| + json.content "hello" + end + + assert_equal "hello", JSON.parse(json)["content"] + end +end From e5be60efca87456d0e25e094b7443cf1b7b4a391 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 5 Sep 2012 16:41:40 +0200 Subject: [PATCH 13/13] Fix key format propagation to children in template. --- lib/jbuilder_template.rb | 6 +++--- test/jbuilder_template_test.rb | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/jbuilder_template.rb b/lib/jbuilder_template.rb index 8ba39803..ab2994f5 100644 --- a/lib/jbuilder_template.rb +++ b/lib/jbuilder_template.rb @@ -3,9 +3,9 @@ def self.encode(context) new(context)._tap { |jbuilder| yield jbuilder }.target! end - def initialize(context) + def initialize(context, *args) @context = context - super() + super(*args) end def partial!(options, locals = {}) @@ -21,7 +21,7 @@ def partial!(options, locals = {}) private def _new_instance - __class__.new(@context) + __class__.new(@context, @key_formatter) end end diff --git a/test/jbuilder_template_test.rb b/test/jbuilder_template_test.rb index 9bba39b6..ed2ee721 100644 --- a/test/jbuilder_template_test.rb +++ b/test/jbuilder_template_test.rb @@ -15,4 +15,25 @@ class JbuilderTemplateTest < ActiveSupport::TestCase assert_equal "hello", JSON.parse(json)["content"] end + + test "key_format! with parameter" do + json = JbuilderTemplate.new(binding) + json.key_format! :camelize => [:lower] + json.camel_style "for JS" + + assert_equal ['camelStyle'], json.attributes!.keys + end + + test "key_format! propagates to child elements" do + json = JbuilderTemplate.new(binding) + json.key_format! :upcase + json.level1 "one" + json.level2 do |json| + json.value "two" + end + + result = json.attributes! + assert_equal "one", result["LEVEL1"] + assert_equal "two", result["LEVEL2"]["VALUE"] + end end