jinx-json 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
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 by a {Serializer}.
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
- # Make the new object from the json data attribute => value hash.
13
- new(json['data'])
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
@@ -1,5 +1,5 @@
1
1
  module Jinx
2
2
  module JSON
3
- VERSION = "2.1.1"
3
+ VERSION = '2.1.2'
4
4
  end
5
5
  end
@@ -2,28 +2,28 @@ require 'spec/spec_helper'
2
2
 
3
3
  module Family
4
4
  describe Address do
5
- it "should serialize an address" do
6
- a = Address.new(:street1 => '16 Elm St', :city => 'Peoria', :state => 'IL')
7
- j = JSON[a.to_json]
8
- j.street1.should == a.street1
9
- j.city.should == a.city
10
- j.state.should == a.state
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 "should serialize the address" do
16
- a = Address.new(:street1 => '16 Elm St', :city => 'Peoria', :state => 'IL')
17
- h = Household.new(:address => a)
18
- j = JSON[h.to_json]
19
- j.address.street1.should == a.street1
20
- j.address.city.should == a.city
21
- j.address.state.should == a.state
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 "should serialize the children" do
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 "should only serialize the owner key" do
37
- h = Household.new
38
- p = Parent.new(:name => 'Oscar', :household => h)
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.should be nil
43
- j.parents.first.household.should be nil
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/serializer'
9
+ require 'jinx/json/serializable'
10
10
 
11
11
  module Family
12
- include Jinx::JSON::Serializer
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.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-04-13 00:00:00 -07:00
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/serializer.rb
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.5.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
@@ -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'