* Add pluggable JSON backends with support for the JSON gem. [rick]
Example: ActiveSupport::JSON.backend = "JSONGem" All internal Rails JSON encoding is now handled by ActiveSupport::JSON.encode(). Use of #to_json is not recommended, as it may clash with other libraries that overwrite it. However, you can recover Rails specific functionality if you really want to use #to_json. gem 'json' ActiveSupport::JSON.backend = "JSONGem" class ActiveRecord::Base alias to_json rails_to_json end
This commit is contained in:
parent
bab2bfa692
commit
3c4c6bd0df
|
@ -254,7 +254,7 @@ module ActionController
|
|||
render_for_text(js)
|
||||
|
||||
elsif 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)
|
||||
|
|
|
@ -973,7 +973,7 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
|
||||
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 @@ module ActionView
|
|||
|
||||
class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
|
||||
def initialize(generator, pattern)
|
||||
super(generator, "$$(#{pattern.to_json})")
|
||||
super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,7 +43,7 @@ module ActionView
|
|||
# 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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
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 @@ module ActionView
|
|||
# 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
|
||||
|
|
|
@ -194,19 +194,19 @@ class TestController < ActionController::Base
|
|||
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
|
||||
|
@ -875,31 +875,31 @@ class RenderTest < ActionController::TestCase
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -328,28 +328,28 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
|
|||
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
|
||||
|
||||
|
@ -386,7 +386,7 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
|
|||
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
|
||||
|
@ -555,8 +555,8 @@ return (value.className == "welcome");
|
|||
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
|
||||
|
@ -607,7 +607,7 @@ return value.reverse();
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -74,13 +74,17 @@ module ActiveRecord #:nodoc:
|
|||
# {"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
|
||||
|
@ -88,7 +92,7 @@ module ActiveRecord #:nodoc:
|
|||
|
||||
class JsonSerializer < ActiveRecord::Serialization::Serializer #:nodoc:
|
||||
def serialize
|
||||
serializable_record.to_json
|
||||
ActiveSupport::JSON.encode(serializable_record)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -26,19 +26,19 @@ class JsonSerializationTest < ActiveRecord::TestCase
|
|||
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 @@ class JsonSerializationTest < ActiveRecord::TestCase
|
|||
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 @@ class JsonSerializationTest < ActiveRecord::TestCase
|
|||
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 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
|||
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 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
|||
}
|
||||
})
|
||||
|
||||
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 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
|||
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 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
|||
}
|
||||
)
|
||||
|
||||
['"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 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
|||
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
|
||||
|
|
|
@ -887,9 +887,12 @@ module ActiveResource
|
|||
# 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.
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
*Edge*
|
||||
|
||||
* Add ActiveSupport.parse_json_times to disable time parsing in JSON backends that don't support it or don't need it. [rick]
|
||||
|
||||
* Add pluggable JSON backends with support for the JSON gem. [rick]
|
||||
Example: ActiveSupport::JSON.backend = "JSONGem"
|
||||
|
||||
All internal Rails JSON encoding is now handled by ActiveSupport::JSON.encode(). Use of #to_json is not recommended, as it may clash with other libraries that overwrite it. However, you can recover Rails specific functionality
|
||||
if you really want to use #to_json.
|
||||
|
||||
gem 'json'
|
||||
ActiveSupport::JSON.backend = "JSONGem"
|
||||
|
||||
class ActiveRecord::Base
|
||||
alias to_json rails_to_json
|
||||
end
|
||||
|
||||
* require 'active_support' no longer orders the whole menu of core extensions. Ask for just what you need: e.g. require 'active_support/core/time' to use timezones, durations, and stdlib date/time extensions. [Jeremy Kemper]
|
||||
|
||||
* Removed rarely-used DRb cache store. [Jeremy Kemper]
|
||||
|
|
|
@ -1,8 +1,37 @@
|
|||
require 'active_support/core_ext/module/delegation'
|
||||
require 'active_support/core_ext/module/attribute_accessors'
|
||||
|
||||
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
|
||||
|
@ -19,7 +48,8 @@ module ActiveSupport
|
|||
@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'
|
|
@ -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
|
|
@ -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
|
|
@ -1,82 +0,0 @@
|
|||
require 'active_support/core_ext/string/starts_ends_with'
|
||||
|
||||
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:
|
||||
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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,7 +6,9 @@ module Enumerable
|
|||
# # => users.to_json(:only => :name)
|
||||
#
|
||||
# will pass the <tt>:only => :name</tt> 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,7 +30,7 @@ class Hash
|
|||
# would pass the <tt>:include => :posts</tt> option to <tt>users</tt>,
|
||||
# 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]
|
||||
|
@ -41,8 +41,10 @@ class Hash
|
|||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,7 +2,9 @@ require 'active_support/core_ext/object/instance_variables'
|
|||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -22,7 +22,7 @@ end
|
|||
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 @@ class String
|
|||
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&')
|
||||
} + '"'
|
||||
end
|
||||
|
||||
alias to_json rails_to_json
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,11 +13,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,7 +8,7 @@ module ActiveSupport
|
|||
seen = (options[:seen] ||= [])
|
||||
raise CircularReferenceError, 'object references itself' if seen.include?(value)
|
||||
seen << value
|
||||
value.send(:to_json, options)
|
||||
value.send(:rails_to_json, options)
|
||||
ensure
|
||||
seen.pop
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ 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
|
||||
end
|
||||
|
|
|
@ -130,7 +130,7 @@ module ActiveSupport
|
|||
# # 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.respond_to?(:use_standard_json_time_format) || ActiveSupport.use_standard_json_time_format
|
||||
xmlschema.inspect
|
||||
else
|
||||
|
@ -138,6 +138,8 @@ module ActiveSupport
|
|||
end
|
||||
end
|
||||
|
||||
alias to_json rails_to_json
|
||||
|
||||
def to_yaml(options = {})
|
||||
if options.kind_of?(YAML::Emitter)
|
||||
utc.to_yaml(options)
|
||||
|
|
|
@ -57,12 +57,12 @@ class TimeWithZoneTest < Test::Unit::TestCase
|
|||
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
|
||||
|
|
|
@ -1,49 +1,75 @@
|
|||
# encoding: UTF-8
|
||||
require 'abstract_unit'
|
||||
require 'active_support/json'
|
||||
require 'active_support/core_ext/kernel/reporting'
|
||||
|
||||
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") => "<unicode escape>",
|
||||
%q("\\\\u0020skip double backslashes") => "\\u0020skip double backslashes",
|
||||
%q({a: "\u003cbr /\u003e"}) => {'a' => "<br />"},
|
||||
%q({b:["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]}
|
||||
%({"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" => "<unicode escape>"},
|
||||
%q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"},
|
||||
%q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"},
|
||||
%q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]}
|
||||
}
|
||||
|
||||
TESTS.each do |json, expected|
|
||||
test "json decodes #{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
|
||||
|
|
|
@ -19,14 +19,14 @@ class TestJSONEncoding < Test::Unit::TestCase
|
|||
[ '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")']]
|
||||
|
@ -47,7 +47,7 @@ class TestJSONEncoding < Test::Unit::TestCase
|
|||
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
|
||||
|
@ -57,45 +57,45 @@ class TestJSONEncoding < Test::Unit::TestCase
|
|||
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
|
||||
|
@ -109,7 +109,7 @@ class TestJSONEncoding < Test::Unit::TestCase
|
|||
:latitude => 123.234
|
||||
}
|
||||
}
|
||||
result = hash.to_json
|
||||
result = ActiveSupport::JSON.encode(hash)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -134,6 +134,6 @@ class JsonOptionsTests < Test::Unit::TestCase
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue