activefacts 0.6.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.
- data/History.txt +4 -0
- data/Manifest.txt +83 -0
- data/README.rdoc +81 -0
- data/Rakefile +41 -0
- data/bin/afgen +46 -0
- data/bin/cql +52 -0
- data/examples/CQL/Address.cql +46 -0
- data/examples/CQL/Blog.cql +54 -0
- data/examples/CQL/CompanyDirectorEmployee.cql +51 -0
- data/examples/CQL/Death.cql +16 -0
- data/examples/CQL/Genealogy.cql +95 -0
- data/examples/CQL/Marriage.cql +18 -0
- data/examples/CQL/Metamodel.cql +238 -0
- data/examples/CQL/MultiInheritance.cql +19 -0
- data/examples/CQL/OilSupply.cql +47 -0
- data/examples/CQL/Orienteering.cql +108 -0
- data/examples/CQL/PersonPlaysGame.cql +17 -0
- data/examples/CQL/SchoolActivities.cql +31 -0
- data/examples/CQL/SimplestUnary.cql +12 -0
- data/examples/CQL/SubtypePI.cql +32 -0
- data/examples/CQL/Warehousing.cql +99 -0
- data/examples/CQL/WindowInRoomInBldg.cql +22 -0
- data/lib/activefacts.rb +10 -0
- data/lib/activefacts/api.rb +25 -0
- data/lib/activefacts/api/concept.rb +384 -0
- data/lib/activefacts/api/constellation.rb +106 -0
- data/lib/activefacts/api/entity.rb +239 -0
- data/lib/activefacts/api/instance.rb +54 -0
- data/lib/activefacts/api/numeric.rb +158 -0
- data/lib/activefacts/api/role.rb +94 -0
- data/lib/activefacts/api/standard_types.rb +67 -0
- data/lib/activefacts/api/support.rb +59 -0
- data/lib/activefacts/api/value.rb +122 -0
- data/lib/activefacts/api/vocabulary.rb +120 -0
- data/lib/activefacts/cql.rb +31 -0
- data/lib/activefacts/cql/CQLParser.treetop +104 -0
- data/lib/activefacts/cql/Concepts.treetop +112 -0
- data/lib/activefacts/cql/DataTypes.treetop +66 -0
- data/lib/activefacts/cql/Expressions.treetop +113 -0
- data/lib/activefacts/cql/FactTypes.treetop +185 -0
- data/lib/activefacts/cql/Language/English.treetop +92 -0
- data/lib/activefacts/cql/LexicalRules.treetop +169 -0
- data/lib/activefacts/cql/Rakefile +6 -0
- data/lib/activefacts/cql/parser.rb +88 -0
- data/lib/activefacts/generate/absorption.rb +87 -0
- data/lib/activefacts/generate/cql.rb +441 -0
- data/lib/activefacts/generate/cql/html.rb +397 -0
- data/lib/activefacts/generate/null.rb +19 -0
- data/lib/activefacts/generate/ordered.rb +557 -0
- data/lib/activefacts/generate/ruby.rb +326 -0
- data/lib/activefacts/generate/sql/server.rb +164 -0
- data/lib/activefacts/generate/text.rb +21 -0
- data/lib/activefacts/input/cql.rb +1268 -0
- data/lib/activefacts/input/orm.rb +926 -0
- data/lib/activefacts/persistence.rb +1 -0
- data/lib/activefacts/persistence/composition.rb +653 -0
- data/lib/activefacts/support.rb +51 -0
- data/lib/activefacts/version.rb +3 -0
- data/lib/activefacts/vocabulary.rb +6 -0
- data/lib/activefacts/vocabulary/extensions.rb +343 -0
- data/lib/activefacts/vocabulary/metamodel.rb +303 -0
- data/script/txt2html +71 -0
- data/spec/absorption_spec.rb +95 -0
- data/spec/api/autocounter.rb +82 -0
- data/spec/api/constellation.rb +130 -0
- data/spec/api/entity_type.rb +101 -0
- data/spec/api/instance.rb +428 -0
- data/spec/api/roles.rb +122 -0
- data/spec/api/value_type.rb +112 -0
- data/spec/api_spec.rb +14 -0
- data/spec/cql_cql_spec.rb +58 -0
- data/spec/cql_parse_spec.rb +31 -0
- data/spec/cql_ruby_spec.rb +60 -0
- data/spec/cql_sql_spec.rb +54 -0
- data/spec/cql_symbol_tables_spec.rb +259 -0
- data/spec/cql_unit_spec.rb +336 -0
- data/spec/cqldump_spec.rb +169 -0
- data/spec/norma_cql_spec.rb +48 -0
- data/spec/norma_ruby_spec.rb +50 -0
- data/spec/norma_sql_spec.rb +45 -0
- data/spec/norma_tables_spec.rb +94 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +173 -0
@@ -0,0 +1,428 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Value instances in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
describe "An instance of every type of Concept" do
|
6
|
+
setup do
|
7
|
+
Object.send :remove_const, :Mod if Object.const_defined?("Mod")
|
8
|
+
module Mod
|
9
|
+
# These are the base value types we're going to test:
|
10
|
+
@base_types = [
|
11
|
+
Int, Real, AutoCounter, String, Date, DateTime
|
12
|
+
]
|
13
|
+
|
14
|
+
# Construct the names of the roles they play:
|
15
|
+
@base_type_roles = @base_types.map do |t|
|
16
|
+
t.name.snakecase
|
17
|
+
end
|
18
|
+
@role_names = @base_type_roles.inject([]) {|a, t|
|
19
|
+
a << :"#{t}_value"
|
20
|
+
} +
|
21
|
+
@base_type_roles.inject([]) {|a, t|
|
22
|
+
a << :"#{t}_sub_value"
|
23
|
+
}
|
24
|
+
|
25
|
+
# Create a value type and a subtype of that value type for each base type:
|
26
|
+
@base_types.each do |base_type|
|
27
|
+
eval %Q{
|
28
|
+
class #{base_type.name}Value < #{base_type.name}
|
29
|
+
value_type
|
30
|
+
end
|
31
|
+
|
32
|
+
class #{base_type.name}SubValue < #{base_type.name}Value
|
33
|
+
# Note no new "value_type" is required here, it comes through inheritance
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create a TestByX, TestByXSub, and TestSubByX class for all base types X
|
39
|
+
# Each class has a has_one and a one_to_one for all roles.
|
40
|
+
# and is identified by the has_one :x role
|
41
|
+
@base_types.each do |base_type|
|
42
|
+
eval %Q{
|
43
|
+
class TestBy#{base_type.name}
|
44
|
+
identified_by :#{base_type.name.snakecase}_value#{
|
45
|
+
@role_names.map do |role_name|
|
46
|
+
%Q{
|
47
|
+
has_one :#{role_name}
|
48
|
+
one_to_one :one_#{role_name}, #{role_name.to_s.camelcase(true)}}
|
49
|
+
end*""
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
class TestBy#{base_type.name}Sub
|
54
|
+
identified_by :#{base_type.name.snakecase}_sub_value#{
|
55
|
+
@role_names.map do |role_name|
|
56
|
+
%Q{
|
57
|
+
has_one :#{role_name}
|
58
|
+
one_to_one :one_#{role_name}, #{role_name.to_s.camelcase(true)}}
|
59
|
+
end*""
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
class TestSubBy#{base_type.name} < TestBy#{base_type.name}
|
64
|
+
# Entity subtypes, inherit identification and all roles
|
65
|
+
end
|
66
|
+
|
67
|
+
class TestBy#{base_type.name}Entity
|
68
|
+
identified_by :test_by_#{base_type.name.snakecase}
|
69
|
+
one_to_one :test_by_#{base_type.name.snakecase}
|
70
|
+
end}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Simple Values
|
75
|
+
@int = 0
|
76
|
+
@real = 0.0
|
77
|
+
@auto_counter = 0
|
78
|
+
@new_auto_counter = :new
|
79
|
+
@string = "zero"
|
80
|
+
@date = [2008, 04, 19]
|
81
|
+
@date_time = [2008, 04, 19, 10, 28, 14]
|
82
|
+
|
83
|
+
# Value Type instances
|
84
|
+
@int_value = Mod::IntValue.new(1)
|
85
|
+
@real_value = Mod::RealValue.new(1.0)
|
86
|
+
@auto_counter_value = Mod::AutoCounterValue.new(1)
|
87
|
+
@new_auto_counter_value = Mod::AutoCounterValue.new(:new)
|
88
|
+
@string_value = Mod::StringValue.new("one")
|
89
|
+
@date_value = Mod::DateValue.new(2008, 04, 20)
|
90
|
+
@date_time_value = Mod::DateTimeValue.new(2008, 04, 20, 10, 28, 14)
|
91
|
+
|
92
|
+
# Value SubType instances
|
93
|
+
@int_sub_value = Mod::IntSubValue.new(4)
|
94
|
+
@real_sub_value = Mod::RealSubValue.new(4.0)
|
95
|
+
@auto_counter_sub_value = Mod::AutoCounterSubValue.new(4)
|
96
|
+
@auto_counter_sub_value_new = Mod::AutoCounterSubValue.new(:new)
|
97
|
+
@string_sub_value = Mod::StringSubValue.new("five")
|
98
|
+
@date_sub_value = Mod::DateSubValue.new(2008, 04, 25)
|
99
|
+
@date_time_sub_value = Mod::DateTimeSubValue.new(2008, 04, 26, 10, 28, 14)
|
100
|
+
|
101
|
+
# Entities identified by Value Type, SubType and Entity-by-value-type instances
|
102
|
+
@test_by_int = Mod::TestByInt.new(2)
|
103
|
+
@test_by_real = Mod::TestByReal.new(2.0)
|
104
|
+
@test_by_auto_counter = Mod::TestByAutoCounter.new(2)
|
105
|
+
@test_by_auto_counter_new = Mod::TestByAutoCounter.new(:new)
|
106
|
+
@test_by_string = Mod::TestByString.new("two")
|
107
|
+
@test_by_date = Mod::TestByDate.new(Date.new(2008,04,28))
|
108
|
+
#@test_by_date = Mod::TestByDate.new(2008,04,28)
|
109
|
+
@test_by_date_time = Mod::TestByDateTime.new(2008,04,28,10,28,15)
|
110
|
+
#@test_by_date_time = Mod::TestByDateTime.new(DateTime.new(2008,04,28,10,28,15))
|
111
|
+
|
112
|
+
@test_by_int_sub = Mod::TestByIntSub.new(2)
|
113
|
+
@test_by_real_sub = Mod::TestByRealSub.new(5.0)
|
114
|
+
@test_by_auto_counter_sub = Mod::TestByAutoCounterSub.new(6)
|
115
|
+
@test_by_auto_counter_new_sub = Mod::TestByAutoCounterSub.new(:new)
|
116
|
+
@test_by_string_sub = Mod::TestByStringSub.new("six")
|
117
|
+
@test_by_date_sub = Mod::TestByDateSub.new(Date.new(2008,04,27))
|
118
|
+
@test_by_date_time_sub = Mod::TestByDateTimeSub.new(2008,04,29,10,28,15)
|
119
|
+
|
120
|
+
@test_by_int_entity = Mod::TestByIntEntity.new(@test_by_int)
|
121
|
+
@test_by_real_entity = Mod::TestByRealEntity.new(@test_by_real)
|
122
|
+
@test_by_auto_counter_entity = Mod::TestByAutoCounterEntity.new(@test_by_auto_counter)
|
123
|
+
@test_by_auto_counter_new_entity = Mod::TestByAutoCounterEntity.new(@test_by_auto_counter_new)
|
124
|
+
@test_by_string_entity = Mod::TestByStringEntity.new(@test_by_string)
|
125
|
+
@test_by_date_entity = Mod::TestByDateEntity.new(@test_by_date)
|
126
|
+
@test_by_date_time_entity = Mod::TestByDateTimeEntity.new(@test_by_date_time)
|
127
|
+
|
128
|
+
# Entity subtypes
|
129
|
+
@test_sub_by_int = Mod::TestSubByInt.new(2)
|
130
|
+
@test_sub_by_real = Mod::TestSubByReal.new(2.0)
|
131
|
+
@test_sub_by_auto_counter = Mod::TestSubByAutoCounter.new(2)
|
132
|
+
@test_sub_by_auto_counter_new = Mod::TestSubByAutoCounter.new(:new)
|
133
|
+
@test_sub_by_string = Mod::TestSubByString.new("two")
|
134
|
+
@test_sub_by_date = Mod::TestSubByDate.new(Date.new(2008,04,28))
|
135
|
+
@test_sub_by_date_time = Mod::TestSubByDateTime.new(2008,04,28,10,28,15)
|
136
|
+
|
137
|
+
# These arrays get zipped together in various ways. Keep them aligned.
|
138
|
+
@values = [
|
139
|
+
@int, @real, @auto_counter, @new_auto_counter,
|
140
|
+
@string, @date, @date_time,
|
141
|
+
]
|
142
|
+
@classes = [
|
143
|
+
Int, Real, AutoCounter, AutoCounter,
|
144
|
+
String, Date, DateTime,
|
145
|
+
]
|
146
|
+
@value_types = [
|
147
|
+
Mod::IntValue, Mod::RealValue, Mod::AutoCounterValue, Mod::AutoCounterValue,
|
148
|
+
Mod::StringValue, Mod::DateValue, Mod::DateTimeValue,
|
149
|
+
Mod::IntSubValue, Mod::RealSubValue, Mod::AutoCounterSubValue, Mod::AutoCounterSubValue,
|
150
|
+
Mod::StringSubValue, Mod::DateSubValue, Mod::DateTimeSubValue,
|
151
|
+
]
|
152
|
+
@value_instances = [
|
153
|
+
@int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
|
154
|
+
@string_value, @date_value, @date_time_value,
|
155
|
+
@int_sub_value, @real_sub_value, @auto_counter_sub_value, @auto_counter_sub_value_new,
|
156
|
+
@string_sub_value, @date_sub_value, @date_time_sub_value,
|
157
|
+
@int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
|
158
|
+
@string_value, @date_value, @date_time_value,
|
159
|
+
]
|
160
|
+
@entity_types = [
|
161
|
+
Mod::TestByInt, Mod::TestByReal, Mod::TestByAutoCounter, Mod::TestByAutoCounter,
|
162
|
+
Mod::TestByString, Mod::TestByDate, Mod::TestByDateTime,
|
163
|
+
Mod::TestByIntSub, Mod::TestByRealSub, Mod::TestByAutoCounterSub, Mod::TestByAutoCounterSub,
|
164
|
+
Mod::TestByStringSub, Mod::TestByDateSub, Mod::TestByDateTimeSub,
|
165
|
+
Mod::TestSubByInt, Mod::TestSubByReal, Mod::TestSubByAutoCounter, Mod::TestSubByAutoCounter,
|
166
|
+
Mod::TestSubByString, Mod::TestSubByDate, Mod::TestSubByDateTime,
|
167
|
+
]
|
168
|
+
@entities = [
|
169
|
+
@test_by_int, @test_by_real, @test_by_auto_counter, @test_by_auto_counter_new,
|
170
|
+
@test_by_string, @test_by_date, @test_by_date_time,
|
171
|
+
@test_by_int_sub, @test_by_real_sub, @test_by_auto_counter_sub, @test_by_auto_counter_new_sub,
|
172
|
+
@test_by_string_sub, @test_by_date_sub, @test_by_date_time_sub,
|
173
|
+
@test_sub_by_int, @test_sub_by_real, @test_sub_by_auto_counter, @test_sub_by_auto_counter_new,
|
174
|
+
@test_sub_by_string, @test_sub_by_date, @test_sub_by_date_time,
|
175
|
+
]
|
176
|
+
@entities_by_entity = [
|
177
|
+
@test_by_int_entity,
|
178
|
+
@test_by_real_entity,
|
179
|
+
@test_by_auto_counter_entity,
|
180
|
+
@test_by_auto_counter_new_entity,
|
181
|
+
@test_by_string_entity,
|
182
|
+
@test_by_date_entity,
|
183
|
+
@test_by_date_time_entity,
|
184
|
+
]
|
185
|
+
@entities_by_entity_types = [
|
186
|
+
Mod::TestByIntEntity, Mod::TestByRealEntity, Mod::TestByAutoCounterEntity, Mod::TestByAutoCounterEntity,
|
187
|
+
Mod::TestByStringEntity, Mod::TestByDateEntity, Mod::TestByDateTimeEntity,
|
188
|
+
]
|
189
|
+
@test_role_names = [
|
190
|
+
:int_value, :real_value, :auto_counter_value, :auto_counter_value,
|
191
|
+
:string_value, :date_value, :date_time_value,
|
192
|
+
:int_sub_value, :real_sub_value, :auto_counter_sub_value, :auto_counter_sub_value,
|
193
|
+
:string_sub_value, :date_sub_value, :date_time_sub_value
|
194
|
+
]
|
195
|
+
@role_values = [
|
196
|
+
3, 3.0, 6, 7,
|
197
|
+
"three", Date.new(2008,4,21), DateTime.new(2008,4,22,10,28,16),
|
198
|
+
]
|
199
|
+
@subtype_role_instances = [
|
200
|
+
Mod::IntSubValue.new(6), Mod::RealSubValue.new(6.0),
|
201
|
+
Mod::AutoCounterSubValue.new(:new), Mod::AutoCounterSubValue.new(8),
|
202
|
+
Mod::StringSubValue.new("seven"),
|
203
|
+
Mod::DateSubValue.new(2008,4,29), Mod::DateTimeSubValue.new(2008,4,30,10,28,16)
|
204
|
+
]
|
205
|
+
end
|
206
|
+
|
207
|
+
it "if a value type, should verbalise" do
|
208
|
+
@value_types.each do |value_type|
|
209
|
+
#puts "#{value_type} verbalises as #{value_type.verbalise}"
|
210
|
+
value_type.respond_to?(:verbalise).should be_true
|
211
|
+
verbalisation = value_type.verbalise
|
212
|
+
verbalisation.should =~ %r{\b#{value_type.basename}\b}
|
213
|
+
verbalisation.should =~ %r{\b#{value_type.superclass.basename}\b}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it "if an entity type, should verbalise" do
|
218
|
+
@entity_types.each do |entity_type|
|
219
|
+
#puts entity_type.verbalise
|
220
|
+
entity_type.respond_to?(:verbalise).should be_true
|
221
|
+
verbalisation = entity_type.verbalise
|
222
|
+
verbalisation.should =~ %r{\b#{entity_type.basename}\b}
|
223
|
+
|
224
|
+
# All identifying roles should be in the verbalisation.
|
225
|
+
# Strictly this should be the role name, but we don't set names here.
|
226
|
+
entity_type.identifying_roles.each do |ir|
|
227
|
+
role = entity_type.roles(ir)
|
228
|
+
role.should_not be_nil
|
229
|
+
player = role.player
|
230
|
+
verbalisation.should =~ %r{\b#{player.basename}\b}
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
it "if a value, should verbalise" do
|
236
|
+
@value_instances.each do |value|
|
237
|
+
#puts value.verbalise
|
238
|
+
value.respond_to?(:verbalise).should be_true
|
239
|
+
verbalisation = value.verbalise
|
240
|
+
verbalisation.should =~ %r{\b#{value.class.basename}\b}
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
it "if an entity, should respond to verbalise" do
|
245
|
+
(@entities+@entities_by_entity).each do |entity|
|
246
|
+
#puts entity.verbalise
|
247
|
+
entity.respond_to?(:verbalise).should be_true
|
248
|
+
verbalisation = entity.verbalise
|
249
|
+
verbalisation.should =~ %r{\b#{entity.class.basename}\b}
|
250
|
+
entity.class.identifying_roles.each do |ir|
|
251
|
+
role = entity.class.roles(ir)
|
252
|
+
role.should_not be_nil
|
253
|
+
player = role.player
|
254
|
+
verbalisation.should =~ %r{\b#{player.basename}\b}
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should respond to constellation" do
|
260
|
+
(@value_instances+@entities+@entities_by_entity).each do |instance|
|
261
|
+
instance.respond_to?(:constellation).should be_true
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should respond to all its roles" do
|
266
|
+
@entities.each do |entity|
|
267
|
+
@test_role_names.each do |role_name|
|
268
|
+
entity.respond_to?(role_name).should be_true
|
269
|
+
entity.respond_to?(:"#{role_name}=").should be_true
|
270
|
+
entity.respond_to?(:"one_#{role_name}").should be_true
|
271
|
+
entity.respond_to?(:"one_#{role_name}=").should be_true
|
272
|
+
end
|
273
|
+
end
|
274
|
+
@entities_by_entity.each do |entity|
|
275
|
+
role = entity.class.roles(entity.class.identifying_roles[0])
|
276
|
+
role_name = role.name
|
277
|
+
entity.respond_to?(role_name).should be_true
|
278
|
+
entity.respond_to?(:"#{role_name}=").should be_true
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should return the Concept in response to .class()" do
|
283
|
+
@value_types.zip(@value_instances).each do |concept, instance|
|
284
|
+
instance.class.should == concept
|
285
|
+
end
|
286
|
+
@entity_types.zip(@entities).each do |concept, instance|
|
287
|
+
instance.class.should == concept
|
288
|
+
end
|
289
|
+
@entities_by_entity_types.zip(@entities_by_entity).each do |concept, instance|
|
290
|
+
instance.class.should == concept
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should return the module in response to .vocabulary()" do
|
295
|
+
(@value_types+@entity_types).zip((@value_instances+@entities+@entities_by_entity)).each do |concept, instance|
|
296
|
+
instance.class.vocabulary.should == Mod
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
it "each entity type should be able to be constructed using simple values" do
|
301
|
+
@entity_types.zip(@values+@values+@values, @classes+@classes+@classes).each do |entity_type, value, klass|
|
302
|
+
# An identifier parameter can be an array containing a simple value too
|
303
|
+
[ value,
|
304
|
+
Array === value ? nil : [value],
|
305
|
+
# entity_type.new(value) # REVISIT: It's not yet the case that an instance of the correct type can be used as a constructor parameter
|
306
|
+
].compact.each do |value|
|
307
|
+
e = nil
|
308
|
+
lambda {
|
309
|
+
#puts "Constructing #{entity_type} using #{value.class} #{value.inspect}:"
|
310
|
+
e = entity_type.new(value)
|
311
|
+
}.should_not raise_error
|
312
|
+
# Verify that the identifying role has a equivalent value (except AutoCounter):
|
313
|
+
role_name = entity_type.identifying_roles[0]
|
314
|
+
role = entity_type.roles(role_name)
|
315
|
+
player = role.player
|
316
|
+
player_superclasses = [ player.superclass, player.superclass.superclass ]
|
317
|
+
e.send(role_name).should == klass.new(*value) unless player_superclasses.include?(AutoCounter)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
it "that are entities should not allow its identifying roles to be assigned" do
|
323
|
+
pending
|
324
|
+
@entities.zip(@test_role_names, @role_values).each do |entity, role_name, value|
|
325
|
+
lambda {
|
326
|
+
entity.send(:"#{role_name}=", value)
|
327
|
+
}.should raise_error
|
328
|
+
end
|
329
|
+
@entities_by_entity.each do |entity|
|
330
|
+
role = entity.class.roles(entity.class.identifying_roles[0])
|
331
|
+
role_name = role.name
|
332
|
+
lambda {
|
333
|
+
entity.send(:"#{role_name}=", nil)
|
334
|
+
}.should raise_error
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
it "should allow its non-identifying roles to be assigned values" do
|
339
|
+
@entities.zip(@test_role_names).each do |entity, identifying_role|
|
340
|
+
@test_role_names.zip(@role_values).each do |role_name, value|
|
341
|
+
next if role_name == identifying_role
|
342
|
+
lambda {
|
343
|
+
entity.send(:"#{role_name}=", value)
|
344
|
+
}.should_not raise_error
|
345
|
+
lambda {
|
346
|
+
entity.send(:"one_#{role_name}=", value)
|
347
|
+
}.should_not raise_error
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should allow its non-identifying roles to be assigned instances" do
|
353
|
+
@entities.zip(@test_role_names).each do |entity, identifying_role|
|
354
|
+
@test_role_names.zip(@value_types, @role_values).each do |role_name, klass, value|
|
355
|
+
next unless value
|
356
|
+
next if role_name == identifying_role
|
357
|
+
instance = klass.new(value)
|
358
|
+
lambda {
|
359
|
+
entity.send(:"#{role_name}=", instance)
|
360
|
+
}.should_not raise_error
|
361
|
+
entity.send(role_name).class.should == klass
|
362
|
+
lambda {
|
363
|
+
entity.send(:"one_#{role_name}=", instance)
|
364
|
+
}.should_not raise_error
|
365
|
+
entity.send(:"one_#{role_name}").class.should == klass
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should allow its non-identifying roles to be assigned instances of value subtypes, retaining the subtype" do
|
371
|
+
@entities.zip(@test_role_names).each do |entity, identifying_role|
|
372
|
+
@test_role_names.zip(@subtype_role_instances).each do |role_name, instance|
|
373
|
+
next unless instance
|
374
|
+
next if role_name == identifying_role
|
375
|
+
lambda {
|
376
|
+
entity.send(:"#{role_name}=", instance)
|
377
|
+
}.should_not raise_error
|
378
|
+
entity.send(role_name).class.should == instance.class
|
379
|
+
lambda {
|
380
|
+
entity.send(:"one_#{role_name}=", instance)
|
381
|
+
}.should_not raise_error
|
382
|
+
entity.send(:"one_#{role_name}").class.should == instance.class
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
it "should add to has_one's conterpart role when non-identifying roles are assigned values" do
|
388
|
+
@entities.zip(@test_role_names).each do |entity, identifying_role|
|
389
|
+
@test_role_names.zip(@role_values).each do |role_name, value|
|
390
|
+
next if role_name == identifying_role or !value
|
391
|
+
|
392
|
+
# Test the has_one role:
|
393
|
+
role = entity.class.roles(role_name)
|
394
|
+
old_counterpart = entity.send(:"#{role_name}")
|
395
|
+
entity.send(:"#{role_name}=", value)
|
396
|
+
counterpart = entity.send(:"#{role_name}")
|
397
|
+
old_counterpart.should_not == counterpart
|
398
|
+
counterpart.send(role.counterpart.name).should be_include(entity)
|
399
|
+
old_counterpart.send(role.counterpart.name).should_not be_include(entity) if old_counterpart
|
400
|
+
|
401
|
+
# Test the one_to_one role:
|
402
|
+
role = entity.class.roles(:"one_#{role_name}")
|
403
|
+
old_counterpart = entity.send(:"one_#{role_name}")
|
404
|
+
entity.send(:"one_#{role_name}=", value)
|
405
|
+
counterpart = entity.send(:"one_#{role_name}")
|
406
|
+
old_counterpart.should_not == counterpart # Make sure we changed it!
|
407
|
+
counterpart.send(role.counterpart.name).should == entity
|
408
|
+
old_counterpart.send(role.counterpart.name).should be_nil if old_counterpart
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
it "should allow its non-identifying roles to be assigned nil" do
|
414
|
+
@entities.zip(@test_role_names).each do |entity, identifying_role|
|
415
|
+
@test_role_names.zip(@role_values).each do |role_name, value|
|
416
|
+
next if role_name == identifying_role
|
417
|
+
entity.send(:"#{role_name}=", value)
|
418
|
+
lambda {
|
419
|
+
entity.send(:"#{role_name}=", nil)
|
420
|
+
}.should_not raise_error
|
421
|
+
lambda {
|
422
|
+
entity.send(:"one_#{role_name}=", nil)
|
423
|
+
}.should_not raise_error
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
end
|
data/spec/api/roles.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Roles of concept classes in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
describe "Roles" do
|
6
|
+
setup do
|
7
|
+
Object.send :remove_const, :Mod if Object.const_defined?("Mod")
|
8
|
+
module Mod
|
9
|
+
class Name < String
|
10
|
+
value_type
|
11
|
+
end
|
12
|
+
class LegalEntity
|
13
|
+
identified_by :name
|
14
|
+
has_one :name
|
15
|
+
end
|
16
|
+
class Contract
|
17
|
+
identified_by :first, :second
|
18
|
+
has_one :first, LegalEntity
|
19
|
+
has_one :second, LegalEntity
|
20
|
+
end
|
21
|
+
class Person < LegalEntity
|
22
|
+
# identified_by # No identifier needed, inherit from superclass
|
23
|
+
# New identifier:
|
24
|
+
identified_by :family, :given
|
25
|
+
has_one :family, Name
|
26
|
+
has_one :given, Name
|
27
|
+
has_one :related_to, LegalEntity
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# print "concept: "; p Mod.concept
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should associate a role name with a matching existing concept" do
|
34
|
+
module Mod
|
35
|
+
class Existing1 < String
|
36
|
+
value_type
|
37
|
+
has_one :name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
role = Mod::Existing1.roles(:name)
|
41
|
+
role.should_not be_nil
|
42
|
+
role.player.should == Mod::Name
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should inject the respective role name into the matching concept" do
|
46
|
+
module Mod
|
47
|
+
class Existing1 < String
|
48
|
+
value_type
|
49
|
+
has_one :name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
Mod::Name.roles(:all_existing1).should_not be_nil
|
53
|
+
Mod::LegalEntity.roles(:all_contract_by_first).should_not be_nil
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should associate a role name with a matching concept after it's created" do
|
57
|
+
module Mod
|
58
|
+
class Existing2 < String
|
59
|
+
value_type
|
60
|
+
has_one :given_name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
# print "Mod::Existing2.roles = "; p Mod::Existing2.roles
|
64
|
+
r = Mod::Existing2.roles(:given_name)
|
65
|
+
r.should_not be_nil
|
66
|
+
Symbol.should === r.player
|
67
|
+
module Mod
|
68
|
+
class GivenName < String
|
69
|
+
value_type
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# puts "Should resolve now:"
|
73
|
+
r = Mod::Existing2.roles(:given_name)
|
74
|
+
r.should_not be_nil
|
75
|
+
r.player.should == Mod::GivenName
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should handle subtyping a value type" do
|
79
|
+
module Mod
|
80
|
+
class FamilyName < Name
|
81
|
+
value_type
|
82
|
+
one_to_one :patriarch, Person
|
83
|
+
end
|
84
|
+
end
|
85
|
+
r = Mod::FamilyName.roles(:patriarch)
|
86
|
+
r.should_not be_nil
|
87
|
+
r.player.should == Mod::Person
|
88
|
+
r.player.roles(:family_name).player.should == Mod::FamilyName
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should instantiate the matching concept on assignment" do
|
92
|
+
c = ActiveFacts::API::Constellation.new(Mod)
|
93
|
+
bloggs = c.LegalEntity("Bloggs")
|
94
|
+
acme = c.LegalEntity("Acme, Inc")
|
95
|
+
contract = c.Contract("Bloggs", acme)
|
96
|
+
#contract = c.Contract("Bloggs", "Acme, Inc")
|
97
|
+
contract.first.should == bloggs
|
98
|
+
contract.second.should == acme
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should append the player into the respective role array in the matching concept" do
|
102
|
+
foo = Mod::Name.new("Foo")
|
103
|
+
le = Mod::LegalEntity.new(foo)
|
104
|
+
le.respond_to?(:name).should be_true
|
105
|
+
name = le.name
|
106
|
+
name.respond_to?(:all_legal_entity).should be_true
|
107
|
+
|
108
|
+
#pending
|
109
|
+
name.all_legal_entity.should === [le]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should instantiate subclasses sensibly" do
|
113
|
+
c = ActiveFacts::API::Constellation.new(Mod)
|
114
|
+
bloggs = c.LegalEntity("Bloggs & Co")
|
115
|
+
#pending
|
116
|
+
p = c.Person("Fred", "Bloggs")
|
117
|
+
p.related_to = "Bloggs & Co"
|
118
|
+
Mod::LegalEntity.should === p.related_to
|
119
|
+
bloggs.object_id.should == p.related_to.object_id
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|