diff options
-rw-r--r-- | .all_images.yml | 17 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 44 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | CHANGES.md | 24 | ||||
-rw-r--r-- | Gemfile | 1 | ||||
-rw-r--r-- | README-json-jruby.md | 2 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | Rakefile | 2 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | ext/json/ext/generator/generator.c | 4 | ||||
-rw-r--r-- | ext/json/ext/parser/parser.c | 23 | ||||
-rw-r--r-- | ext/json/ext/parser/parser.rl | 23 | ||||
-rw-r--r-- | java/src/json/ext/Generator.java | 6 | ||||
-rw-r--r-- | json-java.gemspec | 6 | ||||
-rw-r--r-- | json.gemspec | 6 | ||||
-rw-r--r-- | json_pure.gemspec | 6 | ||||
-rw-r--r-- | lib/json/pure/parser.rb | 2 | ||||
-rw-r--r-- | lib/json/version.rb | 2 | ||||
-rw-r--r-- | tests/json_addition_test.rb | 2 | ||||
-rw-r--r-- | tests/json_parser_test.rb | 5 |
20 files changed, 129 insertions, 58 deletions
diff --git a/.all_images.yml b/.all_images.yml new file mode 100644 index 0000000..9178beb --- /dev/null +++ b/.all_images.yml @@ -0,0 +1,17 @@ +dockerfile: |- + RUN apk add --no-cache build-base git ragel + RUN gem update --system + RUN gem install gem_hadar bundler +script: &script |- + echo -e "\e[1m" + ruby -v + echo -e "\e[0m" + bundle + rake clean test + +images: + ruby:3.1-alpine: *script + ruby:3.0-alpine: *script + ruby:2.7-alpine: *script + ruby:2.6-alpine: *script + ruby:2.5-alpine: *script diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ed36dc..3074be5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,9 +3,16 @@ name: CI on: - push - pull_request +- workflow_dispatch jobs: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + min_version: 2.3 + host: + needs: ruby-versions name: ${{ matrix.os }} ${{ matrix.ruby }} runs-on: ${{ matrix.os }} strategy: @@ -13,35 +20,32 @@ jobs: matrix: os: - ubuntu-20.04 - - ubuntu-18.04 - - macos-11.0 - - macos-10.15 + - ubuntu-22.04 + - macos-11 + - macos-12 - windows-latest - ruby: - - '3.0' - - 2.7 - - 2.6 - - 2.5 - - 2.4 - - 2.3 + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} include: - { os: ubuntu-latest , ruby: jruby-9.1 } # Ruby 2.3 - { os: ubuntu-latest , ruby: jruby-9.2 } # Ruby 2.5 - - { os: ubuntu-latest , ruby: truffleruby } + - { os: ubuntu-latest , ruby: jruby-9.3 } # Ruby 2.7 + exclude: + - { os: windows-latest, ruby: truffleruby } + - { os: windows-latest, ruby: truffleruby-head } + - { os: windows-latest, ruby: jruby } + - { os: windows-latest, ruby: jruby-head } steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby-pkgs@v1 with: ruby-version: ${{ matrix.ruby }} - - - run: sudo apt install ragel - if: ${{ startsWith(matrix.os, 'ubuntu') }} - - - run: brew install ragel - if: ${{ startsWith(matrix.os, 'macos') }} + apt-get: ragel + brew: ragel + # only needed for Ruby 2.3 + mingw: ragel - run: bundle install @@ -52,4 +56,4 @@ jobs: - run: rake build - run: gem install pkg/*.gem - + if: ${{ matrix.ruby != '3.2' }} @@ -14,5 +14,7 @@ Gemfile.lock .DS_Store */**/Makefile */**/*.o +*/**/*.class +*/**/*.jar .byebug_history *.log @@ -1,5 +1,16 @@ # Changes +### 2021-10-24 (2.6.1) + +* Restore version.rb with 2.6.1 + +### 2021-10-14 (2.6.0) + +* Use `rb_enc_interned_str` if available to reduce allocations in `freeze: true` mode. #451. +* Bump required_ruby_version to 2.3. +* Fix compatibility with `GC.compact`. +* Fix some compilation warnings. #469 + ## 2020-12-22 (2.5.1) * Restore the compatibility for constants of JSON class. @@ -94,6 +105,19 @@ I changed these mentions to be consistent with the Ruby license setting in the gemspec files which were already correct now. +## 2017-01-13 (1.8.6) + * Be compatible with ancient ruby 1.8 (maybe?) + +## 2015-09-11 (1.8.5) + * Be compatible with ruby 2.4.0 + * There were still some mentions of dual GPL licensing in the source, but JSON + has just the Ruby license that itself includes an explicit dual-licensing + clause that allows covered software to be distributed under the terms of + the Simplified BSD License instead for all ruby versions >= 1.9.3. This is + however a GPL compatible license according to the Free Software Foundation. + I changed these mentions to be consistent with the Ruby license setting in + the gemspec files which were already correct now. + ## 2015-06-01 (1.8.3) * Fix potential memory leak, thx to nobu. @@ -15,3 +15,4 @@ end gem "rake" gem "test-unit" +gem "all_images", "~> 0" diff --git a/README-json-jruby.md b/README-json-jruby.md index 1336837..7ea4f0f 100644 --- a/README-json-jruby.md +++ b/README-json-jruby.md @@ -23,7 +23,7 @@ Its path must be set on the `jruby.dir` property of `nbproject/project.properties` (defaults to `../jruby`). Additionally, you'll need [Ant](http://ant.apache.org/), and -[Ragel](http://www.cs.queensu.ca/~thurston/ragel/) 6.4 or greater. +[Ragel](http://www.colm.net/open-source/ragel/) 6.4 or greater. Then, from the folder where the sources are located, type: @@ -12,8 +12,7 @@ will be two variants available: extensions, which are both part of the ruby standard library. * The quite a bit faster native extension variant, which is in parts implemented in C or Java and comes with its own unicode conversion - functions and a parser generated by the ragel state machine compiler - http://www.complang.org/ragel/ . + functions and a parser generated by the [Ragel] state machine compiler. Both variants of the JSON generator generate UTF-8 character sequences by default. If an :ascii\_only option with a true value is given, they escape all @@ -71,8 +70,7 @@ with: ## Compiling the extensions yourself If you want to create the `parser.c` file from its `parser.rl` file or draw nice -graphviz images of the state machines, you need ragel from: -http://www.complang.org/ragel/ +graphviz images of the state machines, you need [Ragel]. ## Usage @@ -423,3 +421,5 @@ The latest version of this library can be downloaded at Online Documentation should be located at * https://www.rubydoc.info/gems/json + +[Ragel]: http://www.colm.net/open-source/ragel/ @@ -155,7 +155,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby' 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.6', '-target', '1.6', src + sh 'javac', '-classpath', classpath, '-source', '1.8', '-target', '1.8', src end JAVA_CLASSES << obj end @@ -1 +1 @@ -2.5.1 +2.6.3 diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 711b7b8..8f7c57e 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -998,10 +998,10 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St if (!allow_nan) { if (isinf(value)) { fbuffer_free(buffer); - rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp)); + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp)); } else if (isnan(value)) { fbuffer_free(buffer); - rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp)); + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp)); } } fbuffer_append_str(buffer, tmp); diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index b1dc881..9bd7f19 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -948,7 +948,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); } } np = JSON_parse_float(json, p, pe, result); @@ -990,7 +990,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul if (json->allow_nan) { *result = CInfinity; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8); } } @@ -1002,7 +1002,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul if (json->allow_nan) { *result = CNaN; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2); } } @@ -2348,7 +2348,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if(cs >= JSON_array_first_final) { return p + 1; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return NULL; } } @@ -2363,9 +2363,17 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int char buf[4]; if (bufferSize > MAX_STACK_BUFFER_SIZE) { +# ifdef HAVE_RB_ENC_INTERNED_STR + bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1); +# else bufferStart = buffer = ALLOC_N(char, bufferSize); +# endif } else { +# ifdef HAVE_RB_ENC_INTERNED_STR + bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1); +# else bufferStart = buffer = ALLOCA_N(char, bufferSize); +# endif } while (pe < stringEnd) { @@ -2405,7 +2413,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p + "incomplete unicode character escape sequence at '%s'", p ); } else { UTF32 ch = unescape_unicode((unsigned char *) ++pe); @@ -2418,7 +2426,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete surrogate pair at '%s'", __LINE__, p + "incomplete surrogate pair at '%s'", p ); } if (pe[0] == '\\' && pe[1] == 'u') { @@ -2950,6 +2958,7 @@ static const char MAYBE_UNUSED(_JSON_nfa_pop_trans)[] = { * * Parses the current JSON text _source_ and returns the complete data * structure as a result. +* It raises JSON::ParseError if fail to parse. */ static VALUE cParser_parse(VALUE self) { @@ -3216,7 +3225,7 @@ static VALUE cParser_parse(VALUE self) if (cs >= JSON_first_final && p == pe) { return result; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return Qnil; } } diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index f7be1a5..2dbdc7e 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -222,14 +222,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (json->allow_nan) { *result = CNaN; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2); } } action parse_infinity { if (json->allow_nan) { *result = CInfinity; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8); } } action parse_string { @@ -245,7 +245,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu fexec p + 10; fhold; fbreak; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); } } np = JSON_parse_float(json, fpc, pe, result); @@ -447,7 +447,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if(cs >= JSON_array_first_final) { return p + 1; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return NULL; } } @@ -462,9 +462,17 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int char buf[4]; if (bufferSize > MAX_STACK_BUFFER_SIZE) { +# ifdef HAVE_RB_ENC_INTERNED_STR + bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1); +# else bufferStart = buffer = ALLOC_N(char, bufferSize); +# endif } else { +# ifdef HAVE_RB_ENC_INTERNED_STR + bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1); +# else bufferStart = buffer = ALLOCA_N(char, bufferSize); +# endif } while (pe < stringEnd) { @@ -504,7 +512,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p + "incomplete unicode character escape sequence at '%s'", p ); } else { UTF32 ch = unescape_unicode((unsigned char *) ++pe); @@ -517,7 +525,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete surrogate pair at '%s'", __LINE__, p + "incomplete surrogate pair at '%s'", p ); } if (pe[0] == '\\' && pe[1] == 'u') { @@ -839,6 +847,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) * * Parses the current JSON text _source_ and returns the complete data * structure as a result. + * It raises JSON::ParseError if fail to parse. */ static VALUE cParser_parse(VALUE self) { @@ -855,7 +864,7 @@ static VALUE cParser_parse(VALUE self) if (cs >= JSON_first_final && p == pe) { return result; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return Qnil; } } diff --git a/java/src/json/ext/Generator.java b/java/src/json/ext/Generator.java index fc17640..6a99686 100644 --- a/java/src/json/ext/Generator.java +++ b/java/src/json/ext/Generator.java @@ -292,7 +292,7 @@ public final class Generator { buffer.append(delim); } buffer.append(shift); - Handler<IRubyObject> handler = getHandlerFor(runtime, element); + Handler<IRubyObject> handler = (Handler<IRubyObject>) getHandlerFor(runtime, element); handler.generate(session, element, buffer); } @@ -354,7 +354,7 @@ public final class Generator { buffer.append((byte)':'); buffer.append(space); - Handler<IRubyObject> valueHandler = getHandlerFor(runtime, value); + Handler<IRubyObject> valueHandler = (Handler<IRubyObject>) getHandlerFor(runtime, value); valueHandler.generate(session, value, buffer); session.infectBy(value); } @@ -362,8 +362,8 @@ public final class Generator { state.decreaseDepth(); if (!firstPair[0] && objectNl.length() != 0) { buffer.append(objectNl); - buffer.append(Utils.repeat(state.getIndent(), state.getDepth())); } + buffer.append(Utils.repeat(state.getIndent(), state.getDepth())); buffer.append((byte)'}'); } }; diff --git a/json-java.gemspec b/json-java.gemspec index 1ddfdc9..87d8c87 100644 --- a/json-java.gemspec +++ b/json-java.gemspec @@ -14,12 +14,12 @@ spec = Gem::Specification.new do |s| s.files = Dir["lib/**/*", "LICENSE"] - s.homepage = "http://flori.github.com/json" + s.homepage = "https://flori.github.io/json" s.metadata = { 'bug_tracker_uri' => 'https://github.com/flori/json/issues', 'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md', - 'documentation_uri' => 'http://flori.github.io/json/doc/index.html', - 'homepage_uri' => 'http://flori.github.io/json/', + 'documentation_uri' => 'https://flori.github.io/json/doc/index.html', + 'homepage_uri' => s.homepage, 'source_code_uri' => 'https://github.com/flori/json', 'wiki_uri' => 'https://github.com/flori/json/wiki' } diff --git a/json.gemspec b/json.gemspec index 948e92c..f4b2ae7 100644 --- a/json.gemspec +++ b/json.gemspec @@ -53,12 +53,12 @@ Gem::Specification.new do |s| "lib/json/pure/parser.rb", "lib/json/version.rb", ] - s.homepage = "http://flori.github.com/json" + s.homepage = "https://flori.github.io/json" s.metadata = { 'bug_tracker_uri' => 'https://github.com/flori/json/issues', 'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md', - 'documentation_uri' => 'http://flori.github.io/json/doc/index.html', - 'homepage_uri' => 'http://flori.github.io/json/', + 'documentation_uri' => 'https://flori.github.io/json/doc/index.html', + 'homepage_uri' => s.homepage, 'source_code_uri' => 'https://github.com/flori/json', 'wiki_uri' => 'https://github.com/flori/json/wiki' } diff --git a/json_pure.gemspec b/json_pure.gemspec index e6e2914..883beb0 100644 --- a/json_pure.gemspec +++ b/json_pure.gemspec @@ -41,12 +41,12 @@ Gem::Specification.new do |s| "lib/json/pure/parser.rb".freeze, "lib/json/version.rb".freeze, ] - s.homepage = "http://flori.github.com/json".freeze + s.homepage = "https://flori.github.io/json".freeze s.metadata = { 'bug_tracker_uri' => 'https://github.com/flori/json/issues', 'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md', - 'documentation_uri' => 'http://flori.github.io/json/doc/index.html', - 'homepage_uri' => 'http://flori.github.io/json/', + 'documentation_uri' => 'https://flori.github.io/json/doc/index.html', + 'homepage_uri' => s.homepage, 'source_code_uri' => 'https://github.com/flori/json', 'wiki_uri' => 'https://github.com/flori/json/wiki' } diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb index e1d701b..be48c60 100644 --- a/lib/json/pure/parser.rb +++ b/lib/json/pure/parser.rb @@ -179,7 +179,7 @@ module JSON bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16) i += 1 end - JSON.iconv('utf-8', 'utf-16be', bytes) + JSON.iconv('utf-8', 'utf-16be', bytes).force_encoding(::Encoding::ASCII_8BIT) end end if string.respond_to?(:force_encoding) diff --git a/lib/json/version.rb b/lib/json/version.rb index 7a72272..3d4326d 100644 --- a/lib/json/version.rb +++ b/lib/json/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module JSON # JSON version - VERSION = '2.5.1' + VERSION = '2.6.3' 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/json_addition_test.rb b/tests/json_addition_test.rb index e95ace8..614c735 100644 --- a/tests/json_addition_test.rb +++ b/tests/json_addition_test.rb @@ -165,7 +165,7 @@ class JSONAdditionTest < Test::Unit::TestCase def test_utc_datetime now = Time.now - d = DateTime.parse(now.to_s, :create_additions => true) # usual case + d = DateTime.parse(now.to_s) # usual case assert_equal d, parse(d.to_json, :create_additions => true) d = DateTime.parse(now.utc.to_s) # of = 0 assert_equal d, parse(d.to_json, :create_additions => true) diff --git a/tests/json_parser_test.rb b/tests/json_parser_test.rb index dce693e..146ff7c 100644 --- a/tests/json_parser_test.rb +++ b/tests/json_parser_test.rb @@ -84,6 +84,7 @@ class JSONParserTest < Test::Unit::TestCase assert_equal({ "a" => 23 }, parse(' { "a" : 23 } ')) assert_equal({ "a" => 0.23 }, parse(' { "a" : 0.23 } ')) assert_equal({ "a" => 0.23 }, parse(' { "a" : 0.23 } ')) + assert_equal({ "" => 123 }, parse('{"":123}')) end def test_parse_numbers @@ -114,6 +115,10 @@ class JSONParserTest < Test::Unit::TestCase assert_equal(BigDecimal("0.901234567890123456789E1"),JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"] ) end + def test_parse_string_mixed_unicode + assert_equal(["éé"], JSON.parse("[\"\\u00e9é\"]")) + 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" => {} }] |