son_jay 0.2.0.alpha → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.simplecov +5 -0
- data/Rakefile +17 -3
- data/features/step_definitions/data_staging_steps.rb +6 -0
- data/features/step_definitions/data_unloading_steps.rb +9 -0
- data/features/step_definitions/json_parsing_steps.rb +1 -11
- data/features/step_definitions/model_steps.rb +7 -1
- data/features/support/attribute_value_verification.rb +12 -0
- data/features/support/env.rb +15 -1
- data/lib/son_jay/acts_as_model.rb +1 -1
- data/lib/son_jay/object_model/properties.rb +6 -10
- data/lib/son_jay/object_model/property_definition.rb +4 -4
- data/lib/son_jay/object_model.rb +14 -14
- data/lib/son_jay/value_array.rb +5 -0
- data/lib/son_jay/version.rb +1 -1
- data/son_jay.gemspec +2 -0
- data/spec/model_array_spec.rb +7 -1
- data/spec/object_model_spec.rb +126 -100
- data/spec/spec_helper.rb +14 -0
- data/spec/value_array_spec.rb +12 -0
- metadata +39 -6
- data/spec/object_model/properties_spec.rb +0 -125
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NDg5ODk2NGI0ZTU2MTc4ZjdjMzEzNWNiMjY2OTJmMjNkNmVhOTNlYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzgwYWExZDQ4YTc2MDlhNGQ1NTkyNDgxOWVjMmFjNDRkYzgxZmJkZg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YzFlNjQ5MDEwYWEyN2M3OGE1NmJlNDFlZWMwMDc2NjM3ZjkzZTBmMDg1Zjc5
|
10
|
+
M2FjMmQ1ODk4NjlkYzA4OGExYzU2ZmNmNzc3ZjM3MmJjZmZiZWMzMzJiYWYy
|
11
|
+
YTdmY2E5MGQ0YjJlOTUwZGZmZDU4ZGJlMTFhZDRiNTRhYTZiMWU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NzNjYTZkMGQ4ZThmZTU2M2QyZDVlMmJmZjFjYTc3OTIyZDRmZDA5OGQ5YTMw
|
14
|
+
YzFlMDk1ZDBiNDEyYTQ4NDdlZGMzZjM0NzNkZGM3MDM2MjZhMTA2N2ZiMWU0
|
15
|
+
NmQyZmFkMDY2OTJlZWFkYWUxODgzY2NjNmRiNjQ0ZjBmYjQyOTI=
|
data/.simplecov
ADDED
data/Rakefile
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
desc "Run all specs/features with and w/o ActiveSupport loaded"
|
5
|
+
task :all_tests do
|
6
|
+
system 'rake all_tests_without_active_support'
|
7
|
+
next unless $?.exitstatus == 0
|
8
|
+
system 'rake all_tests_with_active_support'
|
9
|
+
end
|
7
10
|
|
8
11
|
task :default => :all_tests
|
9
12
|
|
13
|
+
desc "Run all specs and features w/o ActiveSupport loaded"
|
14
|
+
task all_tests_without_active_support: %w[all_test_types]
|
15
|
+
|
16
|
+
desc "Run all specs and features with ActiveSupport loaded"
|
17
|
+
task all_tests_with_active_support: %w[load_active_support all_test_types]
|
18
|
+
|
19
|
+
task all_test_types: %w[spec cucumber cucumber:wip]
|
10
20
|
|
11
21
|
RSpec::Core::RakeTask.new(:spec)
|
12
22
|
|
@@ -21,3 +31,7 @@ namespace :cucumber do
|
|
21
31
|
t.profile = 'wip'
|
22
32
|
end
|
23
33
|
end
|
34
|
+
|
35
|
+
task :load_active_support do
|
36
|
+
ENV['LOAD_ACTIVE_SUPPORT'] = '1'
|
37
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
When(/^data is disseminated to the domain object as:$/) do |code|
|
2
|
+
instance = context_data[:instance]
|
3
|
+
object = context_data[:object]
|
4
|
+
context_module.module_eval code
|
5
|
+
end
|
6
|
+
|
7
|
+
Then(/^the domain object attributes are as follows:$/) do |table|
|
8
|
+
object_attributes_match_table! context_data[:object], table
|
9
|
+
end
|
@@ -12,15 +12,5 @@ When(/^the JSON is parsed to a model instance as:$/) do |code|
|
|
12
12
|
end
|
13
13
|
|
14
14
|
Then(/^the instance attributes are as follows:$/) do |table|
|
15
|
-
|
16
|
-
attribute_exprs = row_pairs.map( &:first ).reduce( :+ )
|
17
|
-
expected_exprs = row_pairs.map( &:last ).reduce( :+ )
|
18
|
-
|
19
|
-
instance = context_data[:instance]
|
20
|
-
actuals = attribute_exprs .map{ |expr| eval( "instance.#{expr}" ) }
|
21
|
-
expecteds = expected_exprs .map{ |expr| eval( expr ) }
|
22
|
-
|
23
|
-
actual_hash = Hash[ attribute_exprs.zip( actuals ) ]
|
24
|
-
expected_hash = Hash[ attribute_exprs.zip( expecteds ) ]
|
25
|
-
expect( actual_hash ).to eq( expected_hash )
|
15
|
+
object_attributes_match_table! context_data[:instance], table
|
26
16
|
end
|
@@ -1,3 +1,9 @@
|
|
1
|
-
Given(/^
|
1
|
+
Given(/^a.* object model defined as:$/) do |code|
|
2
2
|
context_module.module_eval code
|
3
3
|
end
|
4
|
+
|
5
|
+
Given(/^a domain object(?: is)? created.* as:$/) do |code|
|
6
|
+
object = nil
|
7
|
+
context_module.module_eval code
|
8
|
+
context_data[:object] = object
|
9
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
def object_attributes_match_table!(obj, table)
|
2
|
+
row_pairs = table.raw.each_slice(2)
|
3
|
+
attribute_exprs = row_pairs.map( &:first ).reduce( :+ )
|
4
|
+
expected_exprs = row_pairs.map( &:last ).reduce( :+ )
|
5
|
+
|
6
|
+
actuals = attribute_exprs .map{ |expr| eval( "obj.#{expr}" ) }
|
7
|
+
expecteds = expected_exprs .map{ |expr| eval( expr ) }
|
8
|
+
|
9
|
+
actual_hash = Hash[ attribute_exprs.zip( actuals ) ]
|
10
|
+
expected_hash = Hash[ attribute_exprs.zip( expecteds ) ]
|
11
|
+
expect( actual_hash ).to eq( expected_hash )
|
12
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
|
1
|
+
with_active_support = !!ENV['LOAD_ACTIVE_SUPPORT']
|
2
|
+
|
3
|
+
if with_active_support
|
4
|
+
gem 'activesupport'
|
5
|
+
require 'active_support/all'
|
6
|
+
puts 'ActiveSupport loaded'
|
7
|
+
end
|
8
|
+
|
9
|
+
gem 'simplecov'
|
10
|
+
require 'simplecov'
|
11
|
+
cmd_active_supp_qual = with_active_support ? 'with' : 'without'
|
12
|
+
SimpleCov.command_name "cucumber:#{cmd_active_supp_qual}_active_support"
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
15
|
+
require 'son_jay'
|
2
16
|
|
3
17
|
module SonJayFeatureSupport
|
4
18
|
def context_data
|
@@ -3,6 +3,7 @@ require 'forwardable'
|
|
3
3
|
module SonJay
|
4
4
|
class ObjectModel
|
5
5
|
class Properties
|
6
|
+
|
6
7
|
class NameError < KeyError
|
7
8
|
def initialize(name)
|
8
9
|
super "No such property name as %s" % name.inspect
|
@@ -26,8 +27,6 @@ module SonJay
|
|
26
27
|
:values ,
|
27
28
|
]
|
28
29
|
|
29
|
-
def_delegator :@data, :has_key?, :has_name?
|
30
|
-
|
31
30
|
def [](name)
|
32
31
|
name = "#{name}"
|
33
32
|
@data.fetch(name)
|
@@ -49,20 +48,17 @@ module SonJay
|
|
49
48
|
|
50
49
|
def load_property(name, value)
|
51
50
|
name = "#{name}"
|
52
|
-
return unless @data.has_key?(name)
|
53
|
-
if @model_properties.include?(name)
|
51
|
+
return unless @data.has_key?( name )
|
52
|
+
if @model_properties.include?( name )
|
54
53
|
@data[name].sonj_content.load_data value
|
55
54
|
else
|
56
55
|
@data[name] = value
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
def to_json(*args)
|
65
|
-
@data.to_json(*args)
|
59
|
+
def to_json(options = ::JSON::State.new)
|
60
|
+
options = ::JSON::State.new(options) unless options.kind_of?(::JSON::State)
|
61
|
+
@data.to_json( options )
|
66
62
|
end
|
67
63
|
|
68
64
|
end
|
@@ -6,7 +6,7 @@ module SonJay
|
|
6
6
|
|
7
7
|
def initialize(name, instruction = nil)
|
8
8
|
@name = name
|
9
|
-
@model_class = model_class_for_instruction(instruction)
|
9
|
+
@model_class = model_class_for_instruction( instruction )
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
@@ -14,8 +14,8 @@ module SonJay
|
|
14
14
|
def model_class_for_instruction(instruction)
|
15
15
|
if instruction.nil?
|
16
16
|
nil
|
17
|
-
elsif instruction.respond_to?(:to_ary)
|
18
|
-
array_model_class(instruction)
|
17
|
+
elsif instruction.respond_to?( :to_ary )
|
18
|
+
array_model_class( instruction )
|
19
19
|
elsif instruction.respond_to?( :new )
|
20
20
|
instruction
|
21
21
|
end
|
@@ -24,7 +24,7 @@ module SonJay
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def array_model_class(instruction)
|
27
|
-
return instruction unless instruction.respond_to?(:to_ary)
|
27
|
+
return instruction unless instruction.respond_to?( :to_ary )
|
28
28
|
return SonJay::ValueArray if instruction == []
|
29
29
|
|
30
30
|
sub_instruction = instruction.first
|
data/lib/son_jay/object_model.rb
CHANGED
@@ -7,6 +7,17 @@ module SonJay
|
|
7
7
|
class ObjectModel
|
8
8
|
include ActsAsModel
|
9
9
|
|
10
|
+
attr_reader :sonj_content
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
definitions = self.class.property_definitions
|
14
|
+
@sonj_content = ObjectModel::Properties.new( definitions )
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json(*args)
|
18
|
+
sonj_content.to_json( *args )
|
19
|
+
end
|
20
|
+
|
10
21
|
class << self
|
11
22
|
|
12
23
|
def properties(&property_initializations)
|
@@ -19,7 +30,7 @@ module SonJay
|
|
19
30
|
|
20
31
|
definitions = []
|
21
32
|
|
22
|
-
definer = PropertiesDefiner.new(definitions)
|
33
|
+
definer = PropertiesDefiner.new( definitions )
|
23
34
|
definer.instance_eval &@property_initializations
|
24
35
|
@property_definitions = definitions
|
25
36
|
|
@@ -42,26 +53,15 @@ module SonJay
|
|
42
53
|
raise InfiniteRegressError if dependants.include?(self)
|
43
54
|
dependants << self
|
44
55
|
hard_model_dependencies.each do |d|
|
45
|
-
next unless d.respond_to?(:validate_model_dependencies!, true)
|
56
|
+
next unless d.respond_to?( :validate_model_dependencies!, true )
|
46
57
|
d.send :validate_model_dependencies!, dependants
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
50
61
|
def hard_model_dependencies
|
51
|
-
property_definitions.map(&:model_class).compact.uniq
|
62
|
+
property_definitions.map( &:model_class ).compact.uniq
|
52
63
|
end
|
53
64
|
end
|
54
65
|
|
55
|
-
attr_reader :sonj_content
|
56
|
-
|
57
|
-
def initialize
|
58
|
-
definitions = self.class.property_definitions
|
59
|
-
@sonj_content = ObjectModel::Properties.new( definitions )
|
60
|
-
end
|
61
|
-
|
62
|
-
def to_json(*args)
|
63
|
-
sonj_content.to_json(*args)
|
64
|
-
end
|
65
|
-
|
66
66
|
end
|
67
67
|
end
|
data/lib/son_jay/value_array.rb
CHANGED
data/lib/son_jay/version.rb
CHANGED
data/son_jay.gemspec
CHANGED
@@ -19,7 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "simplecov"
|
22
23
|
spec.add_development_dependency "rake"
|
23
24
|
spec.add_development_dependency "rspec"
|
24
25
|
spec.add_development_dependency "cucumber"
|
26
|
+
spec.add_development_dependency "activesupport"
|
25
27
|
end
|
data/spec/model_array_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe SonJay::ModelArray do
|
|
20
20
|
} }
|
21
21
|
let( :entry_class ) { Class.new do
|
22
22
|
class Content
|
23
|
-
def initialize(
|
23
|
+
def initialize(entry) ; @entry = entry ; end
|
24
24
|
def load_data(data) ; @entry.loaded_data = data ; end
|
25
25
|
end
|
26
26
|
|
@@ -65,5 +65,11 @@ describe SonJay::ModelArray do
|
|
65
65
|
expect( instance[1].loaded_data ).to eq( 'entry 1 data' )
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
describe '#sonj_content' do
|
70
|
+
it "returns the model array" do
|
71
|
+
expect( subject.sonj_content ).to equal( subject )
|
72
|
+
end
|
73
|
+
end
|
68
74
|
end
|
69
75
|
end
|
data/spec/object_model_spec.rb
CHANGED
@@ -2,133 +2,157 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe SonJay::ObjectModel do
|
4
4
|
|
5
|
-
describe "a subclass that defines value properties" do
|
5
|
+
describe "a subclass that defines (value and modeled-object) properties" do
|
6
|
+
|
7
|
+
let( :model_class ) { subject_module::RootModel }
|
8
|
+
let( :model_instance ) { model_class.new }
|
9
|
+
let( :detail_xy_class ) { subject_module::DetailXY }
|
10
|
+
|
11
|
+
let( :subject_module ) {
|
12
|
+
mod = Module.new
|
13
|
+
mod::M = mod
|
14
|
+
|
15
|
+
module mod::M
|
16
|
+
|
17
|
+
class RootModel < SonJay::ObjectModel
|
18
|
+
class << self
|
19
|
+
def properties_block_called_count
|
20
|
+
@properties_block_called_count ||= 0
|
21
|
+
end
|
22
|
+
attr_writer :properties_block_called_count
|
23
|
+
end
|
24
|
+
|
25
|
+
properties do
|
26
|
+
RootModel.properties_block_called_count += 1
|
27
|
+
property :aaa
|
28
|
+
property :bbb
|
29
|
+
property :detail_xy , model: DetailXY
|
30
|
+
property :detail_z , model: DetailZ
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class DetailXY < SonJay::ObjectModel
|
35
|
+
properties do
|
36
|
+
property :xxx
|
37
|
+
property :yyy
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DetailZ < SonJay::ObjectModel
|
42
|
+
properties do
|
43
|
+
property :zzz
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
mod
|
50
|
+
}
|
51
|
+
|
52
|
+
it "does not immediately invoke its properties block when declared" do
|
53
|
+
expect( model_class.properties_block_called_count ).
|
54
|
+
to eq( 0 )
|
55
|
+
end
|
6
56
|
|
7
57
|
describe '::array_class' do
|
8
58
|
it "returns a model-array subclass for entries of this type" do
|
9
|
-
array_class =
|
10
|
-
puts array_class.ancestors
|
59
|
+
array_class = model_class.array_class
|
11
60
|
expect( array_class.ancestors ).to include( SonJay::ModelArray )
|
12
|
-
expect( array_class.entry_class ).to eq(
|
61
|
+
expect( array_class.entry_class ).to eq( model_class )
|
13
62
|
end
|
14
63
|
end
|
15
64
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
65
|
+
describe "#sonj_content" do
|
66
|
+
let( :sonj_content ) { model_instance.sonj_content }
|
67
|
+
|
68
|
+
it "has number of entries equal to number of defined properties" do
|
69
|
+
expect( sonj_content.length ).to eq( 4 )
|
22
70
|
end
|
23
|
-
}
|
24
71
|
|
25
|
-
|
26
|
-
|
27
|
-
|
72
|
+
it "has name-indexed settable/gettable value properties by string or symbol" do
|
73
|
+
sonj_content[ :aaa ] = 1
|
74
|
+
sonj_content[ 'bbb' ] = 'XYZ'
|
75
|
+
|
76
|
+
expect( sonj_content[ 'aaa' ] ).to eq( 1 )
|
77
|
+
expect( sonj_content[ :bbb ] ).to eq( 'XYZ' )
|
78
|
+
end
|
28
79
|
|
29
|
-
|
30
|
-
expect(
|
80
|
+
it "has nil defaults for value properties" do
|
81
|
+
expect( sonj_content[ 'aaa' ] ).to be_nil
|
82
|
+
expect( sonj_content[ :bbb ] ).to be_nil
|
83
|
+
end
|
31
84
|
|
32
|
-
|
33
|
-
|
85
|
+
it "has name-indexed gettable values for defined modeled-object properties by string or symbol" do
|
86
|
+
expect( sonj_content['detail_xy'] ).
|
87
|
+
to be_kind_of( subject_module::DetailXY )
|
88
|
+
expect( sonj_content[:detail_z] ).
|
89
|
+
to be_kind_of( subject_module::DetailZ )
|
90
|
+
end
|
34
91
|
|
35
|
-
|
36
|
-
expect
|
92
|
+
it "rejects access to an undefined property" do
|
93
|
+
expect{ sonj_content['qq'] }.to raise_exception(
|
94
|
+
described_class::Properties::NameError
|
95
|
+
)
|
37
96
|
end
|
97
|
+
|
38
98
|
end
|
39
99
|
|
40
100
|
it "has direct property accessor methods for each property" do
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
101
|
+
model_instance.aaa, model_instance.bbb = 11, 22
|
102
|
+
expect( [model_instance.aaa, model_instance.bbb] ).to eq( [11, 22] )
|
103
|
+
expect( model_instance.detail_xy ).
|
104
|
+
to be_kind_of( subject_module::DetailXY )
|
105
|
+
expect( model_instance.detail_z ).
|
106
|
+
to be_kind_of( subject_module::DetailZ )
|
45
107
|
end
|
46
108
|
|
47
|
-
it "serializes to a JSON object representation w/
|
48
|
-
instance =
|
49
|
-
instance.
|
109
|
+
it "serializes to a JSON object representation w/ value properties" do
|
110
|
+
instance = detail_xy_class.new
|
111
|
+
instance.xxx, instance.yyy = 'ABC', nil
|
50
112
|
|
51
113
|
actual_json = instance.to_json
|
52
114
|
|
53
115
|
actual_data = JSON.parse( actual_json)
|
54
|
-
expected_data = {'
|
116
|
+
expected_data = {'xxx' => 'ABC', 'yyy' => nil}
|
55
117
|
expect( actual_data ).to eq( expected_data )
|
56
118
|
end
|
57
119
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
}
|
65
|
-
JSON
|
66
|
-
|
67
|
-
instance = subclass.parse_json( json )
|
120
|
+
it "serializes to a JSON object representation w/ value and object properties" do
|
121
|
+
model_instance.aaa = 1
|
122
|
+
model_instance.bbb = 2
|
123
|
+
model_instance.detail_xy.xxx = 11
|
124
|
+
model_instance.detail_xy.yyy = 12
|
125
|
+
model_instance.detail_z.zzz = 21
|
68
126
|
|
69
|
-
|
70
|
-
expect( instance.xyz ).to eq( 'XYZ' )
|
71
|
-
end
|
72
|
-
end
|
127
|
+
actual_json = model_instance.to_json
|
73
128
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
pbcs << 1
|
83
|
-
property :a
|
84
|
-
property :obj_1, model: dmc_1
|
85
|
-
property :obj_2, model: dmc_2
|
86
|
-
end
|
87
|
-
end
|
88
|
-
}
|
89
|
-
|
90
|
-
let( :property_block_calls ) { [] }
|
91
|
-
|
92
|
-
let( :detail_model_class_1 ) {
|
93
|
-
Class.new(described_class) do
|
94
|
-
properties do
|
95
|
-
property :aaa
|
96
|
-
property :bbb
|
97
|
-
end
|
98
|
-
end
|
99
|
-
}
|
100
|
-
|
101
|
-
let( :detail_model_class_2 ) {
|
102
|
-
Class.new(described_class) do
|
103
|
-
properties do
|
104
|
-
property :ccc
|
105
|
-
end
|
106
|
-
end
|
107
|
-
}
|
108
|
-
|
109
|
-
it "does not immediately invoke its properties block when declared" do
|
110
|
-
_ = subclass
|
111
|
-
expect( property_block_calls ).to be_empty
|
112
|
-
end
|
113
|
-
|
114
|
-
describe "#sonj_content" do
|
115
|
-
it "has an entry for each defined property" do
|
116
|
-
content = subclass.new.sonj_content
|
117
|
-
expect( content.length ).to eq( 3 )
|
118
|
-
end
|
129
|
+
actual_data = JSON.parse( actual_json)
|
130
|
+
expected_data = {
|
131
|
+
'aaa' => 1 ,
|
132
|
+
'bbb' => 2 ,
|
133
|
+
'detail_xy' => { 'xxx' => 11, 'yyy' => 12 } ,
|
134
|
+
'detail_z' => { 'zzz' => 21 } ,
|
135
|
+
}
|
136
|
+
expect( actual_data ).to eq( expected_data )
|
119
137
|
end
|
120
138
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
139
|
+
it "parses from JSON to an instance with properties filled in" do
|
140
|
+
json = <<-JSON
|
141
|
+
{
|
142
|
+
"aaa": 123 ,
|
143
|
+
"bbb": "XYZ" ,
|
144
|
+
"detail_xy": { "xxx": "x", "yyy": "y" } ,
|
145
|
+
"detail_z": { "zzz": "z" }
|
146
|
+
}
|
147
|
+
JSON
|
148
|
+
|
149
|
+
instance = model_class.parse_json( json )
|
150
|
+
|
151
|
+
expect( instance.aaa ).to eq( 123 )
|
152
|
+
expect( instance.bbb ).to eq('XYZ')
|
153
|
+
expect( instance.detail_xy.xxx ).to eq('x')
|
154
|
+
expect( instance.detail_xy.yyy ).to eq('y')
|
155
|
+
expect( instance.detail_z.zzz ).to eq('z')
|
132
156
|
end
|
133
157
|
|
134
158
|
end
|
@@ -156,7 +180,8 @@ describe SonJay::ObjectModel do
|
|
156
180
|
}
|
157
181
|
|
158
182
|
it "raises an infinte regress error when property_definitions are resolved" do
|
159
|
-
expect{ subclass.property_definitions }.
|
183
|
+
expect{ subclass.property_definitions }.
|
184
|
+
to raise_exception( SonJay::InfiniteRegressError )
|
160
185
|
end
|
161
186
|
end
|
162
187
|
|
@@ -172,7 +197,8 @@ describe SonJay::ObjectModel do
|
|
172
197
|
}
|
173
198
|
|
174
199
|
it "raises an infinte regress error when property_definitions are resolved" do
|
175
|
-
expect{ subclass.property_definitions }.
|
200
|
+
expect{ subclass.property_definitions }.
|
201
|
+
to raise_exception( SonJay::InfiniteRegressError )
|
176
202
|
end
|
177
203
|
end
|
178
204
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,16 @@
|
|
1
|
+
with_active_support = !!ENV['LOAD_ACTIVE_SUPPORT']
|
2
|
+
|
3
|
+
if with_active_support
|
4
|
+
gem 'activesupport'
|
5
|
+
require 'active_support/all'
|
6
|
+
puts 'ActiveSupport loaded'
|
7
|
+
end
|
8
|
+
|
9
|
+
gem 'simplecov'
|
10
|
+
require 'simplecov'
|
11
|
+
cmd_active_supp_qual = with_active_support ? 'with' : 'without'
|
12
|
+
SimpleCov.command_name "rspec:#{cmd_active_supp_qual}_active_support"
|
13
|
+
|
1
14
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
15
|
+
|
2
16
|
require 'son_jay'
|
data/spec/value_array_spec.rb
CHANGED
@@ -22,4 +22,16 @@ describe SonJay::ValueArray do
|
|
22
22
|
expect( subject.entries ).to eq( [7, 8, 9] )
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
describe '#to_json' do
|
27
|
+
it "returns a JSON representation of the array w/ values" do
|
28
|
+
subject.replace( [1, 2, 'three'] )
|
29
|
+
|
30
|
+
actual_json = subject.to_json
|
31
|
+
|
32
|
+
parsed_json = JSON.parse( actual_json )
|
33
|
+
expect( parsed_json ).to eq( [1, 2, 'three'] )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
25
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: son_jay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Jorgensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: simplecov
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +80,20 @@ dependencies:
|
|
66
80
|
- - ! '>='
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
description: Symmetrical transformation between structured data and JSON
|
70
98
|
email:
|
71
99
|
- stevej@stevej.name
|
@@ -75,6 +103,7 @@ extra_rdoc_files: []
|
|
75
103
|
files:
|
76
104
|
- .gitignore
|
77
105
|
- .rspec
|
106
|
+
- .simplecov
|
78
107
|
- .travis.yml
|
79
108
|
- Gemfile
|
80
109
|
- LICENSE.txt
|
@@ -83,9 +112,12 @@ files:
|
|
83
112
|
- cucumber.yml
|
84
113
|
- features/json_parsing.feature
|
85
114
|
- features/json_serialization.feature
|
115
|
+
- features/step_definitions/data_staging_steps.rb
|
116
|
+
- features/step_definitions/data_unloading_steps.rb
|
86
117
|
- features/step_definitions/json_parsing_steps.rb
|
87
118
|
- features/step_definitions/json_serialization_steps.rb
|
88
119
|
- features/step_definitions/model_steps.rb
|
120
|
+
- features/support/attribute_value_verification.rb
|
89
121
|
- features/support/env.rb
|
90
122
|
- lib/son_jay.rb
|
91
123
|
- lib/son_jay/acts_as_model.rb
|
@@ -99,7 +131,6 @@ files:
|
|
99
131
|
- son_jay.gemspec
|
100
132
|
- spec/acts_as_model_spec.rb
|
101
133
|
- spec/model_array_spec.rb
|
102
|
-
- spec/object_model/properties_spec.rb
|
103
134
|
- spec/object_model/property_definition_spec.rb
|
104
135
|
- spec/object_model_spec.rb
|
105
136
|
- spec/son_jay_spec.rb
|
@@ -120,9 +151,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
151
|
version: '0'
|
121
152
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
153
|
requirements:
|
123
|
-
- - ! '
|
154
|
+
- - ! '>='
|
124
155
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
156
|
+
version: '0'
|
126
157
|
requirements: []
|
127
158
|
rubyforge_project:
|
128
159
|
rubygems_version: 2.2.2
|
@@ -132,13 +163,15 @@ summary: Symmetrical transformation between structured data and JSON
|
|
132
163
|
test_files:
|
133
164
|
- features/json_parsing.feature
|
134
165
|
- features/json_serialization.feature
|
166
|
+
- features/step_definitions/data_staging_steps.rb
|
167
|
+
- features/step_definitions/data_unloading_steps.rb
|
135
168
|
- features/step_definitions/json_parsing_steps.rb
|
136
169
|
- features/step_definitions/json_serialization_steps.rb
|
137
170
|
- features/step_definitions/model_steps.rb
|
171
|
+
- features/support/attribute_value_verification.rb
|
138
172
|
- features/support/env.rb
|
139
173
|
- spec/acts_as_model_spec.rb
|
140
174
|
- spec/model_array_spec.rb
|
141
|
-
- spec/object_model/properties_spec.rb
|
142
175
|
- spec/object_model/property_definition_spec.rb
|
143
176
|
- spec/object_model_spec.rb
|
144
177
|
- spec/son_jay_spec.rb
|
@@ -1,125 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SonJay::ObjectModel::Properties do
|
4
|
-
subject{
|
5
|
-
described_class.new( [
|
6
|
-
SonJay::ObjectModel::PropertyDefinition.new( 'aaa' ) ,
|
7
|
-
SonJay::ObjectModel::PropertyDefinition.new( 'bbb' ) ,
|
8
|
-
SonJay::ObjectModel::PropertyDefinition.new( 'ccc' ) ,
|
9
|
-
SonJay::ObjectModel::PropertyDefinition.new( 'ddd', ddd_model_class ) ,
|
10
|
-
] )
|
11
|
-
}
|
12
|
-
|
13
|
-
let( :ddd_model_class ) { Class.new do
|
14
|
-
class Content
|
15
|
-
def initialize(model) ; @model = model ; end
|
16
|
-
def load_data(data) ; @model.class.loaded_data = data ; end
|
17
|
-
end
|
18
|
-
class << self ; attr_accessor :loaded_data ; end
|
19
|
-
def to_json(*) ; '"ddd..."' ; end
|
20
|
-
def sonj_content ; Content.new(self) ; end
|
21
|
-
end }
|
22
|
-
|
23
|
-
it "has an entry for each property name specified during initialization" do
|
24
|
-
expect( subject.length ).to eq( 4 )
|
25
|
-
expect( subject ).to have_name('aaa')
|
26
|
-
expect( subject ).to have_name('bbb')
|
27
|
-
expect( subject ).to have_name('ccc')
|
28
|
-
expect( subject ).to have_name('ddd')
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "property value access by name" do
|
32
|
-
it "reads nil by default for an existing value property" do
|
33
|
-
expect( subject['aaa'] ).to be_nil
|
34
|
-
end
|
35
|
-
|
36
|
-
it "writes and reads existing value properties" do
|
37
|
-
subject['bbb'] = 10
|
38
|
-
subject['aaa'] = 11
|
39
|
-
|
40
|
-
expect( subject['bbb'] ).to eq( 10 )
|
41
|
-
expect( subject['aaa'] ).to eq( 11 )
|
42
|
-
end
|
43
|
-
|
44
|
-
it "refuses to read a non-existent property" do
|
45
|
-
expect{ subject['abc'] }.to raise_exception( described_class::NameError )
|
46
|
-
end
|
47
|
-
|
48
|
-
it "refuses to write a non-existent property" do
|
49
|
-
expect{ subject['abc'] = 1 }.to raise_exception( described_class::NameError )
|
50
|
-
end
|
51
|
-
|
52
|
-
it "allows reading/writing by symbol or string for property name" do
|
53
|
-
subject['aaa'] = 10
|
54
|
-
subject[:bbb] = 11
|
55
|
-
|
56
|
-
expect( subject[:aaa] ).to eq( 10 )
|
57
|
-
expect( subject['bbb'] ).to eq( 11 )
|
58
|
-
end
|
59
|
-
|
60
|
-
it "reads an instance of the model for a modeled attribute" do
|
61
|
-
expect( subject[:ddd] ).to be_kind_of( ddd_model_class )
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "#to_json" do
|
66
|
-
it "returns a JSON object representation with attribute values" do
|
67
|
-
subject['aaa'] = 'abc'
|
68
|
-
subject['ccc'] = true
|
69
|
-
|
70
|
-
actual_json = subject.to_json
|
71
|
-
|
72
|
-
actual_data = JSON.parse( actual_json )
|
73
|
-
expected_data = {
|
74
|
-
'aaa' => 'abc' ,
|
75
|
-
'bbb' => nil ,
|
76
|
-
'ccc' => true ,
|
77
|
-
'ddd' => "ddd..." ,
|
78
|
-
}
|
79
|
-
expect( actual_data ).to eq( expected_data )
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "load_property" do
|
84
|
-
it "writes to existing value properties" do
|
85
|
-
subject.load_property( 'bbb', 11 )
|
86
|
-
subject.load_property( 'ccc', 12 )
|
87
|
-
|
88
|
-
expect( subject['bbb'] ).to eq( 11 )
|
89
|
-
expect( subject['ccc'] ).to eq( 12 )
|
90
|
-
end
|
91
|
-
|
92
|
-
it "loads data into existing modeled properties" do
|
93
|
-
subject.load_property( 'ddd', 'some data' )
|
94
|
-
expect( ddd_model_class.loaded_data ).to eq( 'some data' )
|
95
|
-
end
|
96
|
-
|
97
|
-
it "ignores attempts to write to non-existent properties" do
|
98
|
-
expect{ subject.load_property('xx', 10) }.
|
99
|
-
not_to change{ subject.length }
|
100
|
-
end
|
101
|
-
|
102
|
-
it "allows string or symbol for property name" do
|
103
|
-
subject.load_property( 'aaa' , 888 )
|
104
|
-
subject.load_property( :ccc , 999 )
|
105
|
-
|
106
|
-
expect( subject['aaa'] ).to eq( 888 )
|
107
|
-
expect( subject['ccc'] ).to eq( 999 )
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "load_data" do
|
112
|
-
it "populates property values from hash entries" do
|
113
|
-
subject.load_data({
|
114
|
-
'bbb' => 'abc' ,
|
115
|
-
'ccc' => false ,
|
116
|
-
'ddd' => 'something...' ,
|
117
|
-
})
|
118
|
-
expect( subject['aaa'] ).to be_nil
|
119
|
-
expect( subject['bbb'] ).to eq( 'abc' )
|
120
|
-
expect( subject['ccc'] ).to eq( false )
|
121
|
-
expect( ddd_model_class.loaded_data ).to eq( 'something...' )
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|