summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml6
-rw-r--r--java/src/json/ext/Generator.java29
-rwxr-xr-xjson-java.gemspec40
-rw-r--r--json.gemspec12
-rw-r--r--lib/json.rb2
-rw-r--r--lib/json/common.rb189
-rwxr-xr-xtests/json_generator_test.rb3
7 files changed, 203 insertions, 78 deletions
diff --git a/.travis.yml b/.travis.yml
index 920a4ac..78b19dd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,14 +13,12 @@ rvm:
- 2.6
- 2.7.0-preview3
- ruby-head
- - jruby
- - jruby-9.2.7.0
+ - jruby-9.1 # Ruby 2.3
+ - jruby-9.2 # Ruby 2.5
- truffleruby
matrix:
allow_failures:
- rvm: ruby-head
- - rvm: jruby
- - rvm: jruby-9.2.7.0
- rvm: truffleruby
script: "bundle exec rake"
sudo: false
diff --git a/java/src/json/ext/Generator.java b/java/src/json/ext/Generator.java
index cd23c73..914d00e 100644
--- a/java/src/json/ext/Generator.java
+++ b/java/src/json/ext/Generator.java
@@ -10,13 +10,10 @@ import org.jruby.RubyArray;
import org.jruby.RubyBasicObject;
import org.jruby.RubyBignum;
import org.jruby.RubyBoolean;
-import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyHash;
-import org.jruby.RubyNumeric;
import org.jruby.RubyString;
-import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
@@ -32,8 +29,7 @@ public final class Generator {
static <T extends IRubyObject> RubyString
generateJson(ThreadContext context, T object,
Handler<? super T> handler, IRubyObject[] args) {
- Session session = new Session(context, args.length > 0 ? args[0]
- : null);
+ Session session = new Session(context, args.length > 0 ? args[0] : null);
return session.infect(handler.generateNew(session, object));
}
@@ -43,7 +39,7 @@ public final class Generator {
*/
static <T extends IRubyObject> RubyString
generateJson(ThreadContext context, T object, IRubyObject[] args) {
- Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
+ Handler<? super T> handler = getHandlerFor(context.runtime, object);
return generateJson(context, object, handler, args);
}
@@ -55,33 +51,18 @@ public final class Generator {
generateJson(ThreadContext context, T object,
GeneratorState config) {
Session session = new Session(context, config);
- Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
+ Handler<? super T> handler = getHandlerFor(context.runtime, object);
return handler.generateNew(session, object);
}
- // NOTE: drop this once Ruby 1.9.3 support is gone!
- private static final int FIXNUM = 1;
- private static final int BIGNUM = 2;
- private static final int ARRAY = 3;
- private static final int STRING = 4;
- private static final int NIL = 5;
- private static final int TRUE = 6;
- private static final int FALSE = 7;
- private static final int HASH = 10;
- private static final int FLOAT = 11;
- // hard-coded due JRuby 1.7 compatibility
- // https://github.com/jruby/jruby/blob/1.7.27/core/src/main/java/org/jruby/runtime/ClassIndex.java
-
/**
* Returns the best serialization handler for the given object.
*/
// Java's generics can't handle this satisfactorily, so I'll just leave
// the best I could get and ignore the warnings
@SuppressWarnings("unchecked")
- private static <T extends IRubyObject>
- Handler<? super T> getHandlerFor(Ruby runtime, T object) {
- switch (((RubyBasicObject) object).getNativeTypeIndex()) {
- // can not use getNativeClassIndex due 1.7 compatibility
+ private static <T extends IRubyObject> Handler<? super T> getHandlerFor(Ruby runtime, T object) {
+ switch (((RubyBasicObject) object).getNativeClassIndex()) {
case NIL : return (Handler) NIL_HANDLER;
case TRUE : return (Handler) TRUE_HANDLER;
case FALSE : return (Handler) FALSE_HANDLER;
diff --git a/json-java.gemspec b/json-java.gemspec
index 1bcd639..78cf9c9 100755
--- a/json-java.gemspec
+++ b/json-java.gemspec
@@ -1,33 +1,35 @@
-#!/usr/bin/env jruby
-require "rubygems"
+# -*- encoding: utf-8 -*-
spec = Gem::Specification.new do |s|
s.name = "json"
s.version = File.read("VERSION").chomp
- s.summary = "JSON implementation for JRuby"
+
+ s.summary = "JSON Implementation for Ruby"
s.description = "A JSON implementation as a JRuby extension."
+ s.licenses = ["Ruby"]
s.author = "Daniel Luz"
s.email = "dev+ruby@mernen.com"
- s.homepage = "http://flori.github.com/json"
- s.platform = 'java'
s.licenses = ["Ruby"]
+ s.platform = 'java'
+
s.files = Dir["{docs,lib,tests}/**/*"]
- if s.respond_to? :specification_version then
- s.specification_version = 4
-
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
- s.add_development_dependency(%q<rake>, [">= 0"])
- s.add_development_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
- else
- s.add_dependency(%q<rake>, [">= 0"])
- s.add_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
- end
- else
- s.add_dependency(%q<rake>, [">= 0"])
- s.add_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
- end
+ s.homepage = "http://flori.github.com/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/',
+ 'source_code_uri' => 'https://github.com/flori/json',
+ 'wiki_uri' => 'https://github.com/flori/json/wiki'
+ }
+
+ s.required_ruby_version = Gem::Requirement.new(">= 2.0")
+ s.test_files = ["tests/test_helper.rb"]
+
+ s.add_development_dependency("rake", [">= 0"])
+ s.add_development_dependency("test-unit", [">= 2.0", "< 4.0"])
end
if $0 == __FILE__
diff --git a/json.gemspec b/json.gemspec
index 0c72e82..8870f88 100644
--- a/json.gemspec
+++ b/json.gemspec
@@ -4,13 +4,15 @@ Gem::Specification.new do |s|
s.name = "json"
s.version = File.read('VERSION').chomp
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
- s.require_paths = ["lib"]
- s.authors = ["Florian Frank"]
+ s.summary = "JSON Implementation for Ruby"
s.description = "This is a JSON implementation as a Ruby extension in C."
+ s.licenses = ["Ruby"]
+ s.authors = ["Florian Frank"]
s.email = "flori@ping.de"
+
s.extensions = ["ext/json/ext/generator/extconf.rb", "ext/json/ext/parser/extconf.rb", "ext/json/extconf.rb"]
s.extra_rdoc_files = ["README.md"]
+ s.rdoc_options = ["--title", "JSON implemention for Ruby", "--main", "README.md"]
s.files = [
".gitignore",
".travis.yml",
@@ -128,10 +130,8 @@ Gem::Specification.new do |s|
'source_code_uri' => 'https://github.com/flori/json',
'wiki_uri' => 'https://github.com/flori/json/wiki'
}
- s.licenses = ["Ruby"]
- s.rdoc_options = ["--title", "JSON implemention for Ruby", "--main", "README.md"]
+
s.required_ruby_version = Gem::Requirement.new(">= 2.0")
- s.summary = "JSON Implementation for Ruby"
s.test_files = ["tests/test_helper.rb"]
s.add_development_dependency("rake", [">= 0"])
diff --git a/lib/json.rb b/lib/json.rb
index 6bb8224..aeb9774 100644
--- a/lib/json.rb
+++ b/lib/json.rb
@@ -319,7 +319,7 @@ require 'json/common'
# opts = {
# array_nl: "\n",
# object_nl: "\n",
-# indent+: ' ',
+# indent: ' ',
# space_before: ' ',
# space: ' '
# }
diff --git a/lib/json/common.rb b/lib/json/common.rb
index ed4e047..f6230a7 100644
--- a/lib/json/common.rb
+++ b/lib/json/common.rb
@@ -4,13 +4,16 @@ require 'json/generic_object'
module JSON
class << self
+ # :call-seq:
+ # JSON[object] -> new_array or new_string
+ #
# If +object+ is a
- # {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects]
- # (implementing +to_str+), calls JSON.parse with +object+ and +opts+:
+ # {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects],
+ # calls JSON.parse with +object+ and +opts+ (see method #parse):
# json = '[0, 1, null]'
# JSON[json]# => [0, 1, nil]
#
- # Otherwise, calls JSON.generate with +object+ and +opts+:
+ # Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
# ruby = [0, 1, nil]
# JSON[ruby] # => '[0,1,null]'
def [](object, opts = {})
@@ -171,10 +174,24 @@ module JSON
# For examples of parsing for all \JSON data types, see
# {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
#
- # ====== Exceptions
+ # Parses nested JSON objects:
+ # source = <<-EOT
+ # {
+ # "name": "Dave",
+ # "age" :40,
+ # "hats": [
+ # "Cattleman's",
+ # "Panama",
+ # "Tophat"
+ # ]
+ # }
+ # EOT
+ # ruby = JSON.parse(source)
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
#
- # Raises an exception if +source+ is not valid JSON:
+ # ---
#
+ # Raises an exception if +source+ is not valid JSON:
# # Raises JSON::ParserError (783: unexpected token at ''):
# JSON.parse('')
#
@@ -201,12 +218,24 @@ module JSON
Parser.new(source, **(opts||{})).parse
end
- # Parses the content of a file (see parse method documentation for more information).
+ # :call-seq:
+ # CSV.load_file(path, opts={}) -> object
+ #
+ # Calls:
+ # parse(File.read(path), opts)
+ #
+ # See method #parse.
def load_file(filespec, opts = {})
parse(File.read(filespec), opts)
end
- # Parses the content of a file (see parse! method documentation for more information).
+ # :call-seq:
+ # CSV.load_file!(path, opts = {})
+ #
+ # Calls:
+ # CSV.parse!(File.read(path, opts))
+ #
+ # See method #parse!
def load_file!(filespec, opts = {})
parse!(File.read(filespec), opts)
end
@@ -247,8 +276,6 @@ module JSON
#
# Raises an exception if any formatting option is not a \String.
#
- # ====== Exceptions
- #
# Raises an exception if +obj+ contains circular references:
# a = []; b = []; a.push(b); b.push(a)
# # Raises JSON::NestingError (nesting of 100 is too deep):
@@ -280,6 +307,9 @@ module JSON
module_function :unparse
# :startdoc:
+ # :call-seq:
+ # JSON.fast_generate(obj, opts) -> new_string
+ #
# Arguments +obj+ and +opts+ here are the same as
# arguments +obj+ and +opts+ in JSON.generate.
#
@@ -384,20 +414,135 @@ module JSON
:create_additions => true,
}
- # 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
- # 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. To modify the
- # default options pass in the optional _options_ argument as well.
+ # :call-seq:
+ # JSON.load(source, proc = nil, options = {}) -> object
#
- # BEWARE: This method is meant to serialise data from trusted user input,
- # like from your own database server or clients under your control, it could
- # be dangerous to allow untrusted users to pass JSON sources into it. The
- # default options for the parser can be changed via the load_default_options
- # method.
+ # Returns the Ruby objects created by parsing the given +source+.
+ #
+ # - Argument +source+ must be, or be convertible to, a \String:
+ # - If +source+ responds to instance method +to_str+,
+ # <tt>source.to_str</tt> becomes the source.
+ # - If +source+ responds to instance method +to_io+,
+ # <tt>source.to_io.read</tt> becomes the source.
+ # - If +source+ responds to instance method +read+,
+ # <tt>source.read</tt> becomes the source.
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
+ # - Option +allow_blank+ specifies a truthy value.
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
+ # - Otherwise, +source+ remains the source.
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
+ # It will be called recursively with each result (depth-first order).
+ # See details below.
+ # BEWARE: This method is meant to serialise data from trusted user input,
+ # like from your own database server or clients under your control, it could
+ # be dangerous to allow untrusted users to pass JSON sources into it.
+ # - Argument +opts+, if given, contains options for the parsing, and must be a
+ # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash+Convertible+Objects].
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
+ # The default options can be changed via method JSON.load_default_options=.
+ #
+ # ---
+ #
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
+ # <tt>parse(source, opts)</tt>; see #parse.
+ #
+ # Source for following examples:
+ # source = <<-EOT
+ # {
+ # "name": "Dave",
+ # "age" :40,
+ # "hats": [
+ # "Cattleman's",
+ # "Panama",
+ # "Tophat"
+ # ]
+ # }
+ # EOT
+ #
+ # Load a \String:
+ # ruby = JSON.load(source)
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
+ #
+ # Load an \IO object:
+ # require 'stringio'
+ # object = JSON.load(StringIO.new(source))
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
+ #
+ # Load a \File object:
+ # path = 't.json'
+ # File.write(path, source)
+ # File.open(path) do |file|
+ # JSON.load(file)
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
+ #
+ # ---
+ #
+ # When +proc+ is given:
+ # - Modifies +source+ as above.
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
+ # - Recursively calls <tt>proc(result)</tt>.
+ # - Returns the final result.
+ #
+ # Example:
+ # require 'json'
+ #
+ # # Some classes for the example.
+ # class Base
+ # def initialize(attributes)
+ # @attributes = attributes
+ # end
+ # end
+ # class User < Base; end
+ # class Account < Base; end
+ # class Admin < Base; end
+ # # The JSON source.
+ # json = <<-EOF
+ # {
+ # "users": [
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
+ # {"type": "User", "username": "john", "email": "john@example.com"}
+ # ],
+ # "accounts": [
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
+ # ],
+ # "admins": {"type": "Admin", "password": "0wn3d"}
+ # }
+ # EOF
+ # # Deserializer method.
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
+ # type = obj.is_a?(Hash) && obj["type"]
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
+ # end
+ # # Call to JSON.load
+ # ruby = JSON.load(json, proc {|obj|
+ # case obj
+ # when Hash
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
+ # when Array
+ # obj.map! {|v| deserialize_obj v }
+ # end
+ # })
+ # pp ruby
+ # Output:
+ # {"users"=>
+ # [#<User:0x00000000064c4c98
+ # @attributes=
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
+ # #<User:0x00000000064c4bd0
+ # @attributes=
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
+ # "accounts"=>
+ # [{"account"=>
+ # #<Account:0x00000000064c4928
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
+ # {"account"=>
+ # #<Account:0x00000000064c4680
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
+ # "admins"=>
+ # #<Admin:0x00000000064c41f8
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
#
- # This method is part of the implementation of the load/dump interface of
- # Marshal and YAML.
def load(source, proc = nil, options = {})
opts = load_default_options.merge options
if source.respond_to? :to_str
@@ -416,7 +561,7 @@ module JSON
end
# Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
- def recurse_proc(result, &proc)
+ def recurse_proc(result, &proc) # :nodoc:
case result
when Array
result.each { |x| recurse_proc x, &proc }
diff --git a/tests/json_generator_test.rb b/tests/json_generator_test.rb
index 13d3b5a..77b539d 100755
--- a/tests/json_generator_test.rb
+++ b/tests/json_generator_test.rb
@@ -49,7 +49,6 @@ EOT
end
def test_remove_const_segv
- return if RUBY_ENGINE == 'jruby'
stress = GC.stress
const = JSON::SAFE_STATE_PROTOTYPE.dup
@@ -76,7 +75,7 @@ EOT
silence do
JSON.const_set :SAFE_STATE_PROTOTYPE, const
end
- end if JSON.const_defined?("Ext")
+ end if JSON.const_defined?("Ext") && RUBY_ENGINE != 'jruby'
def test_generate
json = generate(@hash)