summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Felgentreff <timfelgentreff@gmail.com>2011-09-27 10:42:33 -0700
committerTim Felgentreff <timfelgentreff@gmail.com>2011-09-27 10:42:33 -0700
commit65dd51142e4f3e9a6f5d5956a72b8a95a29639b0 (patch)
tree66423735c4cdd4202144a4fb3930f077235e424e
parentd479587426fb7b3e7cda3a65e28e1c11232fc2cd (diff)
parent56987b27d53765a57b20a0f2611b44a343616e09 (diff)
downloadjson-65dd51142e4f3e9a6f5d5956a72b8a95a29639b0.tar.gz
Merge remote-tracking branch 'json/master'
Conflicts: ext/json/ext/parser/parser.c ext/json/ext/parser/parser.rl json.gemspec
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml2
-rw-r--r--CHANGES12
-rw-r--r--Rakefile26
-rw-r--r--VERSION2
-rwxr-xr-xbin/edit_json.rb9
-rwxr-xr-xbin/prettify_json.rb48
-rw-r--r--ext/json/ext/generator/generator.c65
-rw-r--r--ext/json/ext/generator/generator.h6
-rw-r--r--ext/json/ext/parser/parser.c518
-rw-r--r--ext/json/ext/parser/parser.h1
-rw-r--r--ext/json/ext/parser/parser.rl179
-rwxr-xr-xinstall.rb9
-rw-r--r--java/src/json/ext/Generator.java6
-rw-r--r--java/src/json/ext/GeneratorMethods.java4
-rw-r--r--java/src/json/ext/GeneratorService.java2
-rw-r--r--java/src/json/ext/GeneratorState.java54
-rw-r--r--java/src/json/ext/OptionsReader.java2
-rw-r--r--java/src/json/ext/Parser.java489
-rw-r--r--java/src/json/ext/Parser.rl125
-rw-r--r--java/src/json/ext/ParserService.java2
-rw-r--r--java/src/json/ext/Utils.java2
-rw-r--r--json.gemspec11
-rw-r--r--json_pure.gemspec14
-rw-r--r--lib/json.rb8
-rw-r--r--lib/json/Array.xpm21
-rw-r--r--lib/json/FalseClass.xpm21
-rw-r--r--lib/json/Hash.xpm21
-rw-r--r--lib/json/Key.xpm73
-rw-r--r--lib/json/NilClass.xpm21
-rw-r--r--lib/json/Numeric.xpm28
-rw-r--r--lib/json/String.xpm96
-rw-r--r--lib/json/TrueClass.xpm21
-rw-r--r--lib/json/add/complex.rb22
-rw-r--r--lib/json/add/core.rb250
-rw-r--r--lib/json/add/date.rb34
-rw-r--r--lib/json/add/date_time.rb50
-rw-r--r--lib/json/add/exception.rb31
-rw-r--r--lib/json/add/rails.rb8
-rw-r--r--lib/json/add/range.rb29
-rw-r--r--lib/json/add/rational.rb22
-rw-r--r--lib/json/add/regexp.rb30
-rw-r--r--lib/json/add/struct.rb30
-rw-r--r--lib/json/add/symbol.rb25
-rw-r--r--lib/json/add/time.rb35
-rw-r--r--lib/json/common.rb82
-rw-r--r--lib/json/editor.rb1369
-rw-r--r--lib/json/ext.rb17
-rw-r--r--lib/json/json.xpm1499
-rw-r--r--lib/json/pure/generator.rb19
-rw-r--r--lib/json/pure/parser.rb144
-rw-r--r--lib/json/version.rb2
-rwxr-xr-xtests/test_json.rb36
-rwxr-xr-xtests/test_json_addition.rb9
-rwxr-xr-xtests/test_json_generate.rb35
-rwxr-xr-xtools/server.rb1
56 files changed, 1673 insertions, 4005 deletions
diff --git a/.gitignore b/.gitignore
index 7557261..726ffce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ pkg
.idea
java/Json.iml
Gemfile.lock
+.rvmrc
diff --git a/.travis.yml b/.travis.yml
index 2ebf7fc..cb74e2d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,11 +5,11 @@ bundler_args: --binstubs
rvm:
- 1.8.7
- 1.9.2
+ - 1.9.3
- rbx
- rbx-2.0
- ree
- jruby
- ruby-head
- - 1.8.6
script: "bundle exec rake"
diff --git a/CHANGES b/CHANGES
index 1442162..736ebb3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,16 @@
-2011-07-04 (1.5.4)
+2011-09-18 (1.6.1)
+ * Using -target 1.5 to force Java bits to compile with 1.5.
+2011-09-12 (1.6.0)
+ * Extract utilities (prettifier and GUI-editor) in its own gem json-utils.
+ * Split json/add/core into different files for classes to be serialised.
+2011-08-31 (1.5.4)
* Fix memory leak when used from multiple JRuby. (Patch by
jfirebaugh@github).
+ * Apply patch by Eric Wong <nocode@yhbt.net> that fixes garbage collection problem
+ reported in https://github.com/flori/json/issues/46.
+ * Add :quirks_mode option to parser and generator.
+ * Add support for Rational and Complex number additions via json/add/complex
+ and json/add/rational requires.
2011-06-20 (1.5.3)
* Alias State#configure method as State#merge to increase duck type synonymy with Hash.
* Add as_json methods in json/add/core, so rails can create its json objects
diff --git a/Rakefile b/Rakefile
index e48f6b1..4b51571 100644
--- a/Rakefile
+++ b/Rakefile
@@ -4,7 +4,12 @@ rescue LoadError
end
require 'rbconfig'
-include Config
+begin
+ include RbConfig
+rescue NameError
+ include Config
+end
+
require 'rake/clean'
CLOBBER.include Dir['benchmarks/data/*.{dat,log}'], 'doc', 'Gemfile.lock'
@@ -91,10 +96,6 @@ if defined?(Gem) and defined?(Gem::PackageTask)
s.add_development_dependency 'bullshit'
s.add_development_dependency 'sdoc'
s.add_development_dependency 'rake', '~>0.9.2'
- s.add_dependency 'spruz', '~>0.2.8'
-
- s.bindir = "bin"
- s.executables = [ "edit_json.rb", "prettify_json.rb" ]
s.extra_rdoc_files << 'README.rdoc'
s.rdoc_options <<
@@ -136,9 +137,6 @@ if defined?(Gem) and defined?(Gem::PackageTask)
s.add_development_dependency 'bullshit'
s.add_development_dependency 'sdoc'
- s.bindir = "bin"
- s.executables = [ "edit_json.rb", "prettify_json.rb" ]
-
s.extra_rdoc_files << 'README.rdoc'
s.rdoc_options <<
'--title' << 'JSON implemention for Ruby' << '--main' << 'README.rdoc'
@@ -228,13 +226,13 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
rm_rf JAVA_PARSER_SRC
end
- JRUBY_JAR = File.join(Config::CONFIG["libdir"], "jruby.jar")
+ JRUBY_JAR = File.join(CONFIG["libdir"], "jruby.jar")
if File.exist?(JRUBY_JAR)
JAVA_SOURCES.each do |src|
classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
obj = src.sub(/\.java\Z/, '.class')
file obj => src do
- sh 'javac', '-classpath', classpath, '-source', '1.5', src
+ sh 'javac', '-classpath', classpath, '-source', '1.5', '-target', '1.5', src
end
JAVA_CLASSES << obj
end
@@ -298,7 +296,9 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
task :create_jar => [ :create_parser_jar, :create_generator_jar ]
desc "Build all gems and archives for a new release of the jruby extension."
- task :release => [ :clean, :version, :jruby_gem ]
+ task :build => [ :clean, :version, :jruby_gem ]
+
+ task :release => :build
else
desc "Compiling extension"
task :compile => [ EXT_PARSER_DL, EXT_GENERATOR_DL ]
@@ -400,7 +400,9 @@ else
task :ragel_dot => [ :ragel_dot_png, :ragel_dot_ps ]
desc "Build all gems and archives for a new release of json and json_pure."
- task :release => [ :clean, :gemspec, :package ]
+ task :build => [ :clean, :gemspec, :package ]
+
+ task :release => :build
end
desc "Compile in the the source directory"
diff --git a/VERSION b/VERSION
index 94fe62c..9c6d629 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.5.4
+1.6.1
diff --git a/bin/edit_json.rb b/bin/edit_json.rb
deleted file mode 100755
index 04a8189..0000000
--- a/bin/edit_json.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env ruby
-require 'json/editor'
-
-filename, encoding = ARGV
-JSON::Editor.start(encoding) do |window|
- if filename
- window.file_open(filename)
- end
-end
diff --git a/bin/prettify_json.rb b/bin/prettify_json.rb
deleted file mode 100755
index 3c53183..0000000
--- a/bin/prettify_json.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'json'
-require 'fileutils'
-include FileUtils
-require 'spruz/go'
-include Spruz::GO
-
-opts = go 'slhi:', args = ARGV.dup
-if opts['h'] || opts['l'] && opts['s']
- puts <<EOT
-Usage: #{File.basename($0)} [OPTION] [FILE]
-
-If FILE is skipped, this scripts waits for input from STDIN. Otherwise
-FILE is opened, read, and used as input for the prettifier.
-
-OPTION can be
- -s to output the shortest possible JSON (precludes -l)
- -l to output a longer, better formatted JSON (precludes -s)
- -i EXT prettifies FILE in place, saving a backup to FILE.EXT
- -h this help
-EOT
- exit 0
-end
-
-json_opts = { :max_nesting => false, :create_additions => false }
-
-document =
- if filename = args.first or filename == '-'
- File.read(filename)
- else
- STDIN.read
- end
-
-json = JSON.parse document, json_opts
-
-output = if opts['s']
- JSON.fast_generate json, json_opts
-else # default is -l
- JSON.pretty_generate json, json_opts
-end
-
-if opts['i'] && filename
- cp filename, "#{filename}.#{opts['i']}"
- File.open(filename, 'w') { |f| f.puts output }
-else
- puts output
-end
diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c
index e7d71e9..44dc3fa 100644
--- a/ext/json/ext/generator/generator.c
+++ b/ext/json/ext/generator/generator.c
@@ -13,8 +13,8 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
- i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,
- i_respond_to_p, i_match, i_keys, i_depth, i_dup;
+ i_quirks_mode, i_pack, i_unpack, i_create_id, i_extend, i_key_p,
+ i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth, i_dup;
/*
* Copyright 2001-2004 Unicode, Inc.
@@ -349,6 +349,16 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
}
}
+static void fbuffer_append_str(FBuffer *fb, VALUE str)
+{
+ const char *newstr = StringValuePtr(str);
+ unsigned long len = RSTRING_LEN(str);
+
+ RB_GC_GUARD(str);
+
+ fbuffer_append(fb, newstr, len);
+}
+
static void fbuffer_append_char(FBuffer *fb, char newchr)
{
fbuffer_inc_capa(fb, 1);
@@ -688,6 +698,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
state->allow_nan = RTEST(tmp);
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
state->ascii_only = RTEST(tmp);
+ tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
+ state->quirks_mode = RTEST(tmp);
return self;
}
@@ -708,6 +720,7 @@ static VALUE cState_to_h(VALUE self)
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
+ rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
return result;
@@ -852,7 +865,7 @@ static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
{
VALUE tmp = rb_funcall(obj, i_to_s, 0);
- fbuffer_append(buffer, RSTRING_PAIR(tmp));
+ fbuffer_append_str(buffer, tmp);
}
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
@@ -869,7 +882,7 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
}
}
- fbuffer_append(buffer, RSTRING_PAIR(tmp));
+ fbuffer_append_str(buffer, tmp);
}
static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
@@ -897,7 +910,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
} else if (rb_respond_to(obj, i_to_json)) {
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
Check_Type(tmp, T_STRING);
- fbuffer_append(buffer, RSTRING_PAIR(tmp));
+ fbuffer_append_str(buffer, tmp);
} else {
tmp = rb_funcall(obj, i_to_s, 0);
Check_Type(tmp, T_STRING);
@@ -961,11 +974,14 @@ static VALUE cState_generate(VALUE self, VALUE obj)
{
VALUE result = cState_partial_generate(self, obj);
VALUE re, args[2];
- args[0] = rb_str_new2("\\A\\s*(?:\\[.*\\]|\\{.*\\})\\s*\\Z");
- args[1] = CRegexp_MULTILINE;
- re = rb_class_new_instance(2, args, rb_cRegexp);
- if (NIL_P(rb_funcall(re, i_match, 1, result))) {
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
+ GET_STATE(self);
+ if (!state->quirks_mode) {
+ args[0] = rb_str_new2("\\A\\s*(?:\\[.*\\]|\\{.*\\})\\s*\\Z");
+ args[1] = CRegexp_MULTILINE;
+ re = rb_class_new_instance(2, args, rb_cRegexp);
+ if (NIL_P(rb_funcall(re, i_match, 1, result))) {
+ rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
+ }
}
return result;
}
@@ -985,6 +1001,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
* generated, otherwise an exception is thrown, if these values are
* encountered. This options defaults to false.
+ * * *quirks_mode*: Enables quirks_mode for parser, that is for example
+ * generating single JSON values instead of documents is possible.
*/
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -1288,6 +1306,29 @@ static VALUE cState_ascii_only_p(VALUE self)
}
/*
+ * call-seq: quirks_mode?
+ *
+ * Returns true, if quirks mode is enabled. Otherwise returns false.
+ */
+static VALUE cState_quirks_mode_p(VALUE self)
+{
+ GET_STATE(self);
+ return state->quirks_mode ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq: quirks_mode=(enable)
+ *
+ * If set to true, enables the quirks_mode mode.
+ */
+static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
+{
+ GET_STATE(self);
+ state->quirks_mode = RTEST(enable);
+ return Qnil;
+}
+
+/*
* call-seq: depth
*
* This integer returns the current depth of data structure nesting.
@@ -1345,6 +1386,9 @@ void Init_generator()
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
+ rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
+ rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
+ rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
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);
@@ -1392,6 +1436,7 @@ void Init_generator()
i_max_nesting = rb_intern("max_nesting");
i_allow_nan = rb_intern("allow_nan");
i_ascii_only = rb_intern("ascii_only");
+ i_quirks_mode = rb_intern("quirks_mode");
i_depth = rb_intern("depth");
i_pack = rb_intern("pack");
i_unpack = rb_intern("unpack");
diff --git a/ext/json/ext/generator/generator.h b/ext/json/ext/generator/generator.h
index ee496fe..f882ea0 100644
--- a/ext/json/ext/generator/generator.h
+++ b/ext/json/ext/generator/generator.h
@@ -45,7 +45,10 @@
#define RSTRING_LEN(string) RSTRING(string)->len
#endif
-#define RSTRING_PAIR(string) RSTRING_PTR(string), RSTRING_LEN(string)
+/* We don't need to guard objects for rbx, so let's do nothing at all. */
+#ifndef RB_GC_GUARD
+#define RB_GC_GUARD(object)
+#endif
/* fbuffer implementation */
@@ -123,6 +126,7 @@ typedef struct JSON_Generator_StateStruct {
long max_nesting;
char allow_nan;
char ascii_only;
+ char quirks_mode;
long depth;
} JSON_Generator_State;
diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c
index 5cee27d..b7d0b68 100644
--- a/ext/json/ext/parser/parser.c
+++ b/ext/json/ext/parser/parser.c
@@ -78,15 +78,16 @@ static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
static VALUE CNaN, CInfinity, CMinusInfinity;
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_match, i_match_string, i_aset, i_leftshift;
+ i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_quirks_mode,
+ i_object_class, i_array_class, i_key_p, i_deep_const_get, i_match,
+ i_match_string, i_aset, i_leftshift;
-#line 108 "parser.rl"
+#line 109 "parser.rl"
-#line 90 "parser.c"
+#line 91 "parser.c"
static const int JSON_object_start = 1;
static const int JSON_object_first_final = 27;
static const int JSON_object_error = 0;
@@ -94,7 +95,7 @@ static const int JSON_object_error = 0;
static const int JSON_object_en_main = 1;
-#line 148 "parser.rl"
+#line 150 "parser.rl"
static const char *JSON_parse_object(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -110,14 +111,14 @@ static const char *JSON_parse_object(JSON_Parser *json, const char *p, const cha
*result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
-#line 114 "parser.c"
+#line 115 "parser.c"
{
cs = JSON_object_start;
}
-#line 163 "parser.rl"
+#line 165 "parser.rl"
-#line 121 "parser.c"
+#line 122 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -145,7 +146,7 @@ case 2:
goto st2;
goto st0;
tr2:
-#line 131 "parser.rl"
+#line 132 "parser.rl"
{
const char *np;
json->parsing_name = 1;
@@ -158,7 +159,7 @@ st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
-#line 162 "parser.c"
+#line 163 "parser.c"
switch( (*p) ) {
case 13: goto st3;
case 32: goto st3;
@@ -225,7 +226,7 @@ case 8:
goto st8;
goto st0;
tr11:
-#line 116 "parser.rl"
+#line 117 "parser.rl"
{
VALUE v = Qnil;
const char *np = JSON_parse_value(json, p, pe, &v);
@@ -245,7 +246,7 @@ st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
-#line 249 "parser.c"
+#line 250 "parser.c"
switch( (*p) ) {
case 13: goto st9;
case 32: goto st9;
@@ -334,14 +335,14 @@ case 18:
goto st9;
goto st18;
tr4:
-#line 139 "parser.rl"
+#line 140 "parser.rl"
{ p--; {p++; cs = 27; goto _out;} }
goto st27;
st27:
if ( ++p == pe )
goto _test_eof27;
case 27:
-#line 345 "parser.c"
+#line 346 "parser.c"
goto st0;
st19:
if ( ++p == pe )
@@ -439,7 +440,7 @@ case 26:
_out: {}
}
-#line 164 "parser.rl"
+#line 166 "parser.rl"
if (cs >= JSON_object_first_final) {
if (json->create_additions) {
@@ -458,7 +459,8 @@ case 26:
}
-#line 462 "parser.c"
+
+#line 464 "parser.c"
static const int JSON_value_start = 1;
static const int JSON_value_first_final = 21;
static const int JSON_value_error = 0;
@@ -466,7 +468,7 @@ static const int JSON_value_error = 0;
static const int JSON_value_en_main = 1;
-#line 262 "parser.rl"
+#line 265 "parser.rl"
static const char *JSON_parse_value(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -474,14 +476,14 @@ static const char *JSON_parse_value(JSON_Parser *json, const char *p, const char
int cs = EVIL;
-#line 478 "parser.c"
+#line 480 "parser.c"
{
cs = JSON_value_start;
}
-#line 269 "parser.rl"
+#line 272 "parser.rl"
-#line 485 "parser.c"
+#line 487 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -506,17 +508,17 @@ st0:
cs = 0;
goto _out;
tr0:
-#line 210 "parser.rl"
+#line 213 "parser.rl"
{
const char *np = JSON_parse_string(json, p, pe, result);
if (np == NULL) { p--; {p++; cs = 21; goto _out;} } else {p = (( np))-1;}
}
goto st21;
tr2:
-#line 215 "parser.rl"
+#line 218 "parser.rl"
{
- const char *np;
- if(pe > p + 9 && !strncmp(MinusInfinity, p, 9)) {
+ char *np;
+ if(pe > p + 9 - json->quirks_mode && !strncmp(MinusInfinity, p, 9)) {
if (json->allow_nan) {
*result = CMinusInfinity;
{p = (( p + 10))-1;}
@@ -533,7 +535,7 @@ tr2:
}
goto st21;
tr5:
-#line 233 "parser.rl"
+#line 236 "parser.rl"
{
const char *np;
json->current_nesting++;
@@ -543,7 +545,7 @@ tr5:
}
goto st21;
tr9:
-#line 241 "parser.rl"
+#line 244 "parser.rl"
{
const char *np;
json->current_nesting++;
@@ -553,7 +555,7 @@ tr9:
}
goto st21;
tr16:
-#line 203 "parser.rl"
+#line 206 "parser.rl"
{
if (json->allow_nan) {
*result = CInfinity;
@@ -563,7 +565,7 @@ tr16:
}
goto st21;
tr18:
-#line 196 "parser.rl"
+#line 199 "parser.rl"
{
if (json->allow_nan) {
*result = CNaN;
@@ -573,19 +575,19 @@ tr18:
}
goto st21;
tr22:
-#line 190 "parser.rl"
+#line 193 "parser.rl"
{
*result = Qfalse;
}
goto st21;
tr25:
-#line 187 "parser.rl"
+#line 190 "parser.rl"
{
*result = Qnil;
}
goto st21;
tr28:
-#line 193 "parser.rl"
+#line 196 "parser.rl"
{
*result = Qtrue;
}
@@ -594,9 +596,9 @@ st21:
if ( ++p == pe )
goto _test_eof21;
case 21:
-#line 249 "parser.rl"
+#line 252 "parser.rl"
{ p--; {p++; cs = 21; goto _out;} }
-#line 600 "parser.c"
+#line 602 "parser.c"
goto st0;
st2:
if ( ++p == pe )
@@ -757,7 +759,7 @@ case 20:
_out: {}
}
-#line 270 "parser.rl"
+#line 273 "parser.rl"
if (cs >= JSON_value_first_final) {
return p;
@@ -767,15 +769,15 @@ case 20:
}
-#line 771 "parser.c"
+#line 773 "parser.c"
static const int JSON_integer_start = 1;
-static const int JSON_integer_first_final = 5;
+static const int JSON_integer_first_final = 3;
static const int JSON_integer_error = 0;
static const int JSON_integer_en_main = 1;
-#line 286 "parser.rl"
+#line 289 "parser.rl"
static const char *JSON_parse_integer(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -783,15 +785,15 @@ static const char *JSON_parse_integer(JSON_Parser *json, const char *p, const ch
int cs = EVIL;
-#line 787 "parser.c"
+#line 789 "parser.c"
{
cs = JSON_integer_start;
}
-#line 293 "parser.rl"
+#line 296 "parser.rl"
json->memo = p;
-#line 795 "parser.c"
+#line 797 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -803,7 +805,7 @@ case 1:
case 48: goto st3;
}
if ( 49 <= (*p) && (*p) <= 57 )
- goto st4;
+ goto st5;
goto st0;
st0:
cs = 0;
@@ -815,7 +817,7 @@ case 2:
if ( (*p) == 48 )
goto st3;
if ( 49 <= (*p) && (*p) <= 57 )
- goto st4;
+ goto st5;
goto st0;
st3:
if ( ++p == pe )
@@ -825,33 +827,33 @@ case 3:
goto st0;
goto tr4;
tr4:
-#line 283 "parser.rl"
- { p--; {p++; cs = 5; goto _out;} }
- goto st5;
-st5:
- if ( ++p == pe )
- goto _test_eof5;
-case 5:
-#line 836 "parser.c"
- goto st0;
+#line 286 "parser.rl"
+ { p--; {p++; cs = 4; goto _out;} }
+ goto st4;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
+#line 838 "parser.c"
+ goto st0;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
if ( 48 <= (*p) && (*p) <= 57 )
- goto st4;
+ goto st5;
goto tr4;
}
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
_test_eof: {}
_out: {}
}
-#line 295 "parser.rl"
+#line 298 "parser.rl"
if (cs >= JSON_integer_first_final) {
long len = p - json->memo;
@@ -863,15 +865,15 @@ case 4:
}
-#line 867 "parser.c"
+#line 869 "parser.c"
static const int JSON_float_start = 1;
-static const int JSON_float_first_final = 10;
+static const int JSON_float_first_final = 8;
static const int JSON_float_error = 0;
static const int JSON_float_en_main = 1;
-#line 317 "parser.rl"
+#line 320 "parser.rl"
static const char *JSON_parse_float(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -879,15 +881,15 @@ static const char *JSON_parse_float(JSON_Parser *json, const char *p, const char
int cs = EVIL;
-#line 883 "parser.c"
+#line 885 "parser.c"
{
cs = JSON_float_start;
}
-#line 324 "parser.rl"
+#line 327 "parser.rl"
json->memo = p;
-#line 891 "parser.c"
+#line 893 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -899,7 +901,7 @@ case 1:
case 48: goto st3;
}
if ( 49 <= (*p) && (*p) <= 57 )
- goto st9;
+ goto st7;
goto st0;
st0:
cs = 0;
@@ -911,7 +913,7 @@ case 2:
if ( (*p) == 48 )
goto st3;
if ( 49 <= (*p) && (*p) <= 57 )
- goto st9;
+ goto st7;
goto st0;
st3:
if ( ++p == pe )
@@ -919,8 +921,8 @@ st3:
case 3:
switch( (*p) ) {
case 46: goto st4;
- case 69: goto st6;
- case 101: goto st6;
+ case 69: goto st5;
+ case 101: goto st5;
}
goto st0;
st4:
@@ -928,92 +930,92 @@ st4:
goto _test_eof4;
case 4:
if ( 48 <= (*p) && (*p) <= 57 )
- goto st5;
+ goto st8;
goto st0;
-st5:
+st8:
if ( ++p == pe )
- goto _test_eof5;
-case 5:
+ goto _test_eof8;
+case 8:
switch( (*p) ) {
- case 69: goto st6;
- case 101: goto st6;
+ case 69: goto st5;
+ case 101: goto st5;
}
if ( (*p) > 46 ) {
if ( 48 <= (*p) && (*p) <= 57 )
- goto st5;
+ goto st8;
} else if ( (*p) >= 45 )
goto st0;
- goto tr7;
-tr7:
-#line 311 "parser.rl"
- { p--; {p++; cs = 10; goto _out;} }
- goto st10;
-st10:
+ goto tr9;
+tr9:
+#line 314 "parser.rl"
+ { p--; {p++; cs = 9; goto _out;} }
+ goto st9;
+st9:
if ( ++p == pe )
- goto _test_eof10;
-case 10:
-#line 956 "parser.c"
+ goto _test_eof9;
+case 9:
+#line 958 "parser.c"
goto st0;
-st6:
+st5:
if ( ++p == pe )
- goto _test_eof6;
-case 6:
+ goto _test_eof5;
+case 5:
switch( (*p) ) {
- case 43: goto st7;
- case 45: goto st7;
+ case 43: goto st6;
+ case 45: goto st6;
}
if ( 48 <= (*p) && (*p) <= 57 )
- goto st8;
+ goto st10;
goto st0;
-st7:
+st6:
if ( ++p == pe )
- goto _test_eof7;
-case 7:
+ goto _test_eof6;
+case 6:
if ( 48 <= (*p) && (*p) <= 57 )
- goto st8;
+ goto st10;
goto st0;
-st8:
+st10:
if ( ++p == pe )
- goto _test_eof8;
-case 8:
+ goto _test_eof10;
+case 10:
switch( (*p) ) {
case 69: goto st0;
case 101: goto st0;
}
if ( (*p) > 46 ) {
if ( 48 <= (*p) && (*p) <= 57 )
- goto st8;
+ goto st10;
} else if ( (*p) >= 45 )
goto st0;
- goto tr7;
-st9:
+ goto tr9;
+st7:
if ( ++p == pe )
- goto _test_eof9;
-case 9:
+ goto _test_eof7;
+case 7:
switch( (*p) ) {
case 46: goto st4;
- case 69: goto st6;
- case 101: goto st6;
+ case 69: goto st5;
+ case 101: goto st5;
}
if ( 48 <= (*p) && (*p) <= 57 )
- goto st9;
+ goto st7;
goto st0;
}
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
_test_eof: {}
_out: {}
}
-#line 326 "parser.rl"
+#line 329 "parser.rl"
if (cs >= JSON_float_first_final) {
long len = p - json->memo;
@@ -1026,7 +1028,7 @@ case 9:
-#line 1030 "parser.c"
+#line 1032 "parser.c"
static const int JSON_array_start = 1;
static const int JSON_array_first_final = 17;
static const int JSON_array_error = 0;
@@ -1034,7 +1036,7 @@ static const int JSON_array_error = 0;
static const int JSON_array_en_main = 1;
-#line 366 "parser.rl"
+#line 369 "parser.rl"
static const char *JSON_parse_array(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -1048,14 +1050,14 @@ static const char *JSON_parse_array(JSON_Parser *json, const char *p, const char
*result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
-#line 1052 "parser.c"
+#line 1054 "parser.c"
{
cs = JSON_array_start;
}
-#line 379 "parser.rl"
+#line 382 "parser.rl"
-#line 1059 "parser.c"
+#line 1061 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1094,7 +1096,7 @@ case 2:
goto st2;
goto st0;
tr2:
-#line 343 "parser.rl"
+#line 346 "parser.rl"
{
VALUE v = Qnil;
const char *np = JSON_parse_value(json, p, pe, &v);
@@ -1114,7 +1116,7 @@ st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
-#line 1118 "parser.c"
+#line 1120 "parser.c"
switch( (*p) ) {
case 13: goto st3;
case 32: goto st3;
@@ -1214,14 +1216,14 @@ case 12:
goto st3;
goto st12;
tr4:
-#line 358 "parser.rl"
+#line 361 "parser.rl"
{ p--; {p++; cs = 17; goto _out;} }
goto st17;
st17:
if ( ++p == pe )
goto _test_eof17;
case 17:
-#line 1225 "parser.c"
+#line 1227 "parser.c"
goto st0;
st13:
if ( ++p == pe )
@@ -1277,7 +1279,7 @@ case 16:
_out: {}
}
-#line 380 "parser.rl"
+#line 383 "parser.rl"
if(cs >= JSON_array_first_final) {
return p + 1;
@@ -1358,7 +1360,7 @@ static VALUE json_string_unescape(VALUE result, const char *string, const char *
}
-#line 1362 "parser.c"
+#line 1364 "parser.c"
static const int JSON_string_start = 1;
static const int JSON_string_first_final = 8;
static const int JSON_string_error = 0;
@@ -1366,7 +1368,7 @@ static const int JSON_string_error = 0;
static const int JSON_string_en_main = 1;
-#line 479 "parser.rl"
+#line 482 "parser.rl"
static int
@@ -1386,15 +1388,15 @@ static const char *JSON_parse_string(JSON_Parser *json, const char *p, const cha
int cs = EVIL;
*result = rb_str_buf_new(0);
-#line 1390 "parser.c"
+#line 1394 "parser.c"
{
cs = JSON_string_start;
}
-#line 498 "parser.rl"
+#line 503 "parser.rl"
json->memo = p;
-#line 1398 "parser.c"
+#line 1402 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1419,7 +1421,7 @@ case 2:
goto st0;
goto st2;
tr2:
-#line 465 "parser.rl"
+#line 468 "parser.rl"
{
*result = json_string_unescape(*result, json->memo + 1, p);
if (NIL_P(*result)) {
@@ -1430,14 +1432,14 @@ tr2:
{p = (( p + 1))-1;}
}
}
-#line 476 "parser.rl"
+#line 479 "parser.rl"
{ p--; {p++; cs = 8; goto _out;} }
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
-#line 1441 "parser.c"
+#line 1445 "parser.c"
goto st0;
st3:
if ( ++p == pe )
@@ -1513,7 +1515,7 @@ case 7:
_out: {}
}
-#line 500 "parser.rl"
+#line 505 "parser.rl"
if (json->create_additions) {
VALUE match_string = json->match_string;
@@ -1539,19 +1541,6 @@ case 7:
}
}
-
-
-#line 1545 "parser.c"
-static const int JSON_start = 1;
-static const int JSON_first_final = 10;
-static const int JSON_error = 0;
-
-static const int JSON_en_main = 1;
-
-
-#line 551 "parser.rl"
-
-
/*
* Document-class: JSON::Ext::Parser
*
@@ -1637,13 +1626,14 @@ static inline void parser_iv_set(JSON_Parser *json, const char* iv_name, VALUE v
* defaults to true.
* * *object_class*: Defaults to Hash
* * *array_class*: Defaults to Array
+ * * *quirks_mode*: Enables quirks_mode for parser, that is for example
+ * parsing single JSON values instead of documents is possible.
+ *
*/
static int init_count = 0;
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
- const char *ptr;
- long len;
VALUE source, opts;
GET_PARSER_INIT;
@@ -1655,9 +1645,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}
#endif
rb_scan_args(argc, argv, "11", &source, &opts);
- source = convert_encoding(StringValue(source));
- ptr = RSTRING_PTR(source);
- len = RSTRING_LEN(source);
if (!NIL_P(opts)) {
opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
if (NIL_P(opts)) {
@@ -1687,6 +1674,13 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
} else {
json->symbolize_names = 0;
}
+ tmp = ID2SYM(i_quirks_mode);
+ if (option_given_p(opts, tmp)) {
+ VALUE quirks_mode = rb_hash_aref(opts, tmp);
+ json->quirks_mode = RTEST(quirks_mode) ? 1 : 0;
+ } else {
+ json->quirks_mode = 0;
+ }
tmp = ID2SYM(i_create_additions);
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -1724,21 +1718,30 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
json->create_id = rb_funcall(mJSON, i_create_id, 0);
parser_iv_set(json, "@create_id", json->create_id);
}
+ if (!json->quirks_mode) {
+ source = convert_encoding(StringValue(source));
+ }
json->current_nesting = 0;
- json->len = len;
- json->source = ptr;
+ json->len = RSTRING_LEN(source);
+ json->source = RSTRING_PTR(source);;
json->Vsource = source;
parser_iv_set(json, "@vsource", json->Vsource);
return self;
}
-/*
- * call-seq: parse()
- *
- * Parses the current JSON text _source_ and returns the complete data
- * structure as a result.
- */
-static VALUE cParser_parse(VALUE self)
+
+#line 1719 "parser.c"
+static const int JSON_start = 1;
+static const int JSON_first_final = 10;
+static const int JSON_error = 0;
+
+static const int JSON_en_main = 1;
+
+
+#line 726 "parser.rl"
+
+
+static VALUE cParser_parse_strict(VALUE self)
{
const char *p, *pe;
int cs = EVIL;
@@ -1751,7 +1754,7 @@ static VALUE cParser_parse(VALUE self)
cs = JSON_start;
}
-#line 745 "parser.rl"
+#line 736 "parser.rl"
p = json->source;
pe = p + json->len;
@@ -1811,7 +1814,7 @@ case 5:
goto st1;
goto st5;
tr3:
-#line 540 "parser.rl"
+#line 715 "parser.rl"
{
const char *np;
json->current_nesting = 1;
@@ -1820,7 +1823,7 @@ tr3:
}
goto st10;
tr4:
-#line 533 "parser.rl"
+#line 708 "parser.rl"
{
const char *np;
json->current_nesting = 1;
@@ -1889,7 +1892,7 @@ case 9:
_out: {}
}
-#line 748 "parser.rl"
+#line 739 "parser.rl"
if (cs >= JSON_first_final && p == pe) {
return result;
@@ -1899,6 +1902,197 @@ case 9:
}
}
+
+
+#line 1893 "parser.c"
+static const int JSON_quirks_mode_start = 1;
+static const int JSON_quirks_mode_first_final = 10;
+static const int JSON_quirks_mode_error = 0;
+
+static const int JSON_quirks_mode_en_main = 1;
+
+
+#line 764 "parser.rl"
+
+
+static VALUE cParser_parse_quirks_mode(VALUE self)
+{
+ char *p, *pe;
+ int cs = EVIL;
+ VALUE result = Qnil;
+ GET_PARSER;
+
+
+#line 1912 "parser.c"
+ {
+ cs = JSON_quirks_mode_start;
+ }
+
+#line 774 "parser.rl"
+ p = json->source;
+ pe = p + json->len;
+
+#line 1921 "parser.c"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ switch( (*p) ) {
+ case 13: goto st1;
+ case 32: goto st1;
+ case 34: goto tr2;
+ case 45: goto tr2;
+ case 47: goto st6;
+ case 73: goto tr2;
+ case 78: goto tr2;
+ case 91: goto tr2;
+ case 102: goto tr2;
+ case 110: goto tr2;
+ case 116: goto tr2;
+ case 123: goto tr2;
+ }
+ if ( (*p) > 10 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2;
+ } else if ( (*p) >= 9 )
+ goto st1;
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+tr2:
+#line 756 "parser.rl"
+ {
+ char *np = JSON_parse_value(json, p, pe, &result);
+ if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
+ }
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+#line 1965 "parser.c"
+ switch( (*p) ) {
+ case 13: goto st10;
+ case 32: goto st10;
+ case 47: goto st2;
+ }
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto st10;
+ goto st0;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ switch( (*p) ) {
+ case 42: goto st3;
+ case 47: goto st5;
+ }
+ goto st0;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ if ( (*p) == 42 )
+ goto st4;
+ goto st3;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ switch( (*p) ) {
+ case 42: goto st4;
+ case 47: goto st10;
+ }
+ goto st3;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ if ( (*p) == 10 )
+ goto st10;
+ goto st5;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ switch( (*p) ) {
+ case 42: goto st7;
+ case 47: goto st9;
+ }
+ goto st0;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ if ( (*p) == 42 )
+ goto st8;
+ goto st7;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ switch( (*p) ) {
+ case 42: goto st8;
+ case 47: goto st1;
+ }
+ goto st7;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) == 10 )
+ goto st1;
+ goto st9;
+ }
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 777 "parser.rl"
+
+ if (cs >= JSON_quirks_mode_first_final && p == pe) {
+ return result;
+ } else {
+ rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq: parse()
+ *
+ * Parses the current JSON text _source_ and returns the complete data
+ * structure as a result.
+ */
+static VALUE cParser_parse(VALUE self)
+{
+ GET_PARSER;
+
+ if (json->quirks_mode) {
+ return cParser_parse_quirks_mode(self);
+ } else {
+ return cParser_parse_strict(self);
+ }
+}
+
+
static JSON_Parser *JSON_allocate()
{
JSON_Parser *json = ALLOC(JSON_Parser);
@@ -1940,6 +2134,18 @@ static VALUE cParser_source(VALUE self)
return rb_str_dup(json->Vsource);
}
+/*
+ * call-seq: quirks_mode?()
+ *
+ * Returns a true, if this parser is in quirks_mode, false otherwise.
+ */
+static VALUE cParser_quirks_mode_p(VALUE self)
+{
+ GET_PARSER;
+ return json->quirks_mode ? Qtrue : Qfalse;
+}
+
+
void Init_parser()
{
rb_require("json/common");
@@ -1952,6 +2158,7 @@ void Init_parser()
rb_define_method(cParser, "initialize", cParser_initialize, -1);
rb_define_method(cParser, "parse", cParser_parse, 0);
rb_define_method(cParser, "source", cParser_source, 0);
+ rb_define_method(cParser, "quirks_mode?", cParser_quirks_mode_p, 0);
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
@@ -1965,6 +2172,7 @@ void Init_parser()
i_max_nesting = rb_intern("max_nesting");
i_allow_nan = rb_intern("allow_nan");
i_symbolize_names = rb_intern("symbolize_names");
+ i_quirks_mode = rb_intern("quirks_mode");
i_object_class = rb_intern("object_class");
i_array_class = rb_intern("array_class");
i_match = rb_intern("match");
diff --git a/ext/json/ext/parser/parser.h b/ext/json/ext/parser/parser.h
index 5571787..cf3e558 100644
--- a/ext/json/ext/parser/parser.h
+++ b/ext/json/ext/parser/parser.h
@@ -45,6 +45,7 @@ typedef struct JSON_ParserStruct {
int allow_nan;
int parsing_name;
int symbolize_names;
+ int quirks_mode;
VALUE object_class;
VALUE array_class;
int create_additions;
diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl
index feb0093..5de6118 100644
--- a/ext/json/ext/parser/parser.rl
+++ b/ext/json/ext/parser/parser.rl
@@ -76,8 +76,9 @@ static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
static VALUE CNaN, CInfinity, CMinusInfinity;
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_match, i_match_string, i_aset, i_leftshift;
+ i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_quirks_mode,
+ i_object_class, i_array_class, i_key_p, i_deep_const_get, i_match,
+ i_match_string, i_aset, i_leftshift;
%%{
machine JSON_common;
@@ -138,13 +139,14 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
action exit { fhold; fbreak; }
- a_pair = ignore* begin_name >parse_name
- ignore* name_separator ignore*
- begin_value >parse_value;
+ pair = ignore* begin_name >parse_name ignore* name_separator ignore* begin_value >parse_value;
+ next_pair = ignore* value_separator pair;
- main := begin_object
- (a_pair (ignore* value_separator a_pair)*)?
- ignore* end_object @exit;
+ main := (
+ begin_object
+ (pair (next_pair)*)? ignore*
+ end_object
+ ) @exit;
}%%
static const char *JSON_parse_object(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -178,6 +180,7 @@ static const char *JSON_parse_object(JSON_Parser *json, const char *p, const cha
}
}
+
%%{
machine JSON_value;
include JSON_common;
@@ -213,8 +216,8 @@ static const char *JSON_parse_object(JSON_Parser *json, const char *p, const cha
}
action parse_number {
- const char *np;
- if(pe > fpc + 9 && !strncmp(MinusInfinity, fpc, 9)) {
+ char *np;
+ if(pe > fpc + 9 - json->quirks_mode && !strncmp(MinusInfinity, fpc, 9)) {
if (json->allow_nan) {
*result = CMinusInfinity;
fexec p + 10;
@@ -282,7 +285,7 @@ static const char *JSON_parse_value(JSON_Parser *json, const char *p, const char
action exit { fhold; fbreak; }
- main := '-'? ('0' | [1-9][0-9]*) (^[0-9] @exit);
+ main := '-'? ('0' | [1-9][0-9]*) (^[0-9]? @exit);
}%%
static const char *JSON_parse_integer(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -313,7 +316,7 @@ static const char *JSON_parse_integer(JSON_Parser *json, const char *p, const ch
main := '-'? (
(('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
| (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
- ) (^[0-9Ee.\-] @exit );
+ ) (^[0-9Ee.\-]? @exit );
}%%
static const char *JSON_parse_float(JSON_Parser *json, const char *p, const char *pe, VALUE *result)
@@ -522,34 +525,6 @@ static const char *JSON_parse_string(JSON_Parser *json, const char *p, const cha
}
}
-
-%%{
- machine JSON;
-
- write data;
-
- include JSON_common;
-
- action parse_object {
- const char *np;
- json->current_nesting = 1;
- np = JSON_parse_object(json, fpc, pe, &result);
- if (np == NULL) { fhold; fbreak; } else fexec np;
- }
-
- action parse_array {
- const char *np;
- json->current_nesting = 1;
- np = JSON_parse_array(json, fpc, pe, &result);
- if (np == NULL) { fhold; fbreak; } else fexec np;
- }
-
- main := ignore* (
- begin_object >parse_object |
- begin_array >parse_array
- ) ignore*;
-}%%
-
/*
* Document-class: JSON::Ext::Parser
*
@@ -640,8 +615,6 @@ static inline void parser_iv_set(JSON_Parser *json, const char* iv_name, VALUE v
static int init_count = 0;
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
- const char *ptr;
- long len;
VALUE source, opts;
GET_PARSER_INIT;
@@ -653,9 +626,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}
#endif
rb_scan_args(argc, argv, "11", &source, &opts);
- source = convert_encoding(StringValue(source));
- ptr = RSTRING_PTR(source);
- len = RSTRING_LEN(source);
if (!NIL_P(opts)) {
opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
if (NIL_P(opts)) {
@@ -685,6 +655,13 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
} else {
json->symbolize_names = 0;
}
+ tmp = ID2SYM(i_quirks_mode);
+ if (option_given_p(opts, tmp)) {
+ VALUE quirks_mode = rb_hash_aref(opts, tmp);
+ json->quirks_mode = RTEST(quirks_mode) ? 1 : 0;
+ } else {
+ json->quirks_mode = 0;
+ }
tmp = ID2SYM(i_create_additions);
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -722,21 +699,45 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
json->create_id = rb_funcall(mJSON, i_create_id, 0);
parser_iv_set(json, "@create_id", json->create_id);
}
+ if (!json->quirks_mode) {
+ source = convert_encoding(StringValue(source));
+ }
json->current_nesting = 0;
- json->len = len;
- json->source = ptr;
+ json->len = RSTRING_LEN(source);
+ json->source = RSTRING_PTR(source);;
json->Vsource = source;
parser_iv_set(json, "@vsource", json->Vsource);
return self;
}
-/*
- * call-seq: parse()
- *
- * Parses the current JSON text _source_ and returns the complete data
- * structure as a result.
- */
-static VALUE cParser_parse(VALUE self)
+%%{
+ machine JSON;
+
+ write data;
+
+ include JSON_common;
+
+ action parse_object {
+ char *np;
+ json->current_nesting = 1;
+ np = JSON_parse_object(json, fpc, pe, &result);
+ if (np == NULL) { fhold; fbreak; } else fexec np;
+ }
+
+ action parse_array {
+ char *np;
+ json->current_nesting = 1;
+ np = JSON_parse_array(json, fpc, pe, &result);
+ if (np == NULL) { fhold; fbreak; } else fexec np;
+ }
+
+ main := ignore* (
+ begin_object >parse_object |
+ begin_array >parse_array
+ ) ignore*;
+}%%
+
+static VALUE cParser_parse_strict(VALUE self)
{
const char *p, *pe;
int cs = EVIL;
@@ -756,6 +757,62 @@ static VALUE cParser_parse(VALUE self)
}
}
+
+%%{
+ machine JSON_quirks_mode;
+
+ write data;
+
+ include JSON_common;
+
+ action parse_value {
+ char *np = JSON_parse_value(json, fpc, pe, &result);
+ if (np == NULL) { fhold; fbreak; } else fexec np;
+ }
+
+ main := ignore* (
+ begin_value >parse_value
+ ) ignore*;
+}%%
+
+static VALUE cParser_parse_quirks_mode(VALUE self)
+{
+ char *p, *pe;
+ int cs = EVIL;
+ VALUE result = Qnil;
+ GET_PARSER;
+
+ %% write init;
+ p = json->source;
+ pe = p + json->len;
+ %% write exec;
+
+ if (cs >= JSON_quirks_mode_first_final && p == pe) {
+ return result;
+ } else {
+ rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq: parse()
+ *
+ * Parses the current JSON text _source_ and returns the complete data
+ * structure as a result.
+ */
+static VALUE cParser_parse(VALUE self)
+{
+ GET_PARSER;
+
+ if (json->quirks_mode) {
+ return cParser_parse_quirks_mode(self);
+ } else {
+ return cParser_parse_strict(self);
+ }
+}
+
+
static JSON_Parser *JSON_allocate()
{
JSON_Parser *json = ALLOC(JSON_Parser);
@@ -797,6 +854,18 @@ static VALUE cParser_source(VALUE self)
return rb_str_dup(json->Vsource);
}
+/*
+ * call-seq: quirks_mode?()
+ *
+ * Returns a true, if this parser is in quirks_mode, false otherwise.
+ */
+static VALUE cParser_quirks_mode_p(VALUE self)
+{
+ GET_PARSER;
+ return json->quirks_mode ? Qtrue : Qfalse;
+}
+
+
void Init_parser()
{
rb_require("json/common");
@@ -809,6 +878,7 @@ void Init_parser()
rb_define_method(cParser, "initialize", cParser_initialize, -1);
rb_define_method(cParser, "parse", cParser_parse, 0);
rb_define_method(cParser, "source", cParser_source, 0);
+ rb_define_method(cParser, "quirks_mode?", cParser_quirks_mode_p, 0);
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
@@ -822,6 +892,7 @@ void Init_parser()
i_max_nesting = rb_intern("max_nesting");
i_allow_nan = rb_intern("allow_nan");
i_symbolize_names = rb_intern("symbolize_names");
+ i_quirks_mode = rb_intern("quirks_mode");
i_object_class = rb_intern("object_class");
i_array_class = rb_intern("array_class");
i_match = rb_intern("match");
diff --git a/install.rb b/install.rb
index adf77a0..62fce1a 100755
--- a/install.rb
+++ b/install.rb
@@ -6,21 +6,14 @@ include FileUtils::Verbose
include Config
-bindir = CONFIG["bindir"]
-cd 'bin' do
- filename = 'edit_json.rb'
- #install(filename, bindir)
-end
sitelibdir = CONFIG["sitelibdir"]
cd 'lib' do
install('json.rb', sitelibdir)
mkdir_p File.join(sitelibdir, 'json')
- for file in Dir['json/**/*.{rb,xpm}']
+ for file in Dir['json/**/*}']
d = File.join(sitelibdir, file)
mkdir_p File.dirname(d)
install(file, d)
end
- install(File.join('json', 'editor.rb'), File.join(sitelibdir,'json'))
- install(File.join('json', 'json.xpm'), File.join(sitelibdir,'json'))
end
warn " *** Installed PURE ruby library."
diff --git a/java/src/json/ext/Generator.java b/java/src/json/ext/Generator.java
index fbc394f..78dc078 100644
--- a/java/src/json/ext/Generator.java
+++ b/java/src/json/ext/Generator.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
@@ -85,11 +85,11 @@ public final class Generator {
/**
* A class that concentrates all the information that is shared by
* generators working on a single session.
- *
+ *
* <p>A session is defined as the process of serializing a single root
* object; any handler directly called by container handlers (arrays and
* hashes/objects) shares this object with its caller.
- *
+ *
* <p>Note that anything called indirectly (via {@link GENERIC_HANDLER})
* won't be part of the session.
*/
diff --git a/java/src/json/ext/GeneratorMethods.java b/java/src/json/ext/GeneratorMethods.java
index 356f2d0..637b579 100644
--- a/java/src/json/ext/GeneratorMethods.java
+++ b/java/src/json/ext/GeneratorMethods.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
@@ -25,7 +25,7 @@ import org.jruby.util.ByteList;
/**
* A class that populates the
* <code>Json::Ext::Generator::GeneratorMethods</code> module.
- *
+ *
* @author mernen
*/
class GeneratorMethods {
diff --git a/java/src/json/ext/GeneratorService.java b/java/src/json/ext/GeneratorService.java
index 2f3b07e..ed33639 100644
--- a/java/src/json/ext/GeneratorService.java
+++ b/java/src/json/ext/GeneratorService.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
diff --git a/java/src/json/ext/GeneratorState.java b/java/src/json/ext/GeneratorState.java
index f04eda2..78524a1 100644
--- a/java/src/json/ext/GeneratorState.java
+++ b/java/src/json/ext/GeneratorState.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
@@ -24,10 +24,10 @@ import org.jruby.util.ByteList;
/**
* The <code>JSON::Ext::Generator::State</code> class.
- *
+ *
* <p>This class is used to create State instances, that are use to hold data
* while generating a JSON text from a a Ruby data structure.
- *
+ *
* @author mernen
*/
public class GeneratorState extends RubyObject {
@@ -72,10 +72,17 @@ public class GeneratorState extends RubyObject {
private boolean allowNaN = DEFAULT_ALLOW_NAN;
static final boolean DEFAULT_ALLOW_NAN = false;
/**
- * XXX
+ * If set to <code>true</code> all JSON documents generated do not contain
+ * any other characters than ASCII characters.
*/
private boolean asciiOnly = DEFAULT_ASCII_ONLY;
static final boolean DEFAULT_ASCII_ONLY = false;
+ /**
+ * If set to <code>true</code> all JSON values generated might not be
+ * RFC-conform JSON documents.
+ */
+ private boolean quirksMode = DEFAULT_QUIRKS_MODE;
+ static final boolean DEFAULT_QUIRKS_MODE = false;
/**
* The current depth (inside a #to_json call)
@@ -94,7 +101,7 @@ public class GeneratorState extends RubyObject {
/**
* <code>State.from_state(opts)</code>
- *
+ *
* <p>Creates a State object from <code>opts</code>, which ought to be
* {@link RubyHash Hash} to create a new <code>State</code> instance
* configured by <codes>opts</code>, something else to create an
@@ -136,11 +143,11 @@ public class GeneratorState extends RubyObject {
/**
* <code>State#initialize(opts = {})</code>
- *
+ *
* Instantiates a new <code>State</code> object, configured by <code>opts</code>.
- *
+ *
* <code>opts</code> can have the following keys:
- *
+ *
* <dl>
* <dt><code>:indent</code>
* <dd>a {@link RubyString String} used to indent levels (default: <code>""</code>)
@@ -151,7 +158,7 @@ public class GeneratorState extends RubyObject {
* <dd>a String that is put before a <code>":"</code> pair delimiter
* (default: <code>""</code>)
* <dt><code>:object_nl</code>
- * <dd>a String that is put at the end of a JSON object (default: <code>""</code>)
+ * <dd>a String that is put at the end of a JSON object (default: <code>""</code>)
* <dt><code>:array_nl</code>
* <dd>a String that is put at the end of a JSON array (default: <code>""</code>)
* <dt><code>:allow_nan</code>
@@ -181,17 +188,20 @@ public class GeneratorState extends RubyObject {
this.maxNesting = orig.maxNesting;
this.allowNaN = orig.allowNaN;
this.asciiOnly = orig.asciiOnly;
+ this.quirksMode = orig.quirksMode;
this.depth = orig.depth;
return this;
}
/**
- * XXX
+ * Generates a valid JSON document from object <code>obj</code> and returns
+ * the result. If no valid JSON document can be created this method raises
+ * a GeneratorError exception.
*/
@JRubyMethod
public IRubyObject generate(ThreadContext context, IRubyObject obj) {
RubyString result = Generator.generateJson(context, obj, this);
- if (!objectOrArrayLiteral(result)) {
+ if (!quirksMode && !objectOrArrayLiteral(result)) {
throw Utils.newException(context, Utils.M_GENERATOR_ERROR,
"only generation of JSON objects or arrays allowed");
}
@@ -364,6 +374,22 @@ public class GeneratorState extends RubyObject {
return context.getRuntime().newBoolean(asciiOnly);
}
+ @JRubyMethod(name="quirks_mode")
+ public RubyBoolean quirks_mode_get(ThreadContext context) {
+ return context.getRuntime().newBoolean(quirksMode);
+ }
+
+ @JRubyMethod(name="quirks_mode=")
+ public IRubyObject quirks_mode_set(IRubyObject quirks_mode) {
+ quirksMode = quirks_mode.isTrue();
+ return quirks_mode.getRuntime().newBoolean(quirksMode);
+ }
+
+ @JRubyMethod(name="quirks_mode?")
+ public RubyBoolean quirks_mode_p(ThreadContext context) {
+ return context.getRuntime().newBoolean(quirksMode);
+ }
+
public int getDepth() {
return depth;
}
@@ -390,7 +416,7 @@ public class GeneratorState extends RubyObject {
/**
* <code>State#configure(opts)</code>
- *
+ *
* <p>Configures this State instance with the {@link RubyHash Hash}
* <code>opts</code>, and returns itself.
* @param vOpts The options hash
@@ -418,6 +444,7 @@ public class GeneratorState extends RubyObject {
maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
allowNaN = opts.getBool("allow_nan", DEFAULT_ALLOW_NAN);
asciiOnly = opts.getBool("ascii_only", DEFAULT_ASCII_ONLY);
+ quirksMode = opts.getBool("quirks_mode", DEFAULT_QUIRKS_MODE);
depth = opts.getInt("depth", 0);
@@ -426,7 +453,7 @@ public class GeneratorState extends RubyObject {
/**
* <code>State#to_h()</code>
- *
+ *
* <p>Returns the configuration instance variables as a hash, that can be
* passed to the configure method.
* @return
@@ -443,6 +470,7 @@ public class GeneratorState extends RubyObject {
result.op_aset(context, runtime.newSymbol("array_nl"), array_nl_get(context));
result.op_aset(context, runtime.newSymbol("allow_nan"), allow_nan_p(context));
result.op_aset(context, runtime.newSymbol("ascii_only"), ascii_only_p(context));
+ result.op_aset(context, runtime.newSymbol("quirks_mode"), quirks_mode_p(context));
result.op_aset(context, runtime.newSymbol("max_nesting"), max_nesting_get(context));
result.op_aset(context, runtime.newSymbol("depth"), depth_get(context));
return result;
diff --git a/java/src/json/ext/OptionsReader.java b/java/src/json/ext/OptionsReader.java
index c9c9c94..a0b76b1 100644
--- a/java/src/json/ext/OptionsReader.java
+++ b/java/src/json/ext/OptionsReader.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java
index cea42d4..0b59c8f 100644
--- a/java/src/json/ext/Parser.java
+++ b/java/src/json/ext/Parser.java
@@ -2,7 +2,7 @@
// line 1 "Parser.rl"
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
@@ -31,16 +31,16 @@ import org.jruby.util.ByteList;
/**
* The <code>JSON::Ext::Parser</code> class.
- *
+ *
* <p>This is the JSON parser implemented as a Java class. To use it as the
* standard parser, set
* <pre>JSON.parser = JSON::Ext::Parser</pre>
* This is performed for you when you <code>include "json/ext"</code>.
- *
+ *
* <p>This class does not perform the actual parsing, just acts as an interface
* to Ruby code. When the {@link #parse()} method is invoked, a
* Parser.ParserSession object is instantiated, which handles the process.
- *
+ *
* @author mernen
*/
public class Parser extends RubyObject {
@@ -51,6 +51,7 @@ public class Parser extends RubyObject {
private int maxNesting;
private boolean allowNaN;
private boolean symbolizeNames;
+ private boolean quirksMode;
private RubyClass objectClass;
private RubyClass arrayClass;
private RubyHash match_string;
@@ -71,7 +72,7 @@ public class Parser extends RubyObject {
/**
* Multiple-value return for internal parser methods.
- *
+ *
* <p>All the <code>parse<var>Stuff</var></code> methods return instances of
* <code>ParserResult</code> when successful, or <code>null</code> when
* there's a problem with the input data.
@@ -100,18 +101,18 @@ public class Parser extends RubyObject {
/**
* <code>Parser.new(source, opts = {})</code>
- *
+ *
* <p>Creates a new <code>JSON::Ext::Parser</code> instance for the string
* <code>source</code>.
* It will be configured by the <code>opts</code> Hash.
* <code>opts</code> can have the following keys:
- *
+ *
* <dl>
* <dt><code>:max_nesting</code>
* <dd>The maximum depth of nesting allowed in the parsed data
* structures. Disable depth checking with <code>:max_nesting => false|nil|0</code>,
* it defaults to 19.
- *
+ *
* <dt><code>:allow_nan</code>
* <dd>If set to <code>true</code>, allow <code>NaN</code>,
* <code>Infinity</code> and <code>-Infinity</code> in defiance of RFC 4627
@@ -120,17 +121,25 @@ public class Parser extends RubyObject {
* <dt><code>:symbolize_names</code>
* <dd>If set to <code>true</code>, returns symbols for the names (keys) in
* a JSON object. Otherwise strings are returned, which is also the default.
+ *
+ * <dt><code>:quirks_mode?</code>
+ * <dd>If set to <code>true</code>, if the parse is in quirks_mode, false
+ * otherwise.
*
* <dt><code>:create_additions</code>
* <dd>If set to <code>false</code>, the Parser doesn't create additions
* even if a matchin class and <code>create_id</code> was found. This option
* defaults to <code>true</code>.
- *
+ *
* <dt><code>:object_class</code>
* <dd>Defaults to Hash.
- *
+ *
* <dt><code>:array_class</code>
* <dd>Defaults to Array.
+ *
+ * <dt><code>:quirks_mode</code>
+ * <dd>Enables quirks_mode for parser, that is for example parsing single
+ * JSON values instead of documents is possible.
* </dl>
*/
@JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
@@ -148,19 +157,21 @@ public class Parser extends RubyObject {
if (this.vSource != null) {
throw runtime.newTypeError("already initialized instance");
}
- RubyString source = convertEncoding(context, args[0].convertToString());
OptionsReader opts = new OptionsReader(context, args.length > 1 ? args[1] : null);
this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
this.allowNaN = opts.getBool("allow_nan", false);
this.symbolizeNames = opts.getBool("symbolize_names", false);
+ this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
this.createAdditions = opts.getBool("create_additions", true);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
- this.vSource = source;
+ this.vSource = args[0].convertToString();
+ if (!quirksMode) this.vSource = convertEncoding(context, vSource);
+
return this;
}
@@ -229,7 +240,7 @@ public class Parser extends RubyObject {
/**
* <code>Parser#parse()</code>
- *
+ *
* <p>Parses the current JSON text <code>source</code> and returns the
* complete data structure as a result.
*/
@@ -240,7 +251,7 @@ public class Parser extends RubyObject {
/**
* <code>Parser#source()</code>
- *
+ *
* <p>Returns a copy of the current <code>source</code> string, that was
* used to construct this Parser.
*/
@@ -249,6 +260,17 @@ public class Parser extends RubyObject {
return checkAndGetSource().dup();
}
+ /**
+ * <code>Parser#quirks_mode?()</code>
+ *
+ * <p>If set to <code>true</code>, if the parse is in quirks_mode, false
+ * otherwise.
+ */
+ @JRubyMethod(name = "quirks_mode?")
+ public IRubyObject quirks_mode_p(ThreadContext context) {
+ return context.getRuntime().newBoolean(quirksMode);
+ }
+
public RubyString checkAndGetSource() {
if (vSource != null) {
return vSource;
@@ -268,7 +290,7 @@ public class Parser extends RubyObject {
/**
* A string parsing session.
- *
+ *
* <p>Once a ParserSession is instantiated, the source string should not
* change until the parsing is complete. The ParserSession object assumes
* the source {@link RubyString} is still associated to its original
@@ -309,11 +331,11 @@ public class Parser extends RubyObject {
}
-// line 335 "Parser.rl"
+// line 357 "Parser.rl"
-// line 317 "Parser.java"
+// line 339 "Parser.java"
private static byte[] init__JSON_value_actions_0()
{
return new byte [] {
@@ -427,7 +449,7 @@ static final int JSON_value_error = 0;
static final int JSON_value_en_main = 1;
-// line 441 "Parser.rl"
+// line 463 "Parser.rl"
ParserResult parseValue(int p, int pe) {
@@ -435,14 +457,14 @@ static final int JSON_value_en_main = 1;
IRubyObject result = null;
-// line 439 "Parser.java"
+// line 461 "Parser.java"
{
cs = JSON_value_start;
}
-// line 448 "Parser.rl"
+// line 470 "Parser.rl"
-// line 446 "Parser.java"
+// line 468 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -468,13 +490,13 @@ case 1:
while ( _nacts-- > 0 ) {
switch ( _JSON_value_actions[_acts++] ) {
case 9:
-// line 426 "Parser.rl"
+// line 448 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 478 "Parser.java"
+// line 500 "Parser.java"
}
}
@@ -537,25 +559,25 @@ case 1:
switch ( _JSON_value_actions[_acts++] )
{
case 0:
-// line 343 "Parser.rl"
+// line 365 "Parser.rl"
{
result = getRuntime().getNil();
}
break;
case 1:
-// line 346 "Parser.rl"
+// line 368 "Parser.rl"
{
result = getRuntime().getFalse();
}
break;
case 2:
-// line 349 "Parser.rl"
+// line 371 "Parser.rl"
{
result = getRuntime().getTrue();
}
break;
case 3:
-// line 352 "Parser.rl"
+// line 374 "Parser.rl"
{
if (parser.allowNaN) {
result = getConstant(CONST_NAN);
@@ -565,7 +587,7 @@ case 1:
}
break;
case 4:
-// line 359 "Parser.rl"
+// line 381 "Parser.rl"
{
if (parser.allowNaN) {
result = getConstant(CONST_INFINITY);
@@ -575,9 +597,9 @@ case 1:
}
break;
case 5:
-// line 366 "Parser.rl"
+// line 388 "Parser.rl"
{
- if (pe > p + 9 &&
+ if (pe > p + 9 - (parser.quirksMode ? 1 : 0) &&
absSubSequence(p, p + 9).toString().equals(JSON_MINUS_INFINITY)) {
if (parser.allowNaN) {
@@ -604,7 +626,7 @@ case 1:
}
break;
case 6:
-// line 392 "Parser.rl"
+// line 414 "Parser.rl"
{
ParserResult res = parseString(p, pe);
if (res == null) {
@@ -617,7 +639,7 @@ case 1:
}
break;
case 7:
-// line 402 "Parser.rl"
+// line 424 "Parser.rl"
{
currentNesting++;
ParserResult res = parseArray(p, pe);
@@ -632,7 +654,7 @@ case 1:
}
break;
case 8:
-// line 414 "Parser.rl"
+// line 436 "Parser.rl"
{
currentNesting++;
ParserResult res = parseObject(p, pe);
@@ -646,7 +668,7 @@ case 1:
}
}
break;
-// line 650 "Parser.java"
+// line 672 "Parser.java"
}
}
}
@@ -666,7 +688,7 @@ case 5:
break; }
}
-// line 449 "Parser.rl"
+// line 471 "Parser.rl"
if (cs >= JSON_value_first_final && result != null) {
return new ParserResult(result, p);
@@ -676,7 +698,7 @@ case 5:
}
-// line 680 "Parser.java"
+// line 702 "Parser.java"
private static byte[] init__JSON_integer_actions_0()
{
return new byte [] {
@@ -690,7 +712,7 @@ private static final byte _JSON_integer_actions[] = init__JSON_integer_actions_0
private static byte[] init__JSON_integer_key_offsets_0()
{
return new byte [] {
- 0, 0, 4, 7, 9, 11
+ 0, 0, 4, 7, 9, 9
};
}
@@ -720,7 +742,7 @@ private static final byte _JSON_integer_single_lengths[] = init__JSON_integer_si
private static byte[] init__JSON_integer_range_lengths_0()
{
return new byte [] {
- 0, 1, 1, 1, 1, 0
+ 0, 1, 1, 1, 0, 1
};
}
@@ -730,7 +752,7 @@ private static final byte _JSON_integer_range_lengths[] = init__JSON_integer_ran
private static byte[] init__JSON_integer_index_offsets_0()
{
return new byte [] {
- 0, 0, 4, 7, 9, 11
+ 0, 0, 4, 7, 9, 10
};
}
@@ -740,7 +762,7 @@ private static final byte _JSON_integer_index_offsets[] = init__JSON_integer_ind
private static byte[] init__JSON_integer_indicies_0()
{
return new byte [] {
- 0, 2, 3, 1, 2, 3, 1, 1, 4, 3, 4, 1,
+ 0, 2, 3, 1, 2, 3, 1, 1, 4, 1, 3, 4,
0
};
}
@@ -751,7 +773,7 @@ private static final byte _JSON_integer_indicies[] = init__JSON_integer_indicies
private static byte[] init__JSON_integer_trans_targs_0()
{
return new byte [] {
- 2, 0, 3, 4, 5
+ 2, 0, 3, 5, 4
};
}
@@ -769,28 +791,28 @@ private static final byte _JSON_integer_trans_actions[] = init__JSON_integer_tra
static final int JSON_integer_start = 1;
-static final int JSON_integer_first_final = 5;
+static final int JSON_integer_first_final = 3;
static final int JSON_integer_error = 0;
static final int JSON_integer_en_main = 1;
-// line 468 "Parser.rl"
+// line 490 "Parser.rl"
ParserResult parseInteger(int p, int pe) {
int cs = EVIL;
-// line 786 "Parser.java"
+// line 808 "Parser.java"
{
cs = JSON_integer_start;
}
-// line 474 "Parser.rl"
+// line 496 "Parser.rl"
int memo = p;
-// line 794 "Parser.java"
+// line 816 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -871,13 +893,13 @@ case 1:
switch ( _JSON_integer_actions[_acts++] )
{
case 0:
-// line 462 "Parser.rl"
+// line 484 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 881 "Parser.java"
+// line 903 "Parser.java"
}
}
}
@@ -897,7 +919,7 @@ case 5:
break; }
}
-// line 476 "Parser.rl"
+// line 498 "Parser.rl"
if (cs < JSON_integer_first_final) {
return null;
@@ -912,7 +934,7 @@ case 5:
}
-// line 916 "Parser.java"
+// line 938 "Parser.java"
private static byte[] init__JSON_float_actions_0()
{
return new byte [] {
@@ -926,7 +948,7 @@ private static final byte _JSON_float_actions[] = init__JSON_float_actions_0();
private static byte[] init__JSON_float_key_offsets_0()
{
return new byte [] {
- 0, 0, 4, 7, 10, 12, 18, 22, 24, 30, 35
+ 0, 0, 4, 7, 10, 12, 16, 18, 23, 29, 29
};
}
@@ -937,8 +959,8 @@ private static char[] init__JSON_float_trans_keys_0()
{
return new char [] {
45, 48, 49, 57, 48, 49, 57, 46, 69, 101, 48, 57,
- 69, 101, 45, 46, 48, 57, 43, 45, 48, 57, 48, 57,
- 69, 101, 45, 46, 48, 57, 46, 69, 101, 48, 57, 0
+ 43, 45, 48, 57, 48, 57, 46, 69, 101, 48, 57, 69,
+ 101, 45, 46, 48, 57, 69, 101, 45, 46, 48, 57, 0
};
}
@@ -948,7 +970,7 @@ private static final char _JSON_float_trans_keys[] = init__JSON_float_trans_keys
private static byte[] init__JSON_float_single_lengths_0()
{
return new byte [] {
- 0, 2, 1, 3, 0, 2, 2, 0, 2, 3, 0
+ 0, 2, 1, 3, 0, 2, 0, 3, 2, 0, 2
};
}
@@ -958,7 +980,7 @@ private static final byte _JSON_float_single_lengths[] = init__JSON_float_single
private static byte[] init__JSON_float_range_lengths_0()
{
return new byte [] {
- 0, 1, 1, 0, 1, 2, 1, 1, 2, 1, 0
+ 0, 1, 1, 0, 1, 1, 1, 1, 2, 0, 2
};
}
@@ -968,7 +990,7 @@ private static final byte _JSON_float_range_lengths[] = init__JSON_float_range_l
private static byte[] init__JSON_float_index_offsets_0()
{
return new byte [] {
- 0, 0, 4, 7, 11, 13, 18, 22, 24, 29, 34
+ 0, 0, 4, 7, 11, 13, 17, 19, 24, 29, 30
};
}
@@ -979,8 +1001,8 @@ private static byte[] init__JSON_float_indicies_0()
{
return new byte [] {
0, 2, 3, 1, 2, 3, 1, 4, 5, 5, 1, 6,
- 1, 5, 5, 1, 6, 7, 8, 8, 9, 1, 9, 1,
- 1, 1, 1, 9, 7, 4, 5, 5, 3, 1, 1, 0
+ 1, 7, 7, 8, 1, 8, 1, 4, 5, 5, 3, 1,
+ 5, 5, 1, 6, 9, 1, 1, 1, 1, 8, 9, 0
};
}
@@ -990,7 +1012,7 @@ private static final byte _JSON_float_indicies[] = init__JSON_float_indicies_0()
private static byte[] init__JSON_float_trans_targs_0()
{
return new byte [] {
- 2, 0, 3, 9, 4, 6, 5, 10, 7, 8
+ 2, 0, 3, 7, 4, 5, 8, 6, 10, 9
};
}
@@ -1000,7 +1022,7 @@ private static final byte _JSON_float_trans_targs[] = init__JSON_float_trans_tar
private static byte[] init__JSON_float_trans_actions_0()
{
return new byte [] {
- 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
}
@@ -1008,28 +1030,28 @@ private static final byte _JSON_float_trans_actions[] = init__JSON_float_trans_a
static final int JSON_float_start = 1;
-static final int JSON_float_first_final = 10;
+static final int JSON_float_first_final = 8;
static final int JSON_float_error = 0;
static final int JSON_float_en_main = 1;
-// line 504 "Parser.rl"
+// line 526 "Parser.rl"
ParserResult parseFloat(int p, int pe) {
int cs = EVIL;
-// line 1025 "Parser.java"
+// line 1047 "Parser.java"
{
cs = JSON_float_start;
}
-// line 510 "Parser.rl"
+// line 532 "Parser.rl"
int memo = p;
-// line 1033 "Parser.java"
+// line 1055 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1110,13 +1132,13 @@ case 1:
switch ( _JSON_float_actions[_acts++] )
{
case 0:
-// line 495 "Parser.rl"
+// line 517 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1120 "Parser.java"
+// line 1142 "Parser.java"
}
}
}
@@ -1136,7 +1158,7 @@ case 5:
break; }
}
-// line 512 "Parser.rl"
+// line 534 "Parser.rl"
if (cs < JSON_float_first_final) {
return null;
@@ -1151,7 +1173,7 @@ case 5:
}
-// line 1155 "Parser.java"
+// line 1177 "Parser.java"
private static byte[] init__JSON_string_actions_0()
{
return new byte [] {
@@ -1253,7 +1275,7 @@ static final int JSON_string_error = 0;
static final int JSON_string_en_main = 1;
-// line 556 "Parser.rl"
+// line 578 "Parser.rl"
ParserResult parseString(int p, int pe) {
@@ -1261,15 +1283,15 @@ static final int JSON_string_en_main = 1;
IRubyObject result = null;
-// line 1265 "Parser.java"
+// line 1287 "Parser.java"
{
cs = JSON_string_start;
}
-// line 563 "Parser.rl"
+// line 585 "Parser.rl"
int memo = p;
-// line 1273 "Parser.java"
+// line 1295 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1350,7 +1372,7 @@ case 1:
switch ( _JSON_string_actions[_acts++] )
{
case 0:
-// line 531 "Parser.rl"
+// line 553 "Parser.rl"
{
int offset = byteList.begin();
ByteList decoded = decoder.decode(byteList, memo + 1 - offset,
@@ -1365,13 +1387,13 @@ case 1:
}
break;
case 1:
-// line 544 "Parser.rl"
+// line 566 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1375 "Parser.java"
+// line 1397 "Parser.java"
}
}
}
@@ -1391,7 +1413,7 @@ case 5:
break; }
}
-// line 565 "Parser.rl"
+// line 587 "Parser.rl"
if (parser.createAdditions) {
RubyHash match_string = parser.match_string;
@@ -1408,7 +1430,7 @@ case 5:
}
});
} catch (JumpException e) { }
- if (memoArray[1] != null) {
+ if (memoArray[1] != null) {
RubyClass klass = (RubyClass) memoArray[1];
if (klass.respondsTo("json_creatable?") &&
klass.callMethod(context, "json_creatable?").isTrue()) {
@@ -1426,7 +1448,7 @@ case 5:
}
-// line 1430 "Parser.java"
+// line 1452 "Parser.java"
private static byte[] init__JSON_array_actions_0()
{
return new byte [] {
@@ -1539,7 +1561,7 @@ static final int JSON_array_error = 0;
static final int JSON_array_en_main = 1;
-// line 635 "Parser.rl"
+// line 657 "Parser.rl"
ParserResult parseArray(int p, int pe) {
@@ -1557,14 +1579,14 @@ static final int JSON_array_en_main = 1;
IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
-// line 1561 "Parser.java"
+// line 1583 "Parser.java"
{
cs = JSON_array_start;
}
-// line 652 "Parser.rl"
+// line 674 "Parser.rl"
-// line 1568 "Parser.java"
+// line 1590 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1645,7 +1667,7 @@ case 1:
switch ( _JSON_array_actions[_acts++] )
{
case 0:
-// line 604 "Parser.rl"
+// line 626 "Parser.rl"
{
ParserResult res = parseValue(p, pe);
if (res == null) {
@@ -1662,13 +1684,13 @@ case 1:
}
break;
case 1:
-// line 619 "Parser.rl"
+// line 641 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1672 "Parser.java"
+// line 1694 "Parser.java"
}
}
}
@@ -1688,7 +1710,7 @@ case 5:
break; }
}
-// line 653 "Parser.rl"
+// line 675 "Parser.rl"
if (cs >= JSON_array_first_final) {
return new ParserResult(result, p + 1);
@@ -1698,7 +1720,7 @@ case 5:
}
-// line 1702 "Parser.java"
+// line 1724 "Parser.java"
private static byte[] init__JSON_object_actions_0()
{
return new byte [] {
@@ -1821,7 +1843,7 @@ static final int JSON_object_error = 0;
static final int JSON_object_en_main = 1;
-// line 713 "Parser.rl"
+// line 734 "Parser.rl"
ParserResult parseObject(int p, int pe) {
@@ -1840,14 +1862,14 @@ static final int JSON_object_en_main = 1;
IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
-// line 1844 "Parser.java"
+// line 1866 "Parser.java"
{
cs = JSON_object_start;
}
-// line 731 "Parser.rl"
+// line 752 "Parser.rl"
-// line 1851 "Parser.java"
+// line 1873 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1928,7 +1950,7 @@ case 1:
switch ( _JSON_object_actions[_acts++] )
{
case 0:
-// line 667 "Parser.rl"
+// line 689 "Parser.rl"
{
ParserResult res = parseValue(p, pe);
if (res == null) {
@@ -1945,7 +1967,7 @@ case 1:
}
break;
case 1:
-// line 682 "Parser.rl"
+// line 704 "Parser.rl"
{
ParserResult res = parseString(p, pe);
if (res == null) {
@@ -1965,13 +1987,13 @@ case 1:
}
break;
case 2:
-// line 700 "Parser.rl"
+// line 722 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1975 "Parser.java"
+// line 1997 "Parser.java"
}
}
}
@@ -1991,7 +2013,7 @@ case 5:
break; }
}
-// line 732 "Parser.rl"
+// line 753 "Parser.rl"
if (cs < JSON_object_first_final) {
return null;
@@ -2017,7 +2039,7 @@ case 5:
}
-// line 2021 "Parser.java"
+// line 2043 "Parser.java"
private static byte[] init__JSON_actions_0()
{
return new byte [] {
@@ -2121,25 +2143,25 @@ static final int JSON_error = 0;
static final int JSON_en_main = 1;
-// line 790 "Parser.rl"
+// line 811 "Parser.rl"
- public IRubyObject parse() {
+ public IRubyObject parseStrict() {
int cs = EVIL;
int p, pe;
IRubyObject result = null;
-// line 2134 "Parser.java"
+// line 2156 "Parser.java"
{
cs = JSON_start;
}
-// line 798 "Parser.rl"
+// line 819 "Parser.rl"
p = byteList.begin();
pe = p + byteList.length();
-// line 2143 "Parser.java"
+// line 2165 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -2220,7 +2242,7 @@ case 1:
switch ( _JSON_actions[_acts++] )
{
case 0:
-// line 762 "Parser.rl"
+// line 783 "Parser.rl"
{
currentNesting = 1;
ParserResult res = parseObject(p, pe);
@@ -2234,7 +2256,7 @@ case 1:
}
break;
case 1:
-// line 774 "Parser.rl"
+// line 795 "Parser.rl"
{
currentNesting = 1;
ParserResult res = parseArray(p, pe);
@@ -2247,7 +2269,7 @@ case 1:
}
}
break;
-// line 2251 "Parser.java"
+// line 2273 "Parser.java"
}
}
}
@@ -2267,7 +2289,7 @@ case 5:
break; }
}
-// line 801 "Parser.rl"
+// line 822 "Parser.rl"
if (cs >= JSON_first_final && p == pe) {
return result;
@@ -2276,6 +2298,259 @@ case 5:
}
}
+
+// line 2303 "Parser.java"
+private static byte[] init__JSON_quirks_mode_actions_0()
+{
+ return new byte [] {
+ 0, 1, 0
+ };
+}
+
+private static final byte _JSON_quirks_mode_actions[] = init__JSON_quirks_mode_actions_0();
+
+
+private static byte[] init__JSON_quirks_mode_key_offsets_0()
+{
+ return new byte [] {
+ 0, 0, 16, 18, 19, 21, 22, 24, 25, 27, 28
+ };
+}
+
+private static final byte _JSON_quirks_mode_key_offsets[] = init__JSON_quirks_mode_key_offsets_0();
+
+
+private static char[] init__JSON_quirks_mode_trans_keys_0()
+{
+ return new char [] {
+ 13, 32, 34, 45, 47, 73, 78, 91, 102, 110, 116, 123,
+ 9, 10, 48, 57, 42, 47, 42, 42, 47, 10, 42, 47,
+ 42, 42, 47, 10, 13, 32, 47, 9, 10, 0
+ };
+}
+
+private static final char _JSON_quirks_mode_trans_keys[] = init__JSON_quirks_mode_trans_keys_0();
+
+
+private static byte[] init__JSON_quirks_mode_single_lengths_0()
+{
+ return new byte [] {
+ 0, 12, 2, 1, 2, 1, 2, 1, 2, 1, 3
+ };
+}
+
+private static final byte _JSON_quirks_mode_single_lengths[] = init__JSON_quirks_mode_single_lengths_0();
+
+
+private static byte[] init__JSON_quirks_mode_range_lengths_0()
+{
+ return new byte [] {
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1
+ };
+}
+
+private static final byte _JSON_quirks_mode_range_lengths[] = init__JSON_quirks_mode_range_lengths_0();
+
+
+private static byte[] init__JSON_quirks_mode_index_offsets_0()
+{
+ return new byte [] {
+ 0, 0, 15, 18, 20, 23, 25, 28, 30, 33, 35
+ };
+}
+
+private static final byte _JSON_quirks_mode_index_offsets[] = init__JSON_quirks_mode_index_offsets_0();
+
+
+private static byte[] init__JSON_quirks_mode_indicies_0()
+{
+ return new byte [] {
+ 0, 0, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 1, 4, 5, 1, 6, 4, 6, 7, 4, 7,
+ 5, 8, 9, 1, 10, 8, 10, 0, 8, 0, 9, 7,
+ 7, 11, 7, 1, 0
+ };
+}
+
+private static final byte _JSON_quirks_mode_indicies[] = init__JSON_quirks_mode_indicies_0();
+
+
+private static byte[] init__JSON_quirks_mode_trans_targs_0()
+{
+ return new byte [] {
+ 1, 0, 10, 6, 3, 5, 4, 10, 7, 9, 8, 2
+ };
+}
+
+private static final byte _JSON_quirks_mode_trans_targs[] = init__JSON_quirks_mode_trans_targs_0();
+
+
+private static byte[] init__JSON_quirks_mode_trans_actions_0()
+{
+ return new byte [] {
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+}
+
+private static final byte _JSON_quirks_mode_trans_actions[] = init__JSON_quirks_mode_trans_actions_0();
+
+
+static final int JSON_quirks_mode_start = 1;
+static final int JSON_quirks_mode_first_final = 10;
+static final int JSON_quirks_mode_error = 0;
+
+static final int JSON_quirks_mode_en_main = 1;
+
+
+// line 850 "Parser.rl"
+
+
+ public IRubyObject parseQuirksMode() {
+ int cs = EVIL;
+ int p, pe;
+ IRubyObject result = null;
+
+
+// line 2415 "Parser.java"
+ {
+ cs = JSON_quirks_mode_start;
+ }
+
+// line 858 "Parser.rl"
+ p = byteList.begin();
+ pe = p + byteList.length();
+
+// line 2424 "Parser.java"
+ {
+ int _klen;
+ int _trans = 0;
+ int _acts;
+ int _nacts;
+ int _keys;
+ int _goto_targ = 0;
+
+ _goto: while (true) {
+ switch ( _goto_targ ) {
+ case 0:
+ if ( p == pe ) {
+ _goto_targ = 4;
+ continue _goto;
+ }
+ if ( cs == 0 ) {
+ _goto_targ = 5;
+ continue _goto;
+ }
+case 1:
+ _match: do {
+ _keys = _JSON_quirks_mode_key_offsets[cs];
+ _trans = _JSON_quirks_mode_index_offsets[cs];
+ _klen = _JSON_quirks_mode_single_lengths[cs];
+ if ( _klen > 0 ) {
+ int _lower = _keys;
+ int _mid;
+ int _upper = _keys + _klen - 1;
+ while (true) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( data[p] < _JSON_quirks_mode_trans_keys[_mid] )
+ _upper = _mid - 1;
+ else if ( data[p] > _JSON_quirks_mode_trans_keys[_mid] )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ break _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _JSON_quirks_mode_range_lengths[cs];
+ if ( _klen > 0 ) {
+ int _lower = _keys;
+ int _mid;
+ int _upper = _keys + (_klen<<1) - 2;
+ while (true) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( data[p] < _JSON_quirks_mode_trans_keys[_mid] )
+ _upper = _mid - 2;
+ else if ( data[p] > _JSON_quirks_mode_trans_keys[_mid+1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ break _match;
+ }
+ }
+ _trans += _klen;
+ }
+ } while (false);
+
+ _trans = _JSON_quirks_mode_indicies[_trans];
+ cs = _JSON_quirks_mode_trans_targs[_trans];
+
+ if ( _JSON_quirks_mode_trans_actions[_trans] != 0 ) {
+ _acts = _JSON_quirks_mode_trans_actions[_trans];
+ _nacts = (int) _JSON_quirks_mode_actions[_acts++];
+ while ( _nacts-- > 0 )
+ {
+ switch ( _JSON_quirks_mode_actions[_acts++] )
+ {
+ case 0:
+// line 836 "Parser.rl"
+ {
+ ParserResult res = parseValue(p, pe);
+ if (res == null) {
+ p--;
+ { p += 1; _goto_targ = 5; if (true) continue _goto;}
+ } else {
+ result = res.result;
+ {p = (( res.p))-1;}
+ }
+ }
+ break;
+// line 2517 "Parser.java"
+ }
+ }
+ }
+
+case 2:
+ if ( cs == 0 ) {
+ _goto_targ = 5;
+ continue _goto;
+ }
+ if ( ++p != pe ) {
+ _goto_targ = 1;
+ continue _goto;
+ }
+case 4:
+case 5:
+ }
+ break; }
+ }
+
+// line 861 "Parser.rl"
+
+ if (cs >= JSON_quirks_mode_first_final && p == pe) {
+ return result;
+ } else {
+ throw unexpectedToken(p, pe);
+ }
+ }
+
+ public IRubyObject parse() {
+ if (parser.quirksMode) {
+ return parseQuirksMode();
+ } else {
+ return parseStrict();
+ }
+
+ }
+
/**
* Returns a subsequence of the source ByteList, based on source
* array byte offsets (i.e., the ByteList's own begin offset is not
diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/Parser.rl
index 779d3f3..e8cd874 100644
--- a/java/src/json/ext/Parser.rl
+++ b/java/src/json/ext/Parser.rl
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
@@ -29,16 +29,16 @@ import org.jruby.util.ByteList;
/**
* The <code>JSON::Ext::Parser</code> class.
- *
+ *
* <p>This is the JSON parser implemented as a Java class. To use it as the
* standard parser, set
* <pre>JSON.parser = JSON::Ext::Parser</pre>
* This is performed for you when you <code>include "json/ext"</code>.
- *
+ *
* <p>This class does not perform the actual parsing, just acts as an interface
* to Ruby code. When the {@link #parse()} method is invoked, a
* Parser.ParserSession object is instantiated, which handles the process.
- *
+ *
* @author mernen
*/
public class Parser extends RubyObject {
@@ -49,6 +49,7 @@ public class Parser extends RubyObject {
private int maxNesting;
private boolean allowNaN;
private boolean symbolizeNames;
+ private boolean quirksMode;
private RubyClass objectClass;
private RubyClass arrayClass;
private RubyHash match_string;
@@ -69,7 +70,7 @@ public class Parser extends RubyObject {
/**
* Multiple-value return for internal parser methods.
- *
+ *
* <p>All the <code>parse<var>Stuff</var></code> methods return instances of
* <code>ParserResult</code> when successful, or <code>null</code> when
* there's a problem with the input data.
@@ -98,18 +99,18 @@ public class Parser extends RubyObject {
/**
* <code>Parser.new(source, opts = {})</code>
- *
+ *
* <p>Creates a new <code>JSON::Ext::Parser</code> instance for the string
* <code>source</code>.
* It will be configured by the <code>opts</code> Hash.
* <code>opts</code> can have the following keys:
- *
+ *
* <dl>
* <dt><code>:max_nesting</code>
* <dd>The maximum depth of nesting allowed in the parsed data
* structures. Disable depth checking with <code>:max_nesting => false|nil|0</code>,
* it defaults to 19.
- *
+ *
* <dt><code>:allow_nan</code>
* <dd>If set to <code>true</code>, allow <code>NaN</code>,
* <code>Infinity</code> and <code>-Infinity</code> in defiance of RFC 4627
@@ -118,17 +119,25 @@ public class Parser extends RubyObject {
* <dt><code>:symbolize_names</code>
* <dd>If set to <code>true</code>, returns symbols for the names (keys) in
* a JSON object. Otherwise strings are returned, which is also the default.
+ *
+ * <dt><code>:quirks_mode?</code>
+ * <dd>If set to <code>true</code>, if the parse is in quirks_mode, false
+ * otherwise.
*
* <dt><code>:create_additions</code>
* <dd>If set to <code>false</code>, the Parser doesn't create additions
* even if a matchin class and <code>create_id</code> was found. This option
* defaults to <code>true</code>.
- *
+ *
* <dt><code>:object_class</code>
* <dd>Defaults to Hash.
- *
+ *
* <dt><code>:array_class</code>
* <dd>Defaults to Array.
+ *
+ * <dt><code>:quirks_mode</code>
+ * <dd>Enables quirks_mode for parser, that is for example parsing single
+ * JSON values instead of documents is possible.
* </dl>
*/
@JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
@@ -146,19 +155,21 @@ public class Parser extends RubyObject {
if (this.vSource != null) {
throw runtime.newTypeError("already initialized instance");
}
- RubyString source = convertEncoding(context, args[0].convertToString());
OptionsReader opts = new OptionsReader(context, args.length > 1 ? args[1] : null);
this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
this.allowNaN = opts.getBool("allow_nan", false);
this.symbolizeNames = opts.getBool("symbolize_names", false);
+ this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
this.createAdditions = opts.getBool("create_additions", true);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
- this.vSource = source;
+ this.vSource = args[0].convertToString();
+ if (!quirksMode) this.vSource = convertEncoding(context, vSource);
+
return this;
}
@@ -227,7 +238,7 @@ public class Parser extends RubyObject {
/**
* <code>Parser#parse()</code>
- *
+ *
* <p>Parses the current JSON text <code>source</code> and returns the
* complete data structure as a result.
*/
@@ -238,7 +249,7 @@ public class Parser extends RubyObject {
/**
* <code>Parser#source()</code>
- *
+ *
* <p>Returns a copy of the current <code>source</code> string, that was
* used to construct this Parser.
*/
@@ -247,6 +258,17 @@ public class Parser extends RubyObject {
return checkAndGetSource().dup();
}
+ /**
+ * <code>Parser#quirks_mode?()</code>
+ *
+ * <p>If set to <code>true</code>, if the parse is in quirks_mode, false
+ * otherwise.
+ */
+ @JRubyMethod(name = "quirks_mode?")
+ public IRubyObject quirks_mode_p(ThreadContext context) {
+ return context.getRuntime().newBoolean(quirksMode);
+ }
+
public RubyString checkAndGetSource() {
if (vSource != null) {
return vSource;
@@ -266,7 +288,7 @@ public class Parser extends RubyObject {
/**
* A string parsing session.
- *
+ *
* <p>Once a ParserSession is instantiated, the source string should not
* change until the parsing is complete. The ParserSession object assumes
* the source {@link RubyString} is still associated to its original
@@ -364,7 +386,7 @@ public class Parser extends RubyObject {
}
}
action parse_number {
- if (pe > fpc + 9 &&
+ if (pe > fpc + 9 - (parser.quirksMode ? 1 : 0) &&
absSubSequence(fpc, fpc + 9).toString().equals(JSON_MINUS_INFINITY)) {
if (parser.allowNaN) {
@@ -464,7 +486,7 @@ public class Parser extends RubyObject {
fbreak;
}
- main := '-'? ( '0' | [1-9][0-9]* ) ( ^[0-9] @exit );
+ main := '-'? ( '0' | [1-9][0-9]* ) ( ^[0-9]? @exit );
}%%
ParserResult parseInteger(int p, int pe) {
@@ -500,7 +522,7 @@ public class Parser extends RubyObject {
main := '-'?
( ( ( '0' | [1-9][0-9]* ) '.' [0-9]+ ( [Ee] [+\-]?[0-9]+ )? )
| ( ( '0' | [1-9][0-9]* ) ( [Ee] [+\-]? [0-9]+ ) ) )
- ( ^[0-9Ee.\-] @exit );
+ ( ^[0-9Ee.\-]? @exit );
}%%
ParserResult parseFloat(int p, int pe) {
@@ -578,7 +600,7 @@ public class Parser extends RubyObject {
}
});
} catch (JumpException e) { }
- if (memoArray[1] != null) {
+ if (memoArray[1] != null) {
RubyClass klass = (RubyClass) memoArray[1];
if (klass.respondsTo("json_creatable?") &&
klass.callMethod(context, "json_creatable?").isTrue()) {
@@ -701,15 +723,14 @@ public class Parser extends RubyObject {
fhold;
fbreak;
}
+
+ pair = ignore* begin_name >parse_name ignore* name_separator
+ ignore* begin_value >parse_value;
+ next_pair = ignore* value_separator pair;
- a_pair = ignore*
- begin_name >parse_name
- ignore* name_separator ignore*
- begin_value >parse_value;
-
- main := begin_object
- (a_pair (ignore* value_separator a_pair)*)?
- ignore* end_object @exit;
+ main := (
+ begin_object (pair (next_pair)*)? ignore* end_object
+ ) @exit;
}%%
ParserResult parseObject(int p, int pe) {
@@ -789,7 +810,7 @@ public class Parser extends RubyObject {
ignore*;
}%%
- public IRubyObject parse() {
+ public IRubyObject parseStrict() {
int cs = EVIL;
int p, pe;
IRubyObject result = null;
@@ -806,6 +827,54 @@ public class Parser extends RubyObject {
}
}
+ %%{
+ machine JSON_quirks_mode;
+ include JSON_common;
+
+ write data;
+
+ action parse_value {
+ ParserResult res = parseValue(fpc, pe);
+ if (res == null) {
+ fhold;
+ fbreak;
+ } else {
+ result = res.result;
+ fexec res.p;
+ }
+ }
+
+ main := ignore*
+ ( begin_value >parse_value)
+ ignore*;
+ }%%
+
+ public IRubyObject parseQuirksMode() {
+ int cs = EVIL;
+ int p, pe;
+ IRubyObject result = null;
+
+ %% write init;
+ p = byteList.begin();
+ pe = p + byteList.length();
+ %% write exec;
+
+ if (cs >= JSON_quirks_mode_first_final && p == pe) {
+ return result;
+ } else {
+ throw unexpectedToken(p, pe);
+ }
+ }
+
+ public IRubyObject parse() {
+ if (parser.quirksMode) {
+ return parseQuirksMode();
+ } else {
+ return parseStrict();
+ }
+
+ }
+
/**
* Returns a subsequence of the source ByteList, based on source
* array byte offsets (i.e., the ByteList's own begin offset is not
diff --git a/java/src/json/ext/ParserService.java b/java/src/json/ext/ParserService.java
index f2ecae1..dde8834 100644
--- a/java/src/json/ext/ParserService.java
+++ b/java/src/json/ext/ParserService.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
diff --git a/java/src/json/ext/Utils.java b/java/src/json/ext/Utils.java
index f52ac8d..44d6a55 100644
--- a/java/src/json/ext/Utils.java
+++ b/java/src/json/ext/Utils.java
@@ -1,6 +1,6 @@
/*
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
- *
+ *
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
* for details.
*/
diff --git a/json.gemspec b/json.gemspec
index 3bd955a..65bead0 100644
--- a/json.gemspec
+++ b/json.gemspec
@@ -2,27 +2,26 @@
Gem::Specification.new do |s|
s.name = %q{json}
- s.version = "1.5.4"
+ s.version = "1.6.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = [%q{Florian Frank}]
- s.date = %q{2011-07-08}
+ s.date = %q{2011-09-18}
s.description = %q{This is a JSON implementation as a Ruby extension in C.}
s.email = %q{flori@ping.de}
- s.executables = [%q{edit_json.rb}, %q{prettify_json.rb}]
s.extensions = [%q{ext/json/ext/parser/extconf.rb}, %q{ext/json/ext/generator/extconf.rb}]
s.extra_rdoc_files = [%q{README.rdoc}]
- s.files = [%q{tests}, %q{tests/test_json_string_matching.rb}, %q{tests/test_json_fixtures.rb}, %q{tests/setup_variant.rb}, %q{tests/fixtures}, %q{tests/fixtures/fail6.json}, %q{tests/fixtures/fail9.json}, %q{tests/fixtures/fail10.json}, %q{tests/fixtures/fail24.json}, %q{tests/fixtures/fail28.json}, %q{tests/fixtures/fail13.json}, %q{tests/fixtures/fail4.json}, %q{tests/fixtures/pass3.json}, %q{tests/fixtures/fail11.json}, %q{tests/fixtures/fail14.json}, %q{tests/fixtures/fail3.json}, %q{tests/fixtures/fail12.json}, %q{tests/fixtures/pass16.json}, %q{tests/fixtures/pass15.json}, %q{tests/fixtures/fail20.json}, %q{tests/fixtures/fail8.json}, %q{tests/fixtures/pass2.json}, %q{tests/fixtures/fail5.json}, %q{tests/fixtures/fail1.json}, %q{tests/fixtures/fail25.json}, %q{tests/fixtures/pass17.json}, %q{tests/fixtures/fail7.json}, %q{tests/fixtures/pass26.json}, %q{tests/fixtures/fail21.json}, %q{tests/fixtures/pass1.json}, %q{tests/fixtures/fail23.json}, %q{tests/fixtures/fail18.json}, %q{tests/fixtures/fail2.json}, %q{tests/fixtures/fail22.json}, %q{tests/fixtures/fail27.json}, %q{tests/fixtures/fail19.json}, %q{tests/test_json_unicode.rb}, %q{tests/test_json_addition.rb}, %q{tests/test_json_generate.rb}, %q{tests/test_json_encoding.rb}, %q{tests/test_json.rb}, %q{COPYING}, %q{TODO}, %q{Rakefile}, %q{benchmarks}, %q{benchmarks/data-p4-3GHz-ruby18}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat}, %q{benchmarks/parser2_benchmark.rb}, %q{benchmarks/parser_benchmark.rb}, %q{benchmarks/generator2_benchmark.rb}, %q{benchmarks/generator_benchmark.rb}, %q{benchmarks/ohai.ruby}, %q{benchmarks/data}, %q{benchmarks/ohai.json}, %q{lib}, %q{lib/json}, %q{lib/json/json.xpm}, %q{lib/json/TrueClass.xpm}, %q{lib/json/version.rb}, %q{lib/json/Array.xpm}, %q{lib/json/add}, %q{lib/json/add/core.rb}, %q{lib/json/add/rails.rb}, %q{lib/json/common.rb}, %q{lib/json/pure}, %q{lib/json/pure/generator.rb}, %q{lib/json/pure/parser.rb}, %q{lib/json/ext.rb}, %q{lib/json/pure.rb}, %q{lib/json/Key.xpm}, %q{lib/json/FalseClass.xpm}, %q{lib/json/editor.rb}, %q{lib/json/Numeric.xpm}, %q{lib/json/ext}, %q{lib/json/NilClass.xpm}, %q{lib/json/String.xpm}, %q{lib/json/Hash.xpm}, %q{lib/json.rb}, %q{Gemfile}, %q{README.rdoc}, %q{json_pure.gemspec}, %q{GPL}, %q{CHANGES}, %q{bin}, %q{bin/prettify_json.rb}, %q{bin/edit_json.rb}, %q{COPYING-json-jruby}, %q{ext}, %q{ext/json}, %q{ext/json/ext}, %q{ext/json/ext/parser}, %q{ext/json/ext/parser/parser.h}, %q{ext/json/ext/parser/extconf.rb}, %q{ext/json/ext/parser/parser.rl}, %q{ext/json/ext/parser/parser.c}, %q{ext/json/ext/generator}, %q{ext/json/ext/generator/generator.c}, %q{ext/json/ext/generator/extconf.rb}, %q{ext/json/ext/generator/generator.h}, %q{VERSION}, %q{data}, %q{data/prototype.js}, %q{data/index.html}, %q{data/example.json}, %q{json.gemspec}, %q{java}, %q{java/src}, %q{java/src/json}, %q{java/src/json/ext}, %q{java/src/json/ext/Parser.java}, %q{java/src/json/ext/RuntimeInfo.java}, %q{java/src/json/ext/GeneratorState.java}, %q{java/src/json/ext/OptionsReader.java}, %q{java/src/json/ext/ParserService.java}, %q{java/src/json/ext/Parser.rl}, %q{java/src/json/ext/StringEncoder.java}, %q{java/src/json/ext/GeneratorService.java}, %q{java/src/json/ext/Utils.java}, %q{java/src/json/ext/StringDecoder.java}, %q{java/src/json/ext/Generator.java}, %q{java/src/json/ext/ByteListTranscoder.java}, %q{java/src/json/ext/GeneratorMethods.java}, %q{java/lib}, %q{java/lib/bytelist-1.0.6.jar}, %q{java/lib/jcodings.jar}, %q{diagrams}, %q{README-json-jruby.markdown}, %q{install.rb}, %q{json-java.gemspec}, %q{tools}, %q{tools/fuzz.rb}, %q{tools/server.rb}, %q{./tests/test_json_string_matching.rb}, %q{./tests/test_json_fixtures.rb}, %q{./tests/test_json_unicode.rb}, %q{./tests/test_json_addition.rb}, %q{./tests/test_json_generate.rb}, %q{./tests/test_json_encoding.rb}, %q{./tests/test_json.rb}]
+ s.files = [%q{tests}, %q{tests/test_json_string_matching.rb}, %q{tests/test_json_fixtures.rb}, %q{tests/setup_variant.rb}, %q{tests/fixtures}, %q{tests/fixtures/fail6.json}, %q{tests/fixtures/fail9.json}, %q{tests/fixtures/fail10.json}, %q{tests/fixtures/fail24.json}, %q{tests/fixtures/fail28.json}, %q{tests/fixtures/fail13.json}, %q{tests/fixtures/fail4.json}, %q{tests/fixtures/pass3.json}, %q{tests/fixtures/fail11.json}, %q{tests/fixtures/fail14.json}, %q{tests/fixtures/fail3.json}, %q{tests/fixtures/fail12.json}, %q{tests/fixtures/pass16.json}, %q{tests/fixtures/pass15.json}, %q{tests/fixtures/fail20.json}, %q{tests/fixtures/fail8.json}, %q{tests/fixtures/pass2.json}, %q{tests/fixtures/fail5.json}, %q{tests/fixtures/fail1.json}, %q{tests/fixtures/fail25.json}, %q{tests/fixtures/pass17.json}, %q{tests/fixtures/fail7.json}, %q{tests/fixtures/pass26.json}, %q{tests/fixtures/fail21.json}, %q{tests/fixtures/pass1.json}, %q{tests/fixtures/fail23.json}, %q{tests/fixtures/fail18.json}, %q{tests/fixtures/fail2.json}, %q{tests/fixtures/fail22.json}, %q{tests/fixtures/fail27.json}, %q{tests/fixtures/fail19.json}, %q{tests/test_json_unicode.rb}, %q{tests/test_json_addition.rb}, %q{tests/test_json_generate.rb}, %q{tests/test_json_encoding.rb}, %q{tests/test_json.rb}, %q{COPYING}, %q{TODO}, %q{Rakefile}, %q{benchmarks}, %q{benchmarks/data-p4-3GHz-ruby18}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat}, %q{benchmarks/parser2_benchmark.rb}, %q{benchmarks/parser_benchmark.rb}, %q{benchmarks/generator2_benchmark.rb}, %q{benchmarks/generator_benchmark.rb}, %q{benchmarks/ohai.ruby}, %q{benchmarks/data}, %q{benchmarks/ohai.json}, %q{lib}, %q{lib/json}, %q{lib/json/version.rb}, %q{lib/json/add}, %q{lib/json/add/symbol.rb}, %q{lib/json/add/struct.rb}, %q{lib/json/add/complex.rb}, %q{lib/json/add/rational.rb}, %q{lib/json/add/exception.rb}, %q{lib/json/add/time.rb}, %q{lib/json/add/date_time.rb}, %q{lib/json/add/core.rb}, %q{lib/json/add/range.rb}, %q{lib/json/add/date.rb}, %q{lib/json/add/regexp.rb}, %q{lib/json/common.rb}, %q{lib/json/pure}, %q{lib/json/pure/generator.rb}, %q{lib/json/pure/parser.rb}, %q{lib/json/ext.rb}, %q{lib/json/pure.rb}, %q{lib/json/ext}, %q{lib/json.rb}, %q{Gemfile}, %q{README.rdoc}, %q{json_pure.gemspec}, %q{GPL}, %q{CHANGES}, %q{COPYING-json-jruby}, %q{ext}, %q{ext/json}, %q{ext/json/ext}, %q{ext/json/ext/parser}, %q{ext/json/ext/parser/parser.h}, %q{ext/json/ext/parser/extconf.rb}, %q{ext/json/ext/parser/parser.rl}, %q{ext/json/ext/parser/parser.c}, %q{ext/json/ext/generator}, %q{ext/json/ext/generator/generator.c}, %q{ext/json/ext/generator/extconf.rb}, %q{ext/json/ext/generator/generator.h}, %q{VERSION}, %q{data}, %q{data/prototype.js}, %q{data/index.html}, %q{data/example.json}, %q{json.gemspec}, %q{java}, %q{java/src}, %q{java/src/json}, %q{java/src/json/ext}, %q{java/src/json/ext/Parser.java}, %q{java/src/json/ext/RuntimeInfo.java}, %q{java/src/json/ext/GeneratorState.java}, %q{java/src/json/ext/OptionsReader.java}, %q{java/src/json/ext/ParserService.java}, %q{java/src/json/ext/Parser.rl}, %q{java/src/json/ext/StringEncoder.java}, %q{java/src/json/ext/GeneratorService.java}, %q{java/src/json/ext/Utils.java}, %q{java/src/json/ext/StringDecoder.java}, %q{java/src/json/ext/Generator.java}, %q{java/src/json/ext/ByteListTranscoder.java}, %q{java/src/json/ext/GeneratorMethods.java}, %q{java/lib}, %q{java/lib/bytelist-1.0.6.jar}, %q{java/lib/jcodings.jar}, %q{diagrams}, %q{README-json-jruby.markdown}, %q{install.rb}, %q{json-java.gemspec}, %q{tools}, %q{tools/fuzz.rb}, %q{tools/server.rb}, %q{./tests/test_json_string_matching.rb}, %q{./tests/test_json_fixtures.rb}, %q{./tests/test_json_unicode.rb}, %q{./tests/test_json_addition.rb}, %q{./tests/test_json_generate.rb}, %q{./tests/test_json_encoding.rb}, %q{./tests/test_json.rb}]
s.homepage = %q{http://flori.github.com/json}
s.rdoc_options = [%q{--title}, %q{JSON implemention for Ruby}, %q{--main}, %q{README.rdoc}]
s.require_paths = [%q{ext/json/ext}, %q{ext}, %q{lib}]
s.rubyforge_project = %q{json}
- s.rubygems_version = %q{1.8.5}
+ s.rubygems_version = %q{1.8.6}
s.summary = %q{JSON Implementation for Ruby}
s.test_files = [%q{./tests/test_json_string_matching.rb}, %q{./tests/test_json_fixtures.rb}, %q{./tests/test_json_unicode.rb}, %q{./tests/test_json_addition.rb}, %q{./tests/test_json_generate.rb}, %q{./tests/test_json_encoding.rb}, %q{./tests/test_json.rb}]
if s.respond_to? :specification_version then
- s.specification_version = 4
+ s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_development_dependency(%q<permutation>, [">= 0"])
diff --git a/json_pure.gemspec b/json_pure.gemspec
index a3be22a..5b8cb04 100644
--- a/json_pure.gemspec
+++ b/json_pure.gemspec
@@ -2,45 +2,41 @@
Gem::Specification.new do |s|
s.name = %q{json_pure}
- s.version = "1.5.4"
+ s.version = "1.6.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = [%q{Florian Frank}]
- s.date = %q{2011-07-08}
+ s.date = %q{2011-09-18}
s.description = %q{This is a JSON implementation in pure Ruby.}
s.email = %q{flori@ping.de}
- s.executables = [%q{edit_json.rb}, %q{prettify_json.rb}]
s.extra_rdoc_files = [%q{README.rdoc}]
- s.files = [%q{tests}, %q{tests/test_json_string_matching.rb}, %q{tests/test_json_fixtures.rb}, %q{tests/setup_variant.rb}, %q{tests/fixtures}, %q{tests/fixtures/fail6.json}, %q{tests/fixtures/fail9.json}, %q{tests/fixtures/fail10.json}, %q{tests/fixtures/fail24.json}, %q{tests/fixtures/fail28.json}, %q{tests/fixtures/fail13.json}, %q{tests/fixtures/fail4.json}, %q{tests/fixtures/pass3.json}, %q{tests/fixtures/fail11.json}, %q{tests/fixtures/fail14.json}, %q{tests/fixtures/fail3.json}, %q{tests/fixtures/fail12.json}, %q{tests/fixtures/pass16.json}, %q{tests/fixtures/pass15.json}, %q{tests/fixtures/fail20.json}, %q{tests/fixtures/fail8.json}, %q{tests/fixtures/pass2.json}, %q{tests/fixtures/fail5.json}, %q{tests/fixtures/fail1.json}, %q{tests/fixtures/fail25.json}, %q{tests/fixtures/pass17.json}, %q{tests/fixtures/fail7.json}, %q{tests/fixtures/pass26.json}, %q{tests/fixtures/fail21.json}, %q{tests/fixtures/pass1.json}, %q{tests/fixtures/fail23.json}, %q{tests/fixtures/fail18.json}, %q{tests/fixtures/fail2.json}, %q{tests/fixtures/fail22.json}, %q{tests/fixtures/fail27.json}, %q{tests/fixtures/fail19.json}, %q{tests/test_json_unicode.rb}, %q{tests/test_json_addition.rb}, %q{tests/test_json_generate.rb}, %q{tests/test_json_encoding.rb}, %q{tests/test_json.rb}, %q{COPYING}, %q{TODO}, %q{Rakefile}, %q{benchmarks}, %q{benchmarks/data-p4-3GHz-ruby18}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat}, %q{benchmarks/parser2_benchmark.rb}, %q{benchmarks/parser_benchmark.rb}, %q{benchmarks/generator2_benchmark.rb}, %q{benchmarks/generator_benchmark.rb}, %q{benchmarks/ohai.ruby}, %q{benchmarks/data}, %q{benchmarks/ohai.json}, %q{lib}, %q{lib/json}, %q{lib/json/json.xpm}, %q{lib/json/TrueClass.xpm}, %q{lib/json/version.rb}, %q{lib/json/Array.xpm}, %q{lib/json/add}, %q{lib/json/add/core.rb}, %q{lib/json/add/rails.rb}, %q{lib/json/common.rb}, %q{lib/json/pure}, %q{lib/json/pure/generator.rb}, %q{lib/json/pure/parser.rb}, %q{lib/json/ext.rb}, %q{lib/json/pure.rb}, %q{lib/json/Key.xpm}, %q{lib/json/FalseClass.xpm}, %q{lib/json/editor.rb}, %q{lib/json/Numeric.xpm}, %q{lib/json/ext}, %q{lib/json/NilClass.xpm}, %q{lib/json/String.xpm}, %q{lib/json/Hash.xpm}, %q{lib/json.rb}, %q{Gemfile}, %q{README.rdoc}, %q{json_pure.gemspec}, %q{GPL}, %q{CHANGES}, %q{bin}, %q{bin/prettify_json.rb}, %q{bin/edit_json.rb}, %q{COPYING-json-jruby}, %q{ext}, %q{ext/json}, %q{ext/json/ext}, %q{ext/json/ext/parser}, %q{ext/json/ext/parser/parser.h}, %q{ext/json/ext/parser/extconf.rb}, %q{ext/json/ext/parser/parser.rl}, %q{ext/json/ext/parser/mkmf.log}, %q{ext/json/ext/parser/parser.c}, %q{ext/json/ext/generator}, %q{ext/json/ext/generator/generator.c}, %q{ext/json/ext/generator/extconf.rb}, %q{ext/json/ext/generator/generator.h}, %q{VERSION}, %q{data}, %q{data/prototype.js}, %q{data/index.html}, %q{data/example.json}, %q{json.gemspec}, %q{java}, %q{java/src}, %q{java/src/json}, %q{java/src/json/ext}, %q{java/src/json/ext/Parser.java}, %q{java/src/json/ext/RuntimeInfo.java}, %q{java/src/json/ext/GeneratorState.java}, %q{java/src/json/ext/OptionsReader.java}, %q{java/src/json/ext/ParserService.java}, %q{java/src/json/ext/Parser.rl}, %q{java/src/json/ext/StringEncoder.java}, %q{java/src/json/ext/GeneratorService.java}, %q{java/src/json/ext/Utils.java}, %q{java/src/json/ext/StringDecoder.java}, %q{java/src/json/ext/Generator.java}, %q{java/src/json/ext/ByteListTranscoder.java}, %q{java/src/json/ext/GeneratorMethods.java}, %q{java/lib}, %q{java/lib/bytelist-1.0.6.jar}, %q{java/lib/jcodings.jar}, %q{diagrams}, %q{README-json-jruby.markdown}, %q{install.rb}, %q{json-java.gemspec}, %q{tools}, %q{tools/fuzz.rb}, %q{tools/server.rb}, %q{./tests/test_json_string_matching.rb}, %q{./tests/test_json_fixtures.rb}, %q{./tests/test_json_unicode.rb}, %q{./tests/test_json_addition.rb}, %q{./tests/test_json_generate.rb}, %q{./tests/test_json_encoding.rb}, %q{./tests/test_json.rb}]
+ s.files = [%q{tests}, %q{tests/test_json_string_matching.rb}, %q{tests/test_json_fixtures.rb}, %q{tests/setup_variant.rb}, %q{tests/fixtures}, %q{tests/fixtures/fail6.json}, %q{tests/fixtures/fail9.json}, %q{tests/fixtures/fail10.json}, %q{tests/fixtures/fail24.json}, %q{tests/fixtures/fail28.json}, %q{tests/fixtures/fail13.json}, %q{tests/fixtures/fail4.json}, %q{tests/fixtures/pass3.json}, %q{tests/fixtures/fail11.json}, %q{tests/fixtures/fail14.json}, %q{tests/fixtures/fail3.json}, %q{tests/fixtures/fail12.json}, %q{tests/fixtures/pass16.json}, %q{tests/fixtures/pass15.json}, %q{tests/fixtures/fail20.json}, %q{tests/fixtures/fail8.json}, %q{tests/fixtures/pass2.json}, %q{tests/fixtures/fail5.json}, %q{tests/fixtures/fail1.json}, %q{tests/fixtures/fail25.json}, %q{tests/fixtures/pass17.json}, %q{tests/fixtures/fail7.json}, %q{tests/fixtures/pass26.json}, %q{tests/fixtures/fail21.json}, %q{tests/fixtures/pass1.json}, %q{tests/fixtures/fail23.json}, %q{tests/fixtures/fail18.json}, %q{tests/fixtures/fail2.json}, %q{tests/fixtures/fail22.json}, %q{tests/fixtures/fail27.json}, %q{tests/fixtures/fail19.json}, %q{tests/test_json_unicode.rb}, %q{tests/test_json_addition.rb}, %q{tests/test_json_generate.rb}, %q{tests/test_json_encoding.rb}, %q{tests/test_json.rb}, %q{COPYING}, %q{TODO}, %q{Rakefile}, %q{benchmarks}, %q{benchmarks/data-p4-3GHz-ruby18}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat}, %q{benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat}, %q{benchmarks/parser2_benchmark.rb}, %q{benchmarks/parser_benchmark.rb}, %q{benchmarks/generator2_benchmark.rb}, %q{benchmarks/generator_benchmark.rb}, %q{benchmarks/ohai.ruby}, %q{benchmarks/data}, %q{benchmarks/ohai.json}, %q{lib}, %q{lib/json}, %q{lib/json/version.rb}, %q{lib/json/add}, %q{lib/json/add/symbol.rb}, %q{lib/json/add/struct.rb}, %q{lib/json/add/complex.rb}, %q{lib/json/add/rational.rb}, %q{lib/json/add/exception.rb}, %q{lib/json/add/time.rb}, %q{lib/json/add/date_time.rb}, %q{lib/json/add/core.rb}, %q{lib/json/add/range.rb}, %q{lib/json/add/date.rb}, %q{lib/json/add/regexp.rb}, %q{lib/json/common.rb}, %q{lib/json/pure}, %q{lib/json/pure/generator.rb}, %q{lib/json/pure/parser.rb}, %q{lib/json/ext.rb}, %q{lib/json/pure.rb}, %q{lib/json/ext}, %q{lib/json.rb}, %q{Gemfile}, %q{README.rdoc}, %q{json_pure.gemspec}, %q{GPL}, %q{CHANGES}, %q{COPYING-json-jruby}, %q{ext}, %q{ext/json}, %q{ext/json/ext}, %q{ext/json/ext/parser}, %q{ext/json/ext/parser/parser.h}, %q{ext/json/ext/parser/extconf.rb}, %q{ext/json/ext/parser/parser.rl}, %q{ext/json/ext/parser/parser.c}, %q{ext/json/ext/generator}, %q{ext/json/ext/generator/generator.c}, %q{ext/json/ext/generator/extconf.rb}, %q{ext/json/ext/generator/generator.h}, %q{VERSION}, %q{data}, %q{data/prototype.js}, %q{data/index.html}, %q{data/example.json}, %q{json.gemspec}, %q{java}, %q{java/src}, %q{java/src/json}, %q{java/src/json/ext}, %q{java/src/json/ext/Parser.java}, %q{java/src/json/ext/RuntimeInfo.java}, %q{java/src/json/ext/GeneratorState.java}, %q{java/src/json/ext/OptionsReader.java}, %q{java/src/json/ext/ParserService.java}, %q{java/src/json/ext/Parser.rl}, %q{java/src/json/ext/StringEncoder.java}, %q{java/src/json/ext/GeneratorService.java}, %q{java/src/json/ext/Utils.java}, %q{java/src/json/ext/StringDecoder.java}, %q{java/src/json/ext/Generator.java}, %q{java/src/json/ext/ByteListTranscoder.java}, %q{java/src/json/ext/GeneratorMethods.java}, %q{java/lib}, %q{java/lib/bytelist-1.0.6.jar}, %q{java/lib/jcodings.jar}, %q{diagrams}, %q{README-json-jruby.markdown}, %q{install.rb}, %q{json-java.gemspec}, %q{tools}, %q{tools/fuzz.rb}, %q{tools/server.rb}, %q{./tests/test_json_string_matching.rb}, %q{./tests/test_json_fixtures.rb}, %q{./tests/test_json_unicode.rb}, %q{./tests/test_json_addition.rb}, %q{./tests/test_json_generate.rb}, %q{./tests/test_json_encoding.rb}, %q{./tests/test_json.rb}]
s.homepage = %q{http://flori.github.com/json}
s.rdoc_options = [%q{--title}, %q{JSON implemention for ruby}, %q{--main}, %q{README.rdoc}]
s.require_paths = [%q{lib}]
s.rubyforge_project = %q{json}
- s.rubygems_version = %q{1.8.5}
+ s.rubygems_version = %q{1.8.6}
s.summary = %q{JSON Implementation for Ruby}
s.test_files = [%q{./tests/test_json_string_matching.rb}, %q{./tests/test_json_fixtures.rb}, %q{./tests/test_json_unicode.rb}, %q{./tests/test_json_addition.rb}, %q{./tests/test_json_generate.rb}, %q{./tests/test_json_encoding.rb}, %q{./tests/test_json.rb}]
if s.respond_to? :specification_version then
- s.specification_version = 4
+ s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_development_dependency(%q<permutation>, [">= 0"])
s.add_development_dependency(%q<bullshit>, [">= 0"])
s.add_development_dependency(%q<sdoc>, [">= 0"])
s.add_development_dependency(%q<rake>, ["~> 0.9.2"])
- s.add_runtime_dependency(%q<spruz>, ["~> 0.2.8"])
else
s.add_dependency(%q<permutation>, [">= 0"])
s.add_dependency(%q<bullshit>, [">= 0"])
s.add_dependency(%q<sdoc>, [">= 0"])
s.add_dependency(%q<rake>, ["~> 0.9.2"])
- s.add_dependency(%q<spruz>, ["~> 0.2.8"])
end
else
s.add_dependency(%q<permutation>, [">= 0"])
s.add_dependency(%q<bullshit>, [">= 0"])
s.add_dependency(%q<sdoc>, [">= 0"])
s.add_dependency(%q<rake>, ["~> 0.9.2"])
- s.add_dependency(%q<spruz>, ["~> 0.2.8"])
end
end
diff --git a/lib/json.rb b/lib/json.rb
index d7bc1a2..00fe4ca 100644
--- a/lib/json.rb
+++ b/lib/json.rb
@@ -7,13 +7,13 @@
#
# 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.
+# 2. An ordered list of values. More commonly called 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
+# To parse a JSON string received by another application or generated within
# your existing application:
#
# require 'json'
@@ -42,8 +42,8 @@
# 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:
+# to JSON syntax. <tt>to_json</tt>, however, accepts many Ruby classes
+# even though it acts only as a method for serialization:
#
# require 'json'
#
diff --git a/lib/json/Array.xpm b/lib/json/Array.xpm
deleted file mode 100644
index 27c4801..0000000
--- a/lib/json/Array.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * Array_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ",
-" .......... ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" .......... ",
-" ",
-" ",
-" "};
diff --git a/lib/json/FalseClass.xpm b/lib/json/FalseClass.xpm
deleted file mode 100644
index 25ce608..0000000
--- a/lib/json/FalseClass.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * False_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #FF0000",
-" ",
-" ",
-" ",
-" ...... ",
-" . ",
-" . ",
-" . ",
-" ...... ",
-" . ",
-" . ",
-" . ",
-" . ",
-" . ",
-" ",
-" ",
-" "};
diff --git a/lib/json/Hash.xpm b/lib/json/Hash.xpm
deleted file mode 100644
index cd8f6f7..0000000
--- a/lib/json/Hash.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * Hash_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ",
-" . . ",
-" . . ",
-" . . ",
-" ......... ",
-" . . ",
-" . . ",
-" ......... ",
-" . . ",
-" . . ",
-" . . ",
-" ",
-" ",
-" "};
diff --git a/lib/json/Key.xpm b/lib/json/Key.xpm
deleted file mode 100644
index 9fd7281..0000000
--- a/lib/json/Key.xpm
+++ /dev/null
@@ -1,73 +0,0 @@
-/* XPM */
-static char * Key_xpm[] = {
-"16 16 54 1",
-" c None",
-". c #110007",
-"+ c #0E0900",
-"@ c #000013",
-"# c #070600",
-"$ c #F6F006",
-"% c #ECE711",
-"& c #E5EE00",
-"* c #16021E",
-"= c #120900",
-"- c #EDF12B",
-"; c #000033",
-"> c #0F0000",
-", c #FFFE03",
-"' c #E6E500",
-") c #16021B",
-"! c #F7F502",
-"~ c #000E00",
-"{ c #130000",
-"] c #FFF000",
-"^ c #FFE711",
-"/ c #140005",
-"( c #190025",
-"_ c #E9DD27",
-": c #E7DC04",
-"< c #FFEC09",
-"[ c #FFE707",
-"} c #FFDE10",
-"| c #150021",
-"1 c #160700",
-"2 c #FAF60E",
-"3 c #EFE301",
-"4 c #FEF300",
-"5 c #E7E000",
-"6 c #FFFF08",
-"7 c #0E0206",
-"8 c #040000",
-"9 c #03052E",
-"0 c #041212",
-"a c #070300",
-"b c #F2E713",
-"c c #F9DE13",
-"d c #36091E",
-"e c #00001C",
-"f c #1F0010",
-"g c #FFF500",
-"h c #DEDE00",
-"i c #050A00",
-"j c #FAF14A",
-"k c #F5F200",
-"l c #040404",
-"m c #1A0D00",
-"n c #EDE43D",
-"o c #ECE007",
-" ",
-" ",
-" .+@ ",
-" #$%&* ",
-" =-;>,') ",
-" >!~{]^/ ",
-" (_:<[}| ",
-" 1234567 ",
-" 890abcd ",
-" efghi ",
-" >jkl ",
-" mnol ",
-" >kl ",
-" ll ",
-" ",
-" "};
diff --git a/lib/json/NilClass.xpm b/lib/json/NilClass.xpm
deleted file mode 100644
index 3509f06..0000000
--- a/lib/json/NilClass.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * False_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ",
-" ... ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" ... ",
-" ",
-" ",
-" "};
diff --git a/lib/json/Numeric.xpm b/lib/json/Numeric.xpm
deleted file mode 100644
index e071e2e..0000000
--- a/lib/json/Numeric.xpm
+++ /dev/null
@@ -1,28 +0,0 @@
-/* XPM */
-static char * Numeric_xpm[] = {
-"16 16 9 1",
-" c None",
-". c #FF0000",
-"+ c #0000FF",
-"@ c #0023DB",
-"# c #00EA14",
-"$ c #00FF00",
-"% c #004FAF",
-"& c #0028D6",
-"* c #00F20C",
-" ",
-" ",
-" ",
-" ... +++@#$$$$ ",
-" .+ %& $$ ",
-" . + $ ",
-" . + $$ ",
-" . ++$$$$ ",
-" . + $$ ",
-" . + $ ",
-" . + $ ",
-" . + $ $$ ",
-" .....++++*$$ ",
-" ",
-" ",
-" "};
diff --git a/lib/json/String.xpm b/lib/json/String.xpm
deleted file mode 100644
index f79a89c..0000000
--- a/lib/json/String.xpm
+++ /dev/null
@@ -1,96 +0,0 @@
-/* XPM */
-static char * String_xpm[] = {
-"16 16 77 1",
-" c None",
-". c #000000",
-"+ c #040404",
-"@ c #080806",
-"# c #090606",
-"$ c #EEEAE1",
-"% c #E7E3DA",
-"& c #E0DBD1",
-"* c #D4B46F",
-"= c #0C0906",
-"- c #E3C072",
-"; c #E4C072",
-"> c #060505",
-", c #0B0A08",
-"' c #D5B264",
-") c #D3AF5A",
-"! c #080602",
-"~ c #E1B863",
-"{ c #DDB151",
-"] c #DBAE4A",
-"^ c #DDB152",
-"/ c #DDB252",
-"( c #070705",
-"_ c #0C0A07",
-": c #D3A33B",
-"< c #020201",
-"[ c #DAAA41",
-"} c #040302",
-"| c #E4D9BF",
-"1 c #0B0907",
-"2 c #030201",
-"3 c #020200",
-"4 c #C99115",
-"5 c #080704",
-"6 c #DBC8A2",
-"7 c #E7D7B4",
-"8 c #E0CD9E",
-"9 c #080601",
-"0 c #040400",
-"a c #010100",
-"b c #0B0B08",
-"c c #DCBF83",
-"d c #DCBC75",
-"e c #DEB559",
-"f c #040301",
-"g c #BC8815",
-"h c #120E07",
-"i c #060402",
-"j c #0A0804",
-"k c #D4A747",
-"l c #D6A12F",
-"m c #0E0C05",
-"n c #C8C1B0",
-"o c #1D1B15",
-"p c #D7AD51",
-"q c #070502",
-"r c #080804",
-"s c #BC953B",
-"t c #C4BDAD",
-"u c #0B0807",
-"v c #DBAC47",
-"w c #1B150A",
-"x c #B78A2C",
-"y c #D8A83C",
-"z c #D4A338",
-"A c #0F0B03",
-"B c #181105",
-"C c #C59325",
-"D c #C18E1F",
-"E c #060600",
-"F c #CC992D",
-"G c #B98B25",
-"H c #B3831F",
-"I c #C08C1C",
-"J c #060500",
-"K c #0E0C03",
-"L c #0D0A00",
-" ",
-" .+@# ",
-" .$%&*= ",
-" .-;>,')! ",
-" .~. .{]. ",
-" .^/. (_:< ",
-" .[.}|$12 ",
-" 345678}90 ",
-" a2bcdefgh ",
-" ijkl.mno ",
-" <pq. rstu ",
-" .]v. wx= ",
-" .yzABCDE ",
-" .FGHIJ ",
-" 0KL0 ",
-" "};
diff --git a/lib/json/TrueClass.xpm b/lib/json/TrueClass.xpm
deleted file mode 100644
index 143eef4..0000000
--- a/lib/json/TrueClass.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * TrueClass_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #0BF311",
-" ",
-" ",
-" ",
-" ......... ",
-" . ",
-" . ",
-" . ",
-" . ",
-" . ",
-" . ",
-" . ",
-" . ",
-" . ",
-" ",
-" ",
-" "};
diff --git a/lib/json/add/complex.rb b/lib/json/add/complex.rb
new file mode 100644
index 0000000..d7ebebf
--- /dev/null
+++ b/lib/json/add/complex.rb
@@ -0,0 +1,22 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+defined?(::Complex) or require 'complex'
+
+class Complex
+ def self.json_create(object)
+ Complex(object['r'], object['i'])
+ end
+
+ def as_json(*)
+ {
+ JSON.create_id => self.class.name,
+ 'r' => real,
+ 'i' => imag,
+ }
+ end
+
+ def to_json(*)
+ as_json.to_json
+ end
+end
diff --git a/lib/json/add/core.rb b/lib/json/add/core.rb
index e9850af..77d9dc0 100644
--- a/lib/json/add/core.rb
+++ b/lib/json/add/core.rb
@@ -1,243 +1,11 @@
-# This file contains implementations of ruby core's custom objects for
+# This file requires the implementations of ruby core's custom objects for
# serialisation/deserialisation.
-unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
- require 'json'
-end
-require 'date'
-
-# Symbol serialization/deserialization
-class Symbol
- # 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,
- }
- 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
- end
- if respond_to?(:tv_nsec)
- at(*object.values_at('s', 'n'))
- else
- at(object['s'], object['n'] / 1000)
- end
- end
-
- # 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
- }
- 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)
-
- # 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,
- }
- 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('/')
- if of_b and of_b != '0'
- args << Rational(of_a.to_i, of_b.to_i)
- else
- args << of_a
- end
- args << object['sg']
- civil(*args)
- end
-
- alias start sg unless method_defined?(:start)
-
- # 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,
- 'H' => hour,
- 'M' => min,
- 'S' => sec,
- 'of' => offset.to_s,
- 'sg' => start,
- }
- 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
-
- # 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? ]
- }
- 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
-
- # 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,
- }
- 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
-
- # 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,
- }
- 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
-
- # 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,
- }
- 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
+require 'json/add/date'
+require 'json/add/date_time'
+require 'json/add/exception'
+require 'json/add/range'
+require 'json/add/regexp'
+require 'json/add/struct'
+require 'json/add/symbol'
+require 'json/add/time'
diff --git a/lib/json/add/date.rb b/lib/json/add/date.rb
new file mode 100644
index 0000000..4288237
--- /dev/null
+++ b/lib/json/add/date.rb
@@ -0,0 +1,34 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+require 'date'
+
+# 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)
+
+ # 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,
+ }
+ 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
diff --git a/lib/json/add/date_time.rb b/lib/json/add/date_time.rb
new file mode 100644
index 0000000..5ea42ea
--- /dev/null
+++ b/lib/json/add/date_time.rb
@@ -0,0 +1,50 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+require 'date'
+
+# 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('/')
+ if of_b and of_b != '0'
+ args << Rational(of_a.to_i, of_b.to_i)
+ else
+ args << of_a
+ end
+ args << object['sg']
+ civil(*args)
+ end
+
+ alias start sg unless method_defined?(:start)
+
+ # 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,
+ 'H' => hour,
+ 'M' => min,
+ 'S' => sec,
+ 'of' => offset.to_s,
+ 'sg' => start,
+ }
+ 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
+
+
diff --git a/lib/json/add/exception.rb b/lib/json/add/exception.rb
new file mode 100644
index 0000000..e6ad257
--- /dev/null
+++ b/lib/json/add/exception.rb
@@ -0,0 +1,31 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+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
+
+ # 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,
+ }
+ 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
diff --git a/lib/json/add/rails.rb b/lib/json/add/rails.rb
deleted file mode 100644
index af95e52..0000000
--- a/lib/json/add/rails.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file used to implementations of rails custom objects for
-# serialisation/deserialisation and is obsoleted now.
-
-unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
- require 'json'
-end
-
-$DEBUG and warn "required json/add/rails which is obsolete now!"
diff --git a/lib/json/add/range.rb b/lib/json/add/range.rb
new file mode 100644
index 0000000..e61e553
--- /dev/null
+++ b/lib/json/add/range.rb
@@ -0,0 +1,29 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+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
+
+ # 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? ]
+ }
+ 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
diff --git a/lib/json/add/rational.rb b/lib/json/add/rational.rb
new file mode 100644
index 0000000..867cd92
--- /dev/null
+++ b/lib/json/add/rational.rb
@@ -0,0 +1,22 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+defined?(::Rational) or require 'rational'
+
+class Rational
+ def self.json_create(object)
+ Rational(object['n'], object['d'])
+ end
+
+ def as_json(*)
+ {
+ JSON.create_id => self.class.name,
+ 'n' => numerator,
+ 'd' => denominator,
+ }
+ end
+
+ def to_json(*)
+ as_json.to_json
+ end
+end
diff --git a/lib/json/add/regexp.rb b/lib/json/add/regexp.rb
new file mode 100644
index 0000000..2fcbb6f
--- /dev/null
+++ b/lib/json/add/regexp.rb
@@ -0,0 +1,30 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+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
+
+ # 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,
+ }
+ 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
diff --git a/lib/json/add/struct.rb b/lib/json/add/struct.rb
new file mode 100644
index 0000000..6847cde
--- /dev/null
+++ b/lib/json/add/struct.rb
@@ -0,0 +1,30 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+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
+
+ # 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,
+ }
+ 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
diff --git a/lib/json/add/symbol.rb b/lib/json/add/symbol.rb
new file mode 100644
index 0000000..03dc9a5
--- /dev/null
+++ b/lib/json/add/symbol.rb
@@ -0,0 +1,25 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+
+# Symbol serialization/deserialization
+class Symbol
+ # 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,
+ }
+ 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
diff --git a/lib/json/add/time.rb b/lib/json/add/time.rb
new file mode 100644
index 0000000..abc807a
--- /dev/null
+++ b/lib/json/add/time.rb
@@ -0,0 +1,35 @@
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+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
+ end
+ if respond_to?(:tv_nsec)
+ at(*object.values_at('s', 'n'))
+ else
+ at(object['s'], object['n'] / 1000)
+ end
+ end
+
+ # 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
+ }
+ 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
diff --git a/lib/json/common.rb b/lib/json/common.rb
index 1a5f048..43e249c 100644
--- a/lib/json/common.rb
+++ b/lib/json/common.rb
@@ -2,11 +2,11 @@ require 'json/version'
module JSON
class << self
- # If _object_ is string-like parse the string and return the parsed result
+ # If _object_ is string-like, parse the string and return the parsed result
# as a Ruby data structure. Otherwise generate a JSON text from the Ruby
# data structure object and return it.
#
- # The _opts_ argument is passed through to generate/parse respectively, see
+ # The _opts_ argument is passed through to generate/parse respectively. See
# generate and parse for their documentation.
def [](object, opts = {})
if object.respond_to? :to_str
@@ -16,7 +16,7 @@ module JSON
end
end
- # Returns the JSON parser class, that is used by JSON. This might be either
+ # Returns the JSON parser class that is used by JSON. This is either
# JSON::Ext::Parser or JSON::Pure::Parser.
attr_reader :parser
@@ -28,7 +28,7 @@ module JSON
end
# Return the constant located at _path_. The format of _path_ has to be
- # either ::A::B::C or A::B::C. In any case A has to be located at the top
+ # either ::A::B::C or A::B::C. In any case, A has to be located at the top
# level (absolute namespace path?). If there doesn't exist a constant at
# the given path, an ArgumentError is raised.
def deep_const_get(path) # :nodoc:
@@ -81,15 +81,15 @@ module JSON
$VERBOSE = old
end
- # Returns the JSON generator modul, that is used by JSON. This might be
+ # Returns the JSON generator module that is used by JSON. This is
# either JSON::Ext::Generator or JSON::Pure::Generator.
attr_reader :generator
- # Returns the JSON generator state class, that is used by JSON. This might
- # be either JSON::Ext::Generator::State or JSON::Pure::Generator::State.
+ # Returns the JSON generator state class that is used by JSON. This is
+ # either JSON::Ext::Generator::State or JSON::Pure::Generator::State.
attr_accessor :state
- # This is create identifier, that is used to decide, if the _json_create_
+ # This is create identifier, which is used to decide if the _json_create_
# hook of a class should be called. It defaults to 'json_class'.
attr_accessor :create_id
end
@@ -104,10 +104,10 @@ module JSON
# The base exception for JSON errors.
class JSONError < StandardError; end
- # This exception is raised, if a parser error occurs.
+ # This exception is raised if a parser error occurs.
class ParserError < JSONError; end
- # This exception is raised, if the nesting of parsed datastructures is too
+ # This exception is raised if the nesting of parsed data structures is too
# deep.
class NestingError < ParserError; end
@@ -115,13 +115,13 @@ module JSON
class CircularDatastructure < NestingError; end
# :startdoc:
- # This exception is raised, if a generator or unparser error occurs.
+ # This exception is raised if a generator or unparser error occurs.
class GeneratorError < JSONError; end
# For backwards compatibility
UnparserError = GeneratorError
- # This exception is raised, if the required unicode support is missing on the
- # system. Usually this means, that the iconv library is not installed.
+ # This exception is raised if the required unicode support is missing on the
+ # system. Usually this means that the iconv library is not installed.
class MissingUnicodeSupport < JSONError; end
module_function
@@ -131,16 +131,16 @@ module JSON
# _opts_ can have the following
# keys:
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
- # structures. Disable depth checking with :max_nesting => false, it defaults
+ # structures. Disable depth checking with :max_nesting => false. It defaults
# to 19.
# * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
# to false.
# * *symbolize_names*: If set to true, returns symbols for the names
- # (keys) in a JSON object. Otherwise strings are returned, which is also
+ # (keys) in a JSON object. Otherwise strings are returned. Strings are
# the default.
# * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
+ # additions even if a matching class and create_id was found. This option
# defaults to true.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
@@ -149,19 +149,19 @@ module JSON
end
# Parse the JSON document _source_ into a Ruby data structure and return it.
- # The bang version of the parse method, defaults to the more dangerous values
+ # The bang version of the parse method defaults to the more dangerous values
# for the _opts_ hash, so be sure only to parse trusted _source_ documents.
#
# _opts_ can have the following keys:
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
# structures. Enable depth checking with :max_nesting => anInteger. The parse!
- # methods defaults to not doing max depth checking: This can be dangerous,
+ # methods defaults to not doing max depth checking: This can be dangerous
# if someone wants to fill up your stack.
# * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
# to true.
# * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
+ # additions even if a matching class and create_id was found. This option
# defaults to true.
def parse!(source, opts = {})
opts = {
@@ -188,7 +188,7 @@ module JSON
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
- # generated, otherwise an exception is thrown, if these values are
+ # generated, otherwise an exception is thrown if these values are
# encountered. This options defaults to false.
# * *max_nesting*: The maximum depth of nesting allowed in the data
# structures from which JSON is to be generated. Disable depth checking
@@ -196,9 +196,13 @@ module JSON
#
# See also the fast_generate for the fastest creation method with the least
# amount of sanity checks, and the pretty_generate method for some
- # defaults for a pretty output.
+ # defaults for pretty output.
def generate(obj, opts = nil)
- state = SAFE_STATE_PROTOTYPE.dup
+ if State === opts
+ state, opts = opts, nil
+ else
+ state = SAFE_STATE_PROTOTYPE.dup
+ end
if opts
if opts.respond_to? :to_hash
opts = opts.to_hash
@@ -223,9 +227,13 @@ module JSON
# This method disables the checks for circles in Ruby objects.
#
# *WARNING*: Be careful not to pass any Ruby data structures with circles as
- # _obj_ argument, because this will cause JSON to go into an infinite loop.
+ # _obj_ argument because this will cause JSON to go into an infinite loop.
def fast_generate(obj, opts = nil)
- state = FAST_STATE_PROTOTYPE.dup
+ if State === opts
+ state, opts = opts, nil
+ else
+ state = FAST_STATE_PROTOTYPE.dup
+ end
if opts
if opts.respond_to? :to_hash
opts = opts.to_hash
@@ -249,10 +257,14 @@ module JSON
# The returned document is a prettier form of the document returned by
# #unparse.
#
- # The _opts_ argument can be used to configure the generator, see the
+ # The _opts_ argument can be used to configure the generator. See the
# generate method for a more detailed explanation.
def pretty_generate(obj, opts = nil)
- state = PRETTY_STATE_PROTOTYPE.dup
+ if State === opts
+ state, opts = opts, nil
+ else
+ state = PRETTY_STATE_PROTOTYPE.dup
+ end
if opts
if opts.respond_to? :to_hash
opts = opts.to_hash
@@ -273,7 +285,7 @@ module JSON
# :startdoc:
# Load a ruby data structure from a JSON _source_ and return it. A source can
- # either be a string-like object, an IO like object, or an object responding
+ # either be a string-like object, an IO-like object, or an object responding
# to the read method. If _proc_ was given, it will be called with any nested
# Ruby object as an argument recursively in depth first order.
#
@@ -312,10 +324,10 @@ module JSON
# Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
# the result.
#
- # If anIO (an IO like object or an object that responds to the write method)
+ # If anIO (an IO-like object or an object that responds to the write method)
# was given, the resulting JSON is written to it.
#
- # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
+ # If the number of nested arrays or objects exceeds _limit_, an ArgumentError
# exception is raised. This argument is similar (but not exactly the
# same!) to the _limit_ argument in Marshal.dump.
#
@@ -396,11 +408,11 @@ module ::Kernel
nil
end
- # If _object_ is string-like parse the string and return the parsed result as
- # a Ruby data structure. Otherwise generate a JSON text from the Ruby data
+ # If _object_ is string-like, parse the string and return the parsed result as
+ # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
# structure object and return it.
#
- # The _opts_ argument is passed through to generate/parse respectively, see
+ # The _opts_ argument is passed through to generate/parse respectively. See
# generate and parse for their documentation.
def JSON(object, *args)
if object.respond_to? :to_str
@@ -413,10 +425,10 @@ end
# Extends any Class to include _json_creatable?_ method.
class ::Class
- # Returns true, if this class can be used to create an instance
+ # Returns true if this class can be used to create an instance
# from a serialised JSON string. The class has to implement a class
- # method _json_create_ that expects a hash as first parameter, which includes
- # the required data.
+ # method _json_create_ that expects a hash as first parameter. The hash
+ # should include the required data.
def json_creatable?
respond_to?(:json_create)
end
diff --git a/lib/json/editor.rb b/lib/json/editor.rb
deleted file mode 100644
index 985a554..0000000
--- a/lib/json/editor.rb
+++ /dev/null
@@ -1,1369 +0,0 @@
-# To use the GUI JSON editor, start the edit_json.rb executable script. It
-# requires ruby-gtk to be installed.
-
-require 'gtk2'
-require 'json'
-require 'rbconfig'
-require 'open-uri'
-
-module JSON
- module Editor
- include Gtk
-
- # Beginning of the editor window title
- TITLE = 'JSON Editor'.freeze
-
- # Columns constants
- ICON_COL, TYPE_COL, CONTENT_COL = 0, 1, 2
-
- # JSON primitive types (Containers)
- CONTAINER_TYPES = %w[Array Hash].sort
- # All JSON primitive types
- ALL_TYPES = (%w[TrueClass FalseClass Numeric String NilClass] +
- CONTAINER_TYPES).sort
-
- # The Nodes necessary for the tree representation of a JSON document
- ALL_NODES = (ALL_TYPES + %w[Key]).sort
-
- DEFAULT_DIALOG_KEY_PRESS_HANDLER = lambda do |dialog, event|
- case event.keyval
- when Gdk::Keyval::GDK_Return
- dialog.response Dialog::RESPONSE_ACCEPT
- when Gdk::Keyval::GDK_Escape
- dialog.response Dialog::RESPONSE_REJECT
- end
- end
-
- # Returns the Gdk::Pixbuf of the icon named _name_ from the icon cache.
- def Editor.fetch_icon(name)
- @icon_cache ||= {}
- unless @icon_cache.key?(name)
- path = File.dirname(__FILE__)
- @icon_cache[name] = Gdk::Pixbuf.new(File.join(path, name + '.xpm'))
- end
- @icon_cache[name]
- end
-
- # Opens an error dialog on top of _window_ showing the error message
- # _text_.
- def Editor.error_dialog(window, text)
- dialog = MessageDialog.new(window, Dialog::MODAL,
- MessageDialog::ERROR,
- MessageDialog::BUTTONS_CLOSE, text)
- dialog.show_all
- dialog.run
- rescue TypeError
- dialog = MessageDialog.new(Editor.window, Dialog::MODAL,
- MessageDialog::ERROR,
- MessageDialog::BUTTONS_CLOSE, text)
- dialog.show_all
- dialog.run
- ensure
- dialog.destroy if dialog
- end
-
- # Opens a yes/no question dialog on top of _window_ showing the error
- # message _text_. If yes was answered _true_ is returned, otherwise
- # _false_.
- def Editor.question_dialog(window, text)
- dialog = MessageDialog.new(window, Dialog::MODAL,
- MessageDialog::QUESTION,
- MessageDialog::BUTTONS_YES_NO, text)
- dialog.show_all
- dialog.run do |response|
- return Gtk::Dialog::RESPONSE_YES === response
- end
- ensure
- dialog.destroy if dialog
- end
-
- # Convert the tree model starting from Gtk::TreeIter _iter_ into a Ruby
- # data structure and return it.
- def Editor.model2data(iter)
- return nil if iter.nil?
- case iter.type
- when 'Hash'
- hash = {}
- iter.each { |c| hash[c.content] = Editor.model2data(c.first_child) }
- hash
- when 'Array'
- array = Array.new(iter.n_children)
- iter.each_with_index { |c, i| array[i] = Editor.model2data(c) }
- array
- when 'Key'
- iter.content
- when 'String'
- iter.content
- when 'Numeric'
- content = iter.content
- if /\./.match(content)
- content.to_f
- else
- content.to_i
- end
- when 'TrueClass'
- true
- when 'FalseClass'
- false
- when 'NilClass'
- nil
- else
- fail "Unknown type found in model: #{iter.type}"
- end
- end
-
- # Convert the Ruby data structure _data_ into tree model data for Gtk and
- # returns the whole model. If the parameter _model_ wasn't given a new
- # Gtk::TreeStore is created as the model. The _parent_ parameter specifies
- # the parent node (iter, Gtk:TreeIter instance) to which the data is
- # appended, alternativeley the result of the yielded block is used as iter.
- def Editor.data2model(data, model = nil, parent = nil)
- model ||= TreeStore.new(Gdk::Pixbuf, String, String)
- iter = if block_given?
- yield model
- else
- model.append(parent)
- end
- case data
- when Hash
- iter.type = 'Hash'
- data.sort.each do |key, value|
- pair_iter = model.append(iter)
- pair_iter.type = 'Key'
- pair_iter.content = key.to_s
- Editor.data2model(value, model, pair_iter)
- end
- when Array
- iter.type = 'Array'
- data.each do |value|
- Editor.data2model(value, model, iter)
- end
- when Numeric
- iter.type = 'Numeric'
- iter.content = data.to_s
- when String, true, false, nil
- iter.type = data.class.name
- iter.content = data.nil? ? 'null' : data.to_s
- else
- iter.type = 'String'
- iter.content = data.to_s
- end
- model
- end
-
- # The Gtk::TreeIter class is reopened and some auxiliary methods are added.
- class Gtk::TreeIter
- include Enumerable
-
- # Traverse each of this Gtk::TreeIter instance's children
- # and yield to them.
- def each
- n_children.times { |i| yield nth_child(i) }
- end
-
- # Recursively traverse all nodes of this Gtk::TreeIter's subtree
- # (including self) and yield to them.
- def recursive_each(&block)
- yield self
- each do |i|
- i.recursive_each(&block)
- end
- end
-
- # Remove the subtree of this Gtk::TreeIter instance from the
- # model _model_.
- def remove_subtree(model)
- while current = first_child
- model.remove(current)
- end
- end
-
- # Returns the type of this node.
- def type
- self[TYPE_COL]
- end
-
- # Sets the type of this node to _value_. This implies setting
- # the respective icon accordingly.
- def type=(value)
- self[TYPE_COL] = value
- self[ICON_COL] = Editor.fetch_icon(value)
- end
-
- # Returns the content of this node.
- def content
- self[CONTENT_COL]
- end
-
- # Sets the content of this node to _value_.
- def content=(value)
- self[CONTENT_COL] = value
- end
- end
-
- # This module bundles some method, that can be used to create a menu. It
- # should be included into the class in question.
- module MenuExtension
- include Gtk
-
- # Creates a Menu, that includes MenuExtension. _treeview_ is the
- # Gtk::TreeView, on which it operates.
- def initialize(treeview)
- @treeview = treeview
- @menu = Menu.new
- end
-
- # Returns the Gtk::TreeView of this menu.
- attr_reader :treeview
-
- # Returns the menu.
- attr_reader :menu
-
- # Adds a Gtk::SeparatorMenuItem to this instance's #menu.
- def add_separator
- menu.append SeparatorMenuItem.new
- end
-
- # Adds a Gtk::MenuItem to this instance's #menu. _label_ is the label
- # string, _klass_ is the item type, and _callback_ is the procedure, that
- # is called if the _item_ is activated.
- def add_item(label, keyval = nil, klass = MenuItem, &callback)
- label = "#{label} (C-#{keyval.chr})" if keyval
- item = klass.new(label)
- item.signal_connect(:activate, &callback)
- if keyval
- self.signal_connect(:'key-press-event') do |item, event|
- if event.state & Gdk::Window::ModifierType::CONTROL_MASK != 0 and
- event.keyval == keyval
- callback.call item
- end
- end
- end
- menu.append item
- item
- end
-
- # This method should be implemented in subclasses to create the #menu of
- # this instance. It has to be called after an instance of this class is
- # created, to build the menu.
- def create
- raise NotImplementedError
- end
-
- def method_missing(*a, &b)
- treeview.__send__(*a, &b)
- end
- end
-
- # This class creates the popup menu, that opens when clicking onto the
- # treeview.
- class PopUpMenu
- include MenuExtension
-
- # Change the type or content of the selected node.
- def change_node(item)
- if current = selection.selected
- parent = current.parent
- old_type, old_content = current.type, current.content
- if ALL_TYPES.include?(old_type)
- @clipboard_data = Editor.model2data(current)
- type, content = ask_for_element(parent, current.type,
- current.content)
- if type
- current.type, current.content = type, content
- current.remove_subtree(model)
- toplevel.display_status("Changed a node in tree.")
- window.change
- end
- else
- toplevel.display_status(
- "Cannot change node of type #{old_type} in tree!")
- end
- end
- end
-
- # Cut the selected node and its subtree, and save it into the
- # clipboard.
- def cut_node(item)
- if current = selection.selected
- if current and current.type == 'Key'
- @clipboard_data = {
- current.content => Editor.model2data(current.first_child)
- }
- else
- @clipboard_data = Editor.model2data(current)
- end
- model.remove(current)
- window.change
- toplevel.display_status("Cut a node from tree.")
- end
- end
-
- # Copy the selected node and its subtree, and save it into the
- # clipboard.
- def copy_node(item)
- if current = selection.selected
- if current and current.type == 'Key'
- @clipboard_data = {
- current.content => Editor.model2data(current.first_child)
- }
- else
- @clipboard_data = Editor.model2data(current)
- end
- window.change
- toplevel.display_status("Copied a node from tree.")
- end
- end
-
- # Paste the data in the clipboard into the selected Array or Hash by
- # appending it.
- def paste_node_appending(item)
- if current = selection.selected
- if @clipboard_data
- case current.type
- when 'Array'
- Editor.data2model(@clipboard_data, model, current)
- expand_collapse(current)
- when 'Hash'
- if @clipboard_data.is_a? Hash
- parent = current.parent
- hash = Editor.model2data(current)
- model.remove(current)
- hash.update(@clipboard_data)
- Editor.data2model(hash, model, parent)
- if parent
- expand_collapse(parent)
- elsif @expanded
- expand_all
- end
- window.change
- else
- toplevel.display_status(
- "Cannot paste non-#{current.type} data into '#{current.type}'!")
- end
- else
- toplevel.display_status(
- "Cannot paste node below '#{current.type}'!")
- end
- else
- toplevel.display_status("Nothing to paste in clipboard!")
- end
- else
- toplevel.display_status("Append a node into the root first!")
- end
- end
-
- # Paste the data in the clipboard into the selected Array inserting it
- # before the selected element.
- def paste_node_inserting_before(item)
- if current = selection.selected
- if @clipboard_data
- parent = current.parent or return
- parent_type = parent.type
- if parent_type == 'Array'
- selected_index = parent.each_with_index do |c, i|
- break i if c == current
- end
- Editor.data2model(@clipboard_data, model, parent) do |m|
- m.insert_before(parent, current)
- end
- expand_collapse(current)
- toplevel.display_status("Inserted an element to " +
- "'#{parent_type}' before index #{selected_index}.")
- window.change
- else
- toplevel.display_status(
- "Cannot insert node below '#{parent_type}'!")
- end
- else
- toplevel.display_status("Nothing to paste in clipboard!")
- end
- else
- toplevel.display_status("Append a node into the root first!")
- end
- end
-
- # Append a new node to the selected Hash or Array.
- def append_new_node(item)
- if parent = selection.selected
- parent_type = parent.type
- case parent_type
- when 'Hash'
- key, type, content = ask_for_hash_pair(parent)
- key or return
- iter = create_node(parent, 'Key', key)
- iter = create_node(iter, type, content)
- toplevel.display_status(
- "Added a (key, value)-pair to '#{parent_type}'.")
- window.change
- when 'Array'
- type, content = ask_for_element(parent)
- type or return
- iter = create_node(parent, type, content)
- window.change
- toplevel.display_status("Appendend an element to '#{parent_type}'.")
- else
- toplevel.display_status("Cannot append to '#{parent_type}'!")
- end
- else
- type, content = ask_for_element
- type or return
- iter = create_node(nil, type, content)
- window.change
- end
- end
-
- # Insert a new node into an Array before the selected element.
- def insert_new_node(item)
- if current = selection.selected
- parent = current.parent or return
- parent_parent = parent.parent
- parent_type = parent.type
- if parent_type == 'Array'
- selected_index = parent.each_with_index do |c, i|
- break i if c == current
- end
- type, content = ask_for_element(parent)
- type or return
- iter = model.insert_before(parent, current)
- iter.type, iter.content = type, content
- toplevel.display_status("Inserted an element to " +
- "'#{parent_type}' before index #{selected_index}.")
- window.change
- else
- toplevel.display_status(
- "Cannot insert node below '#{parent_type}'!")
- end
- else
- toplevel.display_status("Append a node into the root first!")
- end
- end
-
- # Recursively collapse/expand a subtree starting from the selected node.
- def collapse_expand(item)
- if current = selection.selected
- if row_expanded?(current.path)
- collapse_row(current.path)
- else
- expand_row(current.path, true)
- end
- else
- toplevel.display_status("Append a node into the root first!")
- end
- end
-
- # Create the menu.
- def create
- add_item("Change node", ?n, &method(:change_node))
- add_separator
- add_item("Cut node", ?X, &method(:cut_node))
- add_item("Copy node", ?C, &method(:copy_node))
- add_item("Paste node (appending)", ?A, &method(:paste_node_appending))
- add_item("Paste node (inserting before)", ?I,
- &method(:paste_node_inserting_before))
- add_separator
- add_item("Append new node", ?a, &method(:append_new_node))
- add_item("Insert new node before", ?i, &method(:insert_new_node))
- add_separator
- add_item("Collapse/Expand node (recursively)", ?e,
- &method(:collapse_expand))
-
- menu.show_all
- signal_connect(:button_press_event) do |widget, event|
- if event.kind_of? Gdk::EventButton and event.button == 3
- menu.popup(nil, nil, event.button, event.time)
- end
- end
- signal_connect(:popup_menu) do
- menu.popup(nil, nil, 0, Gdk::Event::CURRENT_TIME)
- end
- end
- end
-
- # This class creates the File pulldown menu.
- class FileMenu
- include MenuExtension
-
- # Clear the model and filename, but ask to save the JSON document, if
- # unsaved changes have occured.
- def new(item)
- window.clear
- end
-
- # Open a file and load it into the editor. Ask to save the JSON document
- # first, if unsaved changes have occured.
- def open(item)
- window.file_open
- end
-
- def open_location(item)
- window.location_open
- end
-
- # Revert the current JSON document in the editor to the saved version.
- def revert(item)
- window.instance_eval do
- @filename and file_open(@filename)
- end
- end
-
- # Save the current JSON document.
- def save(item)
- window.file_save
- end
-
- # Save the current JSON document under the given filename.
- def save_as(item)
- window.file_save_as
- end
-
- # Quit the editor, after asking to save any unsaved changes first.
- def quit(item)
- window.quit
- end
-
- # Create the menu.
- def create
- title = MenuItem.new('File')
- title.submenu = menu
- add_item('New', &method(:new))
- add_item('Open', ?o, &method(:open))
- add_item('Open location', ?l, &method(:open_location))
- add_item('Revert', &method(:revert))
- add_separator
- add_item('Save', ?s, &method(:save))
- add_item('Save As', ?S, &method(:save_as))
- add_separator
- add_item('Quit', ?q, &method(:quit))
- title
- end
- end
-
- # This class creates the Edit pulldown menu.
- class EditMenu
- include MenuExtension
-
- # Copy data from model into primary clipboard.
- def copy(item)
- data = Editor.model2data(model.iter_first)
- json = JSON.pretty_generate(data, :max_nesting => false)
- c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
- c.text = json
- end
-
- # Copy json text from primary clipboard into model.
- def paste(item)
- c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
- if json = c.wait_for_text
- window.ask_save if @changed
- begin
- window.edit json
- rescue JSON::ParserError
- window.clear
- end
- end
- end
-
- # Find a string in all nodes' contents and select the found node in the
- # treeview.
- def find(item)
- @search = ask_for_find_term(@search) or return
- iter = model.get_iter('0') or return
- iter.recursive_each do |i|
- if @iter
- if @iter != i
- next
- else
- @iter = nil
- next
- end
- elsif @search.match(i[CONTENT_COL])
- set_cursor(i.path, nil, false)
- @iter = i
- break
- end
- end
- end
-
- # Repeat the last search given by #find.
- def find_again(item)
- @search or return
- iter = model.get_iter('0')
- iter.recursive_each do |i|
- if @iter
- if @iter != i
- next
- else
- @iter = nil
- next
- end
- elsif @search.match(i[CONTENT_COL])
- set_cursor(i.path, nil, false)
- @iter = i
- break
- end
- end
- end
-
- # Sort (Reverse sort) all elements of the selected array by the given
- # expression. _x_ is the element in question.
- def sort(item)
- if current = selection.selected
- if current.type == 'Array'
- parent = current.parent
- ary = Editor.model2data(current)
- order, reverse = ask_for_order
- order or return
- begin
- block = eval "lambda { |x| #{order} }"
- if reverse
- ary.sort! { |a,b| block[b] <=> block[a] }
- else
- ary.sort! { |a,b| block[a] <=> block[b] }
- end
- rescue => e
- Editor.error_dialog(self, "Failed to sort Array with #{order}: #{e}!")
- else
- Editor.data2model(ary, model, parent) do |m|
- m.insert_before(parent, current)
- end
- model.remove(current)
- expand_collapse(parent)
- window.change
- toplevel.display_status("Array has been sorted.")
- end
- else
- toplevel.display_status("Only Array nodes can be sorted!")
- end
- else
- toplevel.display_status("Select an Array to sort first!")
- end
- end
-
- # Create the menu.
- def create
- title = MenuItem.new('Edit')
- title.submenu = menu
- add_item('Copy', ?c, &method(:copy))
- add_item('Paste', ?v, &method(:paste))
- add_separator
- add_item('Find', ?f, &method(:find))
- add_item('Find Again', ?g, &method(:find_again))
- add_separator
- add_item('Sort', ?S, &method(:sort))
- title
- end
- end
-
- class OptionsMenu
- include MenuExtension
-
- # Collapse/Expand all nodes by default.
- def collapsed_nodes(item)
- if expanded
- self.expanded = false
- collapse_all
- else
- self.expanded = true
- expand_all
- end
- end
-
- # Toggle pretty saving mode on/off.
- def pretty_saving(item)
- @pretty_item.toggled
- window.change
- end
-
- attr_reader :pretty_item
-
- # Create the menu.
- def create
- title = MenuItem.new('Options')
- title.submenu = menu
- add_item('Collapsed nodes', nil, CheckMenuItem, &method(:collapsed_nodes))
- @pretty_item = add_item('Pretty saving', nil, CheckMenuItem,
- &method(:pretty_saving))
- @pretty_item.active = true
- window.unchange
- title
- end
- end
-
- # This class inherits from Gtk::TreeView, to configure it and to add a lot
- # of behaviour to it.
- class JSONTreeView < Gtk::TreeView
- include Gtk
-
- # Creates a JSONTreeView instance, the parameter _window_ is
- # a MainWindow instance and used for self delegation.
- def initialize(window)
- @window = window
- super(TreeStore.new(Gdk::Pixbuf, String, String))
- self.selection.mode = SELECTION_BROWSE
-
- @expanded = false
- self.headers_visible = false
- add_columns
- add_popup_menu
- end
-
- # Returns the MainWindow instance of this JSONTreeView.
- attr_reader :window
-
- # Returns true, if nodes are autoexpanding, false otherwise.
- attr_accessor :expanded
-
- private
-
- def add_columns
- cell = CellRendererPixbuf.new
- column = TreeViewColumn.new('Icon', cell,
- 'pixbuf' => ICON_COL
- )
- append_column(column)
-
- cell = CellRendererText.new
- column = TreeViewColumn.new('Type', cell,
- 'text' => TYPE_COL
- )
- append_column(column)
-
- cell = CellRendererText.new
- cell.editable = true
- column = TreeViewColumn.new('Content', cell,
- 'text' => CONTENT_COL
- )
- cell.signal_connect(:edited, &method(:cell_edited))
- append_column(column)
- end
-
- def unify_key(iter, key)
- return unless iter.type == 'Key'
- parent = iter.parent
- if parent.any? { |c| c != iter and c.content == key }
- old_key = key
- i = 0
- begin
- key = sprintf("%s.%d", old_key, i += 1)
- end while parent.any? { |c| c != iter and c.content == key }
- end
- iter.content = key
- end
-
- def cell_edited(cell, path, value)
- iter = model.get_iter(path)
- case iter.type
- when 'Key'
- unify_key(iter, value)
- toplevel.display_status('Key has been changed.')
- when 'FalseClass'
- value.downcase!
- if value == 'true'
- iter.type, iter.content = 'TrueClass', 'true'
- end
- when 'TrueClass'
- value.downcase!
- if value == 'false'
- iter.type, iter.content = 'FalseClass', 'false'
- end
- when 'Numeric'
- iter.content =
- if value == 'Infinity'
- value
- else
- (Integer(value) rescue Float(value) rescue 0).to_s
- end
- when 'String'
- iter.content = value
- when 'Hash', 'Array'
- return
- else
- fail "Unknown type found in model: #{iter.type}"
- end
- window.change
- end
-
- def configure_value(value, type)
- value.editable = false
- case type
- when 'Array', 'Hash'
- value.text = ''
- when 'TrueClass'
- value.text = 'true'
- when 'FalseClass'
- value.text = 'false'
- when 'NilClass'
- value.text = 'null'
- when 'Numeric', 'String'
- value.text ||= ''
- value.editable = true
- else
- raise ArgumentError, "unknown type '#{type}' encountered"
- end
- end
-
- def add_popup_menu
- menu = PopUpMenu.new(self)
- menu.create
- end
-
- public
-
- # Create a _type_ node with content _content_, and add it to _parent_
- # in the model. If _parent_ is nil, create a new model and put it into
- # the editor treeview.
- def create_node(parent, type, content)
- iter = if parent
- model.append(parent)
- else
- new_model = Editor.data2model(nil)
- toplevel.view_new_model(new_model)
- new_model.iter_first
- end
- iter.type, iter.content = type, content
- expand_collapse(parent) if parent
- iter
- end
-
- # Ask for a hash key, value pair to be added to the Hash node _parent_.
- def ask_for_hash_pair(parent)
- key_input = type_input = value_input = nil
-
- dialog = Dialog.new("New (key, value) pair for Hash", nil, nil,
- [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
- [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
- )
- dialog.width_request = 640
-
- hbox = HBox.new(false, 5)
- hbox.pack_start(Label.new("Key:"), false)
- hbox.pack_start(key_input = Entry.new)
- key_input.text = @key || ''
- dialog.vbox.pack_start(hbox, false)
- key_input.signal_connect(:activate) do
- if parent.any? { |c| c.content == key_input.text }
- toplevel.display_status('Key already exists in Hash!')
- key_input.text = ''
- else
- toplevel.display_status('Key has been changed.')
- end
- end
-
- hbox = HBox.new(false, 5)
- hbox.pack_start(Label.new("Type:"), false)
- hbox.pack_start(type_input = ComboBox.new(true))
- ALL_TYPES.each { |t| type_input.append_text(t) }
- type_input.active = @type || 0
- dialog.vbox.pack_start(hbox, false)
-
- type_input.signal_connect(:changed) do
- value_input.editable = false
- case ALL_TYPES[type_input.active]
- when 'Array', 'Hash'
- value_input.text = ''
- when 'TrueClass'
- value_input.text = 'true'
- when 'FalseClass'
- value_input.text = 'false'
- when 'NilClass'
- value_input.text = 'null'
- else
- value_input.text = ''
- value_input.editable = true
- end
- end
-
- hbox = HBox.new(false, 5)
- hbox.pack_start(Label.new("Value:"), false)
- hbox.pack_start(value_input = Entry.new)
- value_input.width_chars = 60
- value_input.text = @value || ''
- dialog.vbox.pack_start(hbox, false)
-
- dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
- dialog.show_all
- self.focus = dialog
- dialog.run do |response|
- if response == Dialog::RESPONSE_ACCEPT
- @key = key_input.text
- type = ALL_TYPES[@type = type_input.active]
- content = value_input.text
- return @key, type, content
- end
- end
- return
- ensure
- dialog.destroy
- end
-
- # Ask for an element to be appended _parent_.
- def ask_for_element(parent = nil, default_type = nil, value_text = @content)
- type_input = value_input = nil
-
- dialog = Dialog.new(
- "New element into #{parent ? parent.type : 'root'}",
- nil, nil,
- [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
- [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
- )
- hbox = HBox.new(false, 5)
- hbox.pack_start(Label.new("Type:"), false)
- hbox.pack_start(type_input = ComboBox.new(true))
- default_active = 0
- types = parent ? ALL_TYPES : CONTAINER_TYPES
- types.each_with_index do |t, i|
- type_input.append_text(t)
- if t == default_type
- default_active = i
- end
- end
- type_input.active = default_active
- dialog.vbox.pack_start(hbox, false)
- type_input.signal_connect(:changed) do
- configure_value(value_input, types[type_input.active])
- end
-
- hbox = HBox.new(false, 5)
- hbox.pack_start(Label.new("Value:"), false)
- hbox.pack_start(value_input = Entry.new)
- value_input.width_chars = 60
- value_input.text = value_text if value_text
- configure_value(value_input, types[type_input.active])
-
- dialog.vbox.pack_start(hbox, false)
-
- dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
- dialog.show_all
- self.focus = dialog
- dialog.run do |response|
- if response == Dialog::RESPONSE_ACCEPT
- type = types[type_input.active]
- @content = case type
- when 'Numeric'
- if (t = value_input.text) == 'Infinity'
- 1 / 0.0
- else
- Integer(t) rescue Float(t) rescue 0
- end
- else
- value_input.text
- end.to_s
- return type, @content
- end
- end
- return
- ensure
- dialog.destroy if dialog
- end
-
- # Ask for an order criteria for sorting, using _x_ for the element in
- # question. Returns the order criterium, and true/false for reverse
- # sorting.
- def ask_for_order
- dialog = Dialog.new(
- "Give an order criterium for 'x'.",
- nil, nil,
- [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
- [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
- )
- hbox = HBox.new(false, 5)
-
- hbox.pack_start(Label.new("Order:"), false)
- hbox.pack_start(order_input = Entry.new)
- order_input.text = @order || 'x'
- order_input.width_chars = 60
-
- hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'), false)
-
- dialog.vbox.pack_start(hbox, false)
-
- dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
- dialog.show_all
- self.focus = dialog
- dialog.run do |response|
- if response == Dialog::RESPONSE_ACCEPT
- return @order = order_input.text, reverse_checkbox.active?
- end
- end
- return
- ensure
- dialog.destroy if dialog
- end
-
- # Ask for a find term to search for in the tree. Returns the term as a
- # string.
- def ask_for_find_term(search = nil)
- dialog = Dialog.new(
- "Find a node matching regex in tree.",
- nil, nil,
- [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
- [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
- )
- hbox = HBox.new(false, 5)
-
- hbox.pack_start(Label.new("Regex:"), false)
- hbox.pack_start(regex_input = Entry.new)
- hbox.pack_start(icase_checkbox = CheckButton.new('Icase'), false)
- regex_input.width_chars = 60
- if search
- regex_input.text = search.source
- icase_checkbox.active = search.casefold?
- end
-
- dialog.vbox.pack_start(hbox, false)
-
- dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
- dialog.show_all
- self.focus = dialog
- dialog.run do |response|
- if response == Dialog::RESPONSE_ACCEPT
- begin
- return Regexp.new(regex_input.text, icase_checkbox.active? ? Regexp::IGNORECASE : 0)
- rescue => e
- Editor.error_dialog(self, "Evaluation of regex /#{regex_input.text}/ failed: #{e}!")
- return
- end
- end
- end
- return
- ensure
- dialog.destroy if dialog
- end
-
- # Expand or collapse row pointed to by _iter_ according
- # to the #expanded attribute.
- def expand_collapse(iter)
- if expanded
- expand_row(iter.path, true)
- else
- collapse_row(iter.path)
- end
- end
- end
-
- # The editor main window
- class MainWindow < Gtk::Window
- include Gtk
-
- def initialize(encoding)
- @changed = false
- @encoding = encoding
- super(TOPLEVEL)
- display_title
- set_default_size(800, 600)
- signal_connect(:delete_event) { quit }
-
- vbox = VBox.new(false, 0)
- add(vbox)
- #vbox.border_width = 0
-
- @treeview = JSONTreeView.new(self)
- @treeview.signal_connect(:'cursor-changed') do
- display_status('')
- end
-
- menu_bar = create_menu_bar
- vbox.pack_start(menu_bar, false, false, 0)
-
- sw = ScrolledWindow.new(nil, nil)
- sw.shadow_type = SHADOW_ETCHED_IN
- sw.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
- vbox.pack_start(sw, true, true, 0)
- sw.add(@treeview)
-
- @status_bar = Statusbar.new
- vbox.pack_start(@status_bar, false, false, 0)
-
- @filename ||= nil
- if @filename
- data = read_data(@filename)
- view_new_model Editor.data2model(data)
- end
-
- signal_connect(:button_release_event) do |_,event|
- if event.button == 2
- c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
- if url = c.wait_for_text
- location_open url
- end
- false
- else
- true
- end
- end
- end
-
- # Creates the menu bar with the pulldown menus and returns it.
- def create_menu_bar
- menu_bar = MenuBar.new
- @file_menu = FileMenu.new(@treeview)
- menu_bar.append @file_menu.create
- @edit_menu = EditMenu.new(@treeview)
- menu_bar.append @edit_menu.create
- @options_menu = OptionsMenu.new(@treeview)
- menu_bar.append @options_menu.create
- menu_bar
- end
-
- # Sets editor status to changed, to indicate that the edited data
- # containts unsaved changes.
- def change
- @changed = true
- display_title
- end
-
- # Sets editor status to unchanged, to indicate that the edited data
- # doesn't containt unsaved changes.
- def unchange
- @changed = false
- display_title
- end
-
- # Puts a new model _model_ into the Gtk::TreeView to be edited.
- def view_new_model(model)
- @treeview.model = model
- @treeview.expanded = true
- @treeview.expand_all
- unchange
- end
-
- # Displays _text_ in the status bar.
- def display_status(text)
- @cid ||= nil
- @status_bar.pop(@cid) if @cid
- @cid = @status_bar.get_context_id('dummy')
- @status_bar.push(@cid, text)
- end
-
- # Opens a dialog, asking, if changes should be saved to a file.
- def ask_save
- if Editor.question_dialog(self,
- "Unsaved changes to JSON model. Save?")
- if @filename
- file_save
- else
- file_save_as
- end
- end
- end
-
- # Quit this editor, that is, leave this editor's main loop.
- def quit
- ask_save if @changed
- if Gtk.main_level > 0
- destroy
- Gtk.main_quit
- end
- nil
- end
-
- # Display the new title according to the editor's current state.
- def display_title
- title = TITLE.dup
- title << ": #@filename" if @filename
- title << " *" if @changed
- self.title = title
- end
-
- # Clear the current model, after asking to save all unsaved changes.
- def clear
- ask_save if @changed
- @filename = nil
- self.view_new_model nil
- end
-
- def check_pretty_printed(json)
- pretty = !!((nl_index = json.index("\n")) && nl_index != json.size - 1)
- @options_menu.pretty_item.active = pretty
- end
- private :check_pretty_printed
-
- # Open the data at the location _uri_, if given. Otherwise open a dialog
- # to ask for the _uri_.
- def location_open(uri = nil)
- uri = ask_for_location unless uri
- uri or return
- ask_save if @changed
- data = load_location(uri) or return
- view_new_model Editor.data2model(data)
- end
-
- # Open the file _filename_ or call the #select_file method to ask for a
- # filename.
- def file_open(filename = nil)
- filename = select_file('Open as a JSON file') unless filename
- data = load_file(filename) or return
- view_new_model Editor.data2model(data)
- end
-
- # Edit the string _json_ in the editor.
- def edit(json)
- if json.respond_to? :read
- json = json.read
- end
- data = parse_json json
- view_new_model Editor.data2model(data)
- end
-
- # Save the current file.
- def file_save
- if @filename
- store_file(@filename)
- else
- file_save_as
- end
- end
-
- # Save the current file as the filename
- def file_save_as
- filename = select_file('Save as a JSON file')
- store_file(filename)
- end
-
- # Store the current JSON document to _path_.
- def store_file(path)
- if path
- data = Editor.model2data(@treeview.model.iter_first)
- File.open(path + '.tmp', 'wb') do |output|
- data or break
- if @options_menu.pretty_item.active?
- output.puts JSON.pretty_generate(data, :max_nesting => false)
- else
- output.write JSON.generate(data, :max_nesting => false)
- end
- end
- File.rename path + '.tmp', path
- @filename = path
- toplevel.display_status("Saved data to '#@filename'.")
- unchange
- end
- rescue SystemCallError => e
- Editor.error_dialog(self, "Failed to store JSON file: #{e}!")
- end
-
- # Load the file named _filename_ into the editor as a JSON document.
- def load_file(filename)
- if filename
- if File.directory?(filename)
- Editor.error_dialog(self, "Try to select a JSON file!")
- nil
- else
- @filename = filename
- if data = read_data(filename)
- toplevel.display_status("Loaded data from '#@filename'.")
- end
- display_title
- data
- end
- end
- end
-
- # Load the data at location _uri_ into the editor as a JSON document.
- def load_location(uri)
- data = read_data(uri) or return
- @filename = nil
- toplevel.display_status("Loaded data from '#{uri}'.")
- display_title
- data
- end
-
- def parse_json(json)
- check_pretty_printed(json)
- if @encoding && !/^utf8$/i.match(@encoding)
- json = JSON.iconv 'utf-8', @encoding, json
- end
- JSON::parse(json, :max_nesting => false, :create_additions => false)
- end
- private :parse_json
-
- # Read a JSON document from the file named _filename_, parse it into a
- # ruby data structure, and return the data.
- def read_data(filename)
- open(filename) do |f|
- json = f.read
- return parse_json(json)
- end
- rescue => e
- Editor.error_dialog(self, "Failed to parse JSON file: #{e}!")
- return
- end
-
- # Open a file selecton dialog, displaying _message_, and return the
- # selected filename or nil, if no file was selected.
- def select_file(message)
- filename = nil
- fs = FileSelection.new(message)
- fs.set_modal(true)
- @default_dir = File.join(Dir.pwd, '') unless @default_dir
- fs.set_filename(@default_dir)
- fs.set_transient_for(self)
- fs.signal_connect(:destroy) { Gtk.main_quit }
- fs.ok_button.signal_connect(:clicked) do
- filename = fs.filename
- @default_dir = File.join(File.dirname(filename), '')
- fs.destroy
- Gtk.main_quit
- end
- fs.cancel_button.signal_connect(:clicked) do
- fs.destroy
- Gtk.main_quit
- end
- fs.show_all
- Gtk.main
- filename
- end
-
- # Ask for location URI a to load data from. Returns the URI as a string.
- def ask_for_location
- dialog = Dialog.new(
- "Load data from location...",
- nil, nil,
- [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
- [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
- )
- hbox = HBox.new(false, 5)
-
- hbox.pack_start(Label.new("Location:"), false)
- hbox.pack_start(location_input = Entry.new)
- location_input.width_chars = 60
- location_input.text = @location || ''
-
- dialog.vbox.pack_start(hbox, false)
-
- dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
- dialog.show_all
- dialog.run do |response|
- if response == Dialog::RESPONSE_ACCEPT
- return @location = location_input.text
- end
- end
- return
- ensure
- dialog.destroy if dialog
- end
- end
-
- class << self
- # Starts a JSON Editor. If a block was given, it yields
- # to the JSON::Editor::MainWindow instance.
- def start(encoding = 'utf8') # :yield: window
- Gtk.init
- @window = Editor::MainWindow.new(encoding)
- @window.icon_list = [ Editor.fetch_icon('json') ]
- yield @window if block_given?
- @window.show_all
- Gtk.main
- end
-
- # Edit the string _json_ with encoding _encoding_ in the editor.
- def edit(json, encoding = 'utf8')
- start(encoding) do |window|
- window.edit json
- end
- end
-
- attr_reader :window
- end
- end
-end
diff --git a/lib/json/ext.rb b/lib/json/ext.rb
index 1fbc3fd..7264a85 100644
--- a/lib/json/ext.rb
+++ b/lib/json/ext.rb
@@ -4,21 +4,8 @@ module JSON
# This module holds all the modules/classes that implement JSON's
# functionality as C extensions.
module Ext
- 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
+ require 'json/ext/parser'
+ require 'json/ext/generator'
$DEBUG and warn "Using Ext extension for JSON."
JSON.parser = Parser
JSON.generator = Generator
diff --git a/lib/json/json.xpm b/lib/json/json.xpm
deleted file mode 100644
index 2cb626b..0000000
--- a/lib/json/json.xpm
+++ /dev/null
@@ -1,1499 +0,0 @@
-/* XPM */
-static char * json_xpm[] = {
-"64 64 1432 2",
-" c None",
-". c #641839",
-"+ c #CF163C",
-"@ c #D31C3B",
-"# c #E11A38",
-"$ c #5F242D",
-"% c #320C22",
-"& c #9B532D",
-"* c #F32E34",
-"= c #820F33",
-"- c #4B0F34",
-"; c #8E1237",
-"> c #944029",
-", c #961325",
-"' c #A00C24",
-") c #872C23",
-"! c #694021",
-"~ c #590D1F",
-"{ c #420528",
-"] c #D85A2D",
-"^ c #7E092B",
-"/ c #0E0925",
-"( c #0D081F",
-"_ c #0F081E",
-": c #12071F",
-"< c #360620",
-"[ c #682A21",
-"} c #673F21",
-"| c #780E21",
-"1 c #A82320",
-"2 c #8D1D1F",
-"3 c #970127",
-"4 c #0D0123",
-"5 c #0D0324",
-"6 c #3B1E28",
-"7 c #C28429",
-"8 c #0C0523",
-"9 c #0C041E",
-"0 c #0E031A",
-"a c #11031A",
-"b c #13031B",
-"c c #13031C",
-"d c #11031D",
-"e c #19051E",
-"f c #390E20",
-"g c #9C0C20",
-"h c #C00721",
-"i c #980320",
-"j c #14031E",
-"k c #CD9F32",
-"l c #C29F2E",
-"m c #0F0325",
-"n c #0D0321",
-"o c #0E0324",
-"p c #D08329",
-"q c #9D1B27",
-"r c #1C0320",
-"s c #0D011A",
-"t c #120117",
-"u c #130017",
-"v c #150018",
-"w c #160119",
-"x c #17021A",
-"y c #15021B",
-"z c #11021E",
-"A c #0F021F",
-"B c #8C1821",
-"C c #CF4522",
-"D c #831821",
-"E c #BA7033",
-"F c #EDB339",
-"G c #C89733",
-"H c #280727",
-"I c #0F051F",
-"J c #0E0420",
-"K c #591F27",
-"L c #E47129",
-"M c #612224",
-"N c #0C021D",
-"O c #120018",
-"P c #140017",
-"Q c #170017",
-"R c #190018",
-"S c #1B0019",
-"T c #1B011A",
-"U c #18011B",
-"V c #15011C",
-"W c #12031E",
-"X c #460A21",
-"Y c #A13823",
-"Z c #784323",
-"` c #5A0C21",
-" . c #BC4530",
-".. c #EB5B38",
-"+. c #CE4E3B",
-"@. c #DD9334",
-"#. c #751A27",
-"$. c #11071E",
-"%. c #0F041C",
-"&. c #1E0824",
-"*. c #955A28",
-"=. c #9A5027",
-"-. c #1E0321",
-";. c #11011A",
-">. c #140018",
-",. c #180018",
-"'. c #1F001A",
-"). c #20001B",
-"!. c #1E001A",
-"~. c #1B001A",
-"{. c #16021B",
-"]. c #16041E",
-"^. c #220622",
-"/. c #5F3525",
-"(. c #DE5724",
-"_. c #611021",
-":. c #0F0925",
-"<. c #D1892E",
-"[. c #F27036",
-"}. c #EC633B",
-"|. c #DA293C",
-"1. c #E64833",
-"2. c #912226",
-"3. c #11081C",
-"4. c #110419",
-"5. c #0F041E",
-"6. c #451425",
-"7. c #BF6F28",
-"8. c #332225",
-"9. c #0E021E",
-"0. c #13001B",
-"a. c #17001A",
-"b. c #1C001B",
-"c. c #21001C",
-"d. c #23001C",
-"e. c #21001B",
-"f. c #19021A",
-"g. c #17041E",
-"h. c #150721",
-"i. c #602424",
-"j. c #D51223",
-"k. c #540820",
-"l. c #D04D2D",
-"m. c #EA8933",
-"n. c #875637",
-"o. c #88543A",
-"p. c #E5923A",
-"q. c #891931",
-"r. c #130B25",
-"s. c #10051B",
-"t. c #110217",
-"u. c #12021A",
-"v. c #761826",
-"w. c #E2A728",
-"x. c #300224",
-"y. c #10011E",
-"z. c #16001B",
-"A. c #1B001B",
-"B. c #21001A",
-"C. c #1E0019",
-"D. c #1D0019",
-"E. c #1A011A",
-"F. c #17031C",
-"G. c #120720",
-"H. c #4E0822",
-"I. c #670721",
-"J. c #C07630",
-"K. c #F59734",
-"L. c #BE1B35",
-"M. c #0E1435",
-"N. c #522037",
-"O. c #DB8039",
-"P. c #D45933",
-"Q. c #420927",
-"R. c #0F041D",
-"S. c #140118",
-"T. c #13021D",
-"U. c #100423",
-"V. c #7B6227",
-"W. c #C04326",
-"X. c #0E0020",
-"Y. c #13001D",
-"Z. c #18001B",
-"`. c #1E001B",
-" + c #22001C",
-".+ c #22001B",
-"++ c #1B011B",
-"@+ c #16041D",
-"#+ c #130520",
-"$+ c #860521",
-"%+ c #710520",
-"&+ c #670A2A",
-"*+ c #A66431",
-"=+ c #E97536",
-"-+ c #F8833A",
-";+ c #F77A3A",
-">+ c #C45337",
-",+ c #0A1C35",
-"'+ c #993638",
-")+ c #F7863B",
-"!+ c #F49736",
-"~+ c #94462B",
-"{+ c #0E031F",
-"]+ c #130119",
-"^+ c #160018",
-"/+ c #16011B",
-"(+ c #15021F",
-"_+ c #120123",
-":+ c #A65C28",
-"<+ c #5C4D23",
-"[+ c #0F001F",
-"}+ c #14001D",
-"|+ c #1A001B",
-"1+ c #1F001B",
-"2+ c #24001D",
-"3+ c #25001D",
-"4+ c #24001C",
-"5+ c #1F001C",
-"6+ c #1A011C",
-"7+ c #16021E",
-"8+ c #3F0421",
-"9+ c #BC0522",
-"0+ c #1C041E",
-"a+ c #7F5531",
-"b+ c #E68A38",
-"c+ c #F8933E",
-"d+ c #FA7942",
-"e+ c #FB7543",
-"f+ c #FA6F41",
-"g+ c #F1793D",
-"h+ c #7D3B3A",
-"i+ c #28263B",
-"j+ c #D45441",
-"k+ c #F8A238",
-"l+ c #996B2D",
-"m+ c #0E0421",
-"n+ c #12011A",
-"o+ c #180019",
-"p+ c #17001C",
-"q+ c #12001F",
-"r+ c #4C2B2A",
-"s+ c #DB8130",
-"t+ c #540023",
-"u+ c #0F0120",
-"v+ c #16011C",
-"w+ c #22001D",
-"x+ c #25001F",
-"y+ c #26001F",
-"z+ c #25001E",
-"A+ c #24001E",
-"B+ c #1D001C",
-"C+ c #18011D",
-"D+ c #16031F",
-"E+ c #3C0522",
-"F+ c #9B0821",
-"G+ c #13041E",
-"H+ c #F6462E",
-"I+ c #E6AB37",
-"J+ c #E7A03E",
-"K+ c #FA9F44",
-"L+ c #FB8A48",
-"M+ c #FD7A4A",
-"N+ c #FD794A",
-"O+ c #FD7748",
-"P+ c #FD7E45",
-"Q+ c #FD8343",
-"R+ c #FB5D42",
-"S+ c #6E3A40",
-"T+ c #EE8A37",
-"U+ c #7E252B",
-"V+ c #100520",
-"W+ c #13011A",
-"X+ c #170019",
-"Y+ c #15001C",
-"Z+ c #0F0020",
-"`+ c #564427",
-" @ c #E0BA29",
-".@ c #5E2B25",
-"+@ c #10011F",
-"@@ c #17011C",
-"#@ c #1E001D",
-"$@ c #23001F",
-"%@ c #250020",
-"&@ c #24001F",
-"*@ c #23001E",
-"=@ c #21001E",
-"-@ c #1B001C",
-";@ c #17021D",
-">@ c #14041E",
-",@ c #AC0B25",
-"'@ c #5E1420",
-")@ c #F28635",
-"!@ c #C2733E",
-"~@ c #984C44",
-"{@ c #EA9148",
-"]@ c #FB844B",
-"^@ c #FD7E4C",
-"/@ c #FE7E4C",
-"(@ c #FE7E4B",
-"_@ c #FE7749",
-":@ c #FD7148",
-"<@ c #FB7D46",
-"[@ c #F89641",
-"}@ c #B95634",
-"|@ c #0D0927",
-"1@ c #11041D",
-"2@ c #150119",
-"3@ c #180017",
-"4@ c #16001A",
-"5@ c #13001E",
-"6@ c #110023",
-"7@ c #944C29",
-"8@ c #EE6229",
-"9@ c #3D0324",
-"0@ c #12021F",
-"a@ c #19011D",
-"b@ c #21001F",
-"c@ c #22001F",
-"d@ c #20001E",
-"e@ c #1F001D",
-"f@ c #1C001C",
-"g@ c #19011C",
-"h@ c #3D1621",
-"i@ c #B53622",
-"j@ c #31061F",
-"k@ c #841D34",
-"l@ c #F2703F",
-"m@ c #C14445",
-"n@ c #E67349",
-"o@ c #FB8E4B",
-"p@ c #FD834C",
-"q@ c #FE834D",
-"r@ c #FE834C",
-"s@ c #FE804C",
-"t@ c #FD814B",
-"u@ c #FB7D49",
-"v@ c #F79B43",
-"w@ c #AF1234",
-"x@ c #0D0625",
-"y@ c #13021C",
-"z@ c #1A0019",
-"A@ c #190019",
-"B@ c #410225",
-"C@ c #D39729",
-"D@ c #AA5927",
-"E@ c #0E0422",
-"F@ c #15021E",
-"G@ c #1A011D",
-"H@ c #1D001D",
-"I@ c #15031D",
-"J@ c #240820",
-"K@ c #A01023",
-"L@ c #670B21",
-"M@ c #3D0D33",
-"N@ c #E63C3E",
-"O@ c #EF7C45",
-"P@ c #F59048",
-"Q@ c #FB944A",
-"R@ c #FD904A",
-"S@ c #FE8E4B",
-"T@ c #FE854A",
-"U@ c #FE854B",
-"V@ c #FE884C",
-"W@ c #FC954B",
-"X@ c #F8AB45",
-"Y@ c #C37A35",
-"Z@ c #0D0425",
-"`@ c #13011B",
-" # c #170018",
-".# c #1A0018",
-"+# c #1C0019",
-"@# c #15001B",
-"## c #100120",
-"$# c #311F25",
-"%# c #E68E28",
-"&# c #7A1425",
-"*# c #130321",
-"=# c #17011E",
-"-# c #1A001D",
-";# c #19001B",
-"># c #16021C",
-",# c #130521",
-"'# c #6F3123",
-")# c #6D3022",
-"!# c #C89433",
-"~# c #EA7E3E",
-"{# c #DB2943",
-"]# c #EF7745",
-"^# c #FB8544",
-"/# c #FD9A43",
-"(# c #FE9941",
-"_# c #FE9D43",
-":# c #FEA548",
-"<# c #FEAE49",
-"[# c #FCB944",
-"}# c #CA9F35",
-"|# c #0E0225",
-"1# c #11001B",
-"2# c #160019",
-"3# c #12011B",
-"4# c #0F0220",
-"5# c #351D26",
-"6# c #D85B28",
-"7# c #6C0F26",
-"8# c #190121",
-"9# c #1B001E",
-"0# c #1A001C",
-"a# c #1D001B",
-"b# c #130220",
-"c# c #703A23",
-"d# c #713A23",
-"e# c #140327",
-"f# c #411B36",
-"g# c #C8713E",
-"h# c #7A3A3F",
-"i# c #CE2C3C",
-"j# c #E77338",
-"k# c #9C6535",
-"l# c #9C6233",
-"m# c #9C6332",
-"n# c #9C6A35",
-"o# c #C37D3C",
-"p# c #FEAC41",
-"q# c #FEC23E",
-"r# c #826330",
-"s# c #100122",
-"t# c #120019",
-"u# c #150017",
-"v# c #190017",
-"w# c #1B0018",
-"x# c #12001A",
-"y# c #10021F",
-"z# c #1A0326",
-"A# c #5F292A",
-"B# c #7B4E29",
-"C# c #3C0E25",
-"D# c #1A0020",
-"E# c #14021F",
-"F# c #723B23",
-"G# c #14001A",
-"H# c #58042A",
-"I# c #A28337",
-"J# c #C8813B",
-"K# c #B14B38",
-"L# c #761231",
-"M# c #5A132A",
-"N# c #0D0726",
-"O# c #0C0623",
-"P# c #0B0723",
-"Q# c #0B0A26",
-"R# c #321C2D",
-"S# c #C45B33",
-"T# c #FEBB33",
-"U# c #13052A",
-"V# c #13011F",
-"W# c #160017",
-"X# c #15001A",
-"Y# c #12001D",
-"Z# c #94062A",
-"`# c #630D2C",
-" $ c #85292B",
-".$ c #AA5E29",
-"+$ c #1F0123",
-"@$ c #19011F",
-"#$ c #1E001C",
-"$$ c #15031F",
-"%$ c #712122",
-"&$ c #712223",
-"*$ c #14011B",
-"=$ c #110321",
-"-$ c #AF0C2B",
-";$ c #E7D534",
-">$ c #EAC934",
-",$ c #84582D",
-"'$ c #1B0824",
-")$ c #11041E",
-"!$ c #10021B",
-"~$ c #100119",
-"{$ c #100218",
-"]$ c #0F041A",
-"^$ c #0E0720",
-"/$ c #2C1026",
-"($ c #D8A328",
-"_$ c #140322",
-":$ c #160016",
-"<$ c #14001F",
-"[$ c #120024",
-"}$ c #100128",
-"|$ c #3C032F",
-"1$ c #2C062E",
-"2$ c #29022B",
-"3$ c #A31D29",
-"4$ c #976A25",
-"5$ c #1A0321",
-"6$ c #17031E",
-"7$ c #1B021D",
-"8$ c #20001C",
-"9$ c #14041F",
-"0$ c #703422",
-"a$ c #6F3522",
-"b$ c #8D0328",
-"c$ c #920329",
-"d$ c #0F0326",
-"e$ c #100321",
-"f$ c #11021B",
-"g$ c #130117",
-"h$ c #140016",
-"i$ c #150015",
-"j$ c #140015",
-"k$ c #130116",
-"l$ c #120219",
-"m$ c #11031C",
-"n$ c #12031D",
-"o$ c #170016",
-"p$ c #160020",
-"q$ c #250029",
-"r$ c #670033",
-"s$ c #DCA238",
-"t$ c #F5C736",
-"u$ c #9A732E",
-"v$ c #110227",
-"w$ c #110324",
-"x$ c #811924",
-"y$ c #A04323",
-"z$ c #250721",
-"A$ c #1A041F",
-"B$ c #1E011D",
-"C$ c #1C011C",
-"D$ c #18031D",
-"E$ c #130721",
-"F$ c #6F3623",
-"G$ c #6B3622",
-"H$ c #1A001A",
-"I$ c #14011F",
-"J$ c #12011E",
-"K$ c #11011C",
-"L$ c #140117",
-"M$ c #170015",
-"N$ c #150016",
-"O$ c #120119",
-"P$ c #11011B",
-"Q$ c #11001A",
-"R$ c #130018",
-"S$ c #170118",
-"T$ c #170119",
-"U$ c #18021E",
-"V$ c #1A0126",
-"W$ c #6F2332",
-"X$ c #E5563B",
-"Y$ c #F1B83F",
-"Z$ c #F6CC38",
-"`$ c #9D7A2D",
-" % c #130123",
-".% c #130320",
-"+% c #2A0721",
-"@% c #B00E24",
-"#% c #7D0B23",
-"$% c #1F0522",
-"%% c #1E0220",
-"&% c #1D011E",
-"*% c #1A031E",
-"=% c #15051F",
-"-% c #241322",
-";% c #A32F23",
-">% c #670E21",
-",% c #1C001A",
-"'% c #19001A",
-")% c #180016",
-"!% c #160118",
-"~% c #140219",
-"{% c #11021C",
-"]% c #10021E",
-"^% c #0F011D",
-"/% c #170117",
-"(% c #160219",
-"_% c #17041D",
-":% c #190523",
-"<% c #8C042E",
-"[% c #B65838",
-"}% c #E9D73F",
-"|% c #EED43E",
-"1% c #D85538",
-"2% c #493129",
-"3% c #130120",
-"4% c #15021D",
-"5% c #330822",
-"6% c #8A0825",
-"7% c #3C0424",
-"8% c #1E0322",
-"9% c #1C0321",
-"0% c #180421",
-"a% c #130822",
-"b% c #AF2D24",
-"c% c #BC5623",
-"d% c #2F071F",
-"e% c #1A041C",
-"f% c #1C031C",
-"g% c #1D011C",
-"h% c #160117",
-"i% c #150419",
-"j% c #12081D",
-"k% c #0F0923",
-"l% c #A77027",
-"m% c #A60525",
-"n% c #11021A",
-"o% c #130218",
-"p% c #150319",
-"q% c #16061D",
-"r% c #180923",
-"s% c #9C1D2B",
-"t% c #A32636",
-"u% c #A66E3B",
-"v% c #4B2E3C",
-"w% c #412C36",
-"x% c #36012D",
-"y% c #140123",
-"z% c #17001E",
-"A% c #19011B",
-"B% c #1A0421",
-"C% c #340425",
-"D% c #9E0326",
-"E% c #1F0424",
-"F% c #1C0524",
-"G% c #180724",
-"H% c #A91024",
-"I% c #D55D24",
-"J% c #90071E",
-"K% c #3C051D",
-"L% c #1C021C",
-"M% c #1C011A",
-"N% c #1D001A",
-"O% c #160116",
-"P% c #150216",
-"Q% c #140217",
-"R% c #140618",
-"S% c #120D1D",
-"T% c #231925",
-"U% c #B16A2E",
-"V% c #FDAC34",
-"W% c #D58631",
-"X% c #280E2A",
-"Y% c #0D0A23",
-"Z% c #0F0920",
-"`% c #120C21",
-" & c #1F1026",
-".& c #A3352E",
-"+& c #EE9F36",
-"@& c #5D2A3C",
-"#& c #960D3C",
-"$& c #970638",
-"%& c #A00330",
-"&& c #4D0126",
-"*& c #1C001F",
-"=& c #280120",
-"-& c #290223",
-";& c #1F0425",
-">& c #260726",
-",& c #340A26",
-"'& c #850925",
-")& c #3A0823",
-"!& c #82071D",
-"~& c #5E071D",
-"{& c #18051C",
-"]& c #18021A",
-"^& c #190118",
-"/& c #160217",
-"(& c #150418",
-"_& c #130618",
-":& c #110718",
-"<& c #10081A",
-"[& c #110D1D",
-"}& c #291C24",
-"|& c #A73B2D",
-"1& c #FD6B36",
-"2& c #FD853C",
-"3& c #FD863B",
-"4& c #C24A35",
-"5& c #6B442F",
-"6& c #6D302D",
-"7& c #6E252E",
-"8& c #8E3B32",
-"9& c #DE7739",
-"0& c #F48E3F",
-"a& c #DD8D41",
-"b& c #854F3D",
-"c& c #7E2D35",
-"d& c #33082B",
-"e& c #1C0222",
-"f& c #20001F",
-"g& c #1F0222",
-"h& c #1A0524",
-"i& c #440C27",
-"j& c #BC1427",
-"k& c #20041B",
-"l& c #53061C",
-"m& c #25071B",
-"n& c #11061A",
-"o& c #130418",
-"p& c #140317",
-"q& c #150217",
-"r& c #160318",
-"s& c #12051B",
-"t& c #100C1D",
-"u& c #0E101E",
-"v& c #0C121F",
-"w& c #0C1321",
-"x& c #781725",
-"y& c #B25D2C",
-"z& c #FA6335",
-"A& c #FD633C",
-"B& c #FE6D42",
-"C& c #FE7C42",
-"D& c #FE813F",
-"E& c #FE873C",
-"F& c #FD743B",
-"G& c #FB683B",
-"H& c #FA7A3E",
-"I& c #F98242",
-"J& c #F97844",
-"K& c #F98943",
-"L& c #F79C3D",
-"M& c #A25133",
-"N& c #280B28",
-"O& c #1D021F",
-"P& c #1F011C",
-"Q& c #280321",
-"R& c #1C0724",
-"S& c #3F1C27",
-"T& c #D33C27",
-"U& c #0E061B",
-"V& c #0C091C",
-"W& c #0C0A1B",
-"X& c #0E091A",
-"Y& c #11081B",
-"Z& c #100A20",
-"`& c #0E0D23",
-" * c #551227",
-".* c #B21829",
-"+* c #C42329",
-"@* c #C62C29",
-"#* c #C55429",
-"$* c #E76F2B",
-"%* c #F14232",
-"&* c #F95E3A",
-"** c #FC6740",
-"=* c #FE6E45",
-"-* c #FE7246",
-";* c #FE7545",
-">* c #FE7744",
-",* c #FD7745",
-"'* c #FD7845",
-")* c #FD7847",
-"!* c #FD7948",
-"~* c #FD7B44",
-"{* c #FC7C3B",
-"]* c #6F3130",
-"^* c #140B24",
-"/* c #19031D",
-"(* c #1C011B",
-"_* c #5A011F",
-":* c #B70421",
-"<* c #380824",
-"[* c #3E2626",
-"}* c #9F5626",
-"|* c #13051E",
-"1* c #360A21",
-"2* c #361223",
-"3* c #371724",
-"4* c #381824",
-"5* c #3B1524",
-"6* c #3E1E26",
-"7* c #471A29",
-"8* c #DB252E",
-"9* c #ED2733",
-"0* c #EE5436",
-"a* c #F04237",
-"b* c #F33934",
-"c* c #F53D2F",
-"d* c #D7312B",
-"e* c #AF212B",
-"f* c #3A2C31",
-"g* c #F65F39",
-"h* c #FB6F41",
-"i* c #FD6D45",
-"j* c #FE7047",
-"k* c #FE7647",
-"l* c #FE7847",
-"m* c #FE7848",
-"n* c #FE7748",
-"o* c #FE7948",
-"p* c #FE7C48",
-"q* c #FE7C47",
-"r* c #FE7642",
-"s* c #FE7439",
-"t* c #6D332C",
-"u* c #100B21",
-"v* c #16031B",
-"w* c #2B001B",
-"x* c #22011F",
-"y* c #220521",
-"z* c #1B0A23",
-"A* c #421425",
-"B* c #951924",
-"C* c #381023",
-"D* c #E94028",
-"E* c #E7302B",
-"F* c #EF432D",
-"G* c #F4302E",
-"H* c #F32C30",
-"I* c #CB4432",
-"J* c #DD3235",
-"K* c #EF4B3A",
-"L* c #F0333E",
-"M* c #CC3D3F",
-"N* c #E4313C",
-"O* c #F34834",
-"P* c #D13E2C",
-"Q* c #431825",
-"R* c #0E1424",
-"S* c #3C202C",
-"T* c #F15537",
-"U* c #F97140",
-"V* c #FC6E45",
-"W* c #FE7547",
-"X* c #FE7947",
-"Y* c #FE7B48",
-"Z* c #FE7D48",
-"`* c #FE8047",
-" = c #FE7A42",
-".= c #FE7A38",
-"+= c #6D442B",
-"@= c #0F0B21",
-"#= c #15031A",
-"$= c #49001B",
-"%= c #2F001C",
-"&= c #21021E",
-"*= c #220620",
-"== c #1B0D23",
-"-= c #641625",
-";= c #951823",
-">= c #390F25",
-",= c #AC3A2A",
-"'= c #B6492E",
-")= c #ED7531",
-"!= c #F45A34",
-"~= c #F54C36",
-"{= c #C72D39",
-"]= c #DE283C",
-"^= c #F33B40",
-"/= c #F34142",
-"(= c #D0393F",
-"_= c #E72E39",
-":= c #DB3C2E",
-"<= c #461724",
-"[= c #0F0D1E",
-"}= c #140B1E",
-"|= c #341427",
-"1= c #CB4834",
-"2= c #F7743F",
-"3= c #FB7145",
-"4= c #FE7747",
-"5= c #FE7A47",
-"6= c #FF7B48",
-"7= c #FF7C48",
-"8= c #FE7F47",
-"9= c #FE8247",
-"0= c #FE8642",
-"a= c #FE8439",
-"b= c #6D442D",
-"c= c #0F0A21",
-"d= c #14031A",
-"e= c #20031D",
-"f= c #210821",
-"g= c #191024",
-"h= c #CC1C25",
-"i= c #961423",
-"j= c #2C162C",
-"k= c #BD242E",
-"l= c #EF2C31",
-"m= c #F54C34",
-"n= c #F34037",
-"o= c #F5353A",
-"p= c #F7413D",
-"q= c #F8423D",
-"r= c #F93A39",
-"s= c #F95731",
-"t= c #341425",
-"u= c #110A1D",
-"v= c #140619",
-"w= c #18051B",
-"x= c #200F26",
-"y= c #864833",
-"z= c #F8773F",
-"A= c #FC7445",
-"B= c #FF7E48",
-"C= c #FF7E49",
-"D= c #FF7D49",
-"E= c #FF7D48",
-"F= c #FE8347",
-"G= c #FE8743",
-"H= c #FE893B",
-"I= c #6E452F",
-"J= c #100E23",
-"K= c #14041A",
-"L= c #55041D",
-"M= c #540921",
-"N= c #161124",
-"O= c #CE6A25",
-"P= c #3F1129",
-"Q= c #170A29",
-"R= c #0F0F29",
-"S= c #15132B",
-"T= c #1E182D",
-"U= c #A82B3D",
-"V= c #CB6633",
-"W= c #CC6932",
-"X= c #CC3D2D",
-"Y= c #331225",
-"Z= c #0F091C",
-"`= c #120417",
-" - c #160216",
-".- c #190419",
-"+- c #210F26",
-"@- c #8C4934",
-"#- c #F97A40",
-"$- c #FC7545",
-"%- c #FF7B49",
-"&- c #FE7D46",
-"*- c #FE7E43",
-"=- c #FD7B3E",
-"-- c #FA6934",
-";- c #532328",
-">- c #130B1D",
-",- c #150519",
-"'- c #14041C",
-")- c #120920",
-"!- c #C43624",
-"~- c #A21E23",
-"{- c #F87C30",
-"]- c #C9302D",
-"^- c #300F2A",
-"/- c #591129",
-"(- c #171328",
-"_- c #171628",
-":- c #141829",
-"<- c #101A2B",
-"[- c #0F172B",
-"}- c #0F1226",
-"|- c #0E0C20",
-"1- c #100619",
-"2- c #140316",
-"3- c #19051B",
-"4- c #3C1428",
-"5- c #E04B36",
-"6- c #FA7B41",
-"7- c #FD7346",
-"8- c #FE7548",
-"9- c #FF7849",
-"0- c #FF7749",
-"a- c #FE7B47",
-"b- c #FE7945",
-"c- c #FC7740",
-"d- c #FA7E39",
-"e- c #C1432F",
-"f- c #131523",
-"g- c #130A1C",
-"h- c #420621",
-"i- c #D08423",
-"j- c #F87739",
-"k- c #C03D37",
-"l- c #962B34",
-"m- c #A14332",
-"n- c #E54B30",
-"o- c #9E3E2F",
-"p- c #7F262E",
-"q- c #922D2E",
-"r- c #9C4B2E",
-"s- c #65212C",
-"t- c #101628",
-"u- c #101022",
-"v- c #11091C",
-"w- c #130619",
-"x- c #160A1E",
-"y- c #43252C",
-"z- c #F66439",
-"A- c #FA6942",
-"B- c #FD6C47",
-"C- c #FE6E48",
-"D- c #FE6F48",
-"E- c #FE7049",
-"F- c #FE714A",
-"G- c #FE744A",
-"H- c #FE7846",
-"I- c #FD7243",
-"J- c #FC703E",
-"K- c #FA6C37",
-"L- c #81312B",
-"M- c #121123",
-"N- c #15071D",
-"O- c #16031A",
-"P- c #17021B",
-"Q- c #8F3D22",
-"R- c #F8393E",
-"S- c #E42A3D",
-"T- c #E7473B",
-"U- c #FB503B",
-"V- c #FB4F3A",
-"W- c #F95439",
-"X- c #ED4C38",
-"Y- c #F45938",
-"Z- c #FB6537",
-"`- c #EA5236",
-" ; c #CE6232",
-".; c #CD392C",
-"+; c #181425",
-"@; c #120F21",
-"#; c #130D20",
-"$; c #151225",
-"%; c #903431",
-"&; c #F8703D",
-"*; c #FB6344",
-"=; c #FD6748",
-"-; c #FE6849",
-";; c #FE6949",
-">; c #FE6A49",
-",; c #FE6C4A",
-"'; c #FE704A",
-"); c #FE734A",
-"!; c #FE7449",
-"~; c #FE7347",
-"{; c #FE7145",
-"]; c #FD6C42",
-"^; c #FD753D",
-"/; c #F36E35",
-"(; c #CB452C",
-"_; c #600D24",
-":; c #1C061F",
-"<; c #1E031F",
-"[; c #5B3821",
-"}; c #CE9822",
-"|; c #FA4341",
-"1; c #FB4341",
-"2; c #FC4541",
-"3; c #FC4542",
-"4; c #FC4143",
-"5; c #FC4D42",
-"6; c #FB5042",
-"7; c #FB5342",
-"8; c #FC5242",
-"9; c #FD4F40",
-"0; c #FD503E",
-"a; c #FB6339",
-"b; c #F45E33",
-"c; c #A12A2E",
-"d; c #401E2C",
-"e; c #452D2F",
-"f; c #F74F38",
-"g; c #FA5940",
-"h; c #FC6245",
-"i; c #FE6447",
-"j; c #FE6449",
-"k; c #FE6549",
-"l; c #FE6749",
-"m; c #FE6B49",
-"n; c #FE6D49",
-"o; c #FE6D48",
-"p; c #FE6D47",
-"q; c #FE6D45",
-"r; c #FE6C44",
-"s; c #FE6A42",
-"t; c #FE663C",
-"u; c #FC6233",
-"v; c #752129",
-"w; c #1F0922",
-"x; c #750520",
-"y; c #81061F",
-"z; c #FA3D42",
-"A; c #FB4142",
-"B; c #FD4543",
-"C; c #FD4844",
-"D; c #FD4A45",
-"E; c #FD4D45",
-"F; c #FD5045",
-"G; c #FD5345",
-"H; c #FE5346",
-"I; c #FE5445",
-"J; c #FD5444",
-"K; c #FC4F41",
-"L; c #FA513D",
-"M; c #F95339",
-"N; c #F63736",
-"O; c #F75737",
-"P; c #F95F3B",
-"Q; c #FB5840",
-"R; c #FD5F43",
-"S; c #FE6345",
-"T; c #FE6547",
-"U; c #FE6548",
-"V; c #FE6448",
-"W; c #FE6248",
-"X; c #FE6348",
-"Y; c #FE6748",
-"Z; c #FE6848",
-"`; c #FE6846",
-" > c #FE6A45",
-".> c #FE6D43",
-"+> c #FE703F",
-"@> c #FC6F36",
-"#> c #6F302B",
-"$> c #140A22",
-"%> c #FA3B42",
-"&> c #FC4243",
-"*> c #FD4744",
-"=> c #FE4A45",
-"-> c #FE4C47",
-";> c #FE4D47",
-">> c #FE5047",
-",> c #FE5347",
-"'> c #FE5447",
-")> c #FD5246",
-"!> c #FB503F",
-"~> c #FA543D",
-"{> c #9B3D3B",
-"]> c #A3433B",
-"^> c #F9683D",
-"/> c #FC6940",
-"(> c #FE6342",
-"_> c #FE6645",
-":> c #FE6646",
-"<> c #FE6147",
-"[> c #FE6048",
-"}> c #FE6148",
-"|> c #FE6746",
-"1> c #FE6A46",
-"2> c #FE6F45",
-"3> c #FE7441",
-"4> c #FC7D39",
-"5> c #6C422E",
-"6> c #0F0F23",
-"7> c #FA4142",
-"8> c #FC4643",
-"9> c #FE4D46",
-"0> c #FE4E47",
-"a> c #FE4F48",
-"b> c #FE5148",
-"c> c #FE5348",
-"d> c #FE5548",
-"e> c #FE5247",
-"f> c #FD5445",
-"g> c #FC5544",
-"h> c #F96041",
-"i> c #D33F3D",
-"j> c #392D39",
-"k> c #973C38",
-"l> c #F94E3A",
-"m> c #FD693E",
-"n> c #FE6C43",
-"o> c #FE6047",
-"p> c #FE5D47",
-"q> c #FE5E48",
-"r> c #FE6948",
-"s> c #FE6947",
-"t> c #FE6B47",
-"u> c #FE6E46",
-"v> c #FD6D43",
-"w> c #FB723D",
-"x> c #D54A33",
-"y> c #301C29",
-"z> c #FB4A42",
-"A> c #FD4B44",
-"B> c #FE4F47",
-"C> c #FE5048",
-"D> c #FE5648",
-"E> c #FE5848",
-"F> c #FE5747",
-"G> c #FE5547",
-"H> c #FC5945",
-"I> c #F95742",
-"J> c #F3543D",
-"K> c #A33336",
-"L> c #302032",
-"M> c #152433",
-"N> c #CD3E38",
-"O> c #FD5A3F",
-"P> c #FE6343",
-"Q> c #FE6446",
-"R> c #FE6247",
-"S> c #FE6A47",
-"T> c #FC6542",
-"U> c #FB6A3B",
-"V> c #FA6D34",
-"W> c #D73C2D",
-"X> c #442428",
-"Y> c #281323",
-"Z> c #FD4E42",
-"`> c #FD4D43",
-" , c #FE4D45",
-"., c #FE5248",
-"+, c #FE5947",
-"@, c #FE5C47",
-"#, c #FE5B47",
-"$, c #FE5A47",
-"%, c #FE5847",
-"&, c #FC5C45",
-"*, c #F95B43",
-"=, c #F3613F",
-"-, c #E74F37",
-";, c #8C2431",
-">, c #161E2F",
-",, c #CD4E33",
-"', c #FD503A",
-"), c #FE5D40",
-"!, c #FE6445",
-"~, c #FE6946",
-"{, c #FE6847",
-"], c #FE6747",
-"^, c #FD6644",
-"/, c #FD6241",
-"(, c #FD5B3D",
-"_, c #FE6739",
-":, c #FE6135",
-"<, c #AB4830",
-"[, c #733E2A",
-"}, c #161224",
-"|, c #FC4E42",
-"1, c #FE4D44",
-"2, c #FE4E46",
-"3, c #FE5147",
-"4, c #FE5E47",
-"5, c #FD5C46",
-"6, c #FA5B44",
-"7, c #F45441",
-"8, c #EB393A",
-"9, c #CC3433",
-"0, c #47212F",
-"a, c #59242F",
-"b, c #FC6734",
-"c, c #FC6F3A",
-"d, c #FC723E",
-"e, c #FD6540",
-"f, c #FE6442",
-"g, c #FE6643",
-"h, c #FE6944",
-"i, c #FE6546",
-"j, c #FE6444",
-"k, c #FE6143",
-"l, c #FE5E41",
-"m, c #FE613F",
-"n, c #FE683C",
-"o, c #FE7937",
-"p, c #A25030",
-"q, c #692629",
-"r, c #151122",
-"s, c #FA573F",
-"t, c #FB4D40",
-"u, c #FC4F43",
-"v, c #FE5246",
-"w, c #FF6347",
-"x, c #FE5F48",
-"y, c #F65942",
-"z, c #F0493D",
-"A, c #ED3736",
-"B, c #73262F",
-"C, c #10152C",
-"D, c #3B292F",
-"E, c #363034",
-"F, c #AC3938",
-"G, c #FC6B3B",
-"H, c #FD763C",
-"I, c #FE6D3F",
-"J, c #FE6341",
-"K, c #FE6642",
-"L, c #FE6745",
-"M, c #FE6245",
-"N, c #FE6244",
-"O, c #FE6841",
-"P, c #FF683B",
-"Q, c #EC7035",
-"R, c #D0412D",
-"S, c #3A1627",
-"T, c #CF3938",
-"U, c #F6543C",
-"V, c #FB5040",
-"W, c #FD5544",
-"X, c #FE5A48",
-"Y, c #FE5D48",
-"Z, c #FE5F47",
-"`, c #FF6147",
-" ' c #FD5C45",
-".' c #FB5B43",
-"+' c #FA5A42",
-"@' c #F76040",
-"#' c #F4623D",
-"$' c #F26D38",
-"%' c #EC4130",
-"&' c #380E2B",
-"*' c #13122C",
-"=' c #362D31",
-"-' c #353435",
-";' c #352E37",
-">' c #2D3337",
-",' c #CC5838",
-"'' c #CD6F3A",
-")' c #CE6E3D",
-"!' c #FE793F",
-"~' c #FD7541",
-"{' c #FD6243",
-"]' c #FE6545",
-"^' c #FF6543",
-"/' c #FF6240",
-"(' c #FE723B",
-"_' c #FE8034",
-":' c #442D2C",
-"<' c #311725",
-"[' c #222830",
-"}' c #B73B36",
-"|' c #F94C3D",
-"1' c #FD5543",
-"2' c #FE5B48",
-"3' c #FF5E47",
-"4' c #FE5C48",
-"5' c #FC5B44",
-"6' c #F95640",
-"7' c #C34E3D",
-"8' c #A45A3A",
-"9' c #F37438",
-"0' c #F28935",
-"a' c #AF422F",
-"b' c #240D2B",
-"c' c #88292F",
-"d' c #FA8E34",
-"e' c #FC7E38",
-"f' c #FC5939",
-"g' c #694A37",
-"h' c #693437",
-"i' c #382638",
-"j' c #142439",
-"k' c #9F483A",
-"l' c #C45E3C",
-"m' c #FD7240",
-"n' c #FF6645",
-"o' c #FF6245",
-"p' c #FF6045",
-"q' c #FF6146",
-"r' c #FF6246",
-"s' c #FF6446",
-"t' c #FF6545",
-"u' c #FE763F",
-"v' c #FE7237",
-"w' c #C65331",
-"x' c #3D272A",
-"y' c #0D1E2B",
-"z' c #683032",
-"A' c #F9453A",
-"B' c #FD5341",
-"C' c #FE5A46",
-"D' c #FF5A48",
-"E' c #FE5948",
-"F' c #FD5A47",
-"G' c #FC5D43",
-"H' c #F95B3D",
-"I' c #713F37",
-"J' c #1E2D32",
-"K' c #C44531",
-"L' c #EF7A2F",
-"M' c #6B2E2C",
-"N' c #0F0E2C",
-"O' c #F56633",
-"P' c #FA803A",
-"Q' c #FC673E",
-"R' c #FD673E",
-"S' c #FC6F3C",
-"T' c #FA6E3B",
-"U' c #C6633A",
-"V' c #A06739",
-"W' c #835638",
-"X' c #381F38",
-"Y' c #713B38",
-"Z' c #7B503C",
-"`' c #FE7741",
-" ) c #FE7344",
-".) c #FE6D46",
-"+) c #FF6946",
-"@) c #FF5E46",
-"#) c #FF5D46",
-"$) c #FF5D47",
-"%) c #FF5F48",
-"&) c #FF6248",
-"*) c #FE6941",
-"=) c #FC783C",
-"-) c #C46B35",
-";) c #892730",
-">) c #111629",
-",) c #1F2630",
-"') c #AD3939",
-")) c #FC5D41",
-"!) c #FE5946",
-"~) c #FF5848",
-"{) c #FE5549",
-"]) c #FC5E42",
-"^) c #FA673B",
-"/) c #DB7033",
-"() c #392E2B",
-"_) c #311A28",
-":) c #3C2127",
-"<) c #1D1027",
-"[) c #92102C",
-"}) c #F58336",
-"|) c #FA673E",
-"1) c #FD6642",
-"2) c #FD5A41",
-"3) c #FC6D41",
-"4) c #FC6D3F",
-"5) c #FD683E",
-"6) c #F38C39",
-"7) c #CE6535",
-"8) c #612E34",
-"9) c #1D2637",
-"0) c #71513E",
-"a) c #FF6847",
-"b) c #FF5F47",
-"c) c #FF5A46",
-"d) c #FF5847",
-"e) c #FF5748",
-"f) c #FF594A",
-"g) c #FF5E4B",
-"h) c #FE654C",
-"i) c #FE694B",
-"j) c #FE6B48",
-"k) c #FC6A43",
-"l) c #F7683E",
-"m) c #EC6E39",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" . + @ # $ % ",
-" & * = - ; > , ' ) ! ~ ",
-" { ] ^ / ( _ : < [ } | 1 2 ",
-" 3 4 5 6 7 8 9 0 a b c d e f g h i j ",
-" k l m n o p q r s t u v w x y z A B C D ",
-" E F G H I J K L M N O P Q R S T U V W X Y Z ` ",
-" ...+.@.#.$.%.&.*.=.-.;.>.,.S '.).!.~.{.].^./.(._. ",
-" :.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.!.S f.g.h.i.j.k. ",
-" l.m.n.o.p.q.r.s.t.u.J v.w.x.y.z.A.c.d.d.B.C.D.E.F.G.H.I. ",
-" J.K.L.M.N.O.P.Q.R.t S.T.U.V.W.X.Y.Z.`. +d.d..+B.'.++@+#+$+%+ ",
-" &+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+1+d.2+3+4+d.5+6+7+8+9+0+ ",
-" a+b+c+d+e+f+g+h+i+j+k+l+m+n+^+o+p+q+r+s+t+u+v+b.w+x+y+z+A+w+B+C+D+E+F+G+ ",
-" H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+Q ,.X+Y+Z+`+ @.@+@@@#@$@%@&@*@=@#@-@;@>@,@'@ ",
-" )@!@~@{@]@^@/@(@_@:@<@[@}@|@1@2@3@R ,.4@5@6@7@8@9@0@a@#@b@c@=@d@e@f@g@>@h@i@j@ ",
-" k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@^+R S z@A@z.q+B@C@D@E@F@G@H@#@e@#@#@f@g@I@J@K@L@ ",
-" M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@`@ #.#+#+#S A@@###$#%#&#*#=#-#f@B+B+B+f@;#>#,#'#)# ",
-" !#~#{#]#^#/#(#(#_#:#<#[#}#|#1#^+.#S +#+#z@2#3#4#5#6#7#8#9#0#A.B+B+a#A.@@b#c#d# ",
-" e#f#g#h#i#j#k#l#m#n#o#p#q#r#s#t#u#v#.#w#S R ^+x#y#z#A#B#C#D#-#A.a#`.`.b.g@E#d#F# ",
-" G#0@H#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#>.W#3@v#R R X+X#Y#s#Z#`# $.$+$@$g@f@5+5+#$6+$$%$&$ ",
-" *$=$-$;$>$,$'$)$!$~${$]$^$/$($_$*$u#:$Q 3@,.X+z.<$[$}$|$1$2$3$4$5$6$7$e@8$#$G@9$0$a$ ",
-" ,.4@E#b$c$d$e$f$g$h$i$j$k$l$m$n$`@>.:$o$3@,. #a.p$q$r$s$t$u$v$w$x$y$z$A$B$#@C$D$E$F$G$ ",
-" R S H$v+I$J$K$n+L$:$o$o$M$N$L$O$P$Q$R$N$o$3@S$T$U$V$W$X$Y$Z$`$ %.%+%@%#%$%%%&%*%=%-%;%>% ",
-" E.,%~.'%Z.4@v W#o$)%)%)%Q !%~%{%]%^%Q$u u#/%(%_%:%<%[%}%|%1%2%3%4%=%5%6%7%8%9%0%a%b%c%d% ",
-" e%f%g%a#,%,%z@R 3@3@3@)%Q h%i%j%k%l%m%{+n%o%p%q%r%s%t%u%v%w%x%y%z%A%*%B%C%D%E%F%G%H%I% ",
-" J%K%L%M%N%D.S v#)%)%O%P%Q%R%S%T%U%V%W%X%Y%Z%`% &.&+&@&#&$&%&&&*&f@a##@=&-&;&>&,&'&)& ",
-" !&~&{&]&^&.#w#^&/%/&(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&0&a&b&c&d&e&e@1+5+e@f&g&h&i&j& ",
-" k&l&m&n&o&p&q&r&i%s&3.t&u&v&w&x&y&z&A&B&C&D&E&F&G&H&I&J&K&L&M&N&O&P&1+`.e@f&Q&R&S&T& ",
-" 0 U&V&W&X&<&Y&j%Z&`& *.*+*@*#*$*%*&***=*-*;*>*>*,*'*)*!*~*{*]*^*/*(*a#B+#@_*:*<*[*}* ",
-" |*1*2*3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*E.w*d.e@x*y*z*A*B* ",
-" C*D*E*F*G*H*I*J*K*L*M*N*O*P*Q*R*S*T*U*V*W*l*X*o*o*Y*Z*`* =.=+=@=#='%$=%=e@&=*===-=;= ",
-" >=,='=)=!=~={=]=^=/=(=_=:=<=[=}=|=1=2=3=4=5=p*6=6=7=8=9=0=a=b=c=d=A@~.b.B+e=f=g=h=i= ",
-" j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z=A=5=Z*B=C=D=E=8=F=G=H=I=J=K=S$R z@'%L=M=N=O= ",
-" P=Q=R=S=T=U=V=W=X=Y=Z=`= -.-+-@-#-$-5=p*E=D=%-%-q*&-*-=---;->-,-/%3@^+'-)-!-~- ",
-" {-]-^-/-(-_-:-<-[-}-|-1-2- -3-4-5-6-7-8-n*m*9-0-9-o*a-b-c-d-e-f-g-(&h%w c h-i- ",
-" j-k-l-m-n-o-p-q-r-s-t-u-v-w-,-x-y-z-A-B-C-D-E-E-F-G-_@m*H-I-J-K-L-M-N-O-P-(+Q- ",
-" R-S-T-U-V-W-X-Y-Z-`- ;.;+;@;#;$;%;&;*;=;-;-;;;>;,;';);!;~;{;];^;/;(;_;:;<;[;}; ",
-" |;1;2;3;4;5;6;7;8;9;0;a;b;c;d;e;f;g;h;i;j;j;k;k;l;m;n;o;p;q;r;s;t;u;v;w;x;y; ",
-" z;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;k;Y;Z;`; >r;.>+>@>#>$> ",
-" %>&>*>=>->;>>>,>'>,>)>F;8;!>~>{>]>^>/>(>_>:>i;<>[>X;}>i;|>1>q;2>3>4>5>6> ",
-" 7>8>=>9>0>a>b>c>d>,>e>e>f>g>h>i>j>k>l>m>n>:>i;o>p>q>W;r>s>t>p;u>v>w>x>y> ",
-" z>A>9>0>B>C>c>D>E>F>G>G>F>H>I>J>K>L>M>N>O>P>Q>R>o>R>T;s>S>S>S>t>1>T>U>V>W>X>Y> ",
-" Z>`> ,9>B>.,D>+,@,#,$,%,$,&,*,=,-,;,>,,,',),P>!,!,_>~,t>s>{,],{,],^,/,(,_,:,<,[,}, ",
-" |,`>1,2,3,G>+,4,o>o>4,@,@,5,6,7,8,9,0,a,b,c,d,e,f,g,h, >~,|>T;T;T;i,j,k,l,m,n,o,p,q,r, ",
-" s,t,u,v,G>%,@,o>w,R>x,p>@,5,6,y,z,A,B,C,D,E,F,G,H,I,J,K,L,L,i,i;i;i;Q>S;M,N,P>O,P,Q,R,S, ",
-" T,U,V,W,%,X,Y,Z,`,[>q>@, '.'+'@'#'$'%'&'*'='-';'>',''')'!'~'{'N,i,:>_>]'M,M,Q>_>^'/'('_':'<' ",
-" ['}'|'1'$,X,2'p>3'4'2'@,5'6'7'8'9'0'a'b'c'd'e'f'g'h'i'j'k'l'd,m'g, > >n'o'p'q'r's't'.>u'v'w'x' ",
-" y'z'A'B'C'X,X,2'D'E'E'F'G'H'I'J'K'L'M'N'O'P'Q'R'S'T'U'V'W'X'Y'Z'`' ).)+)r'@)#)$)%)&)l;1>*)=)-);) ",
-" >),)')))!)X,E'X,~){)d>!)])^)/)()_):)<)[)})|)1)f,2)3)4)5)6)7)8)9)0)*--*a)b)c)d)e)f)g)h)i)j)k)l)m) ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/lib/json/pure/generator.rb b/lib/json/pure/generator.rb
index 3687e30..7c9b2ad 100644
--- a/lib/json/pure/generator.rb
+++ b/lib/json/pure/generator.rb
@@ -133,6 +133,8 @@ module JSON
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
# generated, otherwise an exception is thrown, if these values are
# encountered. This options defaults to false.
+ # * *quirks_mode*: Enables quirks_mode for parser, that is for example
+ # generating single JSON values instead of documents is possible.
def initialize(opts = {})
@indent = ''
@space = ''
@@ -141,6 +143,7 @@ module JSON
@array_nl = ''
@allow_nan = false
@ascii_only = false
+ @quirks_mode = false
configure opts
end
@@ -165,6 +168,10 @@ module JSON
# the generated JSON, max_nesting = 0 if no maximum is checked.
attr_accessor :max_nesting
+ # If this attribute is set to true, quirks mode is enabled, otherwise
+ # it's disabled.
+ attr_accessor :quirks_mode
+
# This integer returns the current depth data structure nesting in the
# generated JSON.
attr_accessor :depth
@@ -188,10 +195,17 @@ module JSON
@allow_nan
end
+ # Returns true, if only ASCII characters should be generated. Otherwise
+ # returns false.
def ascii_only?
@ascii_only
end
+ # Returns true, if quirks mode is enabled. Otherwise returns false.
+ def quirks_mode?
+ @quirks_mode
+ end
+
# Configure this State instance with the Hash _opts_, and return
# itself.
def configure(opts)
@@ -203,6 +217,7 @@ module JSON
@allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
@depth = opts[:depth] || 0
+ @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode)
if !opts.key?(:max_nesting) # defaults to 19
@max_nesting = 19
elsif opts[:max_nesting]
@@ -218,7 +233,7 @@ module JSON
# passed to the configure method.
def to_h
result = {}
- for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only depth]
+ for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only quirks_mode depth]
result[iv.intern] = instance_variable_get("@#{iv}")
end
result
@@ -229,7 +244,7 @@ module JSON
# GeneratorError exception.
def generate(obj)
result = obj.to_json(self)
- if result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
+ if !@quirks_mode && result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
raise GeneratorError, "only generation of JSON objects or arrays allowed"
end
result
diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb
index d612018..e24aac1 100644
--- a/lib/json/pure/parser.rb
+++ b/lib/json/pure/parser.rb
@@ -68,42 +68,12 @@ module JSON
# defaults to true.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
+ # * *quirks_mode*: Enables quirks_mode for parser, that is for example
+ # parsing single JSON values instead of documents is possible.
def initialize(source, opts = {})
opts ||= {}
- if defined?(::Encoding)
- if source.encoding == ::Encoding::ASCII_8BIT
- b = source[0, 4].bytes.to_a
- source = case
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
- source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
- when b.size >= 4 && b[0] == 0 && b[2] == 0
- source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
- source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
-
- when b.size >= 4 && b[1] == 0 && b[3] == 0
- source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
- else
- source.dup
- end
- else
- source = source.encode(::Encoding::UTF_8)
- end
- source.force_encoding(::Encoding::ASCII_8BIT)
- else
- b = source
- source = case
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
- JSON.iconv('utf-8', 'utf-32be', b)
- when b.size >= 4 && b[0] == 0 && b[2] == 0
- JSON.iconv('utf-8', 'utf-16be', b)
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
- JSON.iconv('utf-8', 'utf-32le', b)
- when b.size >= 4 && b[1] == 0 && b[3] == 0
- JSON.iconv('utf-8', 'utf-16le', b)
- else
- b
- end
+ unless @quirks_mode = opts[:quirks_mode]
+ source = determine_encoding source
end
super source
if !opts.key?(:max_nesting) # defaults to 19
@@ -113,44 +83,108 @@ module JSON
else
@max_nesting = 0
end
- @allow_nan = !!opts[:allow_nan]
- @symbolize_names = !!opts[:symbolize_names]
- @create_additions = opts.key?(:create_additions) ? !!opts[:create_additions] : true
- @create_id = opts[:create_id] || JSON.create_id
- @object_class = opts[:object_class] || Hash
- @array_class = opts[:array_class] || Array
- @match_string = opts[:match_string]
+ @allow_nan = !!opts[:allow_nan]
+ @symbolize_names = !!opts[:symbolize_names]
+ if opts.key?(:create_additions)
+ @create_additions = !!opts[:create_additions]
+ else
+ @create_additions = true
+ end
+ @create_id = @create_additions ? JSON.create_id : nil
+ @object_class = opts[:object_class] || Hash
+ @array_class = opts[:array_class] || Array
+ @match_string = opts[:match_string]
end
alias source string
+ def quirks_mode?
+ !!@quirks_mode
+ end
+
+ def reset
+ super
+ @current_nesting = 0
+ end
+
# Parses the current JSON string _source_ and returns the complete data
# structure as a result.
def parse
reset
obj = nil
- until eos?
- case
- when scan(OBJECT_OPEN)
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
- @current_nesting = 1
- obj = parse_object
- when scan(ARRAY_OPEN)
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
- @current_nesting = 1
- obj = parse_array
- when skip(IGNORE)
- ;
+ if @quirks_mode
+ while !eos? && skip(IGNORE)
+ end
+ if eos?
+ raise ParserError, "source did not contain any JSON!"
else
- raise ParserError, "source '#{peek(20)}' not in JSON!"
+ obj = parse_value
+ obj == UNPARSED and raise ParserError, "source did not contain any JSON!"
end
+ else
+ until eos?
+ case
+ when scan(OBJECT_OPEN)
+ obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+ @current_nesting = 1
+ obj = parse_object
+ when scan(ARRAY_OPEN)
+ obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+ @current_nesting = 1
+ obj = parse_array
+ when skip(IGNORE)
+ ;
+ else
+ raise ParserError, "source '#{peek(20)}' not in JSON!"
+ end
+ end
+ obj or raise ParserError, "source did not contain any JSON!"
end
- obj or raise ParserError, "source did not contain any JSON!"
obj
end
private
+ def determine_encoding(source)
+ if defined?(::Encoding)
+ if source.encoding == ::Encoding::ASCII_8BIT
+ b = source[0, 4].bytes.to_a
+ source =
+ case
+ when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
+ source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
+ when b.size >= 4 && b[0] == 0 && b[2] == 0
+ source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
+ when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
+ source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
+ when b.size >= 4 && b[1] == 0 && b[3] == 0
+ source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
+ else
+ source.dup
+ end
+ else
+ source = source.encode(::Encoding::UTF_8)
+ end
+ source.force_encoding(::Encoding::ASCII_8BIT)
+ else
+ b = source
+ source =
+ case
+ when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
+ JSON.iconv('utf-8', 'utf-32be', b)
+ when b.size >= 4 && b[0] == 0 && b[2] == 0
+ JSON.iconv('utf-8', 'utf-16be', b)
+ when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
+ JSON.iconv('utf-8', 'utf-32le', b)
+ when b.size >= 4 && b[1] == 0 && b[3] == 0
+ JSON.iconv('utf-8', 'utf-16le', b)
+ else
+ b
+ end
+ end
+ source
+ end
+
# Unescape characters in strings.
UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
UNESCAPE_MAP.update({
diff --git a/lib/json/version.rb b/lib/json/version.rb
index 2175ac0..5983945 100644
--- a/lib/json/version.rb
+++ b/lib/json/version.rb
@@ -1,6 +1,6 @@
module JSON
# JSON version
- VERSION = '1.5.4'
+ VERSION = '1.6.1'
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
diff --git a/tests/test_json.rb b/tests/test_json.rb
index b367e90..eafd758 100755
--- a/tests/test_json.rb
+++ b/tests/test_json.rb
@@ -104,6 +104,42 @@ class TC_JSON < Test::Unit::TestCase
assert_equal({ "a" => 0.23 }, parse(' { "a" : 0.23 } '))
end
+ def test_parse_json_primitive_values
+ assert_raise(JSON::ParserError) { JSON.parse('') }
+ assert_raise(JSON::ParserError) { JSON.parse('', :quirks_mode => true) }
+ assert_raise(JSON::ParserError) { JSON.parse(' /* foo */ ') }
+ assert_raise(JSON::ParserError) { JSON.parse(' /* foo */ ', :quirks_mode => true) }
+ parser = JSON::Parser.new('null')
+ assert_equal false, parser.quirks_mode?
+ assert_raise(JSON::ParserError) { parser.parse }
+ assert_raise(JSON::ParserError) { JSON.parse('null') }
+ assert_equal nil, JSON.parse('null', :quirks_mode => true)
+ parser = JSON::Parser.new('null', :quirks_mode => true)
+ assert_equal true, parser.quirks_mode?
+ assert_equal nil, parser.parse
+ assert_raise(JSON::ParserError) { JSON.parse('false') }
+ assert_equal false, JSON.parse('false', :quirks_mode => true)
+ assert_raise(JSON::ParserError) { JSON.parse('true') }
+ assert_equal true, JSON.parse('true', :quirks_mode => true)
+ assert_raise(JSON::ParserError) { JSON.parse('23') }
+ assert_equal 23, JSON.parse('23', :quirks_mode => true)
+ assert_raise(JSON::ParserError) { JSON.parse('1') }
+ assert_equal 1, JSON.parse('1', :quirks_mode => true)
+ assert_raise(JSON::ParserError) { JSON.parse('3.141') }
+ assert_in_delta 3.141, JSON.parse('3.141', :quirks_mode => true), 1E-3
+ assert_raise(JSON::ParserError) { JSON.parse('18446744073709551616') }
+ assert_equal 2 ** 64, JSON.parse('18446744073709551616', :quirks_mode => true)
+ assert_raise(JSON::ParserError) { JSON.parse('"foo"') }
+ assert_equal 'foo', JSON.parse('"foo"', :quirks_mode => true)
+ assert_raise(JSON::ParserError) { JSON.parse('NaN', :allow_nan => true) }
+ assert JSON.parse('NaN', :quirks_mode => true, :allow_nan => true).nan?
+ assert_raise(JSON::ParserError) { JSON.parse('Infinity', :allow_nan => true) }
+ assert JSON.parse('Infinity', :quirks_mode => true, :allow_nan => true).infinite?
+ assert_raise(JSON::ParserError) { JSON.parse('-Infinity', :allow_nan => true) }
+ assert JSON.parse('-Infinity', :quirks_mode => true, :allow_nan => true).infinite?
+ assert_raise(JSON::ParserError) { JSON.parse('[ 1, ]', :quirks_mode => true) }
+ end
+
if Array.method_defined?(:permutation)
def test_parse_more_complex_arrays
a = [ nil, false, true, "foßbar", [ "n€st€d", true ], { "nested" => true, "n€ßt€ð2" => {} }]
diff --git a/tests/test_json_addition.rb b/tests/test_json_addition.rb
index a8181e8..9f578a4 100755
--- a/tests/test_json_addition.rb
+++ b/tests/test_json_addition.rb
@@ -3,7 +3,9 @@
require 'test/unit'
require File.join(File.dirname(__FILE__), 'setup_variant')
-load 'json/add/core.rb'
+require 'json/add/core'
+require 'json/add/complex'
+require 'json/add/rational'
require 'date'
class TC_JSONAddition < Test::Unit::TestCase
@@ -164,4 +166,9 @@ class TC_JSONAddition < Test::Unit::TestCase
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24))
assert_equal d, JSON.parse(d.to_json)
end
+
+ def test_rational_complex
+ assert_equal Rational(2, 9), JSON(JSON(Rational(2, 9)))
+ assert_equal Complex(2, 9), JSON(JSON(Complex(2, 9)))
+ end
end
diff --git a/tests/test_json_generate.rb b/tests/test_json_generate.rb
index 9b0cff4..da96603 100755
--- a/tests/test_json_generate.rb
+++ b/tests/test_json_generate.rb
@@ -50,6 +50,7 @@ EOT
parsed_json = parse(json)
assert_equal({"1"=>2}, parsed_json)
assert_raise(GeneratorError) { generate(666) }
+ assert_equal '666', generate(666, :quirks_mode => true)
end
def test_generate_pretty
@@ -67,6 +68,7 @@ EOT
parsed_json = parse(json)
assert_equal({"1"=>2}, parsed_json)
assert_raise(GeneratorError) { pretty_generate(666) }
+ assert_equal '666', pretty_generate(666, :quirks_mode => true)
end
def test_fast_generate
@@ -79,9 +81,24 @@ EOT
parsed_json = parse(json)
assert_equal({"1"=>2}, parsed_json)
assert_raise(GeneratorError) { fast_generate(666) }
+ assert_equal '666', fast_generate(666, :quirks_mode => true)
end
-
+ def test_own_state
+ state = State.new
+ json = generate(@hash, state)
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
+ parsed_json = parse(json)
+ assert_equal(@hash, parsed_json)
+ json = generate({1=>2}, state)
+ assert_equal('{"1":2}', json)
+ parsed_json = parse(json)
+ assert_equal({"1"=>2}, parsed_json)
+ assert_raise(GeneratorError) { generate(666, state) }
+ state.quirks_mode = true
+ assert state.quirks_mode?
+ assert_equal '666', generate(666, state)
+ end
def test_states
json = generate({1=>2}, nil)
@@ -107,6 +124,7 @@ EOT
:allow_nan => false,
:array_nl => "\n",
:ascii_only => false,
+ :quirks_mode => false,
:depth => 0,
:indent => " ",
:max_nesting => 19,
@@ -122,6 +140,7 @@ EOT
:allow_nan => false,
:array_nl => "",
:ascii_only => false,
+ :quirks_mode => false,
:depth => 0,
:indent => "",
:max_nesting => 19,
@@ -137,6 +156,7 @@ EOT
:allow_nan => false,
:array_nl => "",
:ascii_only => false,
+ :quirks_mode => false,
:depth => 0,
:indent => "",
:max_nesting => 0,
@@ -177,4 +197,17 @@ EOT
assert_raises(JSON::NestingError) { ary.to_json(s) }
assert_equal 19, s.depth
end
+
+ def test_gc
+ bignum_too_long_to_embed_as_string = 1234567890123456789012345
+ expect = bignum_too_long_to_embed_as_string.to_s
+ stress, GC.stress = GC.stress, true
+
+ 10.times do |i|
+ tmp = bignum_too_long_to_embed_as_string.to_json
+ assert_equal expect, tmp
+ end
+ ensure
+ GC.stress = stress
+ end if GC.respond_to?(:stress=)
end
diff --git a/tools/server.rb b/tools/server.rb
index 084377f..184a01c 100755
--- a/tools/server.rb
+++ b/tools/server.rb
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
+# encoding: utf-8
require 'webrick'
include WEBrick