[前][次][番号順一覧][スレッド一覧]

ruby-changes:2560

From: ko1@a...
Date: 30 Nov 2007 21:09:07 +0900
Subject: [ruby-changes:2560] naruse - Ruby:r14051 (trunk): * lib/json.rb, lib/json/add/{core.rb, rails.rb},

naruse	2007-11-30 21:08:46 +0900 (Fri, 30 Nov 2007)

  New Revision: 14051

  Added directories:
    trunk/lib/json/add/
  Added files:
    trunk/lib/json/add/core.rb
    trunk/lib/json/add/rails.rb
    trunk/test/json/test_json_rails.rb
  Modified files:
    trunk/lib/json.rb

  Log:
    * lib/json.rb, lib/json/add/{core.rb, rails.rb},
      test/json/test_json_rails.rb: additional files of JSON 1.1.2.
      [ruby-dev:32405]
    --
    
    M    lib/json.rb
    A    lib/json/add
    A    lib/json/add/core.rb
    A    lib/json/add/rails.rb
    A    test/json/test_json_rails.rb

  Added: trunk/lib/json/add/

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/json/add/rails.rb?revision=14051&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/json/add/core.rb?revision=14051&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/json/test_json_rails.rb?revision=14051&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/json.rb?r1=14051&r2=14050

Index: lib/json/add/core.rb
===================================================================
--- lib/json/add/core.rb	(revision 0)
+++ lib/json/add/core.rb	(revision 14051)
@@ -0,0 +1,120 @@
+# This file contains implementations of ruby core's custom objects for
+# serialisation/deserialisation.
+
+unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
+  ::JSON::JSON_LOADED
+  require 'json'
+end
+require 'date'
+
+class Time
+  def self.json_create(object)
+    at(*object.values_at('s', 'u'))
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      's' => tv_sec,
+      'u' => tv_usec,
+    }.to_json(*args)
+  end
+end
+
+class Date
+  def self.json_create(object)
+    civil(*object.values_at('y', 'm', 'd', 'sg'))
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      'y' => year,
+      'm' => month,
+      'd' => day,
+      'sg' => @sg,
+    }.to_json(*args)
+  end
+end
+
+class DateTime
+  def self.json_create(object)
+    args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
+    of_a, of_b = object['of'].split('/')
+    args << Rational(of_a.to_i, of_b.to_i)
+    args << object['sg']
+    civil(*args)
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      'y' => year,
+      'm' => month,
+      'd' => day,
+      'H' => hour,
+      'M' => min,
+      'S' => sec,
+      'of' => offset.to_s,
+      'sg' => @sg,
+    }.to_json(*args)
+  end
+end
+
+class Range
+  def self.json_create(object)
+    new(*object['a'])
+  end
+
+  def to_json(*args)
+    {
+      'json_class'   => self.class.name.to_s,
+      'a'         => [ first, last, exclude_end? ]
+    }.to_json(*args)
+  end
+end
+
+class Struct
+  def self.json_create(object)
+    new(*object['v'])
+  end
+
+  def to_json(*args)
+    klass = self.class.name.to_s
+    klass.empty? and raise JSON::JSONError, "Only named structs are supported!"
+    {
+      'json_class' => klass,
+      'v'     => values,
+    }.to_json(*args)
+  end
+end
+
+class Exception
+  def self.json_create(object)
+    result = new(object['m'])
+    result.set_backtrace object['b']
+    result
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      'm'   => message,
+      'b' => backtrace,
+    }.to_json(*args)
+  end
+end
+
+class Regexp
+  def self.json_create(object)
+    new(object['s'], object['o'])
+  end
+
+  def to_json(*)
+    {
+      'json_class' => self.class.name.to_s,
+      'o' => options,
+      's' => source,
+    }.to_json
+  end
+end
Index: lib/json/add/rails.rb
===================================================================
--- lib/json/add/rails.rb	(revision 0)
+++ lib/json/add/rails.rb	(revision 14051)
@@ -0,0 +1,58 @@
+# This file contains implementations of rails custom objects for
+# serialisation/deserialisation.
+
+unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
+  ::JSON::JSON_LOADED
+  require 'json'
+end
+
+class Object
+  def self.json_create(object)
+    obj = new
+    for key, value in object
+      next if key == 'json_class'
+      instance_variable_set "@#{key}", value
+    end
+    obj
+  end
+
+  def to_json(*a)
+    result = {
+      'json_class' => self.class.name
+    }
+    instance_variables.inject(result) do |r, name|
+      r[name[1..-1]] = instance_variable_get name
+      r
+    end
+    result.to_json(*a)
+  end
+end
+
+class Symbol
+  def to_json(*a)
+    to_s.to_json(*a)
+  end
+end
+
+module Enumerable
+  def to_json(*a)
+    to_a.to_json(*a)
+  end
+end
+
+# class Regexp
+#   def to_json(*)
+#     inspect
+#   end
+# end
+#
+# The above rails definition has some problems:
+#
+# 1. { 'foo' => /bar/ }.to_json # => "{foo: /bar/}"
+#    This isn't valid JSON, because the regular expression syntax is not
+#    defined in RFC 4627. (And unquoted strings are disallowed there, too.)
+#    Though it is valid Javascript.
+#
+# 2. { 'foo' => /bar/mix }.to_json # => "{foo: /bar/mix}"
+#    This isn't even valid Javascript.
+
Index: lib/json.rb
===================================================================
--- lib/json.rb	(revision 14050)
+++ lib/json.rb	(revision 14051)
@@ -62,6 +62,13 @@
 # you
 #   require 'json/add/core'
 #
