activefacts 0.8.9 → 0.8.10
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/.gemtest +0 -0
- data/Manifest.txt +28 -33
- data/Rakefile +11 -12
- data/bin/cql +90 -46
- data/examples/CQL/Blog.cql +2 -1
- data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
- data/examples/CQL/Death.cql +1 -1
- data/examples/CQL/Diplomacy.cql +9 -9
- data/examples/CQL/Genealogy.cql +3 -2
- data/examples/CQL/Insurance.cql +10 -7
- data/examples/CQL/JoinEquality.cql +2 -2
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +73 -53
- data/examples/CQL/MetamodelNext.cql +89 -67
- data/examples/CQL/OneToOnes.cql +2 -2
- data/examples/CQL/ServiceDirector.cql +10 -5
- data/examples/CQL/Supervision.cql +3 -3
- data/examples/CQL/Tests.Test5.Load.cql +1 -1
- data/examples/CQL/Warehousing.cql +4 -2
- data/lib/activefacts/cql/CQLParser.treetop +26 -60
- data/lib/activefacts/cql/Context.treetop +12 -2
- data/lib/activefacts/cql/Expressions.treetop +14 -30
- data/lib/activefacts/cql/FactTypes.treetop +165 -110
- data/lib/activefacts/cql/Language/English.treetop +167 -54
- data/lib/activefacts/cql/LexicalRules.treetop +16 -2
- data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
- data/lib/activefacts/cql/Terms.treetop +57 -27
- data/lib/activefacts/cql/ValueTypes.treetop +39 -13
- data/lib/activefacts/cql/compiler.rb +5 -3
- data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
- data/lib/activefacts/cql/compiler/constraint.rb +178 -275
- data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
- data/lib/activefacts/cql/compiler/expression.rb +418 -0
- data/lib/activefacts/cql/compiler/fact.rb +146 -145
- data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
- data/lib/activefacts/cql/compiler/join.rb +159 -0
- data/lib/activefacts/cql/compiler/shared.rb +51 -23
- data/lib/activefacts/cql/compiler/value_type.rb +56 -2
- data/lib/activefacts/cql/parser.rb +15 -4
- data/lib/activefacts/generate/absorption.rb +7 -7
- data/lib/activefacts/generate/cql.rb +100 -37
- data/lib/activefacts/generate/oo.rb +28 -51
- data/lib/activefacts/generate/ordered.rb +60 -36
- data/lib/activefacts/generate/ruby.rb +6 -6
- data/lib/activefacts/generate/sql/server.rb +4 -4
- data/lib/activefacts/input/orm.rb +71 -53
- data/lib/activefacts/persistence.rb +1 -1
- data/lib/activefacts/persistence/columns.rb +27 -23
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +17 -17
- data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
- data/lib/activefacts/persistence/reference.rb +61 -36
- data/lib/activefacts/persistence/tables.rb +61 -59
- data/lib/activefacts/support.rb +54 -29
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +99 -54
- data/lib/activefacts/vocabulary/metamodel.rb +43 -37
- data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
- data/spec/absorption_spec.rb +8 -8
- data/spec/cql/comparison_spec.rb +91 -0
- data/spec/cql/contractions_spec.rb +251 -0
- data/spec/cql/entity_type_spec.rb +319 -0
- data/spec/cql/expressions_spec.rb +63 -0
- data/spec/cql/fact_type_matching_spec.rb +283 -0
- data/spec/cql/french_spec.rb +21 -0
- data/spec/cql/parser/bad_literals_spec.rb +86 -0
- data/spec/cql/parser/constraints_spec.rb +19 -0
- data/spec/cql/parser/entity_types_spec.rb +106 -0
- data/spec/cql/parser/expressions_spec.rb +179 -0
- data/spec/cql/parser/fact_types_spec.rb +41 -0
- data/spec/cql/parser/literals_spec.rb +312 -0
- data/spec/cql/parser/pragmas_spec.rb +89 -0
- data/spec/cql/parser/value_types_spec.rb +42 -0
- data/spec/cql/role_matching_spec.rb +147 -0
- data/spec/cql/samples_spec.rb +9 -9
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/cql_dm_spec.rb +116 -0
- data/spec/cql_mysql_spec.rb +1 -1
- data/spec/cql_ruby_spec.rb +1 -1
- data/spec/cql_sql_spec.rb +3 -3
- data/spec/cql_symbol_tables_spec.rb +30 -30
- data/spec/cqldump_spec.rb +4 -4
- data/spec/helpers/array_matcher.rb +32 -27
- data/spec/helpers/diff_matcher.rb +6 -26
- data/spec/helpers/file_matcher.rb +41 -32
- data/spec/helpers/parse_to_ast_matcher.rb +76 -0
- data/spec/helpers/string_matcher.rb +32 -31
- data/spec/norma_cql_spec.rb +1 -1
- data/spec/norma_ruby_spec.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +1 -1
- data/spec/norma_sql_spec.rb +3 -1
- data/spec/norma_tables_spec.rb +1 -1
- data/spec/ruby_api_spec.rb +23 -0
- data/spec/spec_helper.rb +5 -4
- metadata +66 -66
- data/examples/CQL/OrienteeringER.cql +0 -58
- data/lib/activefacts/api.rb +0 -44
- data/lib/activefacts/api/concept.rb +0 -410
- data/lib/activefacts/api/constellation.rb +0 -128
- data/lib/activefacts/api/entity.rb +0 -256
- data/lib/activefacts/api/instance.rb +0 -60
- data/lib/activefacts/api/instance_index.rb +0 -80
- data/lib/activefacts/api/numeric.rb +0 -167
- data/lib/activefacts/api/role.rb +0 -80
- data/lib/activefacts/api/role_proxy.rb +0 -70
- data/lib/activefacts/api/role_values.rb +0 -117
- data/lib/activefacts/api/standard_types.rb +0 -87
- data/lib/activefacts/api/support.rb +0 -65
- data/lib/activefacts/api/value.rb +0 -135
- data/lib/activefacts/api/vocabulary.rb +0 -82
- data/spec/api/autocounter.rb +0 -82
- data/spec/api/constellation.rb +0 -130
- data/spec/api/entity_type.rb +0 -103
- data/spec/api/instance.rb +0 -461
- data/spec/api/roles.rb +0 -124
- data/spec/api/value_type.rb +0 -112
- data/spec/api_spec.rb +0 -13
- data/spec/cql/matching_spec.rb +0 -517
- data/spec/cql/unit_spec.rb +0 -394
- data/spec/spec.opts +0 -1
|
@@ -136,6 +136,11 @@ module ActiveFacts
|
|
|
136
136
|
value_type :length => 256
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
+
class TransactionTiming < String
|
|
140
|
+
value_type
|
|
141
|
+
restrict 'assert', 'commit'
|
|
142
|
+
end
|
|
143
|
+
|
|
139
144
|
class UnitId < AutoCounter
|
|
140
145
|
value_type
|
|
141
146
|
end
|
|
@@ -169,12 +174,12 @@ module ActiveFacts
|
|
|
169
174
|
|
|
170
175
|
class ContextNote
|
|
171
176
|
identified_by :context_note_id
|
|
172
|
-
has_one :concept # See Concept.all_context_note
|
|
173
177
|
has_one :constraint # See Constraint.all_context_note
|
|
174
178
|
one_to_one :context_note_id, :mandatory => true # See ContextNoteId.context_note
|
|
175
179
|
has_one :context_note_kind, :mandatory => true # See ContextNoteKind.all_context_note
|
|
176
180
|
has_one :discussion, :mandatory => true # See Discussion.all_context_note
|
|
177
181
|
has_one :fact_type # See FactType.all_context_note
|
|
182
|
+
has_one :object_type # See ObjectType.all_context_note
|
|
178
183
|
end
|
|
179
184
|
|
|
180
185
|
class Enforcement
|
|
@@ -201,9 +206,9 @@ module ActiveFacts
|
|
|
201
206
|
|
|
202
207
|
class Instance
|
|
203
208
|
identified_by :instance_id
|
|
204
|
-
has_one :concept, :mandatory => true # See Concept.all_instance
|
|
205
209
|
one_to_one :fact # See Fact.instance
|
|
206
210
|
one_to_one :instance_id, :mandatory => true # See InstanceId.instance
|
|
211
|
+
has_one :object_type, :mandatory => true # See ObjectType.all_instance
|
|
207
212
|
has_one :population, :mandatory => true # See Population.all_instance
|
|
208
213
|
has_one :value # See Value.all_instance
|
|
209
214
|
end
|
|
@@ -215,9 +220,10 @@ module ActiveFacts
|
|
|
215
220
|
|
|
216
221
|
class JoinNode
|
|
217
222
|
identified_by :join, :ordinal
|
|
218
|
-
has_one :concept, :mandatory => true # See Concept.all_join_node
|
|
219
223
|
has_one :join, :mandatory => true # See Join.all_join_node
|
|
224
|
+
has_one :object_type, :mandatory => true # See ObjectType.all_join_node
|
|
220
225
|
has_one :ordinal, :mandatory => true # See Ordinal.all_join_node
|
|
226
|
+
has_one :role_name, :class => Name # See Name.all_join_node_as_role_name
|
|
221
227
|
has_one :subscript # See Subscript.all_join_node
|
|
222
228
|
has_one :value # See Value.all_join_node
|
|
223
229
|
end
|
|
@@ -254,8 +260,8 @@ module ActiveFacts
|
|
|
254
260
|
identified_by :fact_type, :ordinal
|
|
255
261
|
has_one :fact_type, :mandatory => true # See FactType.all_role
|
|
256
262
|
has_one :ordinal, :mandatory => true # See Ordinal.all_role
|
|
257
|
-
|
|
258
|
-
|
|
263
|
+
one_to_one :implicit_fact_type, :counterpart => :implying_role # See ImplicitFactType.implying_role
|
|
264
|
+
has_one :object_type, :mandatory => true # See ObjectType.all_role
|
|
259
265
|
has_one :role_name, :class => Name # See Name.all_role_as_role_name
|
|
260
266
|
end
|
|
261
267
|
|
|
@@ -329,14 +335,6 @@ module ActiveFacts
|
|
|
329
335
|
has_one :value, :mandatory => true # See Value.all_bound
|
|
330
336
|
end
|
|
331
337
|
|
|
332
|
-
class Concept
|
|
333
|
-
identified_by :vocabulary, :name
|
|
334
|
-
maybe :is_independent
|
|
335
|
-
has_one :name, :mandatory => true # See Name.all_concept
|
|
336
|
-
has_one :pronoun # See Pronoun.all_concept
|
|
337
|
-
has_one :vocabulary, :mandatory => true # See Vocabulary.all_concept
|
|
338
|
-
end
|
|
339
|
-
|
|
340
338
|
class ConstraintShape < Shape
|
|
341
339
|
has_one :constraint, :mandatory => true # See Constraint.all_constraint_shape
|
|
342
340
|
end
|
|
@@ -367,10 +365,6 @@ module ActiveFacts
|
|
|
367
365
|
has_one :vocabulary, :mandatory => true # See Vocabulary.all_diagram
|
|
368
366
|
end
|
|
369
367
|
|
|
370
|
-
class EntityType < Concept
|
|
371
|
-
one_to_one :fact_type # See FactType.entity_type
|
|
372
|
-
end
|
|
373
|
-
|
|
374
368
|
class FactTypeShape < Shape
|
|
375
369
|
has_one :display_role_names_setting # See DisplayRoleNamesSetting.all_fact_type_shape
|
|
376
370
|
has_one :fact_type, :mandatory => true # See FactType.all_fact_type_shape
|
|
@@ -397,9 +391,17 @@ module ActiveFacts
|
|
|
397
391
|
has_one :context_note, :mandatory => true # See ContextNote.all_model_note_shape
|
|
398
392
|
end
|
|
399
393
|
|
|
394
|
+
class ObjectType
|
|
395
|
+
identified_by :vocabulary, :name
|
|
396
|
+
maybe :is_independent
|
|
397
|
+
has_one :name, :mandatory => true # See Name.all_object_type
|
|
398
|
+
has_one :pronoun # See Pronoun.all_object_type
|
|
399
|
+
has_one :vocabulary, :mandatory => true # See Vocabulary.all_object_type
|
|
400
|
+
end
|
|
401
|
+
|
|
400
402
|
class ObjectTypeShape < Shape
|
|
401
|
-
has_one :concept, :mandatory => true # See Concept.all_object_type_shape
|
|
402
403
|
maybe :has_expanded_reference_mode
|
|
404
|
+
has_one :object_type, :mandatory => true # See ObjectType.all_object_type_shape
|
|
403
405
|
end
|
|
404
406
|
|
|
405
407
|
class ObjectifiedFactTypeNameShape < Shape
|
|
@@ -461,14 +463,6 @@ module ActiveFacts
|
|
|
461
463
|
maybe :is_mandatory
|
|
462
464
|
end
|
|
463
465
|
|
|
464
|
-
class TypeInheritance < FactType
|
|
465
|
-
identified_by :subtype, :supertype
|
|
466
|
-
has_one :subtype, :class => EntityType, :mandatory => true # See EntityType.all_type_inheritance_as_subtype
|
|
467
|
-
has_one :supertype, :class => EntityType, :mandatory => true # See EntityType.all_type_inheritance_as_supertype
|
|
468
|
-
has_one :assimilation # See Assimilation.all_type_inheritance
|
|
469
|
-
maybe :provides_identification
|
|
470
|
-
end
|
|
471
|
-
|
|
472
466
|
class ValueConstraintShape < ConstraintShape
|
|
473
467
|
has_one :object_type_shape # See ObjectTypeShape.all_value_constraint_shape
|
|
474
468
|
one_to_one :role_display # See RoleDisplay.value_constraint_shape
|
|
@@ -480,8 +474,8 @@ module ActiveFacts
|
|
|
480
474
|
has_one :minimum_bound, :class => Bound # See Bound.all_value_range_as_minimum_bound
|
|
481
475
|
end
|
|
482
476
|
|
|
483
|
-
class ValueType <
|
|
484
|
-
|
|
477
|
+
class ValueType < ObjectType
|
|
478
|
+
has_one :auto_assigned_transaction_timing, :class => TransactionTiming # See TransactionTiming.all_value_type_as_auto_assigned_transaction_timing
|
|
485
479
|
has_one :length # See Length.all_value_type
|
|
486
480
|
has_one :scale # See Scale.all_value_type
|
|
487
481
|
has_one :supertype, :class => ValueType # See ValueType.all_value_type_as_supertype
|
|
@@ -495,20 +489,32 @@ module ActiveFacts
|
|
|
495
489
|
has_one :value_range, :mandatory => true # See ValueRange.all_allowed_range
|
|
496
490
|
end
|
|
497
491
|
|
|
492
|
+
class EntityType < ObjectType
|
|
493
|
+
one_to_one :fact_type # See FactType.entity_type
|
|
494
|
+
end
|
|
495
|
+
|
|
498
496
|
class ImplicitBooleanValueType < ValueType
|
|
499
497
|
end
|
|
500
498
|
|
|
501
|
-
class
|
|
502
|
-
identified_by :
|
|
503
|
-
has_one :name, :mandatory => true # See Name.
|
|
504
|
-
has_one :value_type, :mandatory => true # See ValueType.
|
|
499
|
+
class Facet
|
|
500
|
+
identified_by :value_type, :name
|
|
501
|
+
has_one :name, :mandatory => true # See Name.all_facet
|
|
502
|
+
has_one :value_type, :mandatory => true # See ValueType.all_facet
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
class TypeInheritance < FactType
|
|
506
|
+
identified_by :subtype, :supertype
|
|
507
|
+
has_one :subtype, :class => EntityType, :mandatory => true # See EntityType.all_type_inheritance_as_subtype
|
|
508
|
+
has_one :supertype, :class => EntityType, :mandatory => true # See EntityType.all_type_inheritance_as_supertype
|
|
509
|
+
has_one :assimilation # See Assimilation.all_type_inheritance
|
|
510
|
+
maybe :provides_identification
|
|
505
511
|
end
|
|
506
512
|
|
|
507
|
-
class
|
|
508
|
-
identified_by :
|
|
509
|
-
has_one :
|
|
510
|
-
has_one :value, :mandatory => true # See Value.
|
|
511
|
-
has_one :value_type, :mandatory => true # See ValueType.
|
|
513
|
+
class FacetValue
|
|
514
|
+
identified_by :value_type, :facet
|
|
515
|
+
has_one :facet, :mandatory => true # See Facet.all_facet_value
|
|
516
|
+
has_one :value, :mandatory => true # See Value.all_facet_value
|
|
517
|
+
has_one :value_type, :mandatory => true # See ValueType.all_facet_value
|
|
512
518
|
end
|
|
513
519
|
|
|
514
520
|
end
|
|
@@ -11,15 +11,15 @@ module ActiveFacts
|
|
|
11
11
|
# * Maintains verbalisation context to expand readings using subscripting where needed
|
|
12
12
|
# * Verbalises Joins by iteratively choosing a Join Step and expanding readings
|
|
13
13
|
#
|
|
14
|
-
# The verbalisation context consists of a set of Players, each for one
|
|
15
|
-
# There may be more than one Player for the same
|
|
14
|
+
# The verbalisation context consists of a set of Players, each for one ObjectType.
|
|
15
|
+
# There may be more than one Player for the same ObjectType. If adjectives or role
|
|
16
16
|
# names don't make such duplicates unambiguous, subscripts will be generated.
|
|
17
17
|
# Thus, the verbalisation context must be completely populated before subscript
|
|
18
18
|
# generation, which must be before any Player name gets verbalised.
|
|
19
19
|
#
|
|
20
20
|
# When a Player occurs in a Join, it corresponds to one Join Node of that Join.
|
|
21
21
|
# Each such Player has one or more JoinRoles, which refer to roles played by
|
|
22
|
-
# that
|
|
22
|
+
# that ObjectType. Where a join traverses two roles of a ternary fact type, there
|
|
23
23
|
# will be a residual node that has only a single JoinRole with no other meaning.
|
|
24
24
|
# A JoinRole must be for exactly one Player, so is used to identify a Player.
|
|
25
25
|
#
|
|
@@ -37,11 +37,11 @@ module ActiveFacts
|
|
|
37
37
|
#
|
|
38
38
|
# A constrained RoleSequence that has no explicit Join may have an implicit join,
|
|
39
39
|
# as per ORM2, when the roles aren't in the same fact type. These implicit joins
|
|
40
|
-
# are over only one
|
|
40
|
+
# are over only one ObjectType, by traversing a single FactType (and possibly,
|
|
41
41
|
# multiple TypeInheritance FactTypes) for each RoleRef. Note however that when
|
|
42
|
-
# the
|
|
42
|
+
# the ObjectType is an objectified Fact Type, the FactType traversed might be a
|
|
43
43
|
# phantom of the objectification. In the case of implicit joins, each Player is
|
|
44
|
-
# identified by the projected RoleRef, except for the joined-over
|
|
44
|
+
# identified by the projected RoleRef, except for the joined-over ObjectType whose
|
|
45
45
|
# Player is... well, read the next paragraph!
|
|
46
46
|
#
|
|
47
47
|
# REVISIT: I believe that the foregoing paragraph is out of date, except with
|
|
@@ -54,7 +54,7 @@ module ActiveFacts
|
|
|
54
54
|
# For a SetComparisonConstraint, there are two or more constrained RoleSequences.
|
|
55
55
|
# The matching RoleRefs (by Ordinal position) are for joined players, that is,
|
|
56
56
|
# one individual instance plays both roles. The RoleRefs must (now) be for the
|
|
57
|
-
# same
|
|
57
|
+
# same ObjectType (no implicit subtyping Join is allowed). Instead, the input modules
|
|
58
58
|
# find the closest common supertype and create explicit JoinSteps so its roles
|
|
59
59
|
# can be projected.
|
|
60
60
|
#
|
|
@@ -99,9 +99,9 @@ module ActiveFacts
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
class Player
|
|
102
|
-
attr_accessor :
|
|
103
|
-
def initialize
|
|
104
|
-
@
|
|
102
|
+
attr_accessor :object_type, :join_nodes_by_join, :subscript, :join_roles, :role_refs
|
|
103
|
+
def initialize object_type
|
|
104
|
+
@object_type = object_type
|
|
105
105
|
@join_nodes_by_join = {}
|
|
106
106
|
@subscript = nil
|
|
107
107
|
@join_roles = []
|
|
@@ -111,30 +111,41 @@ module ActiveFacts
|
|
|
111
111
|
# What words are used (across all roles) for disambiguating the references to this player?
|
|
112
112
|
# If more than one set of adjectives was used, this player must have been subject to loose binding.
|
|
113
113
|
# This method is used to decide when subscripts aren't needed.
|
|
114
|
-
def role_adjuncts
|
|
115
|
-
|
|
116
|
-
[
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
def role_adjuncts matching
|
|
115
|
+
if matching == :loose
|
|
116
|
+
adjuncts = []
|
|
117
|
+
else
|
|
118
|
+
adjuncts = @role_refs.map{|rr|
|
|
119
|
+
[
|
|
120
|
+
rr.leading_adjective,
|
|
121
|
+
matching == :rolenames ? rr.role.role_name : nil,
|
|
122
|
+
rr.trailing_adjective
|
|
123
|
+
].compact}.uniq.sort
|
|
124
|
+
end
|
|
125
|
+
adjuncts += [@join_nodes_by_join.values.map{|jn| jn.role_name}.compact[0]].compact
|
|
121
126
|
adjuncts.flatten*"_"
|
|
122
127
|
end
|
|
123
128
|
|
|
124
129
|
def describe
|
|
125
|
-
@
|
|
130
|
+
@object_type.name + (@join_nodes_by_join.size > 0 ? " (in #{@join_nodes_by_join.size} joins)" : "")
|
|
126
131
|
end
|
|
127
132
|
end
|
|
128
133
|
|
|
129
134
|
# Find or create a Player to which we can add this role_ref
|
|
130
135
|
def player(ref)
|
|
131
|
-
if ref.is_a?(ActiveFacts::Metamodel::JoinRole)
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
existing_player = if ref.is_a?(ActiveFacts::Metamodel::JoinRole)
|
|
137
|
+
@player_by_join_role[ref]
|
|
138
|
+
else
|
|
139
|
+
@player_by_role_ref[ref] or ref.join_role && @player_by_join_role[ref.join_role]
|
|
140
|
+
end
|
|
141
|
+
if existing_player
|
|
142
|
+
debug :player, "Using existing player for #{ref.role.object_type.name} #{ref.respond_to?(:role_sequence) && ref.role_sequence.all_reading.size > 0 ? ' in reading' : ''}in '#{ref.role.fact_type.default_reading}'"
|
|
143
|
+
return existing_player
|
|
134
144
|
else
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
debug :player, "Adding new player for #{ref.role.object_type.name} #{ref.respond_to?(:role_sequence) && ref.role_sequence.all_reading.size > 0 ? ' in reading' : ''}in '#{ref.role.fact_type.default_reading}'"
|
|
146
|
+
p = Player.new(ref.role.object_type)
|
|
147
|
+
@players.push(p)
|
|
148
|
+
p
|
|
138
149
|
end
|
|
139
150
|
end
|
|
140
151
|
|
|
@@ -142,7 +153,7 @@ module ActiveFacts
|
|
|
142
153
|
return if player.join_roles.include?(join_role)
|
|
143
154
|
jn = join_role.join_node
|
|
144
155
|
if jn1 = player.join_nodes_by_join[jn.join] and jn1 != jn
|
|
145
|
-
raise "Player for #{player.
|
|
156
|
+
raise "Player for #{player.object_type.name} may only have one join node per join, not #{jn1.object_type.name} and #{jn.object_type.name}"
|
|
146
157
|
end
|
|
147
158
|
player.join_nodes_by_join[jn.join] = jn
|
|
148
159
|
@player_by_join_role[join_role] = player
|
|
@@ -155,7 +166,7 @@ module ActiveFacts
|
|
|
155
166
|
if jr = role_ref.join_role
|
|
156
167
|
add_join_role(player, jr)
|
|
157
168
|
elsif !player.role_refs.include?(role_ref)
|
|
158
|
-
debug :subscript, "Adding reference to player #{player.object_id} for #{role_ref.role.
|
|
169
|
+
debug :subscript, "Adding reference to player #{player.object_id} for #{role_ref.role.object_type.name} in #{role_ref.role_sequence.describe} with #{role_ref.role_sequence.all_reading.size} readings"
|
|
159
170
|
player.role_refs.push(role_ref)
|
|
160
171
|
@player_by_role_ref[role_ref] = player
|
|
161
172
|
end
|
|
@@ -182,11 +193,7 @@ module ActiveFacts
|
|
|
182
193
|
elsif role_name = role_ref.role.role_name and role_name != ''
|
|
183
194
|
role_name
|
|
184
195
|
else
|
|
185
|
-
|
|
186
|
-
role_words << preferred_role_ref.leading_adjective if preferred_role_ref.leading_adjective != ""
|
|
187
|
-
role_words << preferred_role_ref.role.concept.name
|
|
188
|
-
role_words << preferred_role_ref.trailing_adjective if preferred_role_ref.trailing_adjective != ""
|
|
189
|
-
role_name = role_words.compact*"-"
|
|
196
|
+
role_name = preferred_role_ref.cql_name
|
|
190
197
|
if p = player(preferred_role_ref) and p.subscript
|
|
191
198
|
role_name += "(#{p.subscript})"
|
|
192
199
|
end
|
|
@@ -211,10 +218,10 @@ module ActiveFacts
|
|
|
211
218
|
# If any of these join_roles are for a known player, use that, else make a new player.
|
|
212
219
|
existing_players = join_roles.map{|jr| @player_by_join_role[jr] }.compact.uniq
|
|
213
220
|
if existing_players.size > 1
|
|
214
|
-
raise "Can't join these roles to more than one existing player: #{existing_players.map{|p|p.
|
|
221
|
+
raise "Can't join these roles to more than one existing player: #{existing_players.map{|p|p.object_type.name}*', '}!"
|
|
215
222
|
end
|
|
216
223
|
p = existing_players[0] || player(join_roles[0])
|
|
217
|
-
debugger if join_roles.detect{|jr| jr.role.
|
|
224
|
+
debugger if join_roles.detect{|jr| jr.role.object_type != p.object_type }
|
|
218
225
|
debug :subscript, "Joining roles to #{p.describe}" do
|
|
219
226
|
join_roles.each do |jr|
|
|
220
227
|
debug :subscript, "#{jr.describe}" do
|
|
@@ -233,17 +240,17 @@ module ActiveFacts
|
|
|
233
240
|
existing_players =
|
|
234
241
|
role_refs.map{|rr| @player_by_role_ref[rr] || @player_by_join_role[rr.join_role] }.compact.uniq
|
|
235
242
|
if existing_players.size > 1
|
|
236
|
-
raise "Can't join these role_refs to more than one existing player: #{existing_players.map{|p|p.
|
|
243
|
+
raise "Can't join these role_refs to more than one existing player: #{existing_players.map{|p|p.object_type.name}*', '}!"
|
|
237
244
|
end
|
|
238
245
|
p = existing_players[0] || player(role_refs[0])
|
|
239
246
|
|
|
240
|
-
debug :subscript, "#{existing_players[0] ? 'Adding to existing' : 'Creating new'} player for #{role_refs.map{|rr| rr.role.
|
|
247
|
+
debug :subscript, "#{existing_players[0] ? 'Adding to existing' : 'Creating new'} player for #{role_refs.map{|rr| rr.role.object_type.name}.uniq*', '}" do
|
|
241
248
|
role_refs.each do |rr|
|
|
242
|
-
unless p.
|
|
249
|
+
unless p.object_type == rr.role.object_type
|
|
243
250
|
# This happens in SubtypePI because uniqueness constraint is built without its implicit subtyping join.
|
|
244
251
|
# For now, explode only if there's no common supertype:
|
|
245
|
-
if 0 == (p.
|
|
246
|
-
raise "REVISIT: Internal error, trying to add role of #{rr.role.
|
|
252
|
+
if 0 == (p.object_type.supertypes_transitive & rr.role.object_type.supertypes_transitive).size
|
|
253
|
+
raise "REVISIT: Internal error, trying to add role of #{rr.role.object_type.name} to player #{p.object_type.name}"
|
|
247
254
|
end
|
|
248
255
|
end
|
|
249
256
|
add_role_player(p, rr)
|
|
@@ -251,21 +258,44 @@ module ActiveFacts
|
|
|
251
258
|
end
|
|
252
259
|
end
|
|
253
260
|
|
|
254
|
-
|
|
261
|
+
# REVISIT: include_rolenames is a bit of a hack. Role names generally serve to disambiguate players,
|
|
262
|
+
# so subscripts wouldn't be needed, but where a constraint refers to a fact type which is defined with
|
|
263
|
+
# role names, those are considered. We should instead consider only the role names that are defined
|
|
264
|
+
# within the constraint, not in the underlying fact types. For now, this parameter is passed as true
|
|
265
|
+
# from all the object type verbalisations, and not from constraints.
|
|
266
|
+
def create_subscripts(matching = :normal)
|
|
255
267
|
# Create subscripts, where necessary
|
|
256
268
|
@players.each { |p| p.subscript = nil } # Wipe subscripts
|
|
257
269
|
@players.
|
|
258
|
-
map{|p| [p, p.
|
|
259
|
-
each do |player,
|
|
270
|
+
map{|p| [p, p.object_type] }.
|
|
271
|
+
each do |player, object_type|
|
|
260
272
|
next if player.subscript # Done previously
|
|
261
|
-
dups = @players.select
|
|
273
|
+
dups = @players.select do |p|
|
|
274
|
+
p.object_type == object_type &&
|
|
275
|
+
p.role_adjuncts(matching) == player.role_adjuncts(matching)
|
|
276
|
+
end
|
|
262
277
|
if dups.size == 1
|
|
263
|
-
debug :subscript, "No subscript needed for #{
|
|
278
|
+
debug :subscript, "No subscript needed for #{object_type.name}"
|
|
264
279
|
next
|
|
265
280
|
end
|
|
266
|
-
debug :subscript, "Applying subscripts to #{dups.size} occurrences of #{
|
|
267
|
-
|
|
268
|
-
|
|
281
|
+
debug :subscript, "Applying subscripts to #{dups.size} occurrences of #{object_type.name}" do
|
|
282
|
+
s = 0
|
|
283
|
+
dups.
|
|
284
|
+
sort_by{|p| # Guarantee stable numbering
|
|
285
|
+
p.role_adjuncts(:role_name) + ' ' +
|
|
286
|
+
# Tie-breaker:
|
|
287
|
+
p.role_refs.map{|rr| rr.role.fact_type.preferred_reading.text}.sort.to_s
|
|
288
|
+
}.
|
|
289
|
+
each do |player|
|
|
290
|
+
jrname = player.join_roles.map{|jr| jr.role_ref && jr.role_ref.role.role_name}.compact[0]
|
|
291
|
+
rname = (rr = player.role_refs[0]) && rr.role.role_name
|
|
292
|
+
if jrname and !rname
|
|
293
|
+
# puts "Oops: rolename #{rname.inspect} != #{jrname.inspect}" if jrname != rname
|
|
294
|
+
player.join_nodes_by_join.values.each{|jn| jn.role_name = jrname }
|
|
295
|
+
else
|
|
296
|
+
player.subscript = s+1
|
|
297
|
+
s += 1
|
|
298
|
+
end
|
|
269
299
|
end
|
|
270
300
|
end
|
|
271
301
|
end
|
|
@@ -276,7 +306,7 @@ module ActiveFacts
|
|
|
276
306
|
# and also define adjectives by using the hyphenated form (on at least the first occurrence).
|
|
277
307
|
def expand_reading(reading, frequency_constraints = [], define_role_names = nil, value_constraints = [], &subscript_block)
|
|
278
308
|
reading.expand(frequency_constraints, define_role_names, value_constraints) do |role_ref|
|
|
279
|
-
(!(role_ref.role.role_name and define_role_names) and p = player(role_ref) and p.subscript) ? "(#{p.subscript})" : ""
|
|
309
|
+
(!(role_ref.role.role_name and define_role_names != nil) and p = player(role_ref) and p.subscript) ? "(#{p.subscript})" : ""
|
|
280
310
|
end
|
|
281
311
|
end
|
|
282
312
|
|
|
@@ -284,8 +314,8 @@ module ActiveFacts
|
|
|
284
314
|
# REVISIT: This probably doesn't produce the required result. Need to fix the NORMA importer to create the join.
|
|
285
315
|
def role_refs_are_subtype_joined roles
|
|
286
316
|
role_refs = roles.is_a?(Array) ? roles : roles.all_role_ref.to_a
|
|
287
|
-
|
|
288
|
-
|
|
317
|
+
role_refs_by_object_type = role_refs.inject({}) { |h, r| (h[r.role.object_type] ||= []) << r; h }
|
|
318
|
+
role_refs_by_object_type.values.each { |rrs| role_refs_have_same_player(rrs) }
|
|
289
319
|
end
|
|
290
320
|
|
|
291
321
|
# These roles are the players in an implicit counterpart join in a Presence Constraint.
|
|
@@ -293,9 +323,11 @@ module ActiveFacts
|
|
|
293
323
|
# Fix the CQL compiler to create proper joins for these presence constraints instead.
|
|
294
324
|
def roles_have_same_player roles
|
|
295
325
|
role_refs = roles.map do |role|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
326
|
+
role.fact_type.all_reading.map{|reading|
|
|
327
|
+
reading.role_sequence.all_role_ref.detect{|rr| rr.role == role}
|
|
328
|
+
} +
|
|
329
|
+
role.all_role_ref.select{|rr| rr.role_sequence.all_reading.size == 0 }
|
|
330
|
+
end.flatten.uniq
|
|
299
331
|
role_refs_have_same_player(role_refs)
|
|
300
332
|
end
|
|
301
333
|
|
|
@@ -316,10 +348,10 @@ module ActiveFacts
|
|
|
316
348
|
prrs = fact_type.preferred_reading.role_sequence.all_role_ref
|
|
317
349
|
residual_roles = fact_type.all_role.select{|r| !@role_refs.detect{|rr| rr.role == r} }
|
|
318
350
|
residual_roles.each do |role|
|
|
319
|
-
debug :subscript, "Adding residual role for #{role.
|
|
351
|
+
debug :subscript, "Adding residual role for #{role.object_type.name} (in #{fact_type.default_reading}) not covered in role sequence"
|
|
320
352
|
preferred_role_ref = prrs.detect{|rr| rr.role == role}
|
|
321
353
|
if p = @player_by_role_ref[preferred_role_ref] and !p.role_refs.include?(preferred_role_ref)
|
|
322
|
-
raise "Adding DUPLICATE residual role for #{role.
|
|
354
|
+
raise "Adding DUPLICATE residual role for #{role.object_type.name}"
|
|
323
355
|
end
|
|
324
356
|
role_refs_have_same_player([prrs.detect{|rr| rr.role == role}])
|
|
325
357
|
end
|
|
@@ -340,13 +372,13 @@ module ActiveFacts
|
|
|
340
372
|
=begin
|
|
341
373
|
# For each fact type traversed, register a player for each role *not* linked to this join
|
|
342
374
|
# REVISIT: Using the preferred_reading role_ref is wrong here; the same preferred_reading might occur twice,
|
|
343
|
-
# so the respective
|
|
375
|
+
# so the respective object_type will need more than one Player and will be subscripted to keep them from being joined.
|
|
344
376
|
# Accordingly, there must be a join step for each such role, and to enforce that, I raise an exception here on duplication.
|
|
345
377
|
# This isn't needed now all JoinNodes have at least one JoinRole
|
|
346
378
|
|
|
347
379
|
join_steps.map do |js|
|
|
348
380
|
if js.fact_type.is_a?(ActiveFacts::Metamodel::ImplicitFactType)
|
|
349
|
-
js.fact_type.
|
|
381
|
+
js.fact_type.implying_role.fact_type
|
|
350
382
|
else
|
|
351
383
|
js.fact_type
|
|
352
384
|
end
|
|
@@ -358,10 +390,10 @@ module ActiveFacts
|
|
|
358
390
|
prrs = fact_type.preferred_reading.role_sequence.all_role_ref
|
|
359
391
|
residual_roles = fact_type.all_role.select{|r| !r.all_role_ref.detect{|rr| rr.join_node && rr.join_node.join == join} }
|
|
360
392
|
residual_roles.each do |r|
|
|
361
|
-
debug :subscript, "Adding residual role for #{r.
|
|
393
|
+
debug :subscript, "Adding residual role for #{r.object_type.name} (in #{fact_type.default_reading}) not covered in join"
|
|
362
394
|
preferred_role_ref = prrs.detect{|rr| rr.role == r}
|
|
363
395
|
if p = @player_by_role_ref[preferred_role_ref] and !p.role_refs.include?(preferred_role_ref)
|
|
364
|
-
raise "Adding DUPLICATE residual role for #{r.
|
|
396
|
+
raise "Adding DUPLICATE residual role for #{r.object_type.name} not covered in join"
|
|
365
397
|
end
|
|
366
398
|
role_refs_have_same_player([preferred_role_ref])
|
|
367
399
|
end
|
|
@@ -388,7 +420,7 @@ module ActiveFacts
|
|
|
388
420
|
# Choose a reading that start with the (first) role which caused us to emit this fact type:
|
|
389
421
|
reading = fact_type.reading_preferably_starting_with_role(role_by_fact_type[fact_type])
|
|
390
422
|
if join_over and # Find a reading preferably starting with the joined_over role:
|
|
391
|
-
joined_role = fact_type.all_role.select{|r| join_over.subtypes_transitive.include?(r.
|
|
423
|
+
joined_role = fact_type.all_role.select{|r| join_over.subtypes_transitive.include?(r.object_type)}[0]
|
|
392
424
|
reading = fact_type.reading_preferably_starting_with_role joined_role
|
|
393
425
|
|
|
394
426
|
# Use the name of the joined_over object, not the role player, in case of a subtype join:
|
|
@@ -399,13 +431,11 @@ module ActiveFacts
|
|
|
399
431
|
reading.role_sequence.all_role_ref.each do |rr|
|
|
400
432
|
next unless player = @player_by_role_ref[rr]
|
|
401
433
|
next unless subscript = player.subscript
|
|
402
|
-
debug :subscript, "Need to apply subscript #{subscript} to #{rr.role.
|
|
434
|
+
debug :subscript, "Need to apply subscript #{subscript} to #{rr.role.object_type.name}"
|
|
403
435
|
end
|
|
404
436
|
player_by_role = {}
|
|
405
437
|
@player_by_role_ref.keys.each{|rr| player_by_role[rr.role] = @player_by_role_ref[rr] if rr.role.fact_type == fact_type }
|
|
406
|
-
#role_refs = @player_by_role_ref.keys.select{|rr| rr.role.fact_type == fact_type}
|
|
407
438
|
expand_reading_text(nil, reading.text, reading.role_sequence, player_by_role)
|
|
408
|
-
#reading.expand(name_substitutions)
|
|
409
439
|
end
|
|
410
440
|
joiner ? readings*joiner : readings
|
|
411
441
|
end
|
|
@@ -421,37 +451,29 @@ module ActiveFacts
|
|
|
421
451
|
text.gsub(/\{(\d)\}/) do
|
|
422
452
|
role_ref = rrs[$1.to_i]
|
|
423
453
|
# REVISIT: We may need to use the step's role_refs to expand the role players here, not the reading's one (extra adjectives?)
|
|
424
|
-
# REVISIT: There's no way to get literals to be emitted here (value join step?)
|
|
454
|
+
# REVISIT: There's no way to get literals to be emitted here (value join step or query result?)
|
|
425
455
|
|
|
426
456
|
player = player_by_role[role_ref.role]
|
|
427
457
|
|
|
428
|
-
=
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
player = @player_by_role_ref[rr] and subscript = player.subscript
|
|
432
|
-
if !subscript and
|
|
433
|
-
pp = @players.select{|p|p.concept == rr.role.concept} and
|
|
434
|
-
pp.detect{|p|p.subscript}
|
|
435
|
-
# raise "Internal error: Subscripted players (of the same concept #{pp[0].concept.name}) when this player isn't subscripted"
|
|
436
|
-
end
|
|
437
|
-
=end
|
|
438
|
-
|
|
439
|
-
subscripted_player(role_ref, player && player.subscript) +
|
|
440
|
-
objectification_verbalisation(role_ref.role.concept)
|
|
458
|
+
join_role_name = player && player.join_nodes_by_join.values.map{|jn| jn.role_name}.compact[0]
|
|
459
|
+
subscripted_player(role_ref, player && player.subscript, join_role_name) +
|
|
460
|
+
objectification_verbalisation(role_ref.role.object_type)
|
|
441
461
|
end
|
|
442
462
|
end
|
|
443
463
|
end
|
|
444
464
|
|
|
445
|
-
def subscripted_player role_ref, subscript = nil
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
465
|
+
def subscripted_player role_ref, subscript = nil, join_role_name = nil
|
|
466
|
+
prr = @player_by_role_ref[role_ref]
|
|
467
|
+
subscript ||= prr.subscript if prr
|
|
468
|
+
debug :subscript, "Need to apply subscript #{subscript} to #{role_ref.role.object_type.name}" if subscript
|
|
469
|
+
object_type = role_ref.role.object_type
|
|
470
|
+
(join_role_name ||
|
|
471
|
+
[
|
|
472
|
+
role_ref.leading_adjective,
|
|
473
|
+
object_type.name,
|
|
474
|
+
role_ref.trailing_adjective
|
|
475
|
+
].compact*' '
|
|
476
|
+
) +
|
|
455
477
|
(subscript ? "(#{subscript})" : '')
|
|
456
478
|
end
|
|
457
479
|
|
|
@@ -515,9 +537,9 @@ module ActiveFacts
|
|
|
515
537
|
debug :join, "Chose new random step from #{join_steps.size}: #{next_step.describe}"
|
|
516
538
|
if next_step.is_objectification_step
|
|
517
539
|
# if this objectification plays any roles (other than its FT roles) in remaining steps, use one of those first:
|
|
518
|
-
fact_type = next_step.fact_type.
|
|
519
|
-
jn = [next_step.input_join_role.join_node, next_step.output_join_role.join_node].detect{|jn| jn.
|
|
520
|
-
sr = @join_steps_by_join_node[jn].reject{|t| t.fact_type.
|
|
540
|
+
fact_type = next_step.fact_type.implying_role.fact_type
|
|
541
|
+
jn = [next_step.input_join_role.join_node, next_step.output_join_role.join_node].detect{|jn| jn.object_type == fact_type.entity_type}
|
|
542
|
+
sr = @join_steps_by_join_node[jn].reject{|t| r = t.fact_type.implying_role and r.fact_type == fact_type}
|
|
521
543
|
next_step = sr[0] if sr.size > 0
|
|
522
544
|
end
|
|
523
545
|
return next_step
|
|
@@ -534,13 +556,13 @@ module ActiveFacts
|
|
|
534
556
|
# This reading's RoleRef for that role:
|
|
535
557
|
(role_ref = reading.role_sequence.all_role_ref_in_order[$1.to_i]) &&
|
|
536
558
|
# was that RoleRef for the upcoming node?
|
|
537
|
-
role_ref.role.
|
|
559
|
+
role_ref.role.object_type == next_node.object_type
|
|
538
560
|
end
|
|
539
561
|
|
|
540
562
|
def reading_starts_with_node(reading, next_node)
|
|
541
563
|
reading.text =~ /^\{([0-9])\}/ and
|
|
542
564
|
role_ref = reading.role_sequence.all_role_ref.detect{|rr| rr.ordinal == $1.to_i} and
|
|
543
|
-
role_ref.role.
|
|
565
|
+
role_ref.role.object_type == next_node.object_type
|
|
544
566
|
end
|
|
545
567
|
|
|
546
568
|
# The last reading we emitted ended with the object type name for next_node.
|
|
@@ -558,21 +580,21 @@ module ActiveFacts
|
|
|
558
580
|
end
|
|
559
581
|
next_reading
|
|
560
582
|
end
|
|
561
|
-
debug :join, "#{next_reading ? "'"+next_reading.expand+"'" : "No reading"} contracts against last node '#{next_node.
|
|
583
|
+
debug :join, "#{next_reading ? "'"+next_reading.expand+"'" : "No reading"} contracts against last node '#{next_node.object_type.name}'"
|
|
562
584
|
return [next_step, next_reading]
|
|
563
585
|
end
|
|
564
586
|
|
|
565
|
-
# REVISIT: There might be more than one objectification_verbalisation for a given
|
|
566
|
-
def objectification_verbalisation(
|
|
587
|
+
# REVISIT: There might be more than one objectification_verbalisation for a given object_type. Need to get the Join Node here and emit an objectification step involving that node.
|
|
588
|
+
def objectification_verbalisation(object_type)
|
|
567
589
|
objectified_node = nil
|
|
568
|
-
unless
|
|
569
|
-
|
|
590
|
+
unless object_type.is_a?(Metamodel::EntityType) and
|
|
591
|
+
object_type.fact_type and # Not objectified
|
|
570
592
|
objectification_step = @join_steps.
|
|
571
593
|
detect do |js|
|
|
572
594
|
# The objectifying entity type should always be the input_join_node here, but be safe:
|
|
573
595
|
js.is_objectification_step and
|
|
574
|
-
(objectified_node = js.input_join_role.join_node).
|
|
575
|
-
(objectified_node = js.output_join_role.join_node).
|
|
596
|
+
(objectified_node = js.input_join_role.join_node).object_type == object_type ||
|
|
597
|
+
(objectified_node = js.output_join_role.join_node).object_type == object_type
|
|
576
598
|
end
|
|
577
599
|
return ''
|
|
578
600
|
end
|
|
@@ -586,7 +608,7 @@ module ActiveFacts
|
|
|
586
608
|
@join_steps.
|
|
587
609
|
detect{|js|
|
|
588
610
|
js.is_objectification_step and
|
|
589
|
-
js.input_join_role.join_node.
|
|
611
|
+
js.input_join_role.join_node.object_type == object_type || js.output_join_role.join_node.object_type == object_type
|
|
590
612
|
}
|
|
591
613
|
steps << other_step
|
|
592
614
|
debug :join, "Emitting objectification step allows deleting #{other_step.describe}"
|
|
@@ -601,9 +623,9 @@ module ActiveFacts
|
|
|
601
623
|
end
|
|
602
624
|
end
|
|
603
625
|
|
|
604
|
-
# role_refs = steps.map{|step| [step.input_join_role.join_node, step.output_join_role.join_node].map{|jn| jn.all_role_ref.detect{|rr| rr.role.fact_type ==
|
|
626
|
+
# role_refs = steps.map{|step| [step.input_join_role.join_node, step.output_join_role.join_node].map{|jn| jn.all_role_ref.detect{|rr| rr.role.fact_type == object_type.fact_type}}}.flatten.compact.uniq
|
|
605
627
|
|
|
606
|
-
reading =
|
|
628
|
+
reading = object_type.fact_type.preferred_reading
|
|
607
629
|
" (where #{expand_reading_text(objectification_step, reading.text, reading.role_sequence, player_by_role)})"
|
|
608
630
|
end
|
|
609
631
|
|
|
@@ -624,16 +646,19 @@ module ActiveFacts
|
|
|
624
646
|
exit_node = @join_nodes.detect{|jn| jn.all_join_role.detect{|jr| jr.role == last_role_ref.role}}
|
|
625
647
|
exit_step = nil
|
|
626
648
|
|
|
649
|
+
count = 0
|
|
627
650
|
while other_step =
|
|
628
651
|
@join_steps.
|
|
629
652
|
detect{|js|
|
|
630
653
|
next unless js.is_objectification_step
|
|
631
|
-
|
|
654
|
+
# REVISIT: This test is too weak: We need to ensure that the same join nodes are involved, not just the same object types:
|
|
655
|
+
next unless js.input_join_role.join_node.object_type == fact_type.entity_type || js.output_join_role.join_node.object_type == fact_type.entity_type
|
|
632
656
|
exit_step = js if js.output_join_role.join_node == exit_node
|
|
633
657
|
true
|
|
634
658
|
}
|
|
635
659
|
debug :join, "Emitting objectified FT allows deleting #{other_step.describe}"
|
|
636
660
|
step_completed(other_step)
|
|
661
|
+
# raise "The objectification of '#{fact_type.default_reading}' should not cause the deletion of more than #{fact_type.all_role.size} other join steps" if (count += 1) > fact_type.all_role.size
|
|
637
662
|
end
|
|
638
663
|
[ reading, exit_step ? exit_step.input_join_role.join_node : exit_node, exit_step, last_is_contractable]
|
|
639
664
|
end
|
|
@@ -657,7 +682,7 @@ module ActiveFacts
|
|
|
657
682
|
end
|
|
658
683
|
|
|
659
684
|
if next_step
|
|
660
|
-
debug :join, "Chose #{next_step.describe} because it's contractable against last node #{next_node.
|
|
685
|
+
debug :join, "Chose #{next_step.describe} because it's contractable against last node #{next_node.object_type.name} using #{next_reading.expand}"
|
|
661
686
|
|
|
662
687
|
player_by_role =
|
|
663
688
|
next_step.all_join_role.inject({}) {|h, jr| h[jr.role] = @player_by_join_role[jr]; h }
|
|
@@ -671,26 +696,26 @@ module ActiveFacts
|
|
|
671
696
|
|
|
672
697
|
if next_step.is_unary_step
|
|
673
698
|
# Objectified unaries get emitted as unaries, not as objectifications:
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
next_reading =
|
|
699
|
+
role = next_step.input_join_role.role
|
|
700
|
+
role = role.fact_type.implying_role if role.fact_type.is_a?(ImplicitFactType)
|
|
701
|
+
next_reading = role.fact_type.preferred_reading
|
|
677
702
|
readings += " and " unless readings.empty?
|
|
678
703
|
readings += expand_reading_text(next_step, next_reading.text, next_reading.role_sequence, player_by_role)
|
|
679
704
|
step_completed(next_step)
|
|
680
705
|
elsif next_step.is_objectification_step
|
|
681
|
-
fact_type = next_step.fact_type.
|
|
706
|
+
fact_type = next_step.fact_type.implying_role.fact_type
|
|
682
707
|
|
|
683
708
|
# This objectification step is over an implicit fact type, so player_by_role won't have all the players
|
|
684
709
|
# Add the players of other roles associated with steps from this objectified player.
|
|
685
710
|
objectified_node = next_step.input_join_role.join_node
|
|
686
|
-
raise "Assumption violated that the objectification is the input join role" unless objectified_node.
|
|
711
|
+
raise "Assumption violated that the objectification is the input join role" unless objectified_node.object_type.fact_type
|
|
687
712
|
objectified_node.all_join_step.map do |other_step|
|
|
688
713
|
(other_step.all_incidental_join_role.to_a + [other_step.output_join_role]).map do |jr|
|
|
689
714
|
player_by_role[jr.role] = @player_by_join_role[jr]
|
|
690
715
|
end
|
|
691
716
|
end
|
|
692
717
|
|
|
693
|
-
if last_is_contractable and next_node.
|
|
718
|
+
if last_is_contractable and next_node.object_type.is_a?(EntityType) and next_node.object_type.fact_type == fact_type
|
|
694
719
|
# The last reading we emitted ended with the name of the objectification of this fact type, so we can contract the objectification
|
|
695
720
|
# REVISIT: Do we need to use player_by_role here (if this objectification is traversed twice and so is subscripted)
|
|
696
721
|
readings += objectification_verbalisation(fact_type.entity_type)
|