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

ruby-changes:20445

From: naruse <ko1@a...>
Date: Sun, 10 Jul 2011 17:01:20 +0900 (JST)
Subject: [ruby-changes:20445] naruse:r32493 (trunk): * ext/json: Merge json gem 1.5.4+ (f7f78896607b6f6226cd).

naruse	2011-07-10 17:01:04 +0900 (Sun, 10 Jul 2011)

  New Revision: 32493

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=32493

  Log:
    * ext/json: Merge json gem 1.5.4+ (f7f78896607b6f6226cd).
      [Bug #4700]

  Added files:
    trunk/test/json/setup_variant.rb
    trunk/test/json/test_json_string_matching.rb
  Modified files:
    trunk/ChangeLog
    trunk/ext/json/generator/generator.c
    trunk/ext/json/generator/generator.h
    trunk/ext/json/lib/json/add/core.rb
    trunk/ext/json/lib/json/common.rb
    trunk/ext/json/lib/json/ext.rb
    trunk/ext/json/lib/json/version.rb
    trunk/ext/json/lib/json.rb
    trunk/ext/json/parser/extconf.rb
    trunk/ext/json/parser/parser.c
    trunk/ext/json/parser/parser.h
    trunk/ext/json/parser/parser.rl
    trunk/test/json/test_json.rb
    trunk/test/json/test_json_addition.rb
    trunk/test/json/test_json_encoding.rb
    trunk/test/json/test_json_fixtures.rb
    trunk/test/json/test_json_generate.rb
    trunk/test/json/test_json_unicode.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 32492)
+++ ChangeLog	(revision 32493)
@@ -1,3 +1,8 @@
+Sun Jul 10 15:58:12 2011  NARUSE, Yui  <naruse@r...>
+
+	* ext/json: Merge json gem 1.5.4+ (f7f78896607b6f6226cd).
+	  [Bug #4700]
+
 Sun Jul 10 16:41:32 2011  KOSAKI Motohiro  <kosaki.motohiro@g...>
 
 	* vm_core.h (typedef struct rb_vm_struct): create a new
Index: ext/json/generator/generator.c
===================================================================
--- ext/json/generator/generator.c	(revision 32492)
+++ ext/json/generator/generator.c	(revision 32493)
@@ -556,6 +556,7 @@
 /*
  * call-seq: to_json(*)
  *
+ * Returns a JSON string for nil: 'null'.
  */
 static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
 {
@@ -1347,6 +1348,7 @@
     rb_define_method(cState, "depth", cState_depth, 0);
     rb_define_method(cState, "depth=", cState_depth_set, 1);
     rb_define_method(cState, "configure", cState_configure, 1);
+    rb_define_alias(cState, "merge", "configure");
     rb_define_method(cState, "to_h", cState_to_h, 0);
     rb_define_method(cState, "[]", cState_aref, 1);
     rb_define_method(cState, "generate", cState_generate, 1);
Index: ext/json/generator/generator.h
===================================================================
--- ext/json/generator/generator.h	(revision 32492)
+++ ext/json/generator/generator.h	(revision 32493)
@@ -78,9 +78,9 @@
 
 #define UNI_STRICT_CONVERSION 1
 
-typedef unsigned long	UTF32;	/* at least 32 bits */
-typedef unsigned short	UTF16;	/* at least 16 bits */
-typedef unsigned char	UTF8;	/* typically 8 bits */
+typedef unsigned long  UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char  UTF8;  /* typically 8 bits */
 
 #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
 #define UNI_MAX_BMP (UTF32)0x0000FFFF
Index: ext/json/lib/json/ext.rb
===================================================================
--- ext/json/lib/json/ext.rb	(revision 32492)
+++ ext/json/lib/json/ext.rb	(revision 32493)
@@ -4,12 +4,25 @@
   # This module holds all the modules/classes that implement JSON's
   # functionality as C extensions.
   module Ext
-    require 'json/ext/parser'
-    require 'json/ext/generator'
+    begin
+      if defined?(RUBY_ENGINE) == 'constant' and RUBY_ENGINE == 'ruby' and RUBY_VERSION =~ /\A1\.9\./
+        require 'json/ext/1.9/parser'
+        require 'json/ext/1.9/generator'
+      elsif !defined?(RUBY_ENGINE) && RUBY_VERSION =~ /\A1\.8\./
+        require 'json/ext/1.8/parser'
+        require 'json/ext/1.8/generator'
+      else
+        require 'json/ext/parser'
+        require 'json/ext/generator'
+      end
+    rescue LoadError
+      require 'json/ext/parser'
+      require 'json/ext/generator'
+    end
     $DEBUG and warn "Using Ext extension for JSON."
     JSON.parser = Parser
     JSON.generator = Generator
   end
 
-  JSON_LOADED = true unless const_defined?(:JSON_LOADED)
+  JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
 end
Index: ext/json/lib/json/version.rb
===================================================================
--- ext/json/lib/json/version.rb	(revision 32492)
+++ ext/json/lib/json/version.rb	(revision 32493)
@@ -1,6 +1,6 @@
 module JSON
   # JSON version
-  VERSION         = '1.5.0'
+  VERSION         = '1.5.4'
   VERSION_ARRAY   = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
   VERSION_MAJOR   = VERSION_ARRAY[0] # :nodoc:
   VERSION_MINOR   = VERSION_ARRAY[1] # :nodoc:
Index: ext/json/lib/json/add/core.rb
===================================================================
--- ext/json/lib/json/add/core.rb	(revision 32492)
+++ ext/json/lib/json/add/core.rb	(revision 32493)
@@ -1,26 +1,37 @@
 # 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
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
   require 'json'
 end
 require 'date'
 
+# Symbol serialization/deserialization
 class Symbol
-  def to_json(*a)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
       JSON.create_id => self.class.name,
-      's' => to_s,
-    }.to_json(*a)
+      's'            => to_s,
+    }
   end
 
+  # Stores class name (Symbol) with String representation of Symbol as a JSON string.
+  def to_json(*a)
+    as_json.to_json(*a)
+  end
+
+  # Deserializes JSON string by converting the <tt>string</tt> value stored in the object to a Symbol
   def self.json_create(o)
     o['s'].to_sym
   end
 end
 
+# Time serialization/deserialization
 class Time
+
+  # Deserializes JSON string by converting time since epoch to Time
   def self.json_create(object)
     if usec = object.delete('u') # used to be tv_usec -> tv_nsec
       object['n'] = usec * 1000
@@ -32,34 +43,59 @@
     end
   end
 
-  def to_json(*args)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
       JSON.create_id => self.class.name,
-      's' => tv_sec,
-      'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000
-    }.to_json(*args)
+      's'            => tv_sec,
+      'n'            => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000
+    }
   end
+
+  # Stores class name (Time) with number of seconds since epoch and number of
+  # microseconds for Time as JSON string
+  def to_json(*args)
+    as_json.to_json(*args)
+  end
 end
 
+# Date serialization/deserialization
 class Date
+
+  # Deserializes JSON string by converting Julian year <tt>y</tt>, month
+  # <tt>m</tt>, day <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> to Date.
   def self.json_create(object)
     civil(*object.values_at('y', 'm', 'd', 'sg'))
   end
 
   alias start sg unless method_defined?(:start)
 
-  def to_json(*args)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
       JSON.create_id => self.class.name,
       'y' => year,
       'm' => month,
       'd' => day,
       'sg' => start,
-    }.to_json(*args)
+    }
   end
+
+  # Stores class name (Date) with Julian year <tt>y</tt>, month <tt>m</tt>, day
+  # <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
+  def to_json(*args)
+    as_json.to_json(*args)
+  end
 end
 
+# DateTime serialization/deserialization
 class DateTime
+
+  # Deserializes JSON string by converting year <tt>y</tt>, month <tt>m</tt>,
+  # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
+  # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> to DateTime.
   def self.json_create(object)
     args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
     of_a, of_b = object['of'].split('/')
@@ -74,7 +110,9 @@
 
   alias start sg unless method_defined?(:start)
 
-  def to_json(*args)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
       JSON.create_id => self.class.name,
       'y' => year,
@@ -85,64 +123,121 @@
       'S' => sec,
       'of' => offset.to_s,
       'sg' => start,
-    }.to_json(*args)
+    }
   end