+# After requiring this you can, e. g., serialise/deserialise Ruby ranges:
+#
+#   JSON JSON(1..10) # => 1..10
+#
+# To find out how to add JSON support to other or your own classes, read the
+# Examples section below.
+#
 # To get the best compatibility to rails' JSON implementation, you can
 #   require 'json/add/rails'
 #
@@ -125,11 +132,6 @@
 #  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
 #  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
 #
-# It's also possible to call the #to_json method directly.
-#
-#  json = [1, 2, {"a"=>3.141}, false, true, nil, 4..10].to_json
-#  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
-#
 # To create a valid JSON text you have to make sure, that the output is
 # embedded in either a JSON array [] or a JSON object {}. The easiest way to do
 # this, is by putting your values in a Ruby Array or Hash instance.
@@ -145,10 +147,10 @@
 # or arbitrary classes. In this case the json library falls back to call
 # Object#to_json, which is the same as #to_s.to_json.
 #
-# It's possible to extend JSON to support serialization of arbitrary classes by
+# It's possible to add JSON support serialization to arbitrary classes by
 # simply implementing a more specialized version of the #to_json method, that
-# should return a JSON object (a hash converted to JSON with #to_json)
-# like this (don't forget the *a for all the arguments):
+# should return a JSON object (a hash converted to JSON with #to_json) like
+# this (don't forget the *a for all the arguments):
 #
 #  class Range
 #    def to_json(*a)
@@ -159,15 +161,15 @@
 #    end
 #  end
 #
-# The hash key 'json_class' is the class, that will be asked to deserialize the
+# The hash key 'json_class' is the class, that will be asked to deserialise the
 # JSON representation later. In this case it's 'Range', but any namespace of
 # the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
-# used to store the necessary data to configure the object to be deserialized.
+# used to store the necessary data to configure the object to be deserialised.
 #
 # If a the key 'json_class' is found in a JSON object, the JSON parser checks
 # if the given class responds to the json_create class method. If so, it is
 # called with the JSON object converted to a Ruby hash. So a range can
-# be deserialized by implementing Range.json_create like this:
+# be deserialised by implementing Range.json_create like this:
 # 
 #  class Range
 #    def self.json_create(o)
@@ -175,7 +177,7 @@
 #    end
 #  end
 #
-# Now it possible to serialize/deserialize ranges as well:
+# Now it possible to serialise/deserialise ranges as well:
 #
 #  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
 #  # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
Index: test/json/test_json_rails.rb
===================================================================
--- test/json/test_json_rails.rb	(revision 0)
+++ test/json/test_json_rails.rb	(revision 14051)
@@ -0,0 +1,113 @@
+#!/usr/bin/env ruby
+
+require 'test/unit'
+require 'json/add/rails'
+require 'date'
+
+class TC_JSONRails < Test::Unit::TestCase
+  include JSON
+
+  class A
+    def initialize(a)
+      @a = a
+    end
+
+    attr_reader :a
+
+    def ==(other)
+      a == other.a
+    end
+    
+    def self.json_create(object)
+      new(*object['args'])
+    end
+
+    def to_json(*args)
+      {
+        'json_class'  => self.class.name,
+        'args'        => [ @a ],
+      }.to_json(*args)
+    end
+  end
+
+  class B
+    def to_json(*args)
+      {
+        'json_class'  => self.class.name,
+      }.to_json(*args)
+    end
+  end
+
+  class C
+    def to_json(*args)
+      {
+        'json_class'  => 'TC_JSONRails::Nix',
+      }.to_json(*args)
+    end
+  end
+
+  def setup
+  end
+
+  def test_extended_json
+    a = A.new(666)
+    assert A.json_creatable?
+    json = generate(a)
+    a_again = JSON.parse(json)
+    assert_kind_of a.class, a_again
+    assert_equal a, a_again
+  end
+
+  def test_extended_json_disabled
+    a = A.new(666)
+    assert A.json_creatable?
+    json = generate(a)
+    a_again = JSON.parse(json, :create_additions => true)
+    assert_kind_of a.class, a_again
+    assert_equal a, a_again
+    a_hash = JSON.parse(json, :create_additions => false)
+    assert_kind_of Hash, a_hash
+    assert_equal(
+      {"args"=>[666], "json_class"=>"TC_JSONRails::A"}.sort_by { |k,| k },
+      a_hash.sort_by { |k,| k }
+    )
+  end
+
+  def test_extended_json_fail
+    b = B.new
+    assert !B.json_creatable?
+    json = generate(b)
+    assert_equal({ 'json_class' => B.name }, JSON.parse(json))
+  end
+
+  def test_extended_json_fail
+    c = C.new # with rails addition all objects are theoretically creatable
+    assert C.json_creatable?
+    json = generate(c)
+    assert_raises(ArgumentError) { JSON.parse(json) }
+  end
+
+  def test_raw_strings
+    raw = ''
+    raw_array = []
+    for i in 0..255
+      raw << i
+      raw_array << i
+    end
+    json = raw.to_json_raw
+    json_raw_object = raw.to_json_raw_object
+    hash = { 'json_class' => 'String', 'raw'=> raw_array }
+    assert_equal hash, json_raw_object
+    json_raw = <<EOT.chomp
+{\"json_class\":\"String\",\"raw\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]}
+EOT
+# "
+    assert_equal json_raw, json
+    raw_again = JSON.parse(json)
+    assert_equal raw, raw_again
+  end
+
+  def test_symbol
+    assert_equal '"foo"', JSON(:foo) #  we don't want an object here
+  end
+end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]