activefacts-api 0.9.3 → 0.9.4
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/TODO +16 -0
- data/VERSION +1 -1
- data/activefacts-api.gemspec +4 -2
- data/lib/activefacts/api/constellation.rb +118 -50
- data/lib/activefacts/api/date.rb +98 -0
- data/lib/activefacts/api/entity.rb +198 -206
- data/lib/activefacts/api/exceptions.rb +19 -4
- data/lib/activefacts/api/guid.rb +4 -13
- data/lib/activefacts/api/instance.rb +55 -93
- data/lib/activefacts/api/instance_index.rb +1 -32
- data/lib/activefacts/api/numeric.rb +51 -55
- data/lib/activefacts/api/object_type.rb +155 -151
- data/lib/activefacts/api/role.rb +3 -32
- data/lib/activefacts/api/standard_types.rb +8 -4
- data/lib/activefacts/api/support.rb +0 -22
- data/lib/activefacts/api/value.rb +62 -39
- data/lib/activefacts/tracer.rb +8 -6
- data/spec/constellation/constellation_spec.rb +150 -80
- data/spec/constellation/instance_spec.rb +97 -73
- data/spec/fact_type/role_values_spec.rb +33 -12
- data/spec/fact_type/roles_spec.rb +4 -28
- data/spec/identification_scheme/identification_spec.rb +1 -0
- data/spec/identification_scheme/identity_change_spec.rb +4 -4
- data/spec/metadata_spec.rb +269 -0
- data/spec/object_type/entity_type/multipart_identification_spec.rb +1 -2
- data/spec/object_type/value_type/autocounter_spec.rb +4 -4
- data/spec/object_type/value_type/date_time_spec.rb +1 -1
- data/spec/object_type/value_type/guid_spec.rb +3 -3
- data/spec/object_type/value_type/value_type_spec.rb +2 -1
- data/spec/simplecov_helper.rb +3 -2
- metadata +5 -3
@@ -50,25 +50,3 @@ class Module #:nodoc:
|
|
50
50
|
name.gsub(/.*::/, '')
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
54
|
-
module ActiveFacts #:nodoc:
|
55
|
-
# If the args array ends with a hash, remove it.
|
56
|
-
# If the remaining args are fewer than the arg_names,
|
57
|
-
# extract values from the hash and append them to args.
|
58
|
-
# Return the new args array and the hash.
|
59
|
-
# In any case leave the original args unmodified.
|
60
|
-
def self.extract_hash_args(arg_names, args)
|
61
|
-
if Hash === args[-1]
|
62
|
-
arg_hash = args[-1] # Don't pop args, leave it unmodified
|
63
|
-
args = args[0..-2]
|
64
|
-
arg_hash = arg_hash.clone if (args.size < arg_names.size)
|
65
|
-
while args.size < arg_names.size
|
66
|
-
args << arg_hash[n = arg_names[args.size]]
|
67
|
-
arg_hash.delete(n)
|
68
|
-
end
|
69
|
-
else
|
70
|
-
arg_hash = {}
|
71
|
-
end
|
72
|
-
return args, arg_hash
|
73
|
-
end
|
74
|
-
end
|
@@ -6,6 +6,7 @@
|
|
6
6
|
#
|
7
7
|
# The methods of this module are added to Value type classes.
|
8
8
|
#
|
9
|
+
|
9
10
|
module ActiveFacts
|
10
11
|
module API
|
11
12
|
|
@@ -15,14 +16,9 @@ module ActiveFacts
|
|
15
16
|
|
16
17
|
# Value instance methods:
|
17
18
|
def initialize(*args) #:nodoc:
|
18
|
-
|
19
|
+
arg_hash = args[-1].is_a?(Hash) ? args.pop.clone : nil
|
19
20
|
|
20
21
|
super(args)
|
21
|
-
|
22
|
-
(hash ? hash.entries : []).each do |role_name, value|
|
23
|
-
role = self.class.roles(role_name)
|
24
|
-
send(role.setter, value)
|
25
|
-
end
|
26
22
|
end
|
27
23
|
|
28
24
|
# verbalise this Value
|
@@ -31,7 +27,9 @@ module ActiveFacts
|
|
31
27
|
end
|
32
28
|
|
33
29
|
# A value is its own key, unless it's a delegate for a raw value
|
34
|
-
def identifying_role_values #:nodoc:
|
30
|
+
def identifying_role_values(klass = nil) #:nodoc:
|
31
|
+
# The identifying role value for the supertype of a value type is always the same as for the subtype:
|
32
|
+
# raise "Value Types cannot return identifying_role_values for supertypes" if klass and klass != self.class
|
35
33
|
__getobj__ rescue self
|
36
34
|
end
|
37
35
|
|
@@ -75,44 +73,58 @@ module ActiveFacts
|
|
75
73
|
"#{basename} = #{superclass.basename}();"
|
76
74
|
end
|
77
75
|
|
78
|
-
def identifying_role_values(
|
79
|
-
|
80
|
-
|
81
|
-
return arg.identifying_role_values
|
82
|
-
end
|
83
|
-
new(*args).identifying_role_values
|
84
|
-
end
|
85
|
-
|
86
|
-
def assert_instance(constellation, args) #:nodoc:
|
87
|
-
# Build the key for this instance from the args
|
88
|
-
# The key of an instance is the value or array of keys of the identifying values.
|
89
|
-
# The key values aren't necessarily present in the constellation, even after this.
|
90
|
-
key = identifying_role_values(*args)
|
76
|
+
def identifying_role_values(constellation, args) #:nodoc:
|
77
|
+
# Normalise positional arguments into an arguments hash (this changes the passed parameter)
|
78
|
+
arg_hash = args[-1].is_a?(Hash) ? args.pop : {}
|
91
79
|
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
instance.constellation = constellation
|
102
|
-
return *index_instance(instance)
|
80
|
+
# If a single arg is already the correct class or a subclass,
|
81
|
+
# use it directly, otherwise create one.
|
82
|
+
# This appears to be the only way to handle e.g. Date correctly
|
83
|
+
unless args.size == 1 and instance = args[0] and instance.is_a?(self)
|
84
|
+
instance = new_instance(constellation, *args)
|
85
|
+
end
|
86
|
+
args.replace([arg_hash])
|
87
|
+
instance.identifying_role_values
|
103
88
|
end
|
104
89
|
|
105
|
-
|
106
|
-
|
90
|
+
def assert_instance(constellation, args)
|
91
|
+
new_identifier = args == [:new]
|
92
|
+
key = identifying_role_values(constellation, args)
|
93
|
+
# args are now normalized to an array containing a single Hash element
|
94
|
+
arg_hash = args[0]
|
95
|
+
|
96
|
+
if new_identifier
|
97
|
+
instance = key # AutoCounter is its own key
|
98
|
+
else
|
99
|
+
instance_index = constellation.instances[self]
|
100
|
+
unless instance = constellation.has_candidate(self, key) || instance_index[key]
|
101
|
+
instance = new_instance(constellation, key)
|
102
|
+
constellation.candidate(instance)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Assign any extra roles that may have been passed.
|
107
|
+
# An exception here leaves the object as a candidate,
|
108
|
+
# but without the offending role (re-)assigned.
|
109
|
+
arg_hash.each do |k, v|
|
110
|
+
instance.send(:"#{k}=", v)
|
111
|
+
end
|
112
|
+
|
113
|
+
instance
|
114
|
+
end
|
115
|
+
|
116
|
+
def index_instance(constellation, instance) #:nodoc:
|
117
|
+
# Index the instance in the constellation's InstanceIndex for this class:
|
118
|
+
instances = constellation.instances[self]
|
107
119
|
key = instance.identifying_role_values
|
108
120
|
instances[key] = instance
|
109
121
|
|
110
122
|
# Index the instance for each supertype:
|
111
123
|
supertypes.each do |supertype|
|
112
|
-
supertype.index_instance(
|
124
|
+
supertype.index_instance(constellation, instance)
|
113
125
|
end
|
114
126
|
|
115
|
-
|
127
|
+
instance
|
116
128
|
end
|
117
129
|
|
118
130
|
def inherited(other) #:nodoc:
|
@@ -123,15 +135,26 @@ module ActiveFacts
|
|
123
135
|
end
|
124
136
|
end
|
125
137
|
|
126
|
-
def self.included
|
127
|
-
|
138
|
+
def self.included klass #:nodoc:
|
139
|
+
klass.send :extend, ClassMethods
|
140
|
+
|
141
|
+
if !klass.respond_to?(:new_instance)
|
142
|
+
class << klass
|
143
|
+
def new_instance constellation, *args
|
144
|
+
instance = allocate
|
145
|
+
instance.instance_variable_set("@constellation", constellation)
|
146
|
+
instance.send(:initialize, *args)
|
147
|
+
instance
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
128
151
|
|
129
152
|
# Register ourselves with the parent module, which has become a Vocabulary:
|
130
|
-
vocabulary =
|
153
|
+
vocabulary = klass.modspace
|
131
154
|
unless vocabulary.respond_to? :object_type # Extend module with Vocabulary if necessary
|
132
155
|
vocabulary.send :extend, Vocabulary
|
133
156
|
end
|
134
|
-
vocabulary.__add_object_type(
|
157
|
+
vocabulary.__add_object_type(klass)
|
135
158
|
end
|
136
159
|
end
|
137
160
|
end
|
data/lib/activefacts/tracer.rb
CHANGED
@@ -28,12 +28,14 @@ module ActiveFacts
|
|
28
28
|
if @keys[:debug]
|
29
29
|
errors = []
|
30
30
|
success = false
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
(
|
32
|
+
[ENV["DEBUG_PREFERENCE"]].compact +
|
33
|
+
[
|
34
|
+
'pry',
|
35
|
+
'debugger',
|
36
|
+
'ruby-debug'
|
37
|
+
]
|
38
|
+
).each do |debugger|
|
37
39
|
begin
|
38
40
|
require debugger
|
39
41
|
puts "Loaded "+debugger
|
@@ -27,6 +27,7 @@ describe "A Constellation instance" do
|
|
27
27
|
class Name < StringVal
|
28
28
|
value_type
|
29
29
|
#has_one :attr, Name
|
30
|
+
has_one :undefined_role # This will be unsatisfied with the non-existence of the UndefinedRole class
|
30
31
|
end
|
31
32
|
|
32
33
|
class LegalEntity
|
@@ -34,18 +35,18 @@ describe "A Constellation instance" do
|
|
34
35
|
one_to_one :name, :mandatory => true
|
35
36
|
end
|
36
37
|
|
37
|
-
class
|
38
|
+
class Surrogate
|
38
39
|
identified_by :auto_counter_val
|
39
40
|
one_to_one :auto_counter_val
|
40
41
|
end
|
41
42
|
|
42
43
|
class Company < LegalEntity
|
43
|
-
supertypes
|
44
|
+
supertypes Surrogate
|
44
45
|
end
|
45
46
|
|
46
47
|
class Person < LegalEntity
|
47
|
-
identified_by :name, :family_name
|
48
|
-
supertypes :
|
48
|
+
identified_by :name, :family_name # REVISIT: want a way to role_alias :name, :given_name
|
49
|
+
supertypes :surrogate # Use a Symbol binding this time
|
49
50
|
|
50
51
|
has_one :family_name, :class => Name
|
51
52
|
has_one :employer, :class => Company
|
@@ -84,6 +85,13 @@ describe "A Constellation instance" do
|
|
84
85
|
it "should complain when accessing a class that isn't an object type" do
|
85
86
|
class Mod::Bar; end
|
86
87
|
lambda { @constellation.Bar }.should raise_error
|
88
|
+
lambda { @constellation.instances.Bar }.should raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should deny handling an object type defined outside the current module" do
|
92
|
+
class ::Bar; end
|
93
|
+
lambda { @constellation.Bar }.should raise_error
|
94
|
+
lambda { @constellation.instances[Bar] }.should raise_error
|
87
95
|
end
|
88
96
|
|
89
97
|
it "should allow inspection" do
|
@@ -99,7 +107,14 @@ describe "A Constellation instance" do
|
|
99
107
|
# @constellation.query.should == Mod
|
100
108
|
# end
|
101
109
|
|
102
|
-
it "should
|
110
|
+
it "should create methods to assert instances" do
|
111
|
+
# Check that methods have not yet been created:
|
112
|
+
@constellation.should_not respond_to(:Name)
|
113
|
+
@constellation.should_not respond_to(:LegalEntity)
|
114
|
+
@constellation.should_not respond_to(:Company)
|
115
|
+
@constellation.should_not respond_to(:Person)
|
116
|
+
|
117
|
+
# Assert instances
|
103
118
|
name = foo = acme = fred_fly = nil
|
104
119
|
lambda {
|
105
120
|
name = @constellation.Name("foo")
|
@@ -107,6 +122,14 @@ describe "A Constellation instance" do
|
|
107
122
|
acme = @constellation.Company("Acme, Inc", :auto_counter_val => :new)
|
108
123
|
fred_fly = @constellation.Person("fred", "fly", :auto_counter_val => :new)
|
109
124
|
}.should_not raise_error
|
125
|
+
|
126
|
+
# Check that methods have not yet been created:
|
127
|
+
@constellation.should respond_to(:Name)
|
128
|
+
@constellation.should respond_to(:LegalEntity)
|
129
|
+
@constellation.should respond_to(:Company)
|
130
|
+
@constellation.should respond_to(:Person)
|
131
|
+
|
132
|
+
# Check the instances
|
110
133
|
name.class.should == Mod::Name
|
111
134
|
name.constellation.should == @constellation
|
112
135
|
|
@@ -143,47 +166,66 @@ describe "A Constellation instance" do
|
|
143
166
|
fred_fly1.object_id.should == fred_fly2.object_id
|
144
167
|
end
|
145
168
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
169
|
+
describe "re-assertion with any one of multiple identifiers" do
|
170
|
+
before :each do
|
171
|
+
# Create some instances:
|
172
|
+
@name1 = @constellation.Name("foo") # Value type
|
173
|
+
@foo1 = @constellation.LegalEntity("foo") # Entity Type with simple identifier
|
174
|
+
@acme1 = @constellation.Company("Acme, Inc", :auto_counter_val => :new)
|
175
|
+
@acme1_id = @acme1.auto_counter_val
|
176
|
+
end
|
151
177
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
178
|
+
it "should be allowed with a normal value type id" do
|
179
|
+
# Reassert the instances:
|
180
|
+
@name2 = @constellation.Name("foo")
|
181
|
+
@foo2 = @constellation.LegalEntity("foo")
|
182
|
+
@acme2 = nil
|
183
|
+
lambda {
|
184
|
+
# Without the auto_counter_val
|
185
|
+
@acme2 = @constellation.Company("Acme, Inc")
|
186
|
+
}.should_not raise_error
|
187
|
+
|
188
|
+
# This creates a new auto_counter_val, changing the acme instance (and hence, both references to it)
|
189
|
+
@acme2.auto_counter_val = :new
|
190
|
+
@acme2.should == @acme1
|
191
|
+
@acme2.auto_counter_val.should_not be_defined
|
192
|
+
@acme2.auto_counter_val.to_s.should_not == @acme1_id.to_s
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should be allowed with an autocounter id" do
|
196
|
+
acme3 = @constellation.Surrogate(@acme1_id)
|
197
|
+
acme3.should == @acme1
|
198
|
+
end
|
160
199
|
end
|
161
200
|
|
162
|
-
it "
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
acme = @constellation.Company.assert("Acme, Inc", :auto_counter_val => :new)
|
168
|
-
fred_fly = @constellation.Person.assert("fred", "fly", :auto_counter_val => :new)
|
169
|
-
}.should_not raise_error
|
170
|
-
name.class.should == Mod::Name
|
171
|
-
name.constellation.should == @constellation
|
201
|
+
it "Should raise an exception with assigning a role whose referent (object type) has not yet been defined" do
|
202
|
+
n = @constellation.Name("Fred")
|
203
|
+
# This does n;t raise the "settable_roles_exception". I'm no longer sure how I did this, so I can't get coverage on this code :(
|
204
|
+
proc { n.undefined_role = 'foo' }.should raise_error
|
205
|
+
end
|
172
206
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
207
|
+
# Maybe not complete yet
|
208
|
+
describe "assigning additional arguments on asserting a value type" do
|
209
|
+
before :each do
|
210
|
+
# This should work, but...
|
211
|
+
# birth_name = @constellation.Name("Smith", :person_as_birth_name => {:name => "Janet", :family_name => "Jones", :auto_counter_val => :new})
|
212
|
+
# for now, use the following form
|
213
|
+
@birth_name = @constellation.Name("Smith", :person_as_birth_name => ["Janet", "Jones", {:auto_counter_val => :new}])
|
214
|
+
@person = @birth_name.person_as_birth_name
|
215
|
+
end
|
177
216
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
217
|
+
it "should create required instances" do
|
218
|
+
@person.should_not be_nil
|
219
|
+
@person.family_name.should == "Jones"
|
220
|
+
@person.name.should == "Janet"
|
221
|
+
@person.birth_name.should == "Smith"
|
222
|
+
end
|
182
223
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
224
|
+
it "should initialise secondary supertypes" do
|
225
|
+
@acv = @person.auto_counter_val
|
226
|
+
@acv.should_not be_nil
|
227
|
+
@acv.surrogate.should == @person
|
228
|
+
end
|
187
229
|
end
|
188
230
|
|
189
231
|
it "should support population blocks" do
|
@@ -194,7 +236,7 @@ describe "A Constellation instance" do
|
|
194
236
|
Company("Acme, Inc", :auto_counter_val => :new)
|
195
237
|
end
|
196
238
|
@constellation.Name.size.should == 5
|
197
|
-
@constellation.
|
239
|
+
@constellation.Surrogate.size.should == 2
|
198
240
|
end
|
199
241
|
|
200
242
|
it "should verbalise itself" do
|
@@ -202,28 +244,31 @@ describe "A Constellation instance" do
|
|
202
244
|
Name("bar")
|
203
245
|
LegalEntity("foo")
|
204
246
|
c = Company("Acme, Inc", :auto_counter_val => :new)
|
205
|
-
|
247
|
+
c.is_a?(Mod::Surrogate).should == true
|
248
|
+
c.auto_counter_val.should_not == nil
|
249
|
+
p = Person("Fred", "Nerk", :auto_counter_val => :new)
|
250
|
+
p.employer = c
|
206
251
|
p.birth_name = "Nerk"
|
207
252
|
end
|
208
253
|
s = @constellation.verbalise
|
209
254
|
names = s.split(/\n/).grep(/\tEvery /).map{|l| l.sub(/.*Every (.*):$/, '\1')}
|
210
|
-
expected = ["
|
255
|
+
expected = ["Company", "LegalEntity", "Name", "Person", "StringVal", "Surrogate"]
|
211
256
|
names.sort.should == expected
|
212
257
|
end
|
213
258
|
|
214
259
|
it "should support string capitalisation functions" do
|
215
|
-
names = ["Company", "LegalEntity", "Name", "Person", "StringVal", "
|
260
|
+
names = ["Company", "LegalEntity", "Name", "Person", "StringVal", "Surrogate"]
|
216
261
|
camelwords = names.map{|n| n.camelwords }
|
217
|
-
camelwords.should == [["Company"], ["Legal", "Entity"], ["Name"], ["Person"], ["String", "Val"], ["Surrogate"
|
262
|
+
camelwords.should == [["Company"], ["Legal", "Entity"], ["Name"], ["Person"], ["String", "Val"], ["Surrogate"]]
|
218
263
|
|
219
264
|
snakes = names.map{|n| n.snakecase }
|
220
|
-
snakes.should == ["company", "legal_entity", "name", "person", "string_val", "
|
265
|
+
snakes.should == ["company", "legal_entity", "name", "person", "string_val", "surrogate"]
|
221
266
|
|
222
267
|
camelupper = snakes.map{|n| n.camelcase }
|
223
|
-
camelupper.should == ["Company", "LegalEntity", "Name", "Person", "StringVal", "
|
268
|
+
camelupper.should == ["Company", "LegalEntity", "Name", "Person", "StringVal", "Surrogate"]
|
224
269
|
|
225
270
|
camellower = snakes.map{|n| n.camelcase(:lower) }
|
226
|
-
camellower.should == ["company", "legalEntity", "name", "person", "stringVal", "
|
271
|
+
camellower.should == ["company", "legalEntity", "name", "person", "stringVal", "surrogate"]
|
227
272
|
end
|
228
273
|
|
229
274
|
it "should allow inspection of instance indices" do
|
@@ -236,8 +281,8 @@ describe "A Constellation instance" do
|
|
236
281
|
@constellation.Name.keys.sort.should == ["baz"]
|
237
282
|
|
238
283
|
@constellation.StringVal.keys.sort.should == ["baz"]
|
239
|
-
@constellation.StringVal
|
240
|
-
@constellation.StringVal
|
284
|
+
@constellation.StringVal[baz].should == baz
|
285
|
+
@constellation.StringVal["baz"].should == baz
|
241
286
|
end
|
242
287
|
|
243
288
|
describe "instance indices" do
|
@@ -270,8 +315,8 @@ describe "A Constellation instance" do
|
|
270
315
|
@constellation.LegalEntity.keys.sort.should include [name]
|
271
316
|
@constellation.LegalEntity.keys.sort.should include [fred]
|
272
317
|
|
273
|
-
@constellation.
|
274
|
-
@constellation.
|
318
|
+
@constellation.Surrogate.values.should include acme
|
319
|
+
@constellation.Surrogate.values.should include fred_fly
|
275
320
|
end
|
276
321
|
|
277
322
|
it "should handle one-to-ones correctly" do
|
@@ -286,23 +331,47 @@ describe "A Constellation instance" do
|
|
286
331
|
end
|
287
332
|
|
288
333
|
it "should allow retraction of instances" do
|
334
|
+
@constellation.Person
|
289
335
|
person = @constellation.Person "Fred", "Smith", :auto_counter_val => :new, :birth_name => "Nerk"
|
336
|
+
smith = @constellation.Name("Smith")
|
337
|
+
|
338
|
+
# Check things are indexed properly:
|
339
|
+
@constellation.Surrogate.size.should == 1
|
340
|
+
@constellation.LegalEntity.size.should == 1
|
341
|
+
@constellation.Person.size.should == 1
|
342
|
+
person.family_name.should == smith
|
343
|
+
smith.all_person_as_family_name.size.should == 1
|
290
344
|
|
291
|
-
@constellation.retract(
|
345
|
+
@constellation.retract(smith)
|
346
|
+
|
347
|
+
@constellation.Name["Fred"].should_not be_nil # FamilyName is not mandatory, so Fred still exists
|
292
348
|
@constellation.Name["Smith"].should be_nil
|
293
|
-
|
349
|
+
|
350
|
+
@constellation.Surrogate.size.should == 1
|
351
|
+
@constellation.LegalEntity.size.should == 1
|
352
|
+
@constellation.Person.size.should == 1
|
294
353
|
|
295
354
|
person.family_name.should be_nil
|
296
|
-
|
297
|
-
|
355
|
+
|
356
|
+
smith.all_person_as_family_name.size.should == 0
|
298
357
|
end
|
299
358
|
|
300
359
|
it "should retract linked instances (cascading)" do
|
301
|
-
@constellation.Person "Fred", "Smith", :auto_counter_val => :new, :birth_name => "Nerk"
|
302
|
-
@constellation.Person "George", "Smith", :auto_counter_val => :new, :birth_name => "Patrick"
|
360
|
+
fred = @constellation.Person "Fred", "Smith", :auto_counter_val => :new, :birth_name => "Nerk"
|
361
|
+
george = @constellation.Person "George", "Smith", :auto_counter_val => :new, :birth_name => "Patrick"
|
362
|
+
smith = @constellation.Name("Smith")
|
363
|
+
|
303
364
|
@constellation.Person.size.should == 2
|
304
|
-
|
305
|
-
|
365
|
+
fred.family_name.should == smith
|
366
|
+
george.family_name.should == smith
|
367
|
+
smith.all_person_as_family_name.size.should == 2
|
368
|
+
|
369
|
+
@constellation.retract(fred)
|
370
|
+
|
371
|
+
@constellation.Person.size.should == 1 # Fred is gone, George still exists
|
372
|
+
@constellation.Person.values[0].name.should == 'George'
|
373
|
+
fred.family_name.should be_nil
|
374
|
+
smith.all_person_as_family_name.size.should == 1
|
306
375
|
end
|
307
376
|
|
308
377
|
it "should fail to recognise references to unresolved forward referenced classes" do
|
@@ -310,7 +379,7 @@ describe "A Constellation instance" do
|
|
310
379
|
class Foo
|
311
380
|
identified_by :name
|
312
381
|
one_to_one :name
|
313
|
-
has_one :
|
382
|
+
has_one :not_yet
|
314
383
|
has_one :baz, :class => "BAZ"
|
315
384
|
end
|
316
385
|
|
@@ -322,7 +391,7 @@ describe "A Constellation instance" do
|
|
322
391
|
@c = ActiveFacts::API::Constellation.new(Mod2)
|
323
392
|
le = @c.Foo("Foo")
|
324
393
|
lambda {
|
325
|
-
le.
|
394
|
+
le.not_yet
|
326
395
|
}.should raise_error(NoMethodError)
|
327
396
|
lambda {
|
328
397
|
le.baz
|
@@ -330,7 +399,7 @@ describe "A Constellation instance" do
|
|
330
399
|
|
331
400
|
# Now define the classes and try again:
|
332
401
|
module Mod2
|
333
|
-
class
|
402
|
+
class NotYet < String
|
334
403
|
value_type
|
335
404
|
end
|
336
405
|
class BAZ < String
|
@@ -338,8 +407,8 @@ describe "A Constellation instance" do
|
|
338
407
|
end
|
339
408
|
end
|
340
409
|
lambda {
|
341
|
-
le.
|
342
|
-
le.
|
410
|
+
le.not_yet
|
411
|
+
le.not_yet = 'not_yet'
|
343
412
|
}.should_not raise_error
|
344
413
|
lambda {
|
345
414
|
le.baz
|
@@ -448,21 +517,10 @@ describe "A Constellation instance" do
|
|
448
517
|
}.should raise_error
|
449
518
|
end
|
450
519
|
|
451
|
-
it "should complain when role name and counter part mismatch" do
|
452
|
-
lambda {
|
453
|
-
module Mod
|
454
|
-
class CompanyName
|
455
|
-
identified_by :name
|
456
|
-
has_one :company, :class => :person
|
457
|
-
end
|
458
|
-
end
|
459
|
-
}.should raise_error(Exception, /indicates a different counterpart object_type/)
|
460
|
-
end
|
461
|
-
|
462
520
|
it "should error on invalid :class values" do
|
463
521
|
lambda {
|
464
522
|
module Mod
|
465
|
-
class
|
523
|
+
class Surrogate
|
466
524
|
has_one :Name, :class => 3
|
467
525
|
end
|
468
526
|
end
|
@@ -472,7 +530,7 @@ describe "A Constellation instance" do
|
|
472
530
|
it "should error on misleading :class values" do
|
473
531
|
lambda {
|
474
532
|
module Mod
|
475
|
-
class
|
533
|
+
class Surrogate
|
476
534
|
has_one :Name, :class => Extra
|
477
535
|
end
|
478
536
|
end
|
@@ -496,12 +554,24 @@ describe "A Constellation instance" do
|
|
496
554
|
}.should_not raise_error
|
497
555
|
end
|
498
556
|
|
499
|
-
it "should
|
557
|
+
it "should copy values during cross-constellation assignment" do
|
500
558
|
c = @constellation.Company("foo", :auto_counter_val => 23)
|
559
|
+
|
560
|
+
# Now make a new constellation and use the above values to initialise new instances
|
561
|
+
p = nil
|
501
562
|
lambda {
|
502
563
|
c2 = ActiveFacts::API::Constellation.new(Mod)
|
503
564
|
p = c2.Person('Fred', 'Smith', :auto_counter_val => :new)
|
504
|
-
p.employer = [c, {:auto_counter_val =>
|
565
|
+
p.employer = [ c.name, {:auto_counter_val => c.auto_counter_val}]
|
505
566
|
}.should_not raise_error
|
567
|
+
c.auto_counter_val.should_not === p.employer.auto_counter_val
|
568
|
+
c.auto_counter_val.should_not == p.employer.auto_counter_val
|
569
|
+
c.auto_counter_val.to_s.should == p.employer.auto_counter_val.to_s
|
570
|
+
p.employer.should_not === c
|
571
|
+
|
572
|
+
lambda {
|
573
|
+
# Disallowed because it re-assigns the auto_counter_val identification value
|
574
|
+
p.employer = [ "foo", {:auto_counter_val => :new}]
|
575
|
+
}.should raise_error
|
506
576
|
end
|
507
577
|
end
|