activefacts 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +0 -3
- data/Rakefile +7 -5
- data/bin/afgen +5 -2
- data/bin/cql +3 -2
- data/examples/CQL/Genealogy.cql +3 -3
- data/examples/CQL/Metamodel.cql +10 -7
- data/examples/CQL/MultiInheritance.cql +2 -1
- data/examples/CQL/OilSupply.cql +4 -4
- data/examples/CQL/Orienteering.cql +2 -2
- data/lib/activefacts.rb +2 -1
- data/lib/activefacts/api.rb +21 -2
- data/lib/activefacts/api/concept.rb +52 -39
- data/lib/activefacts/api/constellation.rb +8 -6
- data/lib/activefacts/api/entity.rb +41 -37
- data/lib/activefacts/api/instance.rb +5 -3
- data/lib/activefacts/api/numeric.rb +28 -21
- data/lib/activefacts/api/role.rb +29 -43
- data/lib/activefacts/api/standard_types.rb +8 -3
- data/lib/activefacts/api/support.rb +4 -4
- data/lib/activefacts/api/value.rb +9 -3
- data/lib/activefacts/api/vocabulary.rb +17 -7
- data/lib/activefacts/cql.rb +10 -7
- data/lib/activefacts/cql/CQLParser.treetop +6 -0
- data/lib/activefacts/cql/Concepts.treetop +32 -26
- data/lib/activefacts/cql/DataTypes.treetop +6 -0
- data/lib/activefacts/cql/Expressions.treetop +6 -0
- data/lib/activefacts/cql/FactTypes.treetop +6 -0
- data/lib/activefacts/cql/Language/English.treetop +9 -3
- data/lib/activefacts/cql/LexicalRules.treetop +6 -0
- data/lib/activefacts/cql/Rakefile +8 -0
- data/lib/activefacts/cql/parser.rb +4 -2
- data/lib/activefacts/generate/absorption.rb +20 -28
- data/lib/activefacts/generate/cql.rb +28 -16
- data/lib/activefacts/generate/cql/html.rb +327 -321
- data/lib/activefacts/generate/null.rb +7 -3
- data/lib/activefacts/generate/oo.rb +19 -15
- data/lib/activefacts/generate/ordered.rb +457 -461
- data/lib/activefacts/generate/ruby.rb +12 -4
- data/lib/activefacts/generate/sql/server.rb +42 -10
- data/lib/activefacts/generate/text.rb +7 -3
- data/lib/activefacts/input/cql.rb +55 -28
- data/lib/activefacts/input/orm.rb +32 -22
- data/lib/activefacts/persistence.rb +5 -0
- data/lib/activefacts/persistence/columns.rb +66 -32
- data/lib/activefacts/persistence/foreignkey.rb +29 -5
- data/lib/activefacts/persistence/index.rb +57 -25
- data/lib/activefacts/persistence/reference.rb +65 -30
- data/lib/activefacts/persistence/tables.rb +28 -17
- data/lib/activefacts/support.rb +8 -0
- data/lib/activefacts/version.rb +7 -1
- data/lib/activefacts/vocabulary.rb +4 -2
- data/lib/activefacts/vocabulary/extensions.rb +12 -10
- data/lib/activefacts/vocabulary/metamodel.rb +24 -23
- data/spec/api/autocounter.rb +2 -2
- data/spec/api/entity_type.rb +2 -2
- data/spec/api/instance.rb +61 -30
- data/spec/api/roles.rb +9 -9
- data/spec/cql_parse_spec.rb +1 -0
- data/spec/norma_tables_spec.rb +3 -3
- metadata +8 -4
@@ -1,4 +1,9 @@
|
|
1
1
|
#
|
2
|
+
# ActiveFacts Relational mapping and persistence.
|
3
|
+
# Reference from one Concept to another, used to decide the relational mapping.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
2
7
|
# A Reference from one Concept to another is created for each many-1 or 1-1 relationship
|
3
8
|
# (including subtyping), and also for a unary role (implicitly to Boolean concept).
|
4
9
|
# A 1-1 or subtyping reference should be created in only one direction, and may be flipped
|
@@ -11,12 +16,25 @@
|
|
11
16
|
#
|
12
17
|
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
13
18
|
#
|
14
|
-
# REVISIT: References need is_mandatory
|
15
|
-
# REVISIT: Need to index References by to_role, to help in finding PK references etc.
|
16
19
|
|
17
20
|
module ActiveFacts
|
18
|
-
module
|
19
|
-
|
21
|
+
module Persistence
|
22
|
+
|
23
|
+
# This class contains the core data structure used in composing a relational schema.
|
24
|
+
#
|
25
|
+
# A Reference is *from* one Concept *to* another Concept, and relates to the *from_role* and the *to_role*.
|
26
|
+
# When either Concept is an objectified fact type, the corresponding role is nil.
|
27
|
+
# When the Reference from_role is of a unary fact type, there's no to_role or to Concept.
|
28
|
+
# The final kind of Reference is a self-reference which is added to a ValueType that becomes a table.
|
29
|
+
#
|
30
|
+
# When the underlying fact type is a one-to-one (including an inheritance fact type), the Reference may be flipped.
|
31
|
+
#
|
32
|
+
# Each Reference has a name; an array of names in fact, in case of adjectives, etc.
|
33
|
+
# Each Refererence can produce the reading of the underlying fact type.
|
34
|
+
#
|
35
|
+
# A Reference is indexed in the player's *references_from* and *references_to*, and flipping updates those.
|
36
|
+
# Finally, a Reference may be marked as absorbing the whole referenced object, and that can flip too.
|
37
|
+
#
|
20
38
|
class Reference
|
21
39
|
attr_reader :from, :to # A "from" instance is related to one "to" instance
|
22
40
|
attr_reader :from_role, :to_role # For objectified facts, one role will be nil (a phantom)
|
@@ -46,44 +64,53 @@ module ActiveFacts
|
|
46
64
|
end
|
47
65
|
end
|
48
66
|
|
67
|
+
# What type of Role did this Reference arise from?
|
49
68
|
def role_type
|
50
69
|
role = @from_role||@to_role
|
51
70
|
role && role.role_type
|
52
71
|
end
|
53
72
|
|
73
|
+
# Is this Reference covered by a mandatory constraint (implicitly or explicitly)
|
54
74
|
def is_mandatory
|
55
75
|
!@from_role || # All phantom roles of fact types are mandatory
|
56
76
|
is_unary || # Unary fact types become booleans, which must be true or false
|
57
77
|
@from_role.is_mandatory
|
58
78
|
end
|
59
79
|
|
80
|
+
# Is this Reference from a unary Role?
|
60
81
|
def is_unary
|
61
82
|
!@to && @to_role && @to_role.fact_type.all_role.size == 1
|
62
83
|
end
|
63
84
|
|
64
|
-
#
|
85
|
+
# If this Reference is to an objectified FactType, there is no *to_role*
|
65
86
|
def is_to_objectified_fact
|
87
|
+
# This case is the only one that cannot be used in the preferred identifier of @from
|
66
88
|
@to && !@to_role && @from_role
|
67
89
|
end
|
68
90
|
|
91
|
+
# If this Reference is from an objectified FactType, there is no *from_role*
|
69
92
|
def is_from_objectified_fact
|
70
93
|
@to && @to_role && !@from_role
|
71
94
|
end
|
72
95
|
|
96
|
+
# Is this reference an injected role as a result a ValueType being a table?
|
73
97
|
def is_self_value
|
74
98
|
!@to && !@to_role
|
75
99
|
end
|
76
100
|
|
101
|
+
# Is the *to* concept fully absorbed through this reference?
|
77
102
|
def is_absorbing
|
78
103
|
@to && @to.absorbed_via == self
|
79
104
|
end
|
80
105
|
|
106
|
+
# Is this a simple reference?
|
81
107
|
def is_simple_reference
|
82
108
|
# It's a simple reference to a thing if that thing is a table,
|
83
109
|
# or is fully absorbed into another table but not via this reference.
|
84
110
|
@to && (@to.is_table or @to.absorbed_via && !is_absorbing)
|
85
111
|
end
|
86
112
|
|
113
|
+
# Return the array of names for the (perhaps implicit) *to_role* of this Reference
|
87
114
|
def to_names
|
88
115
|
case
|
89
116
|
when is_unary
|
@@ -100,8 +127,8 @@ module ActiveFacts
|
|
100
127
|
end
|
101
128
|
end
|
102
129
|
|
103
|
-
# For a one-to-one (or a subtyping fact type), reverse the direction
|
104
|
-
def flip
|
130
|
+
# For a one-to-one (or a subtyping fact type), reverse the direction.
|
131
|
+
def flip #:nodoc:
|
105
132
|
raise "Illegal flip of #{self}" unless @to and [:one_one, :subtype, :supertype].include?(role_type)
|
106
133
|
|
107
134
|
detabulate
|
@@ -118,7 +145,7 @@ module ActiveFacts
|
|
118
145
|
tabulate
|
119
146
|
end
|
120
147
|
|
121
|
-
def tabulate
|
148
|
+
def tabulate #:nodoc:
|
122
149
|
# Add to @to and @from's reference lists
|
123
150
|
@from.references_from << self
|
124
151
|
@to.references_to << self if @to # Guard against self-values
|
@@ -127,7 +154,7 @@ module ActiveFacts
|
|
127
154
|
self
|
128
155
|
end
|
129
156
|
|
130
|
-
def detabulate
|
157
|
+
def detabulate #:nodoc:
|
131
158
|
# Remove from @to and @from's reference lists if present
|
132
159
|
return unless @from.references_from.delete(self)
|
133
160
|
@to.references_to.delete self if @to # Guard against self-values
|
@@ -135,96 +162,104 @@ module ActiveFacts
|
|
135
162
|
self
|
136
163
|
end
|
137
164
|
|
138
|
-
def to_s
|
165
|
+
def to_s #:nodoc:
|
139
166
|
"reference from #{@from.name}#{@to ? " to #{@to.name}" : ""}" + (@fact_type ? " in '#{@fact_type.default_reading}'" : "")
|
140
167
|
end
|
141
168
|
|
169
|
+
# The reading for the fact type underlying this Reference
|
142
170
|
def reading
|
143
171
|
is_self_value ? "#{from.name} has value" : @fact_type.default_reading
|
144
172
|
end
|
145
173
|
|
146
|
-
def inspect
|
174
|
+
def inspect #:nodoc:
|
175
|
+
to_s
|
176
|
+
end
|
147
177
|
end
|
178
|
+
end
|
148
179
|
|
180
|
+
module Metamodel #:nodoc:
|
149
181
|
class Concept
|
150
182
|
# Say whether the independence of this object is still under consideration
|
151
183
|
# This is used in detecting dependency cycles, such as occurs in the Metamodel
|
152
|
-
attr_accessor :tentative
|
153
|
-
attr_writer :is_table
|
184
|
+
attr_accessor :tentative #:nodoc:
|
185
|
+
attr_writer :is_table # The two Concept subclasses provide the attr_reader method
|
154
186
|
|
155
|
-
def show_tabular
|
187
|
+
def show_tabular #:nodoc:
|
156
188
|
(tentative ? "tentatively " : "") +
|
157
189
|
(is_table ? "" : "not ")+"a table"
|
158
190
|
end
|
159
191
|
|
160
|
-
def definitely_table
|
192
|
+
def definitely_table #:nodoc:
|
161
193
|
@is_table = true
|
162
194
|
@tentative = false
|
163
195
|
end
|
164
196
|
|
165
|
-
def definitely_not_table
|
197
|
+
def definitely_not_table #:nodoc:
|
166
198
|
@is_table = false
|
167
199
|
@tentative = false
|
168
200
|
end
|
169
201
|
|
170
|
-
def probably_table
|
202
|
+
def probably_table #:nodoc:
|
171
203
|
@is_table = true
|
172
204
|
@tentative = true
|
173
205
|
end
|
174
206
|
|
175
|
-
def probably_not_table
|
207
|
+
def probably_not_table #:nodoc:
|
176
208
|
@is_table = false
|
177
209
|
@tentative = true
|
178
210
|
end
|
179
211
|
|
212
|
+
# References from this Concept
|
180
213
|
def references_from
|
181
214
|
@references_from ||= []
|
182
215
|
end
|
183
216
|
|
217
|
+
# References to this Concept
|
184
218
|
def references_to
|
185
219
|
@references_to ||= []
|
186
220
|
end
|
187
221
|
|
188
|
-
|
222
|
+
# True if this Concept has any References (to or from)
|
223
|
+
def has_references #:nodoc:
|
189
224
|
@references_from || @references_to
|
190
225
|
end
|
191
226
|
|
192
|
-
def clear_references
|
227
|
+
def clear_references #:nodoc:
|
193
228
|
# Clear any previous references:
|
194
229
|
@references_to = nil
|
195
230
|
@references_from = nil
|
196
231
|
end
|
197
232
|
|
198
|
-
def populate_references
|
233
|
+
def populate_references #:nodoc:
|
199
234
|
all_role.each do |role|
|
200
235
|
populate_reference role
|
201
236
|
end
|
202
237
|
end
|
203
238
|
|
204
|
-
def populate_reference role
|
239
|
+
def populate_reference role #:nodoc:
|
205
240
|
role_type = role.role_type
|
206
241
|
debug :references, "#{name} has #{role_type} role in '#{role.fact_type.describe}'"
|
207
242
|
case role_type
|
208
243
|
when :many_one
|
209
|
-
Reference.new(self, role).tabulate # A simple reference
|
244
|
+
ActiveFacts::Persistence::Reference.new(self, role).tabulate # A simple reference
|
210
245
|
|
211
246
|
when :one_many
|
212
247
|
if role.fact_type.entity_type == self # A Role of this objectified FactType
|
213
|
-
Reference.new(self, role).tabulate # A simple reference; check that
|
248
|
+
ActiveFacts::Persistence::Reference.new(self, role).tabulate # A simple reference; check that
|
214
249
|
else
|
215
250
|
# Can't absorb many of these into one of those
|
216
251
|
#debug :references, "Ignoring #{role_type} reference from #{name} to #{Reference.new(self, role).to.name}"
|
217
252
|
end
|
218
253
|
|
219
254
|
when :unary
|
220
|
-
Reference.new(self, role).tabulate # A simple reference
|
255
|
+
ActiveFacts::Persistence::Reference.new(self, role).tabulate # A simple reference
|
221
256
|
|
222
257
|
when :supertype # A subtype absorbs a reference to its supertype when separate, or all when partitioned
|
223
258
|
# REVISIT: Or when partitioned
|
224
259
|
if role.fact_type.subtype.is_independent
|
225
260
|
debug :references, "supertype #{name} doesn't absorb a reference to separate subtype #{role.fact_type.subtype.name}"
|
226
261
|
else
|
227
|
-
r = Reference.new(self, role)
|
262
|
+
r = ActiveFacts::Persistence::Reference.new(self, role)
|
228
263
|
r.to.absorbed_via = r
|
229
264
|
debug :references, "supertype #{name} absorbs subtype #{r.to.name}"
|
230
265
|
r.tabulate
|
@@ -232,14 +267,14 @@ module ActiveFacts
|
|
232
267
|
|
233
268
|
when :subtype # This object is a supertype, which can absorb the subtype unless that's independent
|
234
269
|
if is_independent # REVISIT: Or when partitioned
|
235
|
-
Reference.new(self, role).tabulate
|
270
|
+
ActiveFacts::Persistence::Reference.new(self, role).tabulate
|
236
271
|
# If partitioned, the supertype is absorbed into *each* subtype; a reference to the supertype needs to know which
|
237
272
|
else
|
238
273
|
# debug :references, "subtype #{name} is absorbed into #{role.fact_type.supertype.name}"
|
239
274
|
end
|
240
275
|
|
241
276
|
when :one_one
|
242
|
-
r = Reference.new(self, role)
|
277
|
+
r = ActiveFacts::Persistence::Reference.new(self, role)
|
243
278
|
|
244
279
|
# Decide which way the one-to-one is likely to go; it will be flipped later if necessary.
|
245
280
|
# Force the decision if just one is independent:
|
@@ -281,7 +316,7 @@ module ActiveFacts
|
|
281
316
|
end
|
282
317
|
|
283
318
|
class EntityType
|
284
|
-
def populate_references
|
319
|
+
def populate_references #:nodoc:
|
285
320
|
if fact_type && fact_type.all_role.size > 1
|
286
321
|
# NOT: fact_type.all_role.each do |role| # Place roles in the preferred order instead:
|
287
322
|
fact_type.preferred_reading.role_sequence.all_role_ref.map(&:role).each do |role|
|
@@ -293,7 +328,7 @@ module ActiveFacts
|
|
293
328
|
end
|
294
329
|
|
295
330
|
class Vocabulary
|
296
|
-
def populate_all_references
|
331
|
+
def populate_all_references #:nodoc:
|
297
332
|
debug :references, "Populating all concept references" do
|
298
333
|
all_feature.each do |feature|
|
299
334
|
next unless feature.is_a? Concept
|
@@ -1,14 +1,15 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
2
|
+
# ActiveFacts Relational mapping and persistence.
|
3
|
+
# Tables; Calculate the relational composition of a given Vocabulary.
|
4
|
+
# The composition consists of decisions about which Concepts are tables,
|
5
|
+
# and what columns (absorbed roled) those tables will have.
|
5
6
|
#
|
6
|
-
#
|
7
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
7
8
|
#
|
8
|
-
#
|
9
|
+
# This module has the following known problems:
|
9
10
|
#
|
10
|
-
# * When a subtype has no mandatory roles, we should
|
11
|
-
# a
|
11
|
+
# * When a subtype has no mandatory roles, we should support an optional schema transformation step
|
12
|
+
# that introduces a boolean (is_subtype) to indicate it's that subtype.
|
12
13
|
#
|
13
14
|
|
14
15
|
require 'activefacts/persistence/reference'
|
@@ -17,9 +18,12 @@ module ActiveFacts
|
|
17
18
|
module Metamodel
|
18
19
|
|
19
20
|
class ValueType
|
20
|
-
def absorbed_via
|
21
|
+
def absorbed_via #:nodoc:
|
22
|
+
# ValueTypes aren't absorbed in the way EntityTypes are
|
23
|
+
nil
|
24
|
+
end
|
21
25
|
|
22
|
-
#
|
26
|
+
# Returns true if this ValueType is a table
|
23
27
|
def is_table
|
24
28
|
return @is_table if @is_table != nil
|
25
29
|
|
@@ -42,20 +46,27 @@ module ActiveFacts
|
|
42
46
|
@is_table
|
43
47
|
end
|
44
48
|
|
45
|
-
#
|
49
|
+
# Is this ValueType auto-assigned on first save to the database?
|
46
50
|
def is_auto_assigned
|
47
|
-
|
51
|
+
# REVISIT: Find a better way to determine AutoCounters (ValueType unary role?)
|
52
|
+
type = self
|
48
53
|
type = type.supertype while type.supertype
|
49
54
|
type.name =~ /^Auto/
|
50
55
|
end
|
51
56
|
end
|
52
57
|
|
53
58
|
class EntityType
|
54
|
-
|
59
|
+
# A Reference from an entity type that fully absorbs this one
|
60
|
+
def absorbed_via; @absorbed_via; end
|
61
|
+
def absorbed_via=(r) #:nodoc:
|
62
|
+
@absorbed_via = r
|
63
|
+
end
|
55
64
|
|
56
|
-
def is_auto_assigned
|
65
|
+
def is_auto_assigned #:nodoc:
|
66
|
+
false
|
67
|
+
end
|
57
68
|
|
58
|
-
#
|
69
|
+
# Returns true if this EntityType is a table
|
59
70
|
def is_table
|
60
71
|
return @is_table if @is_table != nil # We already make a guess or decision
|
61
72
|
|
@@ -99,7 +110,7 @@ module ActiveFacts
|
|
99
110
|
end
|
100
111
|
end # EntityType class
|
101
112
|
|
102
|
-
class Role
|
113
|
+
class Role #:nodoc:
|
103
114
|
def role_type
|
104
115
|
# TypeInheritance roles are always 1:1
|
105
116
|
if TypeInheritance === fact_type
|
@@ -123,7 +134,7 @@ module ActiveFacts
|
|
123
134
|
all_uniqueness_constraints.
|
124
135
|
detect do |c|
|
125
136
|
c.role_sequence.all_role_ref.size == 1 and
|
126
|
-
c.role_sequence.all_role_ref
|
137
|
+
c.role_sequence.all_role_ref.only.role == self
|
127
138
|
end
|
128
139
|
|
129
140
|
if fact_type.entity_type
|
@@ -152,7 +163,7 @@ module ActiveFacts
|
|
152
163
|
@tables
|
153
164
|
end
|
154
165
|
|
155
|
-
def decide_tables
|
166
|
+
def decide_tables #:nodoc:
|
156
167
|
# Strategy:
|
157
168
|
# 1) Populate references for all Concepts
|
158
169
|
# 2) Decide which Concepts must be and must not be tables
|
data/lib/activefacts/support.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Support code.
|
3
|
+
# The debug method supports indented tracing.
|
4
|
+
# Set the DEBUG environment variable to enable it. Search the code to find the DEBUG keywords, or use "all".
|
5
|
+
#
|
6
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
7
|
+
#
|
1
8
|
#module ActiveFacts
|
2
9
|
$debug_indent = nil
|
3
10
|
$debug_nested = false
|
@@ -38,6 +45,7 @@
|
|
38
45
|
end
|
39
46
|
#end
|
40
47
|
|
48
|
+
# Return all duplicate objects in the array (using hash-equality)
|
41
49
|
class Array
|
42
50
|
def duplicates(&b)
|
43
51
|
inject({}) do |h,e|
|
data/lib/activefacts/version.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
2
|
+
# ActiveFacts Vocabulary Metamodel.
|
3
|
+
# The ActiveFacts Vocabulary API is generated from Metamodel.orm with extensions:
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
4
6
|
#
|
5
7
|
require 'activefacts/vocabulary/metamodel'
|
6
8
|
require 'activefacts/vocabulary/extensions'
|
@@ -1,6 +1,8 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
2
|
+
# ActiveFacts Vocabulary Metamodel.
|
3
|
+
# Extensions to the ActiveFacts Vocabulary classes (which are generated from the Metamodel)
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
4
6
|
#
|
5
7
|
module ActiveFacts
|
6
8
|
module Metamodel
|
@@ -112,7 +114,7 @@ module ActiveFacts
|
|
112
114
|
end
|
113
115
|
|
114
116
|
def subtypes
|
115
|
-
|
117
|
+
all_value_type_as_supertype
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
@@ -122,7 +124,7 @@ module ActiveFacts
|
|
122
124
|
if fact_type
|
123
125
|
|
124
126
|
# For a nested fact type, the PI is a unique constraint over N or N-1 roles
|
125
|
-
fact_roles = fact_type.all_role
|
127
|
+
fact_roles = Array(fact_type.all_role)
|
126
128
|
debug :pi, "Looking for PI on nested fact type #{name}" do
|
127
129
|
pi = catch :pi do
|
128
130
|
fact_roles[0,2].each{|r| # Try the first two roles of the fact type, that's enough
|
@@ -171,7 +173,7 @@ module ActiveFacts
|
|
171
173
|
debug :pi, "PI roles must be played by one of #{all_supertypes.map(&:name)*", "}" if all_supertypes.size > 1
|
172
174
|
all_role.each{|role|
|
173
175
|
next unless role.unique || fact_type
|
174
|
-
ftroles = role.fact_type.all_role
|
176
|
+
ftroles = Array(role.fact_type.all_role)
|
175
177
|
|
176
178
|
# Skip roles in ternary and higher fact types, they're objectified, and in unaries, they can't identify us.
|
177
179
|
next if ftroles.size != 2
|
@@ -262,11 +264,11 @@ module ActiveFacts
|
|
262
264
|
# An array of all direct subtypes:
|
263
265
|
def subtypes
|
264
266
|
# REVISIT: There's no sorting here. Should there be?
|
265
|
-
|
267
|
+
all_type_inheritance_as_supertype.map{|ti| ti.subtype }
|
266
268
|
end
|
267
269
|
|
268
270
|
def all_supertype_inheritance
|
269
|
-
|
271
|
+
all_type_inheritance_as_subtype.sort_by{|ti|
|
270
272
|
[ti.provides_identification ? 0 : 1, ti.supertype.name]
|
271
273
|
}
|
272
274
|
end
|
@@ -280,7 +282,7 @@ module ActiveFacts
|
|
280
282
|
|
281
283
|
# An array of self followed by all supertypes in order:
|
282
284
|
def supertypes_transitive
|
283
|
-
([self] +
|
285
|
+
([self] + all_type_inheritance_as_subtype.map{|ti|
|
284
286
|
# debug ti.class.roles.verbalise; exit
|
285
287
|
ti.supertype.supertypes_transitive
|
286
288
|
}).flatten.uniq
|
@@ -289,7 +291,7 @@ module ActiveFacts
|
|
289
291
|
# A subtype does not have a identifying_supertype if it defines its own identifier
|
290
292
|
def identifying_supertype
|
291
293
|
debug "Looking for identifying_supertype of #{name}"
|
292
|
-
|
294
|
+
all_type_inheritance_as_subtype.detect{|ti|
|
293
295
|
debug "considering supertype #{ti.supertype.name}"
|
294
296
|
next unless ti.provides_identification
|
295
297
|
debug "found identifying supertype of #{name}, it's #{ti.supertype.name}"
|
@@ -356,7 +358,7 @@ module ActiveFacts
|
|
356
358
|
reject{|s| s==' '}. # Remove white space
|
357
359
|
map do |frag| # and go through the bits
|
358
360
|
if frag =~ /\{([0-9]+)\}/
|
359
|
-
role_sequence.all_role_ref
|
361
|
+
role_sequence.all_role_ref.detect{|rr| rr.ordinal == $1.to_i}
|
360
362
|
else
|
361
363
|
frag
|
362
364
|
end
|