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
@@ -8,6 +8,7 @@
|
|
8
8
|
# and allow any Class to become an Entity.
|
9
9
|
#
|
10
10
|
require 'date'
|
11
|
+
require 'activefacts/api/numeric'
|
11
12
|
|
12
13
|
module ActiveFacts
|
13
14
|
module API
|
@@ -20,12 +21,9 @@ module ActiveFacts
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
23
|
-
|
24
|
-
require 'activefacts/api/numeric'
|
25
|
-
|
26
24
|
# Add the methods that convert our classes into ObjectType types:
|
27
25
|
|
28
|
-
ValueClasses = [String, Date, DateTime, Time, Int, Real, AutoCounter]
|
26
|
+
ValueClasses = [String, Date, DateTime, Time, Int, Real, AutoCounter, Decimal]
|
29
27
|
ValueClasses.each{|c|
|
30
28
|
c.send :extend, ActiveFacts::API::ValueClass
|
31
29
|
}
|
@@ -62,19 +60,6 @@ class Class
|
|
62
60
|
end
|
63
61
|
end
|
64
62
|
|
65
|
-
require 'bigdecimal'
|
66
|
-
class Decimal < BigDecimal #:nodoc:
|
67
|
-
extend ActiveFacts::API::ValueClass
|
68
|
-
# The problem here is you can't pass a BigDecimal to BigDecimal.new. Fix it.
|
69
|
-
def self.new(v)
|
70
|
-
if v.is_a?(BigDecimal) || v.is_a?(Bignum)
|
71
|
-
super(v.to_s)
|
72
|
-
else
|
73
|
-
super
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
63
|
# These types are generated on conversion from NORMA's types:
|
79
64
|
class Char < String #:nodoc: # FixedLengthText
|
80
65
|
end
|
@@ -12,7 +12,7 @@ module ActiveFacts
|
|
12
12
|
# Vocabulary is a mixin that adds methods to any Module which has any ObjectType classes (ValueType or EntityType).
|
13
13
|
# A Vocabulary knows all the ObjectType classes including forward-referenced ones,
|
14
14
|
# and can resolve the forward references when the class is finally defined.
|
15
|
-
# Construction of a Constellation requires a
|
15
|
+
# Construction of a Constellation requires a Vocabulary as argument.
|
16
16
|
module Vocabulary
|
17
17
|
# With a parameter, look up an object type by name.
|
18
18
|
# Without, return the hash (keyed by the class' basename) of all object_types in this vocabulary
|
data/lib/activefacts/tracer.rb
CHANGED
@@ -25,7 +25,17 @@ module ActiveFacts
|
|
25
25
|
@stderr.puts "---\nDebugging keys available: #{@available.keys.map{|s| s.to_s}.sort*", "}"
|
26
26
|
}
|
27
27
|
end
|
28
|
-
|
28
|
+
if @keys[:debug]
|
29
|
+
['pry', 'debugger', 'ruby-debug'].each do |debugger|
|
30
|
+
begin
|
31
|
+
require debugger
|
32
|
+
puts "Loaded "+debugger
|
33
|
+
break
|
34
|
+
rescue LoadError
|
35
|
+
end
|
36
|
+
end
|
37
|
+
::Debugger.start rescue nil
|
38
|
+
end
|
29
39
|
end
|
30
40
|
end
|
31
41
|
|
@@ -107,3 +117,5 @@ class Object
|
|
107
117
|
(ActiveFacts.tracer ||= ActiveFacts::Tracer.new).trace(*args, &block)
|
108
118
|
end
|
109
119
|
end
|
120
|
+
|
121
|
+
trace ''
|
@@ -3,9 +3,6 @@
|
|
3
3
|
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
4
|
#
|
5
5
|
|
6
|
-
require 'rspec'
|
7
|
-
require 'activefacts/api'
|
8
|
-
|
9
6
|
describe "A Constellation instance" do
|
10
7
|
before :each do
|
11
8
|
Object.send :remove_const, :Mod if Object.const_defined?("Mod")
|
@@ -16,30 +13,30 @@ describe "A Constellation instance" do
|
|
16
13
|
|
17
14
|
# Create a value type and a subtype of that value type for each base type:
|
18
15
|
@base_types.each do |base_type|
|
19
|
-
|
20
|
-
class #{base_type.basename}
|
16
|
+
Mod.module_eval <<-END
|
17
|
+
class #{base_type.basename}Val < #{base_type.name}
|
21
18
|
value_type
|
22
19
|
end
|
23
20
|
|
24
|
-
class #{base_type.basename}
|
21
|
+
class #{base_type.basename}SubVal < #{base_type.name}Val
|
25
22
|
# Note no new "value_type" is required here, it comes through inheritance
|
26
23
|
end
|
27
24
|
END
|
28
25
|
end
|
29
26
|
|
30
|
-
class Name <
|
27
|
+
class Name < StringVal
|
31
28
|
value_type
|
32
29
|
#has_one :attr, Name
|
33
30
|
end
|
34
31
|
|
35
32
|
class LegalEntity
|
36
33
|
identified_by :name
|
37
|
-
|
34
|
+
one_to_one :name, :mandatory => true
|
38
35
|
end
|
39
36
|
|
40
37
|
class SurrogateId
|
41
|
-
identified_by :
|
42
|
-
|
38
|
+
identified_by :auto_counter_val
|
39
|
+
one_to_one :auto_counter_val
|
43
40
|
end
|
44
41
|
|
45
42
|
class Company < LegalEntity
|
@@ -60,18 +57,18 @@ describe "A Constellation instance" do
|
|
60
57
|
|
61
58
|
describe "Vocabulary" do
|
62
59
|
it "should create the constellation" do
|
63
|
-
Mod.constellation.should
|
60
|
+
Mod.constellation.should be_an_instance_of ActiveFacts::API::Constellation
|
64
61
|
end
|
65
62
|
|
66
63
|
it "should create the constellation by direct populate" do
|
67
64
|
Mod.populate do
|
68
65
|
Name "foo"
|
69
|
-
end.should
|
66
|
+
end.should be_an_instance_of ActiveFacts::API::Constellation
|
70
67
|
end
|
71
68
|
|
72
69
|
it "should verbalise" do
|
73
70
|
s = Mod.verbalise
|
74
|
-
s.should
|
71
|
+
s.should be_an_instance_of String
|
75
72
|
end
|
76
73
|
end
|
77
74
|
|
@@ -107,8 +104,8 @@ describe "A Constellation instance" do
|
|
107
104
|
lambda {
|
108
105
|
name = @constellation.Name("foo")
|
109
106
|
foo = @constellation.LegalEntity("foo")
|
110
|
-
acme = @constellation.Company("Acme, Inc", :
|
111
|
-
fred_fly = @constellation.Person("fred", "fly", :
|
107
|
+
acme = @constellation.Company("Acme, Inc", :auto_counter_val => :new)
|
108
|
+
fred_fly = @constellation.Person("fred", "fly", :auto_counter_val => :new)
|
112
109
|
}.should_not raise_error
|
113
110
|
name.class.should == Mod::Name
|
114
111
|
name.constellation.should == @constellation
|
@@ -132,13 +129,13 @@ describe "A Constellation instance" do
|
|
132
129
|
it "should re-use instances constructed the same way" do
|
133
130
|
name1 = @constellation.Name("foo")
|
134
131
|
foo1 = @constellation.LegalEntity("foo")
|
135
|
-
acme1 = @constellation.Company("Acme, Inc", :
|
136
|
-
fred_fly1 = @constellation.Person("fred", "fly", :
|
132
|
+
acme1 = @constellation.Company("Acme, Inc", :auto_counter_val => :new)
|
133
|
+
fred_fly1 = @constellation.Person("fred", "fly", :auto_counter_val => :new)
|
137
134
|
|
138
135
|
name2 = @constellation.Name("foo")
|
139
136
|
foo2 = @constellation.LegalEntity("foo")
|
140
|
-
acme2 = @constellation.Company("Acme, Inc", :
|
141
|
-
fred_fly2 = @constellation.Person("fred", "fly", :
|
137
|
+
acme2 = @constellation.Company("Acme, Inc") # , :auto_counter_val => :new)
|
138
|
+
fred_fly2 = @constellation.Person("fred", "fly") # , :auto_counter_val => :new)
|
142
139
|
|
143
140
|
name1.object_id.should == name2.object_id
|
144
141
|
foo1.object_id.should == foo2.object_id
|
@@ -146,13 +143,23 @@ describe "A Constellation instance" do
|
|
146
143
|
fred_fly1.object_id.should == fred_fly2.object_id
|
147
144
|
end
|
148
145
|
|
146
|
+
it "should reject re-assertion with additional assignments" do
|
147
|
+
name1 = @constellation.Name("foo")
|
148
|
+
foo1 = @constellation.LegalEntity("foo")
|
149
|
+
acme1 = @constellation.Company("Acme, Inc", :auto_counter_val => :new)
|
150
|
+
|
151
|
+
name2 = @constellation.Name("foo")
|
152
|
+
foo2 = @constellation.LegalEntity("foo")
|
153
|
+
lambda { @constellation.Company("Acme, Inc", :auto_counter_val => :new) }.should raise_error
|
154
|
+
end
|
155
|
+
|
149
156
|
it "should support methods to assert instances via the class for that type" do
|
150
157
|
name = foo = acme = fred_fly = nil
|
151
158
|
lambda {
|
152
159
|
name = @constellation.Name.assert("foo")
|
153
160
|
foo = @constellation.LegalEntity.assert("foo")
|
154
|
-
acme = @constellation.Company.assert("Acme, Inc", :
|
155
|
-
fred_fly = @constellation.Person.assert("fred", "fly", :
|
161
|
+
acme = @constellation.Company.assert("Acme, Inc", :auto_counter_val => :new)
|
162
|
+
fred_fly = @constellation.Person.assert("fred", "fly", :auto_counter_val => :new)
|
156
163
|
}.should_not raise_error
|
157
164
|
name.class.should == Mod::Name
|
158
165
|
name.constellation.should == @constellation
|
@@ -177,8 +184,8 @@ describe "A Constellation instance" do
|
|
177
184
|
@constellation.populate do
|
178
185
|
Name("bar")
|
179
186
|
LegalEntity("foo")
|
180
|
-
Person("Fred", "Nerk", :
|
181
|
-
Company("Acme, Inc", :
|
187
|
+
Person("Fred", "Nerk", :auto_counter_val => :new)
|
188
|
+
Company("Acme, Inc", :auto_counter_val => :new)
|
182
189
|
end
|
183
190
|
@constellation.Name.size.should == 5
|
184
191
|
@constellation.SurrogateId.size.should == 2
|
@@ -188,29 +195,29 @@ describe "A Constellation instance" do
|
|
188
195
|
@constellation.populate do
|
189
196
|
Name("bar")
|
190
197
|
LegalEntity("foo")
|
191
|
-
c = Company("Acme, Inc", :
|
192
|
-
p = Person("Fred", "Nerk", :
|
198
|
+
c = Company("Acme, Inc", :auto_counter_val => :new)
|
199
|
+
p = Person("Fred", "Nerk", :auto_counter_val => :new, :employer => c)
|
193
200
|
p.birth_name = "Nerk"
|
194
201
|
end
|
195
202
|
s = @constellation.verbalise
|
196
203
|
names = s.split(/\n/).grep(/\tEvery /).map{|l| l.sub(/.*Every (.*):$/, '\1')}
|
197
|
-
expected = ["
|
204
|
+
expected = ["AutoCounterVal", "Company", "LegalEntity", "Name", "Person", "StringVal", "SurrogateId"]
|
198
205
|
names.sort.should == expected
|
199
206
|
end
|
200
207
|
|
201
208
|
it "should support string capitalisation functions" do
|
202
|
-
names = ["Company", "LegalEntity", "Name", "Person", "
|
209
|
+
names = ["Company", "LegalEntity", "Name", "Person", "StringVal", "SurrogateId"]
|
203
210
|
camelwords = names.map{|n| n.camelwords }
|
204
|
-
camelwords.should == [["Company"], ["Legal", "Entity"], ["Name"], ["Person"], ["String", "
|
211
|
+
camelwords.should == [["Company"], ["Legal", "Entity"], ["Name"], ["Person"], ["String", "Val"], ["Surrogate", "Id"]]
|
205
212
|
|
206
213
|
snakes = names.map{|n| n.snakecase }
|
207
|
-
snakes.should == ["company", "legal_entity", "name", "person", "
|
214
|
+
snakes.should == ["company", "legal_entity", "name", "person", "string_val", "surrogate_id"]
|
208
215
|
|
209
216
|
camelupper = snakes.map{|n| n.camelcase }
|
210
|
-
camelupper.should == ["Company", "LegalEntity", "Name", "Person", "
|
217
|
+
camelupper.should == ["Company", "LegalEntity", "Name", "Person", "StringVal", "SurrogateId"]
|
211
218
|
|
212
219
|
camellower = snakes.map{|n| n.camelcase(:lower) }
|
213
|
-
camellower.should == ["company", "legalEntity", "name", "person", "
|
220
|
+
camellower.should == ["company", "legalEntity", "name", "person", "stringVal", "surrogateId"]
|
214
221
|
end
|
215
222
|
|
216
223
|
it "should allow inspection of instance indices" do
|
@@ -222,9 +229,9 @@ describe "A Constellation instance" do
|
|
222
229
|
baz = @constellation.Name("baz")
|
223
230
|
@constellation.Name.keys.sort.should == ["baz"]
|
224
231
|
|
225
|
-
@constellation.
|
226
|
-
@constellation.
|
227
|
-
@constellation.
|
232
|
+
@constellation.StringVal.keys.sort.should == ["baz"]
|
233
|
+
@constellation.StringVal.include?(baz).should == baz
|
234
|
+
@constellation.StringVal.include?("baz").should == baz
|
228
235
|
end
|
229
236
|
|
230
237
|
describe "instance indices" do
|
@@ -245,24 +252,24 @@ describe "A Constellation instance" do
|
|
245
252
|
name = "Acme, Inc"
|
246
253
|
fred = "Fred"
|
247
254
|
fly = "Fly"
|
248
|
-
acme = @constellation.Company name, :
|
249
|
-
fred_fly = @constellation.Person fred, fly, :
|
255
|
+
acme = @constellation.Company name, :auto_counter_val => :new
|
256
|
+
fred_fly = @constellation.Person fred, fly, :auto_counter_val => :new
|
250
257
|
|
251
258
|
# REVISIT: This should be illegal:
|
252
|
-
#fred_fly.
|
259
|
+
#fred_fly.auto_counter_val = :new
|
253
260
|
|
254
261
|
@constellation.Person.keys.sort.should == [[fred, fly]]
|
255
262
|
@constellation.Company.keys.sort.should == [[name]]
|
256
263
|
|
257
|
-
@constellation.LegalEntity.keys.sort.should
|
258
|
-
@constellation.LegalEntity.keys.sort.should
|
264
|
+
@constellation.LegalEntity.keys.sort.should include [name]
|
265
|
+
@constellation.LegalEntity.keys.sort.should include [fred]
|
259
266
|
|
260
|
-
@constellation.SurrogateId.values.should
|
261
|
-
@constellation.SurrogateId.values.should
|
267
|
+
@constellation.SurrogateId.values.should include acme
|
268
|
+
@constellation.SurrogateId.values.should include fred_fly
|
262
269
|
end
|
263
270
|
|
264
271
|
it "should handle one-to-ones correctly" do
|
265
|
-
person = @constellation.Person "Fred", "Smith", :
|
272
|
+
person = @constellation.Person "Fred", "Smith", :auto_counter_val => :new, :birth_name => "Nerk"
|
266
273
|
|
267
274
|
nerk = @constellation.Name["Nerk"]
|
268
275
|
nerk.should_not be_nil
|
@@ -273,7 +280,7 @@ describe "A Constellation instance" do
|
|
273
280
|
end
|
274
281
|
|
275
282
|
it "should allow retraction of instances" do
|
276
|
-
person = @constellation.Person "Fred", "Smith", :
|
283
|
+
person = @constellation.Person "Fred", "Smith", :auto_counter_val => :new, :birth_name => "Nerk"
|
277
284
|
|
278
285
|
@constellation.retract(@constellation.Name("Smith"))
|
279
286
|
@constellation.Name["Smith"].should be_nil
|
@@ -282,9 +289,14 @@ describe "A Constellation instance" do
|
|
282
289
|
person.family_name.should be_nil
|
283
290
|
@constellation.retract(@constellation.Name("Fred"))
|
284
291
|
@constellation.Name["Fred"].should be_nil
|
285
|
-
|
286
|
-
|
287
|
-
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should retract linked instances (cascading)" do
|
295
|
+
@constellation.Person "Fred", "Smith", :auto_counter_val => :new, :birth_name => "Nerk"
|
296
|
+
@constellation.Person "George", "Smith", :auto_counter_val => :new, :birth_name => "Patrick"
|
297
|
+
@constellation.Person.size.should == 2
|
298
|
+
@constellation.retract(@constellation.Name("Smith"))
|
299
|
+
@constellation.Person.size.should == 0
|
288
300
|
end
|
289
301
|
|
290
302
|
it "should fail to recognise references to unresolved forward referenced classes" do
|
@@ -338,7 +350,7 @@ describe "A Constellation instance" do
|
|
338
350
|
|
339
351
|
lambda {
|
340
352
|
module Mod
|
341
|
-
class
|
353
|
+
class IntVal
|
342
354
|
has_one :thingummy, :class => Outside::Other
|
343
355
|
end
|
344
356
|
end
|
@@ -377,10 +389,70 @@ describe "A Constellation instance" do
|
|
377
389
|
class ListedCompany < Company
|
378
390
|
end
|
379
391
|
end
|
380
|
-
c = @constellation.ListedCompany("foo", :
|
392
|
+
c = @constellation.ListedCompany("foo", :auto_counter_val => 23)
|
381
393
|
}.should_not raise_error(NameError)
|
382
394
|
end
|
383
395
|
|
396
|
+
it "should be able to attach a new supertype on an entity type to make it a (sub-)subtype" do
|
397
|
+
module Mod
|
398
|
+
class Dad
|
399
|
+
identified_by :name
|
400
|
+
end
|
401
|
+
class Son < Dad
|
402
|
+
identified_by :name
|
403
|
+
end
|
404
|
+
# the grand son will be linked on the fly
|
405
|
+
class GrandSon
|
406
|
+
identified_by :name
|
407
|
+
end
|
408
|
+
end
|
409
|
+
Mod::GrandSon.supertypes(Mod::Son)
|
410
|
+
Mod::GrandSon.supertypes.should include Mod::Son
|
411
|
+
Mod::Son.supertypes.should include Mod::Dad
|
412
|
+
end
|
413
|
+
|
414
|
+
it "should keep information on where the identification came from" do
|
415
|
+
module Mod
|
416
|
+
class Dad
|
417
|
+
identified_by :name
|
418
|
+
end
|
419
|
+
class Son < Dad
|
420
|
+
identified_by :name
|
421
|
+
end
|
422
|
+
# Note the inheritance.
|
423
|
+
class GrandSon < Son
|
424
|
+
identified_by :name
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
Mod::Son.identification_inherited_from.should == Mod::Dad
|
429
|
+
Mod::Son.identification_inherited_from.should == Mod::Dad
|
430
|
+
Mod::GrandSon.identification_inherited_from.should == Mod::Son
|
431
|
+
Mod::GrandSon.overrides_identification_of.should == Mod::Dad
|
432
|
+
end
|
433
|
+
|
434
|
+
it "should disallow using a value type as a supertypes for an entity type" do
|
435
|
+
lambda {
|
436
|
+
module Mod
|
437
|
+
class CompanyName
|
438
|
+
identified_by :name
|
439
|
+
supertypes :name
|
440
|
+
end
|
441
|
+
end
|
442
|
+
}.should raise_error
|
443
|
+
end
|
444
|
+
|
445
|
+
it "should complain when role name and counter part mismatch" do
|
446
|
+
lambda {
|
447
|
+
module Mod
|
448
|
+
class CompanyName
|
449
|
+
identified_by :name
|
450
|
+
has_one :company, :class => :person
|
451
|
+
end
|
452
|
+
end
|
453
|
+
}.should raise_error(Exception, /indicates a different counterpart object_type/)
|
454
|
+
end
|
455
|
+
|
384
456
|
it "should error on invalid :class values" do
|
385
457
|
lambda {
|
386
458
|
module Mod
|
@@ -402,29 +474,28 @@ describe "A Constellation instance" do
|
|
402
474
|
end
|
403
475
|
|
404
476
|
it "should allow assert using an object of the same type" do
|
405
|
-
c = @constellation.Company("foo", :
|
477
|
+
c = @constellation.Company("foo", :auto_counter_val => 23)
|
406
478
|
c2 = ActiveFacts::API::Constellation.new(Mod)
|
407
479
|
lambda {
|
408
|
-
c2.Company(c, :
|
480
|
+
c2.Company(c, :auto_counter_val => :new)
|
409
481
|
}.should_not raise_error
|
410
482
|
c2.Company.keys.should == [["foo"]]
|
411
483
|
end
|
412
484
|
|
413
485
|
it "should allow cross-constellation construction" do
|
414
|
-
c = @constellation.Company("foo", :
|
486
|
+
c = @constellation.Company("foo", :auto_counter_val => 23)
|
415
487
|
lambda {
|
416
488
|
c2 = ActiveFacts::API::Constellation.new(Mod)
|
417
|
-
c2.Company(c.name, :
|
489
|
+
c2.Company(c.name, :auto_counter_val => :new)
|
418
490
|
}.should_not raise_error
|
419
491
|
end
|
420
492
|
|
421
493
|
it "should allow cross-constellation assignment" do
|
422
|
-
c = @constellation.Company("foo", :
|
494
|
+
c = @constellation.Company("foo", :auto_counter_val => 23)
|
423
495
|
lambda {
|
424
496
|
c2 = ActiveFacts::API::Constellation.new(Mod)
|
425
|
-
p = c2.Person('Fred', 'Smith', :
|
426
|
-
p.employer = [c, {:
|
497
|
+
p = c2.Person('Fred', 'Smith', :auto_counter_val => :new)
|
498
|
+
p.employer = [c, {:auto_counter_val => :new}]
|
427
499
|
}.should_not raise_error
|
428
500
|
end
|
429
|
-
|
430
501
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Value instances in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
|
6
|
+
describe ActiveFacts::API::InstanceIndex do
|
7
|
+
before :all do
|
8
|
+
module Mod
|
9
|
+
class ValueA < Int
|
10
|
+
value_type
|
11
|
+
end
|
12
|
+
|
13
|
+
class ValueB < String
|
14
|
+
value_type
|
15
|
+
end
|
16
|
+
|
17
|
+
class EntityA
|
18
|
+
identified_by :value_a
|
19
|
+
one_to_one :value_a
|
20
|
+
has_one :value_b
|
21
|
+
end
|
22
|
+
|
23
|
+
class EntityB < EntityA
|
24
|
+
identified_by :value_b
|
25
|
+
one_to_one :value_b
|
26
|
+
end
|
27
|
+
|
28
|
+
class EntityD < EntityA
|
29
|
+
end
|
30
|
+
|
31
|
+
class EntityC < EntityB
|
32
|
+
supertypes EntityD
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
@constellation = ActiveFacts::API::Constellation.new(Mod)
|
37
|
+
@a = @constellation.EntityA(:value_a => 1, :value_b => 'a')
|
38
|
+
@b = @constellation.EntityB(:value_a => 12, :value_b => 'ab')
|
39
|
+
@c = @constellation.EntityC(:value_a => 123, :value_b => 'abc')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should index an instance under its own class" do
|
43
|
+
@constellation.instances[Mod::EntityC].size.should == 1
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should index instances of subtypes" do
|
47
|
+
@constellation.instances[Mod::EntityA].size.should == 3
|
48
|
+
@constellation.instances[Mod::EntityB].size.should == 2
|
49
|
+
@constellation.instances[Mod::EntityD].size.should == 1
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#flatten_key" do
|
53
|
+
it "should use identifying role values when using an entity type" do
|
54
|
+
@constellation.EntityA[@a].should == @a
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should recursively try to use identifying role values within an array" do
|
58
|
+
value_b = @constellation.ValueB('abc')
|
59
|
+
@constellation.EntityC[[value_b]].should == @c
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should use the value as-is if it doesn't have identifying role values" do
|
63
|
+
@constellation.EntityC[%w{abc}].should == @c
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "should iterate over instances" do
|
68
|
+
[:each, :map, :detect].each do |api|
|
69
|
+
it "Should pass the key and object to #{api}" do
|
70
|
+
a_index = @constellation.EntityA
|
71
|
+
a_index.size.should == 3
|
72
|
+
a_index.send(api) do |k, v, *a|
|
73
|
+
[[1], [12], [123]].should include(k)
|
74
|
+
[@a, @b, @c].should include(v)
|
75
|
+
a.size.should == 0
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
b_index = @constellation.EntityB
|
80
|
+
b_index.size.should == 2
|
81
|
+
b_index.send(api) do |k, v, *a|
|
82
|
+
[['ab'], ['abc']].should include(k)
|
83
|
+
[@b, @c].should include v
|
84
|
+
a.size.should == 0
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|