Created
June 6, 2009 01:16
-
-
Save jeremy/124616 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Users: JSON.encode(whatever) | |
# | |
# Implementors: override dump_json(options) returning a Hash, Array, etc | |
# or: override encode_json(encoder) using the encoder API to return a JSON string | |
require 'active_support/core_ext/array/wrap' | |
require 'active_support/core_ext/object/instance_variables' | |
module ActiveSupport | |
module JSON | |
# Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info. | |
def self.encode(value, options = nil) | |
Encoder.new(options).encode(value) | |
end | |
class Encoder | |
class CircularReferenceError < StandardError; end | |
attr_reader :options | |
def initialize(options) | |
@options = options | |
@seen = [] | |
end | |
def encode(value) | |
check_for_circular_references(value) do | |
value.dump_json(options).encode_json(self) | |
end | |
end | |
def escape(string) | |
Encoding.escape(string) | |
end | |
private | |
def check_for_circular_references(value) | |
if @seen.any? { |object| object.equal?(value) } | |
raise CircularReferenceError, 'object references itself' | |
end | |
@seen.unshift value | |
yield | |
ensure | |
@seen.shift | |
end | |
end | |
end | |
end | |
class Object | |
def dump_json(options) self end | |
def encode_json(encoder) encoder.encode(instance_values) end | |
end | |
# A string that returns itself as its JSON-encoded form. | |
class ActiveSupport::JSON::Variable < String | |
def encode_json(encoder) self end | |
end | |
class TrueClass | |
JSON_VALUE = ActiveSupport::JSON::Variable.new('true').freeze | |
def dump_json(options) JSON_VALUE end | |
end | |
class FalseClass | |
JSON_VALUE = ActiveSupport::JSON::Variable.new('false').freeze | |
def dump_json(options) JSON_VALUE end | |
end | |
class NilClass | |
JSON_VALUE = ActiveSupport::JSON::Variable.new('null').freeze | |
def dump_json(options) JSON_VALUE end | |
end | |
class String | |
def encode_json(encoder) encoder.escape(self) end | |
end | |
class Symbol | |
def dump_json(options) to_s end | |
end | |
class Numeric | |
def encode_json(encoder) to_s end | |
end | |
class Regexp | |
def encode_json(encoder) inspect end | |
end | |
module Enumerable | |
def encode_json(encoder) "[#{map { |v| encoder.encode(v) } * ','}]" end | |
end | |
class Hash | |
def dump_json(options) | |
if options | |
if attrs = options[:only] | |
slice(*Array.wrap(attrs)) | |
elsif attrs = options[:except] | |
except(*Array.wrap(attrs)) | |
end | |
else | |
super | |
end | |
end | |
def encode_json(encoder) | |
"{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v)}" } * ','}}" | |
end | |
end | |
class Time | |
def dump_json(options) | |
if ActiveSupport.use_standard_json_time_format | |
xmlschema | |
else | |
%(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}) | |
end | |
end | |
end | |
class Date | |
def dump_json(options) | |
if ActiveSupport.use_standard_json_time_format | |
strftime("%Y-%m-%d") | |
else | |
strftime("%Y/%m/%d") | |
end | |
end | |
end | |
class DateTime | |
def dump_json(options) | |
if ActiveSupport.use_standard_json_time_format | |
xmlschema | |
else | |
strftime('%Y/%m/%d %H:%M:%S %z') | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment