jinx-json 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -1
- data/History.md +4 -0
- data/lib/jinx/json/date.rb +32 -0
- data/lib/jinx/json/deserializable.rb +17 -0
- data/lib/jinx/json/deserializer.rb +30 -3
- data/lib/jinx/json/serializable.rb +88 -0
- data/lib/jinx/json/set.rb +0 -0
- data/lib/jinx/json/state.rb +24 -0
- data/lib/jinx/json/version.rb +1 -1
- data/spec/serializer_spec.rb +27 -19
- data/spec/spec_helper.rb +2 -2
- metadata +9 -8
- data/Gemfile.lock +0 -43
- data/lib/jinx/json/serializer.rb +0 -90
- data/lib/jinx/json.rb +0 -1
data/Gemfile
CHANGED
@@ -4,6 +4,6 @@ gemspec
|
|
4
4
|
group :development do
|
5
5
|
gem 'ruby-debug'
|
6
6
|
# Uncomment to use a local gem.
|
7
|
-
gem 'jinx', :path => File.dirname(__FILE__) + '/../core'
|
7
|
+
#gem 'jinx', :path => File.dirname(__FILE__) + '/../core'
|
8
8
|
gem 'jinx-json', :path => File.dirname(__FILE__), :require => 'jinx/json'
|
9
9
|
end
|
data/History.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
This history lists major release themes. See the GitHub commits (https://github.com/jinx/json)
|
2
2
|
for change details.
|
3
3
|
|
4
|
+
2.1.2 / 2012-06-12
|
5
|
+
------------------
|
6
|
+
* Support caSmall web service.
|
7
|
+
|
4
8
|
2.1.1 / 2012-04-13
|
5
9
|
------------------
|
6
10
|
* Initial public release spun off from caruby/core.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'java'
|
3
|
+
|
4
|
+
class DateTime
|
5
|
+
# @param [String] json the JSON to deserialize
|
6
|
+
# @return [Date] the deserialized object
|
7
|
+
def self.json_create(json)
|
8
|
+
parse(json['data'])
|
9
|
+
end
|
10
|
+
|
11
|
+
# Adds JSON serialization to Ruby Date.
|
12
|
+
#
|
13
|
+
# @param args the JSON serialization options
|
14
|
+
# @return [String] the serialized date
|
15
|
+
def to_json(*args)
|
16
|
+
{
|
17
|
+
'json_class' => self.class.name,
|
18
|
+
'data' => to_s
|
19
|
+
}.to_json(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Java::JavaUtil::Date
|
24
|
+
# Adds JSON serialization to Java Date.
|
25
|
+
# The JSON is deserialized as a Ruby Date.
|
26
|
+
#
|
27
|
+
# @param args the JSON serialization options
|
28
|
+
# @return [String] the serialized date
|
29
|
+
def to_json(*args)
|
30
|
+
to_ruby_date.to_json(*args)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'jinx/helpers/hashable'
|
2
|
+
|
3
|
+
module Jinx
|
4
|
+
module JSON
|
5
|
+
# This Deserializable mix-in adds a {Deserializer} to each class which extends this module.
|
6
|
+
module Deserializable
|
7
|
+
def included(other)
|
8
|
+
super
|
9
|
+
if Class === other then
|
10
|
+
other.extend(Deserializer)
|
11
|
+
else
|
12
|
+
other.extend(Deserializable)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,16 +1,43 @@
|
|
1
1
|
require 'jinx/helpers/hashable'
|
2
2
|
|
3
|
+
module JSON
|
4
|
+
# Bumps the default JSON nesting level to 100.
|
5
|
+
def self.parse(source, opts={})
|
6
|
+
visited = Thread.current[:jinx_json_deserialized] ||= {}
|
7
|
+
opts = opts.merge(:max_nesting => 100) unless opts.has_key?(:max_nesting)
|
8
|
+
begin
|
9
|
+
Parser.new(source, opts).parse
|
10
|
+
ensure
|
11
|
+
visited.clear
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
3
16
|
module Jinx
|
4
17
|
module JSON
|
5
18
|
# JSON => {Jinx::Resource} deserializer.
|
6
19
|
#
|
7
|
-
# This Deserializer reconstitutes a jinxed object from a JSON string built
|
20
|
+
# This Deserializer reconstitutes a jinxed object from a JSON string built
|
21
|
+
# by a {Serializable}.
|
8
22
|
module Deserializer
|
9
23
|
# @param [String] json the JSON to deserialize
|
10
24
|
# @return [Jinx::Resource] the deserialized object
|
11
25
|
def json_create(json)
|
12
|
-
#
|
13
|
-
|
26
|
+
# the thread-local oid => object hash
|
27
|
+
visited = Thread.current[:jinx_json_deserialized]
|
28
|
+
# the payload
|
29
|
+
vh = json['data']
|
30
|
+
# the oid
|
31
|
+
oid = vh.delete('object_id')
|
32
|
+
# If the object has already been built, then return that object.
|
33
|
+
ref = visited[oid]
|
34
|
+
if ref then
|
35
|
+
# Fill in a place-holder with content.
|
36
|
+
ref.merge_attributes(vh) unless vh.empty?
|
37
|
+
return ref
|
38
|
+
end
|
39
|
+
# Make the new object from the attribute => value hash.
|
40
|
+
visited[oid] = new(vh)
|
14
41
|
end
|
15
42
|
end
|
16
43
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'jinx/json/state'
|
3
|
+
require 'jinx/json/collection'
|
4
|
+
require 'jinx/json/date'
|
5
|
+
require 'jinx/json/deserializable'
|
6
|
+
require 'jinx/json/deserializer'
|
7
|
+
|
8
|
+
module Jinx
|
9
|
+
module JSON
|
10
|
+
# Serializable is the JSON serializer {Jinx::Resource} mix-in.
|
11
|
+
#
|
12
|
+
# {#to_json} creates a JSON string from a jinxed object. The JSON payload is
|
13
|
+
# suitable for transfer to a remote {Deserializer}. This {Serializable} module
|
14
|
+
# is included directly in the jinxed application domain module after
|
15
|
+
# including {Jinx::Resource}, e.g.:
|
16
|
+
# module MyApp
|
17
|
+
# include Jinx::JSON::Serializable, Jinx:Resource
|
18
|
+
# which includes +Resource+ followed by the +Serializable+.
|
19
|
+
#
|
20
|
+
# The module which includes Serializable is extended with the {Importer}, which
|
21
|
+
# enables deserialization of the serialized JSON.
|
22
|
+
#
|
23
|
+
# The JSON payload is built as follows:
|
24
|
+
# * non-domain properties are serialized
|
25
|
+
# * dependent references are serialized recursively
|
26
|
+
# * independent reference primary and secondary key content is serialized
|
27
|
+
# * circular references are precluded by truncating the reference with a
|
28
|
+
# surrogate object id
|
29
|
+
module Serializable
|
30
|
+
def self.included(other)
|
31
|
+
super
|
32
|
+
if Class === other then
|
33
|
+
other.extend(Deserializer)
|
34
|
+
else
|
35
|
+
other.extend(Deserializable)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param [State, Hash, nil] state the JSON state or serialization options
|
40
|
+
# @return [String] the JSON representation of this {Jinx::Resource}
|
41
|
+
def to_json(state=nil)
|
42
|
+
# Make a new State from the options if this is a top-level call.
|
43
|
+
state = State.for(state) unless State === state
|
44
|
+
# the JSON content
|
45
|
+
{
|
46
|
+
'json_class' => json_class_name,
|
47
|
+
'data' => json_value_hash(state.visited)
|
48
|
+
}.to_json(state)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# The JSON class name must be scoped by the Resource package module, not the
|
54
|
+
# Java package, in order to recognize the Jinx::Resource JSON hooks.
|
55
|
+
#
|
56
|
+
# @return [String] the class name qualified by the Resource package module name context
|
57
|
+
def json_class_name
|
58
|
+
[self.class.domain_module, self.class.name.demodulize].join('::')
|
59
|
+
end
|
60
|
+
|
61
|
+
# Builds a serializable attribute => value hash with content as follows:
|
62
|
+
# * If this domain object has not yet been visited, then the hash includes all attributes,
|
63
|
+
# as well as the +Jinx::Resource#proxy_object_id+.
|
64
|
+
# * If this domain object has already been visited, then the hash includes only the
|
65
|
+
# +proxy_object_id+.
|
66
|
+
# Each +Set+ attribute value is converted to an array, since JSON does not serialize
|
67
|
+
# a +Set+ properly.
|
68
|
+
#
|
69
|
+
# The {Deserializer} is responsible for reconstituting the domain object graph from the
|
70
|
+
# serialized content.
|
71
|
+
#
|
72
|
+
# @param [<Resource>] visited the serialized objects
|
73
|
+
# @return [{Symbol => Object}] the serializable value hash
|
74
|
+
def json_value_hash(visited)
|
75
|
+
# If already visited, then the only content is the object id.
|
76
|
+
if visited.include?(self) then
|
77
|
+
return {:object_id => proxy_object_id}
|
78
|
+
end
|
79
|
+
visited << self
|
80
|
+
vh = value_hash
|
81
|
+
vh.each { |pa, v| vh[pa] = v.to_a if Set === v }
|
82
|
+
# Add the object id.
|
83
|
+
vh[:object_id] = proxy_object_id
|
84
|
+
vh
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
File without changes
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Jinx
|
4
|
+
module JSON
|
5
|
+
# This State module bumps the JSON default +:max_nesting+ to 100 and tracks
|
6
|
+
# the visited objects in a modified +JSON::Pure::Generator::State+.
|
7
|
+
module State
|
8
|
+
# @param [Hash, nil] opts the generator options
|
9
|
+
# return [State] the state for the given options
|
10
|
+
def self.for(opts)
|
11
|
+
opts ||= {}
|
12
|
+
opts[:max_nesting] ||= 100
|
13
|
+
state = ::JSON::Pure::Generator::State.from_state(opts)
|
14
|
+
class << state
|
15
|
+
# @return [<Jinx::JSON::Serializable>] the serialized objects
|
16
|
+
def visited
|
17
|
+
@visited ||= Set.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
state
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/jinx/json/version.rb
CHANGED
data/spec/serializer_spec.rb
CHANGED
@@ -2,28 +2,28 @@ require 'spec/spec_helper'
|
|
2
2
|
|
3
3
|
module Family
|
4
4
|
describe Address do
|
5
|
-
it
|
6
|
-
|
7
|
-
j = JSON[
|
8
|
-
j.street1.should ==
|
9
|
-
j.city.should ==
|
10
|
-
j.state.should ==
|
5
|
+
it 'should serialize an address' do
|
6
|
+
addr = Address.new(:street1 => '16 Elm St', :city => 'Peoria', :state => 'IL')
|
7
|
+
j = JSON[addr.to_json]
|
8
|
+
j.street1.should == addr.street1
|
9
|
+
j.city.should == addr.city
|
10
|
+
j.state.should == addr.state
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
describe Household do
|
15
|
-
it
|
16
|
-
|
17
|
-
|
18
|
-
j = JSON[
|
19
|
-
j.address.street1.should ==
|
20
|
-
j.address.city.should ==
|
21
|
-
j.address.state.should ==
|
15
|
+
it 'should serialize the address' do
|
16
|
+
addr = Address.new(:street1 => '16 Elm St', :city => 'Peoria', :state => 'IL')
|
17
|
+
hshd = Household.new(:address => addr)
|
18
|
+
j = JSON[hshd.to_json]
|
19
|
+
j.address.street1.should == addr.street1
|
20
|
+
j.address.city.should == addr.city
|
21
|
+
j.address.state.should == addr.state
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
describe Parent do
|
26
|
-
it
|
26
|
+
it 'should serialize the children' do
|
27
27
|
p = Parent.new(:name => 'Oscar')
|
28
28
|
c = Child.new(:name => 'Beauregard', :parents => [p])
|
29
29
|
p.children << c
|
@@ -33,14 +33,22 @@ module Family
|
|
33
33
|
end
|
34
34
|
|
35
35
|
describe Child do
|
36
|
-
it
|
37
|
-
|
38
|
-
p = Parent.new(:name => 'Oscar', :household =>
|
36
|
+
it 'should serialize the parent' do
|
37
|
+
hshd = Household.new
|
38
|
+
p = Parent.new(:name => 'Oscar', :household => hshd)
|
39
39
|
c = Child.new(:name => 'Beauregard', :parents => [p])
|
40
40
|
p.children << c
|
41
41
|
j = JSON[c.to_json]
|
42
|
-
j.parents.first.name.
|
43
|
-
j.parents.first.household.
|
42
|
+
j.parents.first.name.should_not be nil
|
43
|
+
j.parents.first.household.should_not be nil
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'Date' do
|
47
|
+
it 'should serialize a Java date as a Ruby date' do
|
48
|
+
date = Java.now
|
49
|
+
j = JSON[date.to_json]
|
50
|
+
j.should be_within(0.005).of(date.to_ruby_date)
|
51
|
+
end
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,8 +6,8 @@ Bundler.require(:test, :development)
|
|
6
6
|
require Bundler.environment.specs.detect { |s| s.name == 'jinx' }.full_gem_path + '/examples/family/lib/family'
|
7
7
|
|
8
8
|
# Add serialization
|
9
|
-
require 'jinx/json/
|
9
|
+
require 'jinx/json/serializable'
|
10
10
|
|
11
11
|
module Family
|
12
|
-
include Jinx::JSON::
|
12
|
+
include Jinx::JSON::Serializable
|
13
13
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: jinx-json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 2.1.
|
5
|
+
version: 2.1.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- OHSU
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
14
|
-
default_executable:
|
13
|
+
date: 2012-06-12 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: bundler
|
@@ -81,21 +80,22 @@ files:
|
|
81
80
|
- .rspec
|
82
81
|
- .yardopts
|
83
82
|
- Gemfile
|
84
|
-
- Gemfile.lock
|
85
83
|
- History.md
|
86
84
|
- LEGAL
|
87
85
|
- LICENSE
|
88
86
|
- README.md
|
89
87
|
- Rakefile
|
90
88
|
- jinx-json.gemspec
|
91
|
-
- lib/jinx/json.rb
|
92
89
|
- lib/jinx/json/collection.rb
|
90
|
+
- lib/jinx/json/date.rb
|
91
|
+
- lib/jinx/json/deserializable.rb
|
93
92
|
- lib/jinx/json/deserializer.rb
|
94
|
-
- lib/jinx/json/
|
93
|
+
- lib/jinx/json/serializable.rb
|
94
|
+
- lib/jinx/json/set.rb
|
95
|
+
- lib/jinx/json/state.rb
|
95
96
|
- lib/jinx/json/version.rb
|
96
97
|
- spec/serializer_spec.rb
|
97
98
|
- spec/spec_helper.rb
|
98
|
-
has_rdoc: yard
|
99
99
|
homepage: http://github.com/jinx/json
|
100
100
|
licenses:
|
101
101
|
- MIT
|
@@ -119,10 +119,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
119
|
requirements: []
|
120
120
|
|
121
121
|
rubyforge_project: jinx
|
122
|
-
rubygems_version: 1.
|
122
|
+
rubygems_version: 1.8.15
|
123
123
|
signing_key:
|
124
124
|
specification_version: 3
|
125
125
|
summary: Jinx JSON plug-in.
|
126
126
|
test_files:
|
127
127
|
- spec/serializer_spec.rb
|
128
128
|
- spec/spec_helper.rb
|
129
|
+
has_rdoc: yard
|
data/Gemfile.lock
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
jinx-json (2.1.1)
|
5
|
-
bundler
|
6
|
-
jinx
|
7
|
-
json_pure
|
8
|
-
|
9
|
-
PATH
|
10
|
-
remote: /Users/loneyf/workspace/jinx/core
|
11
|
-
specs:
|
12
|
-
jinx (2.1.1)
|
13
|
-
bundler
|
14
|
-
|
15
|
-
GEM
|
16
|
-
remote: http://rubygems.org/
|
17
|
-
specs:
|
18
|
-
columnize (0.3.6)
|
19
|
-
diff-lcs (1.1.3)
|
20
|
-
json_pure (1.6.3)
|
21
|
-
rake (0.9.2.2)
|
22
|
-
rspec (2.9.0)
|
23
|
-
rspec-core (~> 2.9.0)
|
24
|
-
rspec-expectations (~> 2.9.0)
|
25
|
-
rspec-mocks (~> 2.9.0)
|
26
|
-
rspec-core (2.9.0)
|
27
|
-
rspec-expectations (2.9.1)
|
28
|
-
diff-lcs (~> 1.1.3)
|
29
|
-
rspec-mocks (2.9.0)
|
30
|
-
ruby-debug (0.10.4)
|
31
|
-
columnize (>= 0.1)
|
32
|
-
ruby-debug-base (~> 0.10.4.0)
|
33
|
-
ruby-debug-base (0.10.4-java)
|
34
|
-
|
35
|
-
PLATFORMS
|
36
|
-
java
|
37
|
-
|
38
|
-
DEPENDENCIES
|
39
|
-
jinx!
|
40
|
-
jinx-json!
|
41
|
-
rake
|
42
|
-
rspec (>= 2.6)
|
43
|
-
ruby-debug
|
data/lib/jinx/json/serializer.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'jinx/json/collection'
|
3
|
-
|
4
|
-
module Jinx
|
5
|
-
module JSON
|
6
|
-
# {Jinx::Resource} => JSON serializer.
|
7
|
-
#
|
8
|
-
# This Serializer creates a JSON string from a jinxed object. The JSON payload is
|
9
|
-
# suitable for transfer to a remote {Deserializer}. This {Serializer} is included
|
10
|
-
# directly in the jinxed application domain module after including {Jinx::Resource},
|
11
|
-
# e.g.:
|
12
|
-
# module MyApp
|
13
|
-
# include Jinx::JSON::Serializer, Jinx:Resource
|
14
|
-
# which includes +Resource+ followed by the +Serializer+.
|
15
|
-
#
|
16
|
-
# The module which includes this Serializer is extended with the {Importer}, which
|
17
|
-
# enables deserialization of the serialized JSON.
|
18
|
-
#
|
19
|
-
# The JSON payload is built as follows:
|
20
|
-
# * non-domain properties are serialized
|
21
|
-
# * dependent references are serialized recursively
|
22
|
-
# * independent reference primary and secondary key content is serialized
|
23
|
-
module Serializer
|
24
|
-
# @param args the JSON serialization options
|
25
|
-
# @return [String] the JSON representation of this {Jinx::Resource}
|
26
|
-
def to_json(*args)
|
27
|
-
{
|
28
|
-
'json_class' => json_class_name,
|
29
|
-
'data' => json_value_hash
|
30
|
-
}.to_json(*args)
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
# The JSON class name must be scoped by the Resource package module, not the
|
36
|
-
# Java package, in order to recognize the Jinx::Resource JSON hooks.
|
37
|
-
#
|
38
|
-
# @return [String] the class name qualified by the Resource package module name context
|
39
|
-
def json_class_name
|
40
|
-
[self.class.domain_module, self.class.name.demodulize].join('::')
|
41
|
-
end
|
42
|
-
|
43
|
-
# Builds a serializable attribute => value hash. If _key_only _ is true, then only
|
44
|
-
# the key attributes are included in the hash. Otherwise, all properties are included
|
45
|
-
# in the hash.
|
46
|
-
#
|
47
|
-
# An independent or owner attribute value is a copy of the referenced domain object
|
48
|
-
# consisting of only the primary and secondary key attributes.
|
49
|
-
#
|
50
|
-
# @return [{Symbol => Object}] the serializable value hash
|
51
|
-
def json_value_hash
|
52
|
-
vh = value_hash(self.class.nondomain_attributes)
|
53
|
-
vh.merge!(value_hash(self.class.dependent_attributes))
|
54
|
-
self.class.independent_attributes.each do |ia|
|
55
|
-
ref = send(ia)
|
56
|
-
vh[ia] = json_independent_reference(ref) unless ref.nil_or_empty?
|
57
|
-
end
|
58
|
-
vh
|
59
|
-
end
|
60
|
-
|
61
|
-
# @param [Resource] the referenced object
|
62
|
-
# @return [Resource] a copy of the referenced object which only contains
|
63
|
-
# key property values
|
64
|
-
def json_independent_reference(ref)
|
65
|
-
return ref.map { |item| json_independent_reference(item) } if ref.collection?
|
66
|
-
vh = json_key_hash(ref)
|
67
|
-
ref.copy(vh) unless vh.empty?
|
68
|
-
end
|
69
|
-
|
70
|
-
# @param (see #json_independent_reference)
|
71
|
-
# @return [{Symbol => Object}, nil] the key attribute => value hash, or nil
|
72
|
-
# if there is no complete key
|
73
|
-
def json_key_hash(ref)
|
74
|
-
vh = ref.value_hash(ref.class.primary_key_attributes)
|
75
|
-
ref.class.secondary_key_attributes.each do |ka|
|
76
|
-
value = json_key_value(ref, ka)
|
77
|
-
vh[ka] = value if value
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# @param (see #json_independent_reference)
|
82
|
-
# @param [Symbol] the key value
|
83
|
-
# @return the key attribute value
|
84
|
-
def json_key_value(ref, attribute)
|
85
|
-
value = ref.send(attribute)
|
86
|
-
Resource === value ? json_independent_reference(value) : value
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
data/lib/jinx/json.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'json'
|