From 5dbc467050095542b61b971ed60efdb40facacd7 Mon Sep 17 00:00:00 2001 From: Mayur Kambariya Date: Mon, 12 Jan 2026 13:25:36 +0530 Subject: [PATCH 1/2] Performance improvement for array and hash --- lib/jbuilder.rb | 39 +++++++++++++++++++++++------------ lib/jbuilder/key_formatter.rb | 5 +++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 1290839..3325b64 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -19,7 +19,7 @@ def initialize( deep_format_keys: @@deep_format_keys, &block ) - @attributes = {} + @attributes = BLANK @key_formatter = key_formatter @ignore_nil = ignore_nil @deep_format_keys = deep_format_keys @@ -32,7 +32,7 @@ def self.encode(...) new(...).target! end - BLANK = Blank.new + BLANK = Blank.new.freeze def set!(key, value = BLANK, *args, &block) result = if ::Kernel.block_given? @@ -302,7 +302,7 @@ def _merge_block(key) def _merge_values(current_value, updates) if _blank?(updates) current_value - elsif _blank?(current_value) || updates.nil? || current_value.empty? && ::Array === updates + elsif _blank?(current_value) || updates.nil? || (current_value.respond_to?(:empty?) && current_value.empty? && ::Array === updates) updates elsif ::Array === current_value && ::Array === updates current_value + updates @@ -316,20 +316,25 @@ def _merge_values(current_value, updates) def _key(key) if @key_formatter @key_formatter.format(key) - elsif key.is_a?(::Symbol) - key.name else - key.to_s + key.is_a?(::Symbol) ? key.name : key.to_s end end def _format_keys(hash_or_array) return hash_or_array unless @deep_format_keys - if ::Array === hash_or_array + case hash_or_array + when ::Array + # Use map! when possible to avoid creating new 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)] }] + when ::Hash + # Use transform_keys when available (Ruby 2.5+) for better performance + if hash_or_array.respond_to?(:transform_keys) + hash_or_array.transform_keys { |k| _key(k) }.transform_values { |v| _format_keys(v) } + else + ::Hash[hash_or_array.collect { |k, v| [_key(k), _format_keys(v)] }] + end else hash_or_array end @@ -344,9 +349,17 @@ def _set_value(key, value) end def _map_collection(collection) - collection.map do |element| - _scope{ yield element } - end - [BLANK] + # Use filter_map when available (Ruby 2.7+) for better performance + if collection.respond_to?(:filter_map) + collection.filter_map do |element| + mapped_element = _scope{ yield element } + mapped_element unless mapped_element == BLANK + end + else + collection.map do |element| + _scope{ yield element } + end - [BLANK] + end end def _scope @@ -363,7 +376,7 @@ def _is_collection?(object) end def _blank?(value=@attributes) - BLANK == value + value == BLANK end end diff --git a/lib/jbuilder/key_formatter.rb b/lib/jbuilder/key_formatter.rb index e73916b..59f97c0 100644 --- a/lib/jbuilder/key_formatter.rb +++ b/lib/jbuilder/key_formatter.rb @@ -12,6 +12,11 @@ def initialize(*formats, **formats_with_options) end def format(key) + # Check cache without mutex for common case (reading) + cached_value = @cache[key] + return cached_value if cached_value + + # Only use mutex when writing to cache @mutex.synchronize do @cache[key] ||= begin value = key.is_a?(Symbol) ? key.name : key.to_s From 3728bf497a2344dc746a0486d49fc8305ae88528 Mon Sep 17 00:00:00 2001 From: Mayur Kambariya Date: Mon, 12 Jan 2026 13:33:28 +0530 Subject: [PATCH 2/2] Revert attributes variable assignment --- lib/jbuilder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index 3325b64..6e7535d 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -19,7 +19,7 @@ def initialize( deep_format_keys: @@deep_format_keys, &block ) - @attributes = BLANK + @attributes = {} @key_formatter = key_formatter @ignore_nil = ignore_nil @deep_format_keys = deep_format_keys