Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

JSON: speed up date/time encoding

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
  • Loading branch information...
commit 864b92cd25d70bb623d43dbe3b28488c93885e61 1 parent ebfd971
@jeremy jeremy authored
Showing with 19 additions and 24 deletions.
  1. +19 −24 activesupport/lib/active_support/json/encoding.rb
View
43 activesupport/lib/active_support/json/encoding.rb
@@ -63,33 +63,28 @@ def to_json(*)
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

1 comment on commit 864b92c

Please sign in to comment.
Something went wrong with that request. Please try again.