+
+  # Stores class name (DateTime) with Julian year <tt>y</tt>, month <tt>m</tt>,
+  # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
+  # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
+  def to_json(*args)
+    as_json.to_json(*args)
+  end
 end
 
+# Range serialization/deserialization
 class Range
+
+  # Deserializes JSON string by constructing new Range object with arguments
+  # <tt>a</tt> serialized by <tt>to_json</tt>.
   def self.json_create(object)
     new(*object['a'])
   end
 
-  def to_json(*args)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
-      JSON.create_id   => self.class.name,
-      'a'         => [ first, last, exclude_end? ]
-    }.to_json(*args)
+      JSON.create_id  => self.class.name,
+      'a'             => [ first, last, exclude_end? ]
+    }
   end
+
+  # Stores class name (Range) with JSON array of arguments <tt>a</tt> which
+  # include <tt>first</tt> (integer), <tt>last</tt> (integer), and
+  # <tt>exclude_end?</tt> (boolean) as JSON string.
+  def to_json(*args)
+    as_json.to_json(*args)
+  end
 end
 
+# Struct serialization/deserialization
 class Struct
+
+  # Deserializes JSON string by constructing new Struct object with values
+  # <tt>v</tt> serialized by <tt>to_json</tt>.
   def self.json_create(object)
     new(*object['v'])
   end
 
-  def to_json(*args)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     klass = self.class.name
     klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
     {
       JSON.create_id => klass,
-      'v'     => values,
-    }.to_json(*args)
+      'v'            => values,
+    }
   end
+
+  # Stores class name (Struct) with Struct values <tt>v</tt> as a JSON string.
+  # Only named structs are supported.
+  def to_json(*args)
+    as_json.to_json(*args)
+  end
 end
 
+# Exception serialization/deserialization
 class Exception
+
+  # Deserializes JSON string by constructing new Exception object with message
+  # <tt>m</tt> and backtrace <tt>b</tt> serialized with <tt>to_json</tt>
   def self.json_create(object)
     result = new(object['m'])
     result.set_backtrace object['b']
     result
   end
 
-  def to_json(*args)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
       JSON.create_id => self.class.name,
-      'm'   => message,
-      'b' => backtrace,
-    }.to_json(*args)
+      'm'            => message,
+      'b'            => backtrace,
+    }
   end
+
+  # Stores class name (Exception) with message <tt>m</tt> and backtrace array
+  # <tt>b</tt> as JSON string
+  def to_json(*args)
+    as_json.to_json(*args)
+  end
 end
 
+# Regexp serialization/deserialization
 class Regexp
+
+  # Deserializes JSON string by constructing new Regexp object with source
+  # <tt>s</tt> (Regexp or String) and options <tt>o</tt> serialized by
+  # <tt>to_json</tt>
   def self.json_create(object)
     new(object['s'], object['o'])
   end
 
-  def to_json(*)
+  # Returns a hash, that will be turned into a JSON object and represent this
+  # object.
+  def as_json(*)
     {
       JSON.create_id => self.class.name,
       'o' => options,
       's' => source,
-    }.to_json
+    }
   end
+
+  # Stores class name (Regexp) with options <tt>o</tt> and source <tt>s</tt>
+  # (Regexp or String) as JSON string
+  def to_json(*)
+    as_json.to_json
+  end
 end
Index: ext/json/lib/json/common.rb
===================================================================
--- ext/json/lib/json/common.rb	(revision 32492)
+++ ext/json/lib/json/common.rb	(revision 32493)
@@ -23,7 +23,7 @@
     # Set the JSON parser class _parser_ to be used by JSON.
     def parser=(parser) # :nodoc:
       @parser = parser
-      remove_const :Parser if const_defined? :Parser
+      remove_const :Parser if JSON.const_defined_in?(self, :Parser)
       const_set :Parser, parser
     end
 
@@ -34,8 +34,8 @@
     def deep_const_get(path) # :nodoc:
       path.to_s.split(/::/).inject(Object) do |p, c|
         case
-        when c.empty?             then p
-        when p.const_defined?(c)  then p.const_get(c)
+        when c.empty?                     then p
+        when JSON.const_defined_in?(p, c) then p.const_get(c)
         else
           begin
             p.const_missing(c)
@@ -292,6 +292,7 @@
     result
   end
 
