diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 8669d1d7ccb8d..95cf3e74159c8 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -952,7 +952,7 @@ def render(options = nil, extra_options = {}, &block) #:doc: elsif options.include?(:json) json = options[:json] - json = json.to_json unless json.is_a?(String) + json = ActiveSupport::JSON.encode(json) unless json.is_a?(String) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? response.content_type ||= Mime::JSON render_for_text(json, options[:status]) diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 91ef72e54b053..0502e17f70b9c 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -973,7 +973,7 @@ def drop_receiving(id, options = {}) def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : - "#{method}(#{ids.first.to_json})") + "#{method}(#{ActiveSupport::JSON.encode(ids.first)})") end def page @@ -997,7 +997,7 @@ def render(*options_for_render) end def javascript_object_for(object) - object.respond_to?(:to_json) ? object.to_json : object.inspect + ActiveSupport::JSON.encode(object) end def arguments_for_call(arguments, block = nil) @@ -1139,7 +1139,7 @@ def append_to_function_chain!(call) class JavaScriptElementProxy < JavaScriptProxy #:nodoc: def initialize(generator, id) @id = id - super(generator, "$(#{id.to_json})") + super(generator, "$(#{ActiveSupport::JSON.encode(id)})") end # Allows access of element attributes through +attribute+. Examples: @@ -1184,10 +1184,12 @@ def respond_to?(method) true end - def to_json(options = nil) + def rails_to_json(options = nil) @variable end + alias to_json rails_to_json + private def append_to_function_chain!(call) @generator << @variable if @empty @@ -1211,7 +1213,7 @@ def each_slice(variable, number, &block) enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block else add_variable_assignment!(variable) - append_enumerable_function!("eachSlice(#{number.to_json});") + append_enumerable_function!("eachSlice(#{ActiveSupport::JSON.encode(number)});") end end @@ -1232,7 +1234,7 @@ def inject(variable, memo, &block) def pluck(variable, property) add_variable_assignment!(variable) - append_enumerable_function!("pluck(#{property.to_json});") + append_enumerable_function!("pluck(#{ActiveSupport::JSON.encode(property)});") end def zip(variable, *arguments, &block) @@ -1296,7 +1298,7 @@ def append_enumerable_function!(call) class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ def initialize(generator, pattern) - super(generator, "$$(#{pattern.to_json})") + super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})") end end end diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index e16935ea87ea8..04af2781d717f 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -43,7 +43,7 @@ module ScriptaculousHelper # You can change the behaviour with various options, see # http://script.aculo.us for more documentation. def visual_effect(name, element_id = false, js_options = {}) - element = element_id ? element_id.to_json : "element" + element = element_id ? ActiveSupport::JSON.encode(element_id) : "element" js_options[:queue] = if js_options[:queue].is_a?(Hash) '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}' @@ -138,7 +138,7 @@ def sortable_element(element_id, options = {}) end def sortable_element_js(element_id, options = {}) #:nodoc: - options[:with] ||= "Sortable.serialize(#{element_id.to_json})" + options[:with] ||= "Sortable.serialize(#{ActiveSupport::JSON.encode(element_id)})" options[:onUpdate] ||= "function(){" + remote_function(options) + "}" options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) } @@ -149,7 +149,7 @@ def sortable_element_js(element_id, options = {}) #:nodoc: options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment] options[:only] = array_or_string_for_javascript(options[:only]) if options[:only] - %(Sortable.create(#{element_id.to_json}, #{options_for_javascript(options)});) + %(Sortable.create(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end # Makes the element with the DOM ID specified by +element_id+ draggable. @@ -164,7 +164,7 @@ def draggable_element(element_id, options = {}) end def draggable_element_js(element_id, options = {}) #:nodoc: - %(new Draggable(#{element_id.to_json}, #{options_for_javascript(options)});) + %(new Draggable(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end # Makes the element with the DOM ID specified by +element_id+ receive @@ -219,7 +219,7 @@ def drop_receiving_element_js(element_id, options = {}) #:nodoc: # Confirmation happens during the onDrop callback, so it can be removed from the options options.delete(:confirm) if options[:confirm] - %(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});) + %(Droppables.add(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 9930824b8f342..112e9efce0c33 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -198,19 +198,19 @@ def render_json_nil end def render_json_hello_world - render :json => {:hello => 'world'}.to_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') end def render_json_hello_world_with_callback - render :json => {:hello => 'world'}.to_json, :callback => 'alert' + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert' end def render_json_with_custom_content_type - render :json => {:hello => 'world'}.to_json, :content_type => 'text/javascript' + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript' end def render_symbol_json - render :json => {:hello => 'world'}.to_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') end def render_json_with_render_to_string @@ -898,31 +898,31 @@ def test_render_json_nil def test_render_json get :render_json_hello_world - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_callback get :render_json_hello_world_with_callback - assert_equal 'alert({"hello": "world"})', @response.body + assert_equal 'alert({"hello":"world"})', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_custom_content_type get :render_json_with_custom_content_type - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'text/javascript', @response.content_type end def test_render_symbol_json get :render_symbol_json - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_render_to_string get :render_json_with_render_to_string - assert_equal '{"hello": "partial html"}', @response.body + assert_equal '{"hello":"partial html"}', @response.body assert_equal 'application/json', @response.content_type end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index d6b86a396460f..2ef4cde953e28 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -327,28 +327,28 @@ def test_replace_element_with_string def test_remove assert_equal 'Element.remove("foo");', @generator.remove('foo') - assert_equal '["foo", "bar", "baz"].each(Element.remove);', + assert_equal '["foo","bar","baz"].each(Element.remove);', @generator.remove('foo', 'bar', 'baz') end def test_show assert_equal 'Element.show("foo");', @generator.show('foo') - assert_equal '["foo", "bar", "baz"].each(Element.show);', + assert_equal '["foo","bar","baz"].each(Element.show);', @generator.show('foo', 'bar', 'baz') end def test_hide assert_equal 'Element.hide("foo");', @generator.hide('foo') - assert_equal '["foo", "bar", "baz"].each(Element.hide);', + assert_equal '["foo","bar","baz"].each(Element.hide);', @generator.hide('foo', 'bar', 'baz') end def test_toggle assert_equal 'Element.toggle("foo");', @generator.toggle('foo') - assert_equal '["foo", "bar", "baz"].each(Element.toggle);', + assert_equal '["foo","bar","baz"].each(Element.toggle);', @generator.toggle('foo', 'bar', 'baz') end @@ -385,7 +385,7 @@ def test_to_s assert_equal <<-EOS.chomp, @generator.to_s Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" }); Element.insert("element", { bottom: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" }); -["foo", "bar"].each(Element.remove); +["foo","bar"].each(Element.remove); Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E"); EOS end @@ -554,8 +554,8 @@ def test_collection_proxy_with_zip end assert_equal <<-EOS.strip, @generator.to_s -var a = [1, 2, 3].zip([4, 5, 6], [7, 8, 9]); -var b = [1, 2, 3].zip([4, 5, 6], [7, 8, 9], function(array) { +var a = [1, 2, 3].zip([4,5,6], [7,8,9]); +var b = [1, 2, 3].zip([4,5,6], [7,8,9], function(array) { return array.reverse(); }); EOS @@ -606,7 +606,7 @@ def test_debug_rjs def test_literal literal = @generator.literal("function() {}") - assert_equal "function() {}", literal.to_json + assert_equal "function() {}", ActiveSupport::JSON.encode(literal) assert_equal "", @generator.to_s end diff --git a/activerecord/lib/active_record/serializers/json_serializer.rb b/activerecord/lib/active_record/serializers/json_serializer.rb index 1fd65ed006d55..836190eff7143 100644 --- a/activerecord/lib/active_record/serializers/json_serializer.rb +++ b/activerecord/lib/active_record/serializers/json_serializer.rb @@ -72,13 +72,17 @@ def self.included(base) # {"comments": [{"body": "Don't think too hard"}], # "title": "So I was thinking"}]} def to_json(options = {}) + json = JsonSerializer.new(self, options).to_s if include_root_in_json - "{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}" + "{#{self.class.json_class_name}:#{json}}" else - JsonSerializer.new(self, options).to_s + json end end + # For compatibility with ActiveSupport::JSON.encode + alias rails_to_json to_json + def from_json(json) self.attributes = ActiveSupport::JSON.decode(json) self @@ -86,7 +90,7 @@ def from_json(json) class JsonSerializer < ActiveRecord::Serialization::Serializer #:nodoc: def serialize - serializable_record.to_json + ActiveSupport::JSON.encode(serializable_record) end end diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index 975acde096f2d..0ffbc9bf3b8ef 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -26,19 +26,19 @@ def test_should_demodulize_root_in_json NamespacedContact.include_root_in_json = true @contact = NamespacedContact.new :name => 'whatever' json = @contact.to_json - assert_match %r{^\{"namespaced_contact": \{}, json + assert_match %r{^\{"namespaced_contact":\{}, json end def test_should_include_root_in_json Contact.include_root_in_json = true json = @contact.to_json - assert_match %r{^\{"contact": \{}, json - assert_match %r{"name": "Konata Izumi"}, json - assert_match %r{"age": 16}, json - assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_match %r{"awesome": true}, json - assert_match %r{"preferences": \{"shows": "anime"\}}, json + assert_match %r{^\{"contact":\{}, json + assert_match %r{"name":"Konata Izumi"}, json + assert_match %r{"age":16}, json + assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_match %r{"awesome":true}, json + assert_match %r{"preferences":\{"shows":"anime"\}}, json ensure Contact.include_root_in_json = false end @@ -46,31 +46,31 @@ def test_should_include_root_in_json def test_should_encode_all_encodable_attributes json = @contact.to_json - assert_match %r{"name": "Konata Izumi"}, json - assert_match %r{"age": 16}, json - assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_match %r{"awesome": true}, json - assert_match %r{"preferences": \{"shows": "anime"\}}, json + assert_match %r{"name":"Konata Izumi"}, json + assert_match %r{"age":16}, json + assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_match %r{"awesome":true}, json + assert_match %r{"preferences":\{"shows":"anime"\}}, json end def test_should_allow_attribute_filtering_with_only json = @contact.to_json(:only => [:name, :age]) - assert_match %r{"name": "Konata Izumi"}, json - assert_match %r{"age": 16}, json - assert_no_match %r{"awesome": true}, json - assert !json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_no_match %r{"preferences": \{"shows": "anime"\}}, json + assert_match %r{"name":"Konata Izumi"}, json + assert_match %r{"age":16}, json + assert_no_match %r{"awesome":true}, json + assert !json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_no_match %r{"preferences":\{"shows":"anime"\}}, json end def test_should_allow_attribute_filtering_with_except json = @contact.to_json(:except => [:name, :age]) - assert_no_match %r{"name": "Konata Izumi"}, json - assert_no_match %r{"age": 16}, json - assert_match %r{"awesome": true}, json - assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_match %r{"preferences": \{"shows": "anime"\}}, json + assert_no_match %r{"name":"Konata Izumi"}, json + assert_no_match %r{"age":16}, json + assert_match %r{"awesome":true}, json + assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_match %r{"preferences":\{"shows":"anime"\}}, json end def test_methods_are_called_on_object @@ -79,12 +79,12 @@ def @contact.label; "Has cheezburger"; end def @contact.favorite_quote; "Constraints are liberating"; end # Single method. - assert_match %r{"label": "Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label) + assert_match %r{"label":"Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label) # Both methods. methods_json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote]) - assert_match %r{"label": "Has cheezburger"}, methods_json - assert_match %r{"favorite_quote": "Constraints are liberating"}, methods_json + assert_match %r{"label":"Has cheezburger"}, methods_json + assert_match %r{"favorite_quote":"Constraints are liberating"}, methods_json end end @@ -99,42 +99,42 @@ def setup def test_includes_uses_association_name json = @david.to_json(:include => :posts) - assert_match %r{"posts": \[}, json + assert_match %r{"posts":\[}, json - assert_match %r{"id": 1}, json - assert_match %r{"name": "David"}, json + assert_match %r{"id":1}, json + assert_match %r{"name":"David"}, json - assert_match %r{"author_id": 1}, json - assert_match %r{"title": "Welcome to the weblog"}, json - assert_match %r{"body": "Such a lovely day"}, json + assert_match %r{"author_id":1}, json + assert_match %r{"title":"Welcome to the weblog"}, json + assert_match %r{"body":"Such a lovely day"}, json - assert_match %r{"title": "So I was thinking"}, json - assert_match %r{"body": "Like I hopefully always am"}, json + assert_match %r{"title":"So I was thinking"}, json + assert_match %r{"body":"Like I hopefully always am"}, json end def test_includes_uses_association_name_and_applies_attribute_filters json = @david.to_json(:include => { :posts => { :only => :title } }) - assert_match %r{"name": "David"}, json - assert_match %r{"posts": \[}, json + assert_match %r{"name":"David"}, json + assert_match %r{"posts":\[}, json - assert_match %r{"title": "Welcome to the weblog"}, json - assert_no_match %r{"body": "Such a lovely day"}, json + assert_match %r{"title":"Welcome to the weblog"}, json + assert_no_match %r{"body":"Such a lovely day"}, json - assert_match %r{"title": "So I was thinking"}, json - assert_no_match %r{"body": "Like I hopefully always am"}, json + assert_match %r{"title":"So I was thinking"}, json + assert_no_match %r{"body":"Like I hopefully always am"}, json end def test_includes_fetches_second_level_associations json = @david.to_json(:include => { :posts => { :include => { :comments => { :only => :body } } } }) - assert_match %r{"name": "David"}, json - assert_match %r{"posts": \[}, json + assert_match %r{"name":"David"}, json + assert_match %r{"posts":\[}, json - assert_match %r{"comments": \[}, json - assert_match %r{\{"body": "Thank you again for the welcome"\}}, json - assert_match %r{\{"body": "Don't think too hard"\}}, json - assert_no_match %r{"post_id": }, json + assert_match %r{"comments":\[}, json + assert_match %r{\{"body":"Thank you again for the welcome"\}}, json + assert_match %r{\{"body":"Don't think too hard"\}}, json + assert_no_match %r{"post_id":}, json end def test_includes_fetches_nth_level_associations @@ -151,11 +151,11 @@ def test_includes_fetches_nth_level_associations } }) - assert_match %r{"name": "David"}, json - assert_match %r{"posts": \[}, json + assert_match %r{"name":"David"}, json + assert_match %r{"posts":\[}, json - assert_match %r{"taggings": \[}, json - assert_match %r{"tag": \{"name": "General"\}}, json + assert_match %r{"taggings":\[}, json + assert_match %r{"tag":\{"name":"General"\}}, json end def test_should_not_call_methods_on_associations_that_dont_respond @@ -163,20 +163,20 @@ def @david.favorite_quote; "Constraints are liberating"; end json = @david.to_json(:include => :posts, :methods => :favorite_quote) assert !@david.posts.first.respond_to?(:favorite_quote) - assert_match %r{"favorite_quote": "Constraints are liberating"}, json - assert_equal %r{"favorite_quote": }.match(json).size, 1 + assert_match %r{"favorite_quote":"Constraints are liberating"}, json + assert_equal %r{"favorite_quote":}.match(json).size, 1 end def test_should_allow_only_option_for_list_of_authors authors = [@david, @mary] - assert_equal %([{"name": "David"}, {"name": "Mary"}]), authors.to_json(:only => :name) + assert_equal %([{"name":"David"},{"name":"Mary"}]), authors.to_json(:only => :name) end def test_should_allow_except_option_for_list_of_authors authors = [@david, @mary] - assert_equal %([{"id": 1}, {"id": 2}]), authors.to_json(:except => [:name, :author_address_id, :author_address_extra_id]) + assert_equal %([{"id":1},{"id":2}]), authors.to_json(:except => [:name, :author_address_id, :author_address_extra_id]) end def test_should_allow_includes_for_list_of_authors @@ -188,8 +188,8 @@ def test_should_allow_includes_for_list_of_authors } ) - ['"name": "David"', '"posts": [', '{"id": 1}', '{"id": 2}', '{"id": 4}', - '{"id": 5}', '{"id": 6}', '"name": "Mary"', '"posts": [{"id": 7}]'].each do |fragment| + ['"name":"David"', '"posts":[', '{"id":1}', '{"id":2}', '{"id":4}', + '{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[{"id":7}]'].each do |fragment| assert json.include?(fragment), json end end @@ -200,6 +200,6 @@ def test_should_allow_options_for_hash_of_authors 2 => @mary } - assert_equal %({"1": {"name": "David"}}), authors_hash.to_json(:only => [1, :name]) + assert_equal %({"1":{"name":"David"}}), authors_hash.to_json(:only => [1, :name]) end end diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 8ff7ab4bd1166..b04f705a4e686 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -894,9 +894,12 @@ def to_xml(options={}) # person.to_json(:except => ["first_name"]) # # => {"last_name": "Smith"} def to_json(options={}) - attributes.to_json(options) + ActiveSupport::JSON.encode(attributes, options) end + # For compatibility with ActiveSupport::JSON.encode + alias rails_to_json to_json + # Returns the serialized string representation of the resource in the configured # serialization format specified in ActiveResource::Base.format. The options # applicable depend on the configured encoding format. diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index 2bdb4a7b11189..ee3cde6eaa121 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,6 +1,34 @@ module ActiveSupport # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. mattr_accessor :use_standard_json_time_format + # Look for and parse json strings that look like ISO 8601 times. + mattr_accessor :parse_json_times + + module JSON + # matches YAML-formatted dates + DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/ + + class << self + attr_reader :backend + delegate :decode, :to => :backend + + def backend=(name) + if name.is_a?(Module) + @backend = name + else + require "active_support/json/backends/#{name.to_s.downcase}.rb" + @backend = ActiveSupport::JSON::Backends::const_get(name) + end + end + + def with_backend(name) + old_backend, self.backend = backend, name + yield + ensure + self.backend = old_backend + end + end + end class << self def escape_html_entities_in_json @@ -17,7 +45,8 @@ def escape_html_entities_in_json=(value) @escape_html_entities_in_json = value end end + + JSON.backend = 'Yaml' end -require 'active_support/json/encoding' -require 'active_support/json/decoding' +require 'active_support/json/encoding' \ No newline at end of file diff --git a/activesupport/lib/active_support/json/backends/jsongem.rb b/activesupport/lib/active_support/json/backends/jsongem.rb new file mode 100644 index 0000000000000..de847e30a31d6 --- /dev/null +++ b/activesupport/lib/active_support/json/backends/jsongem.rb @@ -0,0 +1,36 @@ +module ActiveSupport + module JSON + ParseError = ::JSON::ParserError + + module Backends + module JSONGem + extend self + + # Converts a JSON string into a Ruby object. + def decode(json) + data = ::JSON.parse(json) + if ActiveSupport.parse_json_times + convert_dates_from(data) + else + data + end + end + + private + def convert_dates_from(data) + case data + when DATE_REGEX + DateTime.parse(data) + when Array + data.map! { |d| convert_dates_from(d) } + when Hash + data.each do |key, value| + data[key] = convert_dates_from(value) + end + else data + end + end + end + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb new file mode 100644 index 0000000000000..97dd46852c5cf --- /dev/null +++ b/activesupport/lib/active_support/json/backends/yaml.rb @@ -0,0 +1,83 @@ +require 'active_support/core_ext/string/starts_ends_with' + +module ActiveSupport + module JSON + class ParseError < StandardError + end + + module Backends + module Yaml + extend self + + # Converts a JSON string into a Ruby object. + def decode(json) + YAML.load(convert_json_to_yaml(json)) + rescue ArgumentError => e + raise ParseError, "Invalid JSON string" + end + + protected + # Ensure that ":" and "," are always followed by a space + def convert_json_to_yaml(json) #:nodoc: + require 'strscan' unless defined? ::StringScanner + scanner, quoting, marks, pos, times = ::StringScanner.new(json), false, [], nil, [] + while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/) + case char = scanner[1] + when '"', "'" + if !quoting + quoting = char + pos = scanner.pos + elsif quoting == char + if json[pos..scanner.pos-2] =~ DATE_REGEX + # found a date, track the exact positions of the quotes so we can remove them later. + # oh, and increment them for each current mark, each one is an extra padded space that bumps + # the position in the final YAML output + total_marks = marks.size + times << pos+total_marks << scanner.pos+total_marks + end + quoting = false + end + when ":","," + marks << scanner.pos - 1 unless quoting + end + end + + if marks.empty? + json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do + ustr = $1 + if ustr.start_with?('u') + [ustr[1..-1].to_i(16)].pack("U") + elsif ustr == '\\' + '\\\\' + else + ustr + end + end + else + left_pos = [-1].push(*marks) + right_pos = marks << scanner.pos + scanner.rest_size + output = [] + left_pos.each_with_index do |left, i| + scanner.pos = left.succ + output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do + ustr = $1 + if ustr.start_with?('u') + [ustr[1..-1].to_i(16)].pack("U") + elsif ustr == '\\' + '\\\\' + else + ustr + end + end + end + output = output * " " + + times.each { |i| output[i-1] = ' ' } + output.gsub!(/\\\//, '/') + output + end + end + end + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb deleted file mode 100644 index 0e079341ff7ec..0000000000000 --- a/activesupport/lib/active_support/json/decoding.rb +++ /dev/null @@ -1,82 +0,0 @@ -require 'yaml' -require 'strscan' - -module ActiveSupport - module JSON - class ParseError < StandardError - end - - class << self - # Converts a JSON string into a Ruby object. - def decode(json) - YAML.load(convert_json_to_yaml(json)) - rescue ArgumentError => e - raise ParseError, "Invalid JSON string" - end - - protected - # matches YAML-formatted dates - DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/ - - # Ensure that ":" and "," are always followed by a space - def convert_json_to_yaml(json) #:nodoc: - scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, [] - while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/) - case char = scanner[1] - when '"', "'" - if !quoting - quoting = char - pos = scanner.pos - elsif quoting == char - if json[pos..scanner.pos-2] =~ DATE_REGEX - # found a date, track the exact positions of the quotes so we can remove them later. - # oh, and increment them for each current mark, each one is an extra padded space that bumps - # the position in the final YAML output - total_marks = marks.size - times << pos+total_marks << scanner.pos+total_marks - end - quoting = false - end - when ":","," - marks << scanner.pos - 1 unless quoting - end - end - - if marks.empty? - json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do - ustr = $1 - if ustr.starts_with?('u') - [ustr[1..-1].to_i(16)].pack("U") - elsif ustr == '\\' - '\\\\' - else - ustr - end - end - else - left_pos = [-1].push(*marks) - right_pos = marks << scanner.pos + scanner.rest_size - output = [] - left_pos.each_with_index do |left, i| - scanner.pos = left.succ - output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do - ustr = $1 - if ustr.starts_with?('u') - [ustr[1..-1].to_i(16)].pack("U") - elsif ustr == '\\' - '\\\\' - else - ustr - end - end - end - output = output * " " - - times.each { |i| output[i-1] = ' ' } - output.gsub!(/\\\//, '/') - output - end - end - end - end -end diff --git a/activesupport/lib/active_support/json/encoders/date.rb b/activesupport/lib/active_support/json/encoders/date.rb index cc84de13881f0..79c395736262d 100644 --- a/activesupport/lib/active_support/json/encoders/date.rb +++ b/activesupport/lib/active_support/json/encoders/date.rb @@ -11,11 +11,13 @@ class Date # # With ActiveSupport.use_standard_json_time_format = false # Date.new(2005,2,1).to_json # # => "2005/02/01" - def to_json(options = nil) + def rails_to_json(options = nil) if ActiveSupport.use_standard_json_time_format %("#{strftime("%Y-%m-%d")}") else %("#{strftime("%Y/%m/%d")}") end end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/date_time.rb b/activesupport/lib/active_support/json/encoders/date_time.rb index 6c85824105751..cdfc39b9f306e 100644 --- a/activesupport/lib/active_support/json/encoders/date_time.rb +++ b/activesupport/lib/active_support/json/encoders/date_time.rb @@ -11,11 +11,13 @@ class DateTime # # With ActiveSupport.use_standard_json_time_format = false # DateTime.civil(2005,2,1,15,15,10).to_json # # => "2005/02/01 15:15:10 +0000" - def to_json(options = nil) + def rails_to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect else strftime('"%Y/%m/%d %H:%M:%S %z"') end end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/enumerable.rb b/activesupport/lib/active_support/json/encoders/enumerable.rb index 881b1d62c1c45..e1c3ec249d0e8 100644 --- a/activesupport/lib/active_support/json/encoders/enumerable.rb +++ b/activesupport/lib/active_support/json/encoders/enumerable.rb @@ -6,7 +6,9 @@ module Enumerable # # => users.to_json(:only => :name) # # will pass the :only => :name option to each user. - def to_json(options = {}) #:nodoc: - "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ', '}]" + def rails_to_json(options = {}) #:nodoc: + "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]" end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/false_class.rb b/activesupport/lib/active_support/json/encoders/false_class.rb index bf0844334b49a..a7657cca379d0 100644 --- a/activesupport/lib/active_support/json/encoders/false_class.rb +++ b/activesupport/lib/active_support/json/encoders/false_class.rb @@ -1,5 +1,7 @@ class FalseClass - def to_json(options = nil) #:nodoc: + def rails_to_json(options = nil) #:nodoc: 'false' end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/hash.rb b/activesupport/lib/active_support/json/encoders/hash.rb index e38b4f3e16ee0..bc58b3311308e 100644 --- a/activesupport/lib/active_support/json/encoders/hash.rb +++ b/activesupport/lib/active_support/json/encoders/hash.rb @@ -28,7 +28,7 @@ class Hash # would pass the :include => :posts option to users, # allowing the posts association in the User model to be converted to JSON # as well. - def to_json(options = {}) #:nodoc: + def rails_to_json(options = {}) #:nodoc: hash_keys = self.keys if except = options[:except] @@ -39,8 +39,10 @@ def to_json(options = {}) #:nodoc: result = '{' result << hash_keys.map do |key| - "#{ActiveSupport::JSON.encode(key.to_s)}: #{ActiveSupport::JSON.encode(self[key], options)}" - end * ', ' + "#{ActiveSupport::JSON.encode(key.to_s)}:#{ActiveSupport::JSON.encode(self[key], options)}" + end * ',' result << '}' end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/nil_class.rb b/activesupport/lib/active_support/json/encoders/nil_class.rb index 4763471ac4d7a..b31e1dd2491e5 100644 --- a/activesupport/lib/active_support/json/encoders/nil_class.rb +++ b/activesupport/lib/active_support/json/encoders/nil_class.rb @@ -1,5 +1,7 @@ class NilClass - def to_json(options = nil) #:nodoc: + def rails_to_json(options = nil) #:nodoc: 'null' end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/numeric.rb b/activesupport/lib/active_support/json/encoders/numeric.rb index 38713fb3695a0..491b330c39ca3 100644 --- a/activesupport/lib/active_support/json/encoders/numeric.rb +++ b/activesupport/lib/active_support/json/encoders/numeric.rb @@ -1,5 +1,7 @@ class Numeric - def to_json(options = nil) #:nodoc: + def rails_to_json(options = nil) #:nodoc: to_s end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/object.rb b/activesupport/lib/active_support/json/encoders/object.rb index ca215d4964dd6..5556eb540d90f 100644 --- a/activesupport/lib/active_support/json/encoders/object.rb +++ b/activesupport/lib/active_support/json/encoders/object.rb @@ -1,6 +1,8 @@ class Object # Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info. - def to_json(options = {}) + def rails_to_json(options = {}) ActiveSupport::JSON.encode(instance_values, options) end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/regexp.rb b/activesupport/lib/active_support/json/encoders/regexp.rb index b6116b70b57c2..63ccd7c490e8a 100644 --- a/activesupport/lib/active_support/json/encoders/regexp.rb +++ b/activesupport/lib/active_support/json/encoders/regexp.rb @@ -1,5 +1,7 @@ class Regexp - def to_json(options = nil) #:nodoc: + def rails_to_json(options = nil) #:nodoc: inspect end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/string.rb b/activesupport/lib/active_support/json/encoders/string.rb index 5ef797955a78b..27bef3b9cc235 100644 --- a/activesupport/lib/active_support/json/encoders/string.rb +++ b/activesupport/lib/active_support/json/encoders/string.rb @@ -22,7 +22,7 @@ module Encoding ActiveSupport.escape_html_entities_in_json = true class String - def to_json(options = nil) #:nodoc: + def rails_to_json(options = nil) #:nodoc: json = '"' + gsub(ActiveSupport::JSON::Encoding.escape_regex) { |s| ActiveSupport::JSON::Encoding::ESCAPED_CHARS[s] } @@ -33,4 +33,6 @@ def to_json(options = nil) #:nodoc: s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&') } + '"' end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/symbol.rb b/activesupport/lib/active_support/json/encoders/symbol.rb index 485112f97cff0..6487bf8cb7dff 100644 --- a/activesupport/lib/active_support/json/encoders/symbol.rb +++ b/activesupport/lib/active_support/json/encoders/symbol.rb @@ -1,5 +1,7 @@ class Symbol - def to_json(options = {}) #:nodoc: + def rails_to_json(options = {}) #:nodoc: ActiveSupport::JSON.encode(to_s, options) end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/time.rb b/activesupport/lib/active_support/json/encoders/time.rb index f45a0059e8376..786273afc55ba 100644 --- a/activesupport/lib/active_support/json/encoders/time.rb +++ b/activesupport/lib/active_support/json/encoders/time.rb @@ -11,11 +11,13 @@ class Time # # With ActiveSupport.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).to_json # # => "2005/02/01 15:15:10 +0000" - def to_json(options = nil) + def rails_to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect else %("#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}") end end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoders/true_class.rb b/activesupport/lib/active_support/json/encoders/true_class.rb index 037d812b3ff65..ac7c7d1e871cd 100644 --- a/activesupport/lib/active_support/json/encoders/true_class.rb +++ b/activesupport/lib/active_support/json/encoders/true_class.rb @@ -1,5 +1,7 @@ class TrueClass - def to_json(options = nil) #:nodoc: + def rails_to_json(options = nil) #:nodoc: 'true' end + + alias to_json rails_to_json end diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index aaaa3cdfd2aee..2aa5ffc8507e1 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -8,7 +8,7 @@ def self.encode(value, options = {}) seen = (options[:seen] ||= []) raise CircularReferenceError, 'object references itself' if seen.include?(value) seen << value - value.send(:to_json, options) + value.rails_to_json(options) ensure seen.pop end diff --git a/activesupport/lib/active_support/json/variable.rb b/activesupport/lib/active_support/json/variable.rb index 7fd23b0a9e089..9924168196012 100644 --- a/activesupport/lib/active_support/json/variable.rb +++ b/activesupport/lib/active_support/json/variable.rb @@ -2,9 +2,11 @@ module ActiveSupport module JSON # A string that returns itself as its JSON-encoded form. class Variable < String - def to_json(options=nil) + def rails_to_json(options=nil) self end + + alias to_json rails_to_json end end end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 518ca7742f558..5572f6137954b 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -120,7 +120,7 @@ def xmlschema(fraction_digits = 0) # # With ActiveSupport.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json # # => "2005/02/01 15:15:10 +0000" - def to_json(options = nil) + def rails_to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect else @@ -128,6 +128,8 @@ def to_json(options = nil) end end + alias to_json rails_to_json + def to_yaml(options = {}) if options.kind_of?(YAML::Emitter) utc.to_yaml(options) diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index accfe51ed6041..03ed783ce5f51 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -55,12 +55,12 @@ def test_zone end def test_to_json - assert_equal "\"1999/12/31 19:00:00 -0500\"", @twz.to_json + assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(@twz) end def test_to_json_with_use_standard_json_time_format_config_set_to_true old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true - assert_equal "\"1999-12-31T19:00:00-05:00\"", @twz.to_json + assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(@twz) ensure ActiveSupport.use_standard_json_time_format = old end diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index 8fe40557d677e..7ffd3f8a60bbe 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -1,49 +1,74 @@ # encoding: UTF-8 require 'abstract_unit' -class TestJSONDecoding < Test::Unit::TestCase +class TestJSONDecoding < ActiveSupport::TestCase TESTS = { %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, - %q({returnTo:{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}}, %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}}, %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]}, %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]}, - %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, - %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, + %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, + %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, # multibyte %({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"}, - %({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)}, - %({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)}, + %({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)}, + %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)}, # no time zone - %({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, + %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, # needs to be *exact* - %({a: " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, - %({a: "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, + %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, + %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, %([]) => [], %({}) => {}, - %(1) => 1, - %("") => "", - %("\\"") => "\"", - %(null) => nil, - %(true) => true, - %(false) => false, - %q("http:\/\/test.host\/posts\/1") => "http://test.host/posts/1", - %q("\u003cunicode\u0020escape\u003e") => "", - %q("\\\\u0020skip double backslashes") => "\\u0020skip double backslashes", - %q({a: "\u003cbr /\u003e"}) => {'a' => "
"}, - %q({b:["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["","",""]} + %({"a":1}) => {"a" => 1}, + %({"a": ""}) => {"a" => ""}, + %({"a":"\\""}) => {"a" => "\""}, + %({"a": null}) => {"a" => nil}, + %({"a": true}) => {"a" => true}, + %({"a": false}) => {"a" => false}, + %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"}, + %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => ""}, + %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"}, + %q({"a": "\u003cbr /\u003e"}) => {'a' => "
"}, + %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["","",""]} } - - TESTS.each do |json, expected| - define_method :"test_json_decoding_#{json}" do - assert_nothing_raised do - assert_equal expected, ActiveSupport::JSON.decode(json) + + backends = %w(Yaml) + begin + gem 'json', '>= 1.1' + require 'json' + backends << "JSONGem" + rescue Gem::LoadError + # Skip JSON gem tests + end + + backends.each do |backend| + TESTS.each do |json, expected| + test "json decodes #{json} with the #{backend} backend" do + ActiveSupport.parse_json_times = true + silence_warnings do + ActiveSupport::JSON.with_backend backend do + assert_nothing_raised do + assert_equal expected, ActiveSupport::JSON.decode(json) + end + end + end + end + end + end + + if backends.include?("JSONGem") + test "json decodes time json with time parsing disabled" do + ActiveSupport.parse_json_times = false + expected = {"a" => "2007-01-01 01:12:34 Z"} + ActiveSupport::JSON.with_backend "JSONGem" do + assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) end end end - + def test_failed_json_decoding assert_raise(ActiveSupport::JSON::ParseError) { ActiveSupport::JSON.decode(%({: 1})) } end -end +end \ No newline at end of file diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 7d2eedad61932..823eab0a93809 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -18,14 +18,14 @@ def initialize(a, b) [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], [ 'http://test.host/posts/1', %("http://test.host/posts/1")]] - ArrayTests = [[ ['a', 'b', 'c'], %([\"a\", \"b\", \"c\"]) ], - [ [1, 'a', :b, nil, false], %([1, \"a\", \"b\", null, false]) ]] + ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ], + [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] SymbolTests = [[ :a, %("a") ], [ :this, %("this") ], [ :"a b", %("a b") ]] - ObjectTests = [[ Foo.new(1, 2), %({\"a\": 1, \"b\": 2}) ]] + ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]] VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'], [ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']] @@ -46,7 +46,7 @@ def initialize(a, b) ActiveSupport.escape_html_entities_in_json = class_tests !~ /^Standard/ ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/ self.class.const_get(class_tests).each do |pair| - assert_equal pair.last, pair.first.to_json + assert_equal pair.last, ActiveSupport::JSON.encode(pair.first) end ensure ActiveSupport.escape_html_entities_in_json = false @@ -56,45 +56,45 @@ def initialize(a, b) end def test_hash_encoding - assert_equal %({\"a\": \"b\"}), { :a => :b }.to_json - assert_equal %({\"a\": 1}), { 'a' => 1 }.to_json - assert_equal %({\"a\": [1, 2]}), { 'a' => [1,2] }.to_json - assert_equal %({"1": 2}), { 1 => 2 }.to_json + assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b) + assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1) + assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode('a' => [1,2]) + assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2) - sorted_json = '{' + {:a => :b, :c => :d}.to_json[1..-2].split(', ').sort.join(', ') + '}' - assert_equal %({\"a\": \"b\", \"c\": \"d\"}), sorted_json + sorted_json = '{' + ActiveSupport::JSON.encode(:a => :b, :c => :d)[1..-2].split(',').sort.join(',') + '}' + assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json end def test_utf8_string_encoded_properly_when_kcode_is_utf8 with_kcode 'UTF8' do - assert_equal '"\\u20ac2.99"', '€2.99'.to_json - assert_equal '"\\u270e\\u263a"', '✎☺'.to_json + assert_equal '"\\u20ac2.99"', ActiveSupport::JSON.encode('€2.99') + assert_equal '"\\u270e\\u263a"', ActiveSupport::JSON.encode('✎☺') end end def test_exception_raised_when_encoding_circular_reference a = [1] a << a - assert_raise(ActiveSupport::JSON::CircularReferenceError) { a.to_json } + assert_raise(ActiveSupport::JSON::CircularReferenceError) { ActiveSupport::JSON.encode(a) } end def test_hash_key_identifiers_are_always_quoted values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"} - assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(values.to_json) + assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values)) end def test_hash_should_allow_key_filtering_with_only - assert_equal %({"a": 1}), { 'a' => 1, :b => 2, :c => 3 }.to_json(:only => 'a') + assert_equal %({"a":1}), ActiveSupport::JSON.encode({'a' => 1, :b => 2, :c => 3}, :only => 'a') end def test_hash_should_allow_key_filtering_with_except - assert_equal %({"b": 2}), { 'foo' => 'bar', :b => 2, :c => 3 }.to_json(:except => ['foo', :c]) + assert_equal %({"b":2}), ActiveSupport::JSON.encode({'foo' => 'bar', :b => 2, :c => 3}, :except => ['foo', :c]) end def test_time_to_json_includes_local_offset ActiveSupport.use_standard_json_time_format = true with_env_tz 'US/Eastern' do - assert_equal %("2005-02-01T15:15:10-05:00"), Time.local(2005,2,1,15,15,10).to_json + assert_equal %("2005-02-01T15:15:10-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) end ensure ActiveSupport.use_standard_json_time_format = false @@ -108,7 +108,7 @@ def test_nested_hash_with_float :latitude => 123.234 } } - result = hash.to_json + result = ActiveSupport::JSON.encode(hash) end end @@ -133,6 +133,6 @@ def test_enumerable_should_passthrough_options_to_elements ActiveSupport::JSON.expects(:encode).with(2, json_options) ActiveSupport::JSON.expects(:encode).with('foo', json_options) - [1, 2, 'foo'].to_json(json_options) + [1, 2, 'foo'].rails_to_json(json_options) end end