son_jay 0.4.1 → 0.5.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.
@@ -62,97 +62,21 @@ describe SonJay::ObjectModel do
62
62
  end
63
63
  end
64
64
 
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 )
70
- end
71
-
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
79
-
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
84
-
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
91
-
92
- it "rejects assignment of an undefined property" do
93
- expect{ sonj_content['qq'] = 0 }.to raise_exception(
94
- SonJay::PropertyNameError
95
- )
96
- end
97
-
98
- it "returns nil for name-indexed access to a non-existent property" do
99
- expect( sonj_content[ 'qq' ] ).to be_nil
100
- expect( sonj_content[ :rr ] ).to be_nil
101
- end
102
-
103
- it "has fetchable value properties by name string or symbol" do
104
- sonj_content[ :aaa ] = 1
105
- sonj_content[ 'bbb' ] = 'XYZ'
106
-
107
- expect( sonj_content.fetch( 'aaa' ) ).to eq( 1 )
108
- expect( sonj_content.fetch( :bbb ) ).to eq( 'XYZ' )
109
- end
110
-
111
- it "has nil defaults for value property fetches" do
112
- expect( sonj_content.fetch( 'aaa' ) ).to be_nil
113
- expect( sonj_content.fetch( :bbb ) ).to be_nil
114
- end
115
-
116
- it "has name-indexed fetchable values for defined modeled-object properties by string or symbol" do
117
- expect( sonj_content.fetch('detail_xy') ).
118
- to be_kind_of( subject_module::DetailXY )
119
- expect( sonj_content.fetch(:detail_z) ).
120
- to be_kind_of( subject_module::DetailZ )
121
- end
122
-
123
- it "rejects fetch of an undefined property by name" do
124
- expect{ sonj_content.fetch('qq') }.to raise_exception(
125
- SonJay::PropertyNameError
126
- )
127
- expect{ sonj_content.fetch(:rr) }.to raise_exception(
128
- SonJay::PropertyNameError
129
- )
130
- end
131
-
132
- context "without extras allowed" do
133
- it "rejects access to extra properties object" do
134
- expect{ sonj_content.extra }.
135
- to raise_exception( SonJay::DisabledMethodError )
136
- end
137
- end
65
+ it "has direct property accessor methods for each property" do
66
+ model_instance.aaa, model_instance.bbb = 11, 22
67
+ content = model_instance.model_content
138
68
 
139
- context "with extras allowed" do
140
- before do
141
- model_class.class_eval do
142
- allow_extras
143
- end
144
- end
69
+ expect( [content['aaa'], content['bbb']] ).
70
+ to eq( [11, 22] )
145
71
 
146
- it "allows access to extra properties object" do
147
- expect( sonj_content.extra.to_h ).to eq( {} )
148
- end
149
- end
72
+ expect( [model_instance.aaa, model_instance.bbb] ).
73
+ to eq( [11, 22] )
150
74
 
151
- end
75
+ expect( model_instance.detail_xy ).
76
+ to equal( content['detail_xy'] )
77
+ expect( model_instance.detail_z ).
78
+ to equal( content['detail_z'] )
152
79
 
153
- it "has direct property accessor methods for each property" do
154
- model_instance.aaa, model_instance.bbb = 11, 22
155
- expect( [model_instance.aaa, model_instance.bbb] ).to eq( [11, 22] )
156
80
  expect( model_instance.detail_xy ).
157
81
  to be_kind_of( subject_module::DetailXY )
158
82
  expect( model_instance.detail_z ).
@@ -242,7 +166,7 @@ describe SonJay::ObjectModel do
242
166
  end
243
167
 
244
168
  it "has number of entries equal to total number of defined properties" do
245
- expect( model_instance.sonj_content.length ).to eq( 6 )
169
+ expect( model_instance.model_content.length ).to eq( 6 )
246
170
  end
247
171
 
248
172
  end
@@ -257,7 +181,7 @@ describe SonJay::ObjectModel do
257
181
  )
258
182
  end
259
183
 
260
- it "parses from JSON with extra properties to an instance with defined properties filled in" do
184
+ it "parses from JSON with extra properties to an instance with only defined properties filled in" do
261
185
  json = <<-JSON
262
186
  {
263
187
  "aaa": 123 ,
@@ -277,6 +201,21 @@ describe SonJay::ObjectModel do
277
201
  expect( instance.detail_xy.yyy ).to eq('y')
278
202
  expect( instance.detail_z.zzz ).to eq('z')
279
203
  end
204
+
205
+ it "can be explicitly, shallowly converted to an isolated hash" do
206
+ model_instance.aaa = 111
207
+ model_instance.bbb = 222
208
+
209
+ actual_hash = model_instance.to_h
210
+
211
+ model_instance.bbb = 999
212
+
213
+ expect( actual_hash.length ).to eq( 4 )
214
+ expect( actual_hash[ 'aaa' ] ).to eq( 111 )
215
+ expect( actual_hash[ 'bbb' ] ).to eq( 222 )
216
+ expect( actual_hash[ 'detail_xy' ] ).to equal( model_instance.detail_xy )
217
+ expect( actual_hash[ 'detail_z' ] ).to equal( model_instance.detail_z )
218
+ end
280
219
  end
281
220
 
282
221
  context "with extras allowed" do
@@ -298,15 +237,15 @@ describe SonJay::ObjectModel do
298
237
  expect( model_instance.aaa ).to eq( 111 )
299
238
  expect( model_instance.bbb ).to eq( 222 )
300
239
 
301
- expect( model_instance.sonj_content.extra.to_h ).
240
+ expect( model_instance.model_content.extra.to_h ).
302
241
  to eq( 'qqq' => 333, 'rrr' => 444 )
303
242
  end
304
243
 
305
244
  it "allows name-index reading of both defined and arbitrary, extra properties" do
306
245
  model_instance.aaa = 111
307
246
  model_instance.bbb = 222
308
- model_instance.sonj_content.extra[ 'qqq' ] = 333
309
- model_instance.sonj_content.extra[ :rrr ] = 444
247
+ model_instance.model_content.extra[ 'qqq' ] = 333
248
+ model_instance.model_content.extra[ :rrr ] = 444
310
249
  expect( model_instance[ :aaa ] ).to eq( 111 )
311
250
  expect( model_instance[ 'bbb' ] ).to eq( 222 )
312
251
  expect( model_instance[ :qqq ] ).to eq( 333 )
@@ -355,6 +294,80 @@ describe SonJay::ObjectModel do
355
294
  end
356
295
  end
357
296
 
297
+ context "with subclasses" do
298
+ before do
299
+ module subject_module::M
300
+ class SubA < RootModel
301
+ properties do
302
+ property :ccc
303
+ end
304
+ end
305
+
306
+ class SubB < RootModel
307
+ allow_extras
308
+
309
+ properties do
310
+ property :detail_z2, model: DetailZ
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ let( :sub_a_class ) { subject_module::SubA }
317
+ let( :sub_b_class ) { subject_module::SubB }
318
+ let!( :sub_a_instance ) { sub_a_class.new }
319
+ let!( :sub_b_instance ) { sub_b_class.new }
320
+
321
+ it "allows a subclass to inherit property definitions from its parent" do
322
+ missing_property_names_a =
323
+ model_class.property_definitions.map( &:name ) -
324
+ sub_a_class.property_definitions.map( &:name )
325
+ expect( missing_property_names_a ).to eq( [] )
326
+
327
+ missing_property_names_b =
328
+ model_class.property_definitions.map( &:name ) -
329
+ sub_b_class.property_definitions.map( &:name )
330
+ expect( missing_property_names_b ).to eq( [] )
331
+ end
332
+
333
+ it "does not leak subclass property definitions to its parent" do
334
+ property_names = model_class.property_definitions.map(&:name)
335
+ expect( property_names ).not_to include( 'ccc' )
336
+ expect( property_names ).not_to include( 'detail_z2' )
337
+ end
338
+
339
+ it "allows a subclass to inherit property access behavior from its parent" do
340
+ sub_a_instance.aaa = 123
341
+ expect( sub_a_instance.aaa ).to eq( 123 )
342
+ end
343
+
344
+ it "allows adding value properties to the subclass" do
345
+ expect( sub_a_instance ).to respond_to( :ccc )
346
+ end
347
+
348
+ it "does not leak subclass value property definitions to its parent class" do
349
+ expect( model_instance ).not_to respond_to( :ccc )
350
+ end
351
+
352
+ it "allows adding model properties to the subclass" do
353
+ expect( sub_b_instance.detail_z2 ).to respond_to( :zzz )
354
+ end
355
+
356
+ it "does not leak subclass model property definitions to its parent class" do
357
+ expect( model_instance ).not_to respond_to( :detail_z2 )
358
+ end
359
+
360
+ it "supports subclass allowing extras when the parent class does not" do
361
+ sub_b_instance['xyz'] = 123
362
+ expect( sub_b_instance['xyz'] ).to eq( 123 )
363
+ end
364
+
365
+ it "does not leak allowing of extras to its parent class" do
366
+ expect{
367
+ model_instance['xyz'] = 123
368
+ }.to raise_exception( SonJay::PropertyNameError )
369
+ end
370
+ end
358
371
  end
359
372
 
360
373
  describe "a subclass with a directly self-referential property specification" do
@@ -400,6 +413,7 @@ describe SonJay::ObjectModel do
400
413
  expect{ subclass.property_definitions }.
401
414
  to raise_exception( SonJay::InfiniteRegressError )
402
415
  end
416
+
403
417
  end
404
418
 
405
419
  end
data/spec/son_jay_spec.rb CHANGED
@@ -2,6 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe SonJay do
4
4
  it 'has a version number' do
5
- SonJay::VERSION.should_not be_nil
5
+ expect( SonJay::VERSION ).not_to be_nil
6
6
  end
7
7
  end
@@ -6,9 +6,9 @@ describe SonJay::ValueArray do
6
6
  expect( subject << 1 << 2 ).to eq( [1, 2] )
7
7
  end
8
8
 
9
- describe '#sonj_content' do
9
+ describe '#model_content' do
10
10
  it "returns the instance itself" do
11
- expect( subject.sonj_content ).to eq( subject )
11
+ expect( subject.model_content ).to eq( subject )
12
12
  end
13
13
  end
14
14
 
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.1
4
+ version: 0.5.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: 2015-05-05 00:00:00.000000000 Z
11
+ date: 2015-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -124,11 +124,11 @@ files:
124
124
  - lib/son_jay/acts_as_model.rb
125
125
  - lib/son_jay/model_array.rb
126
126
  - lib/son_jay/object_model.rb
127
- - lib/son_jay/object_model/extra_data.rb
128
- - lib/son_jay/object_model/properties.rb
129
- - lib/son_jay/object_model/properties/abstract.rb
130
- - lib/son_jay/object_model/properties/properties_with_extra.rb
131
- - lib/son_jay/object_model/properties/properties_without_extra.rb
127
+ - lib/son_jay/object_model/content.rb
128
+ - lib/son_jay/object_model/content/abstract.rb
129
+ - lib/son_jay/object_model/content/content_with_extra.rb
130
+ - lib/son_jay/object_model/content/content_without_extra.rb
131
+ - lib/son_jay/object_model/content_data.rb
132
132
  - lib/son_jay/object_model/properties_definer.rb
133
133
  - lib/son_jay/object_model/property_definition.rb
134
134
  - lib/son_jay/object_model/property_definitions.rb
@@ -137,7 +137,9 @@ files:
137
137
  - son_jay.gemspec
138
138
  - spec/acts_as_model_spec.rb
139
139
  - spec/model_array_spec.rb
140
- - spec/object_model/extra_data_spec.rb
140
+ - spec/object_model/content/content_with_extra_spec.rb
141
+ - spec/object_model/content/content_without_extra_spec.rb
142
+ - spec/object_model/content_data_spec.rb
141
143
  - spec/object_model/property_definition_spec.rb
142
144
  - spec/object_model_spec.rb
143
145
  - spec/son_jay_spec.rb
@@ -179,7 +181,9 @@ test_files:
179
181
  - features/support/env.rb
180
182
  - spec/acts_as_model_spec.rb
181
183
  - spec/model_array_spec.rb
182
- - spec/object_model/extra_data_spec.rb
184
+ - spec/object_model/content/content_with_extra_spec.rb
185
+ - spec/object_model/content/content_without_extra_spec.rb
186
+ - spec/object_model/content_data_spec.rb
183
187
  - spec/object_model/property_definition_spec.rb
184
188
  - spec/object_model_spec.rb
185
189
  - spec/son_jay_spec.rb
@@ -1,36 +0,0 @@
1
- require 'forwardable'
2
-
3
- module SonJay
4
- class ObjectModel
5
-
6
- class ExtraData
7
- extend Forwardable
8
-
9
- def initialize
10
- @data = {}
11
- end
12
-
13
- def []=(name, value)
14
- name = "#{name}" unless String === name
15
- @data[name] = value
16
- end
17
-
18
- def [](name)
19
- name = "#{name}" unless String === name
20
- @data[name]
21
- end
22
-
23
- def hash_merge(other)
24
- @data.merge( other )
25
- end
26
-
27
- def to_h
28
- @data.dup
29
- end
30
-
31
- def_delegator :@data, :empty?
32
-
33
- end
34
-
35
- end
36
- end
@@ -1,27 +0,0 @@
1
- module SonJay
2
- class ObjectModel
3
- module Properties
4
-
5
- class PropertiesWithExtra < Abstract
6
-
7
- def extra
8
- @extra ||= ObjectModel::ExtraData.new
9
- end
10
-
11
- private
12
-
13
- def load_extra_property(name_string, value)
14
- extra[ name_string ] = value
15
- end
16
-
17
- def hash_for_json
18
- extra.empty? ?
19
- @data :
20
- extra.hash_merge( @data )
21
- end
22
-
23
- end
24
-
25
- end
26
- end
27
- end
@@ -1,20 +0,0 @@
1
- require 'son_jay/object_model/properties/abstract'
2
- require 'son_jay/object_model/properties/properties_without_extra'
3
- require 'son_jay/object_model/properties/properties_with_extra'
4
-
5
- module SonJay
6
- class ObjectModel
7
-
8
- module Properties
9
-
10
- def self.new(property_definitions, allow_extra)
11
- klass = allow_extra ?
12
- self::PropertiesWithExtra :
13
- self::PropertiesWithoutExtra
14
- klass.new( property_definitions )
15
- end
16
-
17
- end
18
-
19
- end
20
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe SonJay::ObjectModel::ExtraData do
4
-
5
- it "provides value access by name symbol or string" do
6
- subject[ :aaa ] = 1
7
- subject[ 'bbb' ] = 2
8
- expect( subject[ 'aaa' ] ).to eq( 1 )
9
- expect( subject[ :bbb ] ).to eq( 2 )
10
- end
11
-
12
- it "merges with a hash, returning a hash" do
13
- subject[ :aa ] = 1
14
- subject[ :bb ] = 2
15
-
16
- actual = subject.hash_merge(
17
- "bb" => 22,
18
- "cc" => 33
19
- )
20
-
21
- expect( actual ).to eq(
22
- 'aa' => 1,
23
- 'bb' => 22,
24
- 'cc' => 33
25
- )
26
- end
27
-
28
- it "indicates when it is empty" do
29
- expect( subject ).to be_empty
30
- end
31
-
32
- it "indicates when it is not empty" do
33
- subject[:a] = 'a'
34
- expect( subject ).not_to be_empty
35
- end
36
-
37
- end