+  # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
   def recurse_proc(result, &proc)
     case result
     when Array
@@ -340,17 +341,38 @@
     raise ArgumentError, "exceed depth limit"
   end
 
+  # Swap consecutive bytes of _string_ in place.
+  def self.swap!(string) # :nodoc:
+    0.upto(string.size / 2) do |i|
+      break unless string[2 * i + 1]
+      string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
+    end
+    string
+  end
+
   # Shortuct for iconv.
-  if String.method_defined?(:encode)
+  if ::String.method_defined?(:encode)
+    # Encodes string using Ruby's _String.encode_
     def self.iconv(to, from, string)
       string.encode(to, from)
     end
   else
     require 'iconv'
+    # Encodes string using _iconv_ library
     def self.iconv(to, from, string)
       Iconv.conv(to, from, string)
     end
   end
+
+  if ::Object.method(:const_defined?).arity == 1
+    def self.const_defined_in?(modul, constant)
+      modul.const_defined?(constant)
+    end
+  else
+    def self.const_defined_in?(modul, constant)
+      modul.const_defined?(constant, false)
+    end
+  end
 end
 
 module ::Kernel
@@ -389,6 +411,7 @@
   end
 end
 
+# Extends any Class to include _json_creatable?_ method.
 class ::Class
   # Returns true, if this class can be used to create an instance
   # from a serialised JSON string. The class has to implement a class
Index: ext/json/lib/json.rb
===================================================================
--- ext/json/lib/json.rb	(revision 32492)
+++ ext/json/lib/json.rb	(revision 32493)
@@ -1,3 +1,55 @@
+##
+# = JavaScript Object Notation (JSON)
+#
+# JSON is a lightweight data-interchange format. It is easy for us
+# humans to read and write. Plus, equally simple for machines to generate or parse.
+# JSON is completely language agnostic, making it the ideal interchange format.
+#
+# Built on two universally available structures:
+#   1. A collection of name/value pairs. Often referred to as an _object_, hash table, record, struct, keyed list, or associative array.
+#   2. An orderd list of values. More commonly named as an _array_, vector, sequence, or list.
+#
+# To read more about JSON visit: http://json.org
+#
+# == Parsing JSON
+#
+# To parse a JSON string received by another application, or generated within
+# your existing application:
+#
+#   require 'json'
+#
+#   my_hash = JSON.parse('{"hello": "goodbye"}')
+#   puts my_hash["hello"] => "goodbye"
+#
+# Notice the extra quotes <tt>''</tt> around the hash notation. Ruby expects
+# the argument to be a string and can't convert objects like a hash or array.
+#
+# Ruby converts your string into a hash
+#
+# == Generating JSON
+#
+# Creating a JSON string for communication or serialization is
+# just as simple.
+#
+#   require 'json'
+#
+#   my_hash = {:hello => "goodbye"}
+#   puts JSON.generate(my_hash) => "{\"hello\":\"goodbye\"}"
+#
+# Or an alternative way:
+#
+#   require 'json'
+#   puts {:hello => "goodbye"}.to_json => "{\"hello\":\"goodbye\"}"
+#
+# <tt>JSON.generate</tt> only allows objects or arrays to be converted
+# to JSON syntax. While <tt>to_json</tt> accepts many Ruby classes
+# even though it only acts a method for serialization:
+#
+#   require 'json'
+#
+#   1.to_json => "1"
+#
+
 require 'json/common'
 module JSON
   require 'json/version'
Index: ext/json/parser/parser.h
===================================================================
--- ext/json/parser/parser.h	(revision 32492)
+++ ext/json/parser/parser.h	(revision 32493)
@@ -9,18 +9,23 @@
 
 #ifdef HAVE_RUBY_ENCODING_H
 #include "ruby/encoding.h"
-#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
+#define FORCE_UTF8(obj) ((obj) = rb_enc_associate(rb_str_dup(obj), rb_utf8_encoding()))
 #else
 #define FORCE_UTF8(obj)
 #endif
+#ifdef HAVE_RUBY_ST_H
+#include "ruby/st.h"
+#else
+#include "st.h"
+#endif
 
 #define option_given_p(opts, key) RTEST(rb_funcall(opts, i_key_p, 1, key))
 
 /* unicode */
 
-typedef unsigned long	UTF32;	/* at least 32 bits */
-typedef unsigned short UTF16;	/* at least 16 bits */
-typedef unsigned char	UTF8;	  /* typically 8 bits */
+typedef unsigned long UTF32;  /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8;   /* typically 8 bits */
 
 #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
 #define UNI_SUR_HIGH_START  (UTF32)0xD800
@@ -41,6 +46,8 @@
     int symbolize_names;
     VALUE object_class;
     VALUE array_class;
+    int create_additions;
+    VALUE match_string;
 } JSON_Parser;
 
 #define GET_PARSER                          \
Index: ext/json/parser/extconf.rb
===================================================================
--- ext/json/parser/extconf.rb	(revision 32492)
+++ ext/json/parser/extconf.rb	(revision 32493)
@@ -1,5 +1,10 @@
 require 'mkmf'
 require 'rbconfig'
 
-have_header("re.h")
+if RUBY_VERSION < "1.9"
+  have_header("re.h")
+else
+  have_header("ruby/re.h")
+  have_header("ruby/encoding.h")
+end
 create_makefile 'json/ext/parser'
Index: ext/json/parser/parser.rl
===================================================================
--- ext/json/parser/parser.rl	(revision 32492)
+++ ext/json/parser/parser.rl	(revision 32493)
@@ -77,7 +77,7 @@
 
 static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
           i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,
-          i_array_class, i_key_p, i_deep_const_get;
+          i_array_class, i_key_p, i_deep_const_get, i_match, i_match_string, i_aset, i_leftshift;
 
 %%{
     machine JSON_common;
@@ -119,7 +119,11 @@
         if (np == NULL) {
             fhold; fbreak;
         } else {
-            rb_hash_aset(*result, last_name, v);
+            if (NIL_P(json->object_class)) {
+                rb_hash_aset(*result, last_name, v);
+            } else {
+                rb_funcall(*result, i_aset, 2, last_name, v);
+            }
             fexec np;
         }
     }
@@ -159,7 +163,7 @@
     %% write exec;
 
     if (cs >= JSON_object_first_final) {
-        if (RTEST(json->create_id)) {
+        if (json->create_additions) {
             VALUE klassname = rb_hash_aref(*result, json->create_id);
             if (!NIL_P(klassname)) {
                 VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
@@ -342,7 +346,11 @@
         if (np == NULL) {
             fhold; fbreak;
         } else {
-            rb_ary_push(*result, v);
+            if (NIL_P(json->array_class)) {
+                rb_ary_push(*result, v);
+            } else {
+                rb_funcall(*result, i_leftshift, 1, v);
+            }
             fexec np;
         }
     }
@@ -470,15 +478,39 @@
     main := '"' ((^([\"\\] | 0..0x1f) | '\\'[\"\\/bfnrt] | '\\u'[0-9a-fA-F]{4} | '\\'^([\"\\/bfnrtu]|0..0x1f))* %parse_string) '"' @exit;
 }%%
 
+static int
+match_i(VALUE regexp, VALUE klass, VALUE memo)
+{
+    if (regexp == Qundef) return ST_STOP;
+    if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
+      RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
+        rb_ary_push(memo, klass);
+        return ST_STOP;
+    }
+    return ST_CONTINUE;
+}
+
 static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
 {
     int cs = EVIL;
+    VALUE match_string;
 
     *result = rb_str_buf_new(0);
     %% write init;
     json->memo = p;
     %% write exec;
 
+    if (json->create_additions && RTEST(match_string = json->match_string)) {
+          VALUE klass;
+          VALUE memo = rb_ary_new2(2);
+          rb_ary_push(memo, *result);
+          rb_hash_foreach(match_string, match_i, memo);
+          klass = rb_ary_entry(memo, 1);
+          if (RTEST(klass)) {
+              *result = rb_funcall(klass, i_json_create, 1, *result);
+          }
+    }
+
     if (json->symbolize_names && json->parsing_name) {
       *result = rb_str_intern(*result);
     }
@@ -629,27 +661,26 @@
             }
             tmp = ID2SYM(i_allow_nan);
             if (option_given_p(opts, tmp)) {
-                VALUE allow_nan = rb_hash_aref(opts, tmp);
-                json->allow_nan = (... truncated)

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

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