提交 e567a5eb 编写于 作者: S Sam Stephenson

Add ActiveSupport::JSON and Object#to_json for converting Ruby objects to JSON strings

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3356 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 0b55ce71
*SVN*
* Add ActiveSupport::JSON and Object#to_json for converting Ruby objects to JSON strings. [Sam Stephenson]
* Add Object#with_options for DRYing up multiple calls to methods having shared options. [Sam Stephenson] Example:
ActionController::Routing::Routes.draw do |map|
......
......@@ -34,4 +34,6 @@
require 'active_support/ordered_options'
require 'active_support/option_merger'
require 'active_support/values/time_zone'
\ No newline at end of file
require 'active_support/values/time_zone'
require 'active_support/json'
......@@ -54,6 +54,17 @@ def suppress(*exception_classes)
def with_options(options)
yield ActiveSupport::OptionMerger.new(self, options)
end
def instance_values
instance_variables.inject({}) do |values, name|
values[name[1..-1]] = instance_variable_get(name)
values
end
end
def to_json
ActiveSupport::JSON.encode(self)
end
end
class Class #:nodoc:
......
......@@ -2,10 +2,12 @@
require File.dirname(__FILE__) + '/string/conversions'
require File.dirname(__FILE__) + '/string/access'
require File.dirname(__FILE__) + '/string/starts_ends_with'
require File.dirname(__FILE__) + '/string/iterators'
class String #:nodoc:
include ActiveSupport::CoreExtensions::String::Access
include ActiveSupport::CoreExtensions::String::Conversions
include ActiveSupport::CoreExtensions::String::Inflections
include ActiveSupport::CoreExtensions::String::StartsEndsWith
include ActiveSupport::CoreExtensions::String::Iterators
end
require 'strscan'
module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module String #:nodoc:
# Custom string iterators
module Iterators
# Yields a single-character string for each character in the string.
# When $KCODE = 'UTF8', multi-byte characters are yielded appropriately.
def each_char
scanner, char = StringScanner.new(self), /./mu
loop { yield(scanner.scan(char) || break) }
end
end
end
end
end
require 'active_support/json/encoders'
module ActiveSupport
module JSON #:nodoc:
class CircularReferenceError < StandardError; end
class << self
REFERENCE_STACK_VARIABLE = :json_reference_stack
def encode(value)
raise_on_circular_reference(value) do
Encoders[value.class].call(value)
end
end
protected
def raise_on_circular_reference(value)
stack = Thread.current[REFERENCE_STACK_VARIABLE] ||= []
raise CircularReferenceError, 'object references itself' if
stack.include? value
stack << value
yield
ensure
stack.pop
end
end
end
end
module ActiveSupport
module JSON #:nodoc:
module Encoders
mattr_accessor :encoders
@@encoders = {}
class << self
def define_encoder(klass, &block)
encoders[klass] = block
end
def [](klass)
klass.ancestors.each do |k|
encoder = encoders[k]
return encoder if encoder
end
end
end
end
end
end
Dir[File.dirname(__FILE__) + '/encoders/*.rb'].each do |file|
require file[0..-4]
end
module ActiveSupport
module JSON #:nodoc:
module Encoders
define_encoder Object do |object|
object.instance_values.to_json
end
define_encoder TrueClass do
'true'
end
define_encoder FalseClass do
'false'
end
define_encoder NilClass do
'null'
end
define_encoder String do |string|
returning value = '"' do
string.each_char do |char|
value << case
when char == "\010": '\b'
when char == "\f": '\f'
when char == "\n": '\n'
when char == "\r": '\r'
when char == "\t": '\t'
when char == '"': '\"'
when char == '\\': '\\\\'
when char.length > 1: "\\u#{'%04x' % char.unpack('U').first}"
else; char
end
end
value << '"'
end
end
define_encoder Numeric do |numeric|
numeric.to_s
end
define_encoder Symbol do |symbol|
symbol.to_s.to_json
end
define_encoder Enumerable do |enumerable|
"[#{enumerable.map { |value| value.to_json } * ', '}]"
end
define_encoder Hash do |hash|
returning result = '{' do
result << hash.map do |pair|
pair.map { |value| value.to_json } * ': '
end * ', '
result << '}'
end
end
end
end
end
......@@ -104,4 +104,11 @@ def protected_instance_variables
assert !@dest.instance_variables.include?('@quux')
assert_equal 'baz', @dest.instance_variable_get('@baz')
end
def test_instance_values
object = Object.new
object.instance_variable_set :@a, 1
object.instance_variable_set :@b, 2
assert_equal({'a' => 1, 'b' => 2}, object.instance_values)
end
end
......@@ -89,4 +89,14 @@ def test_starts_ends_with
assert s.ends_with?('lo')
assert !s.ends_with?('el')
end
def test_each_char_with_utf8_string_when_kcode_is_utf8
old_kcode, $KCODE = $KCODE, 'UTF8'
'€2.99'.each_char do |char|
assert_not_equal 1, char.length
break
end
ensure
$KCODE = old_kcode
end
end
$:.unshift File.dirname(__FILE__) + '/../lib'
require 'active_support'
require 'test/unit'
class Foo
def initialize(a, b)
@a, @b = a, b
end
end
class TestJSONEmitters < Test::Unit::TestCase
TrueTests = [[ true, %(true) ]]
FalseTests = [[ false, %(false) ]]
NilTests = [[ nil, %(null) ]]
NumericTests = [[ 1, %(1) ],
[ 2.5, %(2.5) ]]
StringTests = [[ 'this is the string', %("this is the string") ],
[ 'a "string" with quotes', %("a \\"string\\" with quotes") ]]
ArrayTests = [[ ['a', 'b', 'c'], %([\"a\", \"b\", \"c\"]) ],
[ [1, 'a', :b, nil, false], %([1, \"a\", \"b\", null, false]) ]]
HashTests = [[ {:a => :b, :c => :d}, %({\"c\": \"d\", \"a\": \"b\"}) ]]
SymbolTests = [[ :a, %("a") ],
[ :this, %("this") ],
[ :"a b", %("a b") ]]
ObjectTests = [[ Foo.new(1, 2), %({\"a\": 1, \"b\": 2}) ]]
constants.grep(/Tests$/).each do |class_tests|
define_method("test_#{class_tests[0..-6].downcase}") do
self.class.const_get(class_tests).each do |pair|
assert_equal pair.last, pair.first.to_json
end
end
end
def test_utf8_string_encoded_properly_when_kcode_is_utf8
old_kcode, $KCODE = $KCODE, 'UTF8'
assert_equal '"\\u20ac2.99"', '€2.99'.to_json
assert_equal '"\\u270e\\u263a"', '✎☺'.to_json
ensure
$KCODE = old_kcode
end
def test_exception_raised_when_encoding_circular_reference
a = [1]
a << a
assert_raises(ActiveSupport::JSON::CircularReferenceError) { a.to_json }
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册