activefacts-api 0.8.12 → 0.9.1
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/.rspec +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +14 -0
- data/Rakefile +21 -9
- data/VERSION +1 -1
- data/activefacts-api.gemspec +31 -12
- data/lib/activefacts/api.rb +1 -0
- data/lib/activefacts/api/constellation.rb +3 -1
- data/lib/activefacts/api/entity.rb +74 -29
- data/lib/activefacts/api/exceptions.rb +17 -0
- data/lib/activefacts/api/instance.rb +96 -1
- data/lib/activefacts/api/instance_index.rb +35 -37
- data/lib/activefacts/api/numeric.rb +62 -56
- data/lib/activefacts/api/object_type.rb +49 -23
- data/lib/activefacts/api/role.rb +8 -2
- data/lib/activefacts/api/role_values.rb +8 -26
- data/lib/activefacts/api/standard_types.rb +2 -17
- data/lib/activefacts/api/vocabulary.rb +1 -1
- data/lib/activefacts/tracer.rb +13 -1
- data/spec/{constellation_spec.rb → constellation/constellation_spec.rb} +127 -56
- data/spec/constellation/instance_index_spec.rb +90 -0
- data/spec/{instance_spec.rb → constellation/instance_spec.rb} +48 -42
- data/spec/{role_values_spec.rb → fact_type/role_values_spec.rb} +28 -19
- data/spec/{roles_spec.rb → fact_type/roles_spec.rb} +55 -21
- data/spec/fixtures/tax.rb +45 -0
- data/spec/{identification_spec.rb → identification_scheme/identification_spec.rb} +88 -74
- data/spec/identification_scheme/identity_change_spec.rb +118 -0
- data/spec/identification_scheme/identity_supertype_change_spec.rb +63 -0
- data/spec/{entity_type_spec.rb → object_type/entity_type/entity_type_spec.rb} +2 -4
- data/spec/object_type/entity_type/multipart_identification_spec.rb +77 -0
- data/spec/{autocounter_spec.rb → object_type/value_type/autocounter_spec.rb} +2 -4
- data/spec/object_type/value_type/numeric_spec.rb +63 -0
- data/spec/{value_type_spec.rb → object_type/value_type/value_type_spec.rb} +10 -14
- data/spec/simplecov_helper.rb +8 -0
- data/spec/spec_helper.rb +1 -1
- metadata +100 -19
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Value instances in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
3
5
|
|
4
6
|
describe "An Entity Type" do
|
5
7
|
before :all do
|
@@ -28,16 +30,14 @@ describe "An Entity Type" do
|
|
28
30
|
end
|
29
31
|
|
30
32
|
it "should fail if the role isn't one-to-one" do
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
has_one :name
|
37
|
-
end
|
33
|
+
proc do
|
34
|
+
module Mod
|
35
|
+
class Cat
|
36
|
+
identified_by :name
|
37
|
+
has_one :name
|
38
38
|
end
|
39
|
-
end
|
40
|
-
end
|
39
|
+
end
|
40
|
+
end.should raise_error
|
41
41
|
end
|
42
42
|
|
43
43
|
describe "when asserted" do
|
@@ -81,11 +81,13 @@ describe "An Entity Type" do
|
|
81
81
|
end
|
82
82
|
|
83
83
|
it "should fail if the new value already exists" do
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
84
|
+
proc do
|
85
|
+
@fly.name = 'Acme'
|
86
|
+
end.should raise_error
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should not fail if the new value is self" do
|
90
|
+
lambda { @bus.name = 'Acme' }.should_not raise_error
|
89
91
|
end
|
90
92
|
|
91
93
|
describe "to a previously-nonexistent value" do
|
@@ -103,15 +105,11 @@ describe "An Entity Type" do
|
|
103
105
|
end
|
104
106
|
|
105
107
|
it "should be found under the new identifier" do
|
106
|
-
|
107
|
-
@c.Business['Bloggs'].should == @bus
|
108
|
-
end
|
108
|
+
@c.Business[['Bloggs']].should == @bus
|
109
109
|
end
|
110
110
|
|
111
111
|
it "should be in the constellation's index under the new identifier" do
|
112
|
-
|
113
|
-
@c.Business.keys[0].should == ['Bloggs']
|
114
|
-
end
|
112
|
+
@c.Business.keys.should include ['Bloggs']
|
115
113
|
end
|
116
114
|
|
117
115
|
it "should be the counterpart of the new identifier" do
|
@@ -119,24 +117,23 @@ describe "An Entity Type" do
|
|
119
117
|
end
|
120
118
|
|
121
119
|
it "should not be found in the constellation using the old value" do
|
122
|
-
|
123
|
-
@c.Business[['Acme']].should be_nil
|
124
|
-
end
|
120
|
+
@c.Business[['Acme']].should be_nil
|
125
121
|
end
|
126
122
|
|
127
123
|
it "the old value's back-reference is set to nil" do
|
128
124
|
@acme.business.should be_nil
|
129
125
|
end
|
130
126
|
|
131
|
-
describe "and the old identifying value plays no other roles" do
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
127
|
+
#describe "and the old identifying value plays no other roles" do
|
128
|
+
# describe "and the player of the identifying role is not independent" do
|
129
|
+
# it "should retract the previous value" do
|
130
|
+
# pending "All value types default to independent" do
|
131
|
+
# @c.Name['Acme'].should be_nil
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
#end
|
136
|
+
|
140
137
|
end
|
141
138
|
end
|
142
139
|
|
@@ -157,11 +154,11 @@ describe "An Entity Type" do
|
|
157
154
|
@bus.retract
|
158
155
|
end
|
159
156
|
|
160
|
-
it "should retract the identifying value also" do
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
end
|
157
|
+
#it "should retract the identifying value also" do
|
158
|
+
# pending "All value types default to independent" do
|
159
|
+
# @c.Name['Acme'].should be_nil
|
160
|
+
# end
|
161
|
+
#end
|
165
162
|
|
166
163
|
it "should not appear as the value's counterpart role" do
|
167
164
|
@acme.business.should be_nil
|
@@ -204,24 +201,39 @@ describe "An Entity Type" do
|
|
204
201
|
has_one :building
|
205
202
|
has_one :number
|
206
203
|
end
|
204
|
+
|
205
|
+
class OwnershipId < Int
|
206
|
+
value_type
|
207
|
+
end
|
208
|
+
|
209
|
+
class Owner
|
210
|
+
identified_by :ownership_id, :building
|
211
|
+
has_one :ownership_id
|
212
|
+
has_one :building
|
213
|
+
end
|
214
|
+
|
215
|
+
class OwnerRoom
|
216
|
+
identified_by :owner, :room
|
217
|
+
has_one :owner
|
218
|
+
has_one :room
|
219
|
+
end
|
207
220
|
end
|
208
221
|
end
|
222
|
+
|
209
223
|
before :each do
|
210
224
|
@c = ActiveFacts::API::Constellation.new(Mod)
|
211
225
|
end
|
212
226
|
|
213
227
|
it "should fail if any role is one-to-one" do
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
one_to_one :number # Error, invalid identifier
|
221
|
-
end
|
228
|
+
proc do
|
229
|
+
module Mod
|
230
|
+
class Floor
|
231
|
+
identified_by :building, :number
|
232
|
+
has_one :building
|
233
|
+
one_to_one :number # Error, invalid identifier
|
222
234
|
end
|
223
|
-
end
|
224
|
-
end
|
235
|
+
end
|
236
|
+
end.should raise_error
|
225
237
|
end
|
226
238
|
|
227
239
|
describe "when asserted" do
|
@@ -230,6 +242,9 @@ describe "An Entity Type" do
|
|
230
242
|
@mackay = @c.Name['Mackay']
|
231
243
|
@r = @c.Room(@b, 101)
|
232
244
|
@rn = @r.number
|
245
|
+
|
246
|
+
@o = @c.Owner(1_001, @b)
|
247
|
+
@or = @c.OwnerRoom(@o, @r)
|
233
248
|
end
|
234
249
|
|
235
250
|
it "should return a new instance if not previously present" do
|
@@ -271,15 +286,14 @@ describe "An Entity Type" do
|
|
271
286
|
@mackay = @c.Name['Mackay']
|
272
287
|
@r = @c.Room(@b, 101)
|
273
288
|
@rn = @r.number
|
289
|
+
|
290
|
+
@o = @c.Owner(1_001, @b)
|
291
|
+
@or = @c.OwnerRoom(@o, @r)
|
274
292
|
end
|
275
293
|
|
276
294
|
it "should fail if the new value already exists" do
|
277
295
|
@c.Room(@b, 102)
|
278
|
-
|
279
|
-
proc {
|
280
|
-
@r.number = 102
|
281
|
-
}.should raise_error
|
282
|
-
end
|
296
|
+
lambda { @r.number = 102 }.should raise_error
|
283
297
|
end
|
284
298
|
|
285
299
|
describe "to a previously-nonexistent value" do
|
@@ -298,16 +312,18 @@ describe "An Entity Type" do
|
|
298
312
|
end
|
299
313
|
|
300
314
|
it "should be found under the new identifier" do
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
315
|
+
@c.Room[[@b.identifying_role_values, 103]].should == @r
|
316
|
+
@c.Room[[['Mackay'], 101]].should be_nil
|
317
|
+
end
|
318
|
+
|
319
|
+
it "should be found under the new identifier even on deep associations" do
|
320
|
+
@c.OwnerRoom[[@o.identifying_role_values, @r.identifying_role_values]].should == @or
|
321
|
+
@c.OwnerRoom[[[1_001, ['Mackay']], [['Mackay'], 103]]].should == @or
|
322
|
+
@c.OwnerRoom[[[1_001, ['Mackay']], [['Mackay'], 101]]].should be_nil
|
305
323
|
end
|
306
324
|
|
307
325
|
it "should be in the constellation's index under the new identifier" do
|
308
|
-
|
309
|
-
@c.Room.keys[0].should == [['Mackay'], @r.number]
|
310
|
-
end
|
326
|
+
@c.Room.keys[0].should == [['Mackay'], @r.number]
|
311
327
|
end
|
312
328
|
|
313
329
|
it "should be included in the counterparts of the new identifier roles" do
|
@@ -316,24 +332,22 @@ describe "An Entity Type" do
|
|
316
332
|
end
|
317
333
|
|
318
334
|
it "should not be found in the constellation using the old value" do
|
319
|
-
|
320
|
-
@c.Room.keys[0].should_not == [['Mackay'],101]
|
321
|
-
end
|
335
|
+
@c.Room.keys[0].should_not == [['Mackay'],101]
|
322
336
|
end
|
323
337
|
|
324
338
|
it "the old value's back-reference is set to nil" do
|
325
|
-
@rn.all_room.to_a.should_not
|
339
|
+
@rn.all_room.to_a.should_not include @r
|
326
340
|
end
|
327
341
|
|
328
|
-
describe "and the old identifying value plays no other roles" do
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
end
|
342
|
+
#describe "and the old identifying value plays no other roles" do
|
343
|
+
# describe "and the player of the identifying role is not independent" do
|
344
|
+
# it "should retract the previous value" do
|
345
|
+
# pending "All value types default to independent" do
|
346
|
+
# @c.Number[101].should be_nil
|
347
|
+
# end
|
348
|
+
# end
|
349
|
+
# end
|
350
|
+
#end
|
337
351
|
end
|
338
352
|
end
|
339
353
|
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Value instances in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'fixtures/tax'
|
7
|
+
include ActiveFacts::API
|
8
|
+
|
9
|
+
describe "identity" do
|
10
|
+
before :each do
|
11
|
+
@c1 = Constellation.new(Tax)
|
12
|
+
@juliar = "Juliar Gillard"
|
13
|
+
|
14
|
+
@p1 = @c1.Australian(@juliar)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be indexed" do
|
18
|
+
@c1.Name.keys.should == [@juliar]
|
19
|
+
@c1.Name.values.should == [@juliar]
|
20
|
+
@c1.Person.keys.should == [[@juliar]]
|
21
|
+
@c1.Person.values.should == [@p1]
|
22
|
+
@c1.Australian.keys.should == [[@juliar]]
|
23
|
+
@c1.Australian.values.should == [@p1]
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "change" do
|
27
|
+
before :each do
|
28
|
+
@tony = "Tony Abbot"
|
29
|
+
@p3 = @c1.AustralianTaxPayer(:tfn => 123, :name => @tony)
|
30
|
+
|
31
|
+
@r1 = @c1.AustralianTaxReturn(@p3, 2010)
|
32
|
+
@c1.AustralianTaxReturn.keys.should == [[[123], [2010]]]
|
33
|
+
@c1.AustralianTaxReturn.values.should == [@r1]
|
34
|
+
|
35
|
+
@c1.Name.keys.should =~ [@juliar, @tony]
|
36
|
+
@c1.Name.values.should =~ [@juliar, @tony]
|
37
|
+
@c1.Person.keys.should =~ [[@juliar], [@tony]]
|
38
|
+
@c1.Person.values.should =~ [@p1, @p3]
|
39
|
+
@c1.Australian.keys.should =~ [[@juliar], [@tony]]
|
40
|
+
@c1.Australian.values.should =~ [@p1, @p3]
|
41
|
+
@c1.AustralianTaxPayer.keys.should =~ [[123]]
|
42
|
+
@c1.AustralianTaxPayer.values.should =~ [@p3]
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "that implies change of subtype" do
|
46
|
+
before :each do
|
47
|
+
@p2 = nil
|
48
|
+
@change = proc {
|
49
|
+
@p2 = @c1.AustralianTaxPayer(:tfn => 789, :name => "Juliar Gillard")
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should be denied" do
|
54
|
+
@change.should raise_error(DuplicateIdentifyingValueException)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not change instance subtype" do
|
58
|
+
@p1.class.should == Tax::Australian
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should have no side-effects" do
|
62
|
+
begin
|
63
|
+
@change.call
|
64
|
+
rescue DuplicateIdentifyingValueException => e
|
65
|
+
end
|
66
|
+
|
67
|
+
@p2.should be_nil
|
68
|
+
@c1.Name.values.should =~ [@juliar, @tony]
|
69
|
+
@c1.Name.keys.should =~ [@juliar, @tony]
|
70
|
+
@c1.TFN.keys.should =~ [123]
|
71
|
+
@c1.Person.values.should =~ [@p1, @p3]
|
72
|
+
@c1.Person.keys.should =~ [[@juliar],[@tony]]
|
73
|
+
@c1.Australian.values.should =~ [@p1, @p3]
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should have no side-effects (retracting values which shouldn't)" do
|
77
|
+
@p2_tfn = @c1.TFN(789)
|
78
|
+
begin
|
79
|
+
@change.call
|
80
|
+
rescue DuplicateIdentifyingValueException => e
|
81
|
+
end
|
82
|
+
|
83
|
+
@c1.TFN.keys.should =~ [123, 789]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "causing conflict" do
|
88
|
+
it "should fail and make no change" do
|
89
|
+
proc {
|
90
|
+
@p3.name = "Juliar Gillard" # Must fail; must leave @p3 untouched.
|
91
|
+
}.should raise_error # (ActiveFacts::API::AmbiguousIdentityChange)
|
92
|
+
|
93
|
+
@p3.name.should == @tony
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "without conflict" do
|
98
|
+
before :each do
|
99
|
+
@p3.tfn = 456
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should be allowed" do
|
103
|
+
@p3.identifying_role_values.should == [456]
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should be re-indexed" do
|
107
|
+
@c1.AustralianTaxPayer.keys.should == [[456]]
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should be propagated" do
|
111
|
+
key = [[456], [2010]]
|
112
|
+
@r1.identifying_role_values.should == key
|
113
|
+
@c1.AustralianTaxReturn.keys.should == [key]
|
114
|
+
@c1.AustralianTaxReturn.values.should == [@r1]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Value instances in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
|
6
|
+
describe 'identity change on subtype' do
|
7
|
+
before :all do
|
8
|
+
module Mod
|
9
|
+
class EntityA
|
10
|
+
identified_by :value_a
|
11
|
+
one_to_one :value_a
|
12
|
+
has_one :value_b
|
13
|
+
end
|
14
|
+
|
15
|
+
class ValueA < Int
|
16
|
+
value_type
|
17
|
+
end
|
18
|
+
|
19
|
+
class ValueB < String
|
20
|
+
value_type
|
21
|
+
end
|
22
|
+
|
23
|
+
class EntityB < EntityA
|
24
|
+
identified_by :value_b
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@constellation = ActiveFacts::API::Constellation.new(Mod)
|
29
|
+
@a = @constellation.EntityA(123)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should fail if the value is the same" do
|
33
|
+
lambda { @b = @constellation.EntityB(123, 'abc') }.should raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
context "on a deep-subtype" do
|
37
|
+
before :all do
|
38
|
+
module Mod
|
39
|
+
class EntityC < EntityB
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
@c = @constellation.EntityC(:value_a => 1, :value_b => 'abc')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should fail if the value already exist" do
|
47
|
+
@a.value_a.should == 123
|
48
|
+
@c.value_a.should == 1
|
49
|
+
lambda { @a.value_a = 1 }.should raise_error(ActiveFacts::API::DuplicateIdentifyingValueException)
|
50
|
+
lambda { @c.value_a = 123 }.should raise_error(ActiveFacts::API::DuplicateIdentifyingValueException)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should keep the previous value intact" do
|
54
|
+
@a.value_a.should == 123
|
55
|
+
@c.value_a.should == 1
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should allow the change when the value doesn't exist" do
|
59
|
+
@c.value_a = 987
|
60
|
+
@c.value_a.should == 987
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# ActiveFacts tests: Entity classes in the Runtime API
|
3
3
|
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
4
|
#
|
5
|
-
require 'rspec'
|
6
|
-
require 'activefacts/api'
|
7
5
|
|
8
6
|
describe "Entity Type class definitions" do
|
9
7
|
before :each do
|
@@ -16,7 +14,7 @@ describe "Entity Type class definitions" do
|
|
16
14
|
end
|
17
15
|
class Person < LegalEntity
|
18
16
|
identified_by :name
|
19
|
-
|
17
|
+
one_to_one :name, :class => Name
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -77,7 +75,7 @@ describe "Entity Type class definitions" do
|
|
77
75
|
Mod::Person.roles.include?(:name).should be_true
|
78
76
|
end
|
79
77
|
|
80
|
-
it "should fail on a
|
78
|
+
it "should fail on a ValClass" do
|
81
79
|
lambda{
|
82
80
|
class SomeClass < String
|
83
81
|
identified_by
|