From 864b92cd25d70bb623d43dbe3b28488c93885e61 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 11 Dec 2013 23:25:17 -0700 Subject: JSON: speed up date/time encoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comparing dates & times with other objects using #== is slow. Internally, it hits #<=> which calls #to_datetime on objects that don't respond to it, so we incur the cost of raising an exception with a possibly-deep backtrace. Cost of #jsonify on a Time object: Calculating ------------------------------------- old 3644 i/100ms new 12652 i/100ms ------------------------------------------------- old 43373.8 (±3.5%) i/s - 218640 in 5.047017s new 173437.6 (±5.2%) i/s - 872988 in 5.047747s --- activesupport/lib/active_support/json/encoding.rb | 43 ++++++++++------------- 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 060dcb6995..2859075e10 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -63,33 +63,28 @@ module ActiveSupport private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES, :ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, :EscapedString - # Recursively turn the given object into a "jsonified" Ruby data structure - # that the JSON gem understands - i.e. we want only Hash, Array, String, - # Numeric, true, false and nil in the final tree. Calls #as_json on it if - # it's not from one of these base types. - # - # This allows developers to implement #as_json withouth having to worry - # about what base types of objects they are allowed to return and having - # to remember calling #as_json recursively. - # - # By default, the options hash is not passed to the children data structures - # to avoid undesiarable result. Develoers must opt-in by implementing - # custom #as_json methods (e.g. Hash#as_json and Array#as_json). + # Convert an object into a "JSON-ready" representation composed of + # primitives like Hash, Array, String, Numeric, and true/false/nil. + # Recursively calls #as_json to the object to recursively build a + # fully JSON-ready object. + # + # This allows developers to implement #as_json without having to + # worry about what base types of objects they are allowed to return + # or having to remember to call #as_json recursively. + # + # Note: the +options+ hash passed to +object.to_json+ is only passed + # to +object.as_json+, not any of this method's recursive +#as_json+ + # calls. def jsonify(value) - if value.is_a?(Hash) - Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }] - elsif value.is_a?(Array) - value.map { |v| jsonify(v) } - elsif value.is_a?(String) + case value + when String EscapedString.new(value) - elsif value.is_a?(Numeric) + when Numeric, NilClass, TrueClass, FalseClass value - elsif value == true - true - elsif value == false - false - elsif value == nil - nil + when Hash + Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }] + when Array + value.map { |v| jsonify(v) } else jsonify value.as_json end -- cgit v1.2.3