son_jay 0.2.0.alpha → 0.3.0
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.
- 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
|