activefacts 0.7.0 → 0.7.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/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
|