activefacts 1.0.2 → 1.1.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.
- checksums.yaml +5 -13
- data/Rakefile +2 -2
- data/bin/afgen +1 -1
- data/bin/cql +118 -27
- data/examples/CQL/Insurance.cql +2 -2
- data/examples/CQL/Metamodel.cql +3 -3
- data/examples/CQL/SchoolActivities.cql +1 -1
- data/examples/CQL/Warehousing.cql +5 -4
- data/lib/activefacts/cql.rb +1 -1
- data/lib/activefacts/cql/Language/English.treetop +2 -1
- data/lib/activefacts/cql/compiler.rb +6 -6
- data/lib/activefacts/cql/compiler/clause.rb +69 -46
- data/lib/activefacts/cql/compiler/constraint.rb +14 -14
- data/lib/activefacts/cql/compiler/entity_type.rb +24 -24
- data/lib/activefacts/cql/compiler/fact.rb +40 -27
- data/lib/activefacts/cql/compiler/fact_type.rb +16 -16
- data/lib/activefacts/cql/compiler/query.rb +12 -12
- data/lib/activefacts/cql/compiler/shared.rb +9 -0
- data/lib/activefacts/cql/compiler/value_type.rb +4 -4
- data/lib/activefacts/cql/parser.rb +9 -9
- data/lib/activefacts/generate/cql.rb +41 -20
- data/lib/activefacts/generate/helpers/oo.rb +33 -70
- data/lib/activefacts/generate/helpers/ordered.rb +61 -87
- data/lib/activefacts/generate/ruby.rb +12 -72
- data/lib/activefacts/generate/transform/surrogate.rb +13 -13
- data/lib/activefacts/input/orm.rb +72 -71
- data/lib/activefacts/persistence/columns.rb +66 -31
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +12 -12
- data/lib/activefacts/persistence/object_type.rb +15 -12
- data/lib/activefacts/persistence/reference.rb +20 -18
- data/lib/activefacts/persistence/tables.rb +40 -36
- data/lib/activefacts/support.rb +69 -123
- data/lib/activefacts/version.rb +2 -2
- data/lib/activefacts/vocabulary/extensions.rb +42 -39
- data/lib/activefacts/vocabulary/metamodel.rb +11 -1
- data/lib/activefacts/vocabulary/verbaliser.rb +28 -28
- data/spec/cql/contractions_spec.rb +1 -1
- data/spec/cql/entity_type_spec.rb +1 -1
- data/spec/cql/fact_type_matching_spec.rb +3 -3
- data/spec/cql/role_matching_spec.rb +4 -4
- data/spec/cql/samples_spec.rb +2 -2
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/helpers/array_matcher.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +2 -2
- data/spec/norma_tables_spec.rb +3 -2
- metadata +47 -68
@@ -10,7 +10,7 @@ module ActiveFacts
|
|
10
10
|
def finalise
|
11
11
|
constellation.FactType.values.each do |fact_type|
|
12
12
|
if c = fact_type.check_and_add_spanning_uniqueness_constraint
|
13
|
-
|
13
|
+
trace :constraint, "Checking for existence of at least one uniqueness constraint over the roles of #{fact_type.default_reading.inspect}"
|
14
14
|
fact_type.check_and_add_spanning_uniqueness_constraint = nil
|
15
15
|
c.call
|
16
16
|
end
|
@@ -166,7 +166,6 @@ module ActiveFacts
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def is_mandatory
|
169
|
-
link_fact_type ||
|
170
169
|
all_role_ref.detect{|rr|
|
171
170
|
rs = rr.role_sequence
|
172
171
|
rs.all_role_ref.size == 1 and
|
@@ -185,12 +184,16 @@ module ActiveFacts
|
|
185
184
|
def is_functional
|
186
185
|
fact_type.entity_type or
|
187
186
|
fact_type.all_role.size != 2 or
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
187
|
+
is_unique
|
188
|
+
end
|
189
|
+
|
190
|
+
def is_unique
|
191
|
+
all_role_ref.detect do |rr|
|
192
|
+
rr.role_sequence.all_role_ref.size == 1 and
|
193
|
+
rr.role_sequence.all_presence_constraint.detect do |pc|
|
194
|
+
pc.max_frequency == 1 and !pc.enforcement # Alethic uniqueness constraint
|
195
|
+
end
|
196
|
+
end
|
194
197
|
end
|
195
198
|
|
196
199
|
end
|
@@ -289,7 +292,7 @@ module ActiveFacts
|
|
289
292
|
|
290
293
|
# For a nested fact type, the PI is a unique constraint over N or N-1 roles
|
291
294
|
fact_roles = Array(fact_type.all_role)
|
292
|
-
|
295
|
+
trace :pi, "Looking for PI on nested fact type #{name}" do
|
293
296
|
pi = catch :pi do
|
294
297
|
fact_roles[0,2].each{|r| # Try the first two roles of the fact type, that's enough
|
295
298
|
r.all_role_ref.map{|rr| # All role sequences that reference this role
|
@@ -323,18 +326,18 @@ module ActiveFacts
|
|
323
326
|
}
|
324
327
|
throw :pi, nil
|
325
328
|
end
|
326
|
-
|
327
|
-
|
329
|
+
trace :pi, "Got PI #{pi.name||pi.object_id} for nested #{name}" if pi
|
330
|
+
trace :pi, "Looking for PI on entity that nests this fact" unless pi
|
328
331
|
raise "Oops, pi for nested fact is #{pi.class}" unless !pi || pi.is_a?(ActiveFacts::Metamodel::PresenceConstraint)
|
329
332
|
return @preferred_identifier = pi if pi
|
330
333
|
end
|
331
334
|
end
|
332
335
|
|
333
|
-
|
334
|
-
|
336
|
+
trace :pi, "Looking for PI for ordinary entity #{name} with #{all_role.size} roles:" do
|
337
|
+
trace :pi, "Roles are in fact types #{all_role.map{|r| r.fact_type.describe(r)}*", "}"
|
335
338
|
pi = catch :pi do
|
336
339
|
all_supertypes = supertypes_transitive
|
337
|
-
|
340
|
+
trace :pi, "PI roles must be played by one of #{all_supertypes.map(&:name)*", "}" if all_supertypes.size > 1
|
338
341
|
all_role.each{|role|
|
339
342
|
next unless role.unique || fact_type
|
340
343
|
ftroles = Array(role.fact_type.all_role)
|
@@ -342,41 +345,41 @@ module ActiveFacts
|
|
342
345
|
# Skip roles in ternary and higher fact types, they're objectified, and in unaries, they can't identify us.
|
343
346
|
next if ftroles.size != 2
|
344
347
|
|
345
|
-
|
348
|
+
trace :pi, "Considering role in #{role.fact_type.describe(role)}"
|
346
349
|
|
347
350
|
# Find the related role which must be included in any PI:
|
348
351
|
# Note this works with unary fact types:
|
349
352
|
pi_role = ftroles[ftroles[0] != role ? 0 : -1]
|
350
353
|
|
351
354
|
next if ftroles.size == 2 && pi_role.object_type == self
|
352
|
-
|
355
|
+
trace :pi, " Considering #{pi_role.object_type.name} as a PI role"
|
353
356
|
|
354
357
|
# If this is an identifying role, the PI is a PC whose role_sequence spans the role.
|
355
358
|
# Walk through all role_sequences that span this role, and test each:
|
356
359
|
pi_role.all_role_ref.each{|rr|
|
357
360
|
role_sequence = rr.role_sequence # A role sequence that includes a possible role
|
358
361
|
|
359
|
-
|
362
|
+
trace :pi, " Considering role sequence #{role_sequence.describe}"
|
360
363
|
|
361
364
|
# All roles in this role_sequence must be in fact types which
|
362
365
|
# (apart from that role) only have roles played by the original
|
363
366
|
# entity type or a supertype.
|
364
|
-
#
|
367
|
+
#trace :pi, " All supertypes #{all_supertypes.map{|st| "#{st.object_id}=>#{st.name}"}*", "}"
|
365
368
|
if role_sequence.all_role_ref.detect{|rsr|
|
366
369
|
fact_type = rsr.role.fact_type
|
367
|
-
|
370
|
+
trace :pi, " Role Sequence touches #{fact_type.describe(pi_role)}"
|
368
371
|
|
369
372
|
fact_type_roles = fact_type.all_role
|
370
|
-
|
373
|
+
trace :pi, " residual is #{fact_type_roles.map{|r| r.object_type.name}.inspect} minus #{rsr.role.object_type.name}"
|
371
374
|
residual_roles = fact_type_roles-[rsr.role]
|
372
375
|
residual_roles.detect{|rfr|
|
373
|
-
|
376
|
+
trace :pi, " Checking residual role #{rfr.object_type.object_id}=>#{rfr.object_type.name}"
|
374
377
|
# This next line looks right, but breaks things. Find out what and why:
|
375
378
|
# !rfr.unique or
|
376
379
|
!all_supertypes.include?(rfr.object_type)
|
377
380
|
}
|
378
381
|
}
|
379
|
-
|
382
|
+
trace :pi, " Discounting this role_sequence because it includes alien roles"
|
380
383
|
next
|
381
384
|
end
|
382
385
|
|
@@ -384,7 +387,7 @@ module ActiveFacts
|
|
384
387
|
rr.role_sequence.all_presence_constraint.detect{|pc|
|
385
388
|
# Found it!
|
386
389
|
if pc.is_preferred_identifier
|
387
|
-
|
390
|
+
trace :pi, "found PI #{pc.name||pc.object_id}, is_preferred_identifier=#{pc.is_preferred_identifier.inspect} over #{pc.role_sequence.describe}"
|
388
391
|
throw :pi, pc
|
389
392
|
end
|
390
393
|
}
|
@@ -393,13 +396,13 @@ module ActiveFacts
|
|
393
396
|
throw :pi, nil
|
394
397
|
end
|
395
398
|
raise "Oops, pi for entity is #{pi.class}" if pi && !pi.is_a?(ActiveFacts::Metamodel::PresenceConstraint)
|
396
|
-
|
399
|
+
trace :pi, "Got PI #{pi.name||pi.object_id} for #{name}" if pi
|
397
400
|
|
398
401
|
if !pi
|
399
402
|
if (supertype = identifying_supertype)
|
400
403
|
# This shouldn't happen now, as an identifying supertype is connected by a fact type
|
401
404
|
# that has a uniqueness constraint marked as the preferred identifier.
|
402
|
-
#
|
405
|
+
#trace :pi, "PI not found for #{name}, looking in supertype #{supertype.name}"
|
403
406
|
#pi = supertype.preferred_identifier
|
404
407
|
#return nil
|
405
408
|
elsif fact_type
|
@@ -420,11 +423,11 @@ module ActiveFacts
|
|
420
423
|
break if pi
|
421
424
|
}
|
422
425
|
if !pi && possible_pi
|
423
|
-
|
426
|
+
trace :pi, "Using existing PC as PI for #{name}"
|
424
427
|
pi = possible_pi
|
425
428
|
end
|
426
429
|
else
|
427
|
-
|
430
|
+
trace :pi, "No PI found for #{name}"
|
428
431
|
end
|
429
432
|
end
|
430
433
|
raise "No PI found for #{name}" unless pi
|
@@ -464,14 +467,14 @@ module ActiveFacts
|
|
464
467
|
|
465
468
|
# A subtype does not have a identifying_supertype if it defines its own identifier
|
466
469
|
def identifying_supertype
|
467
|
-
|
470
|
+
trace "Looking for identifying_supertype of #{name}"
|
468
471
|
all_type_inheritance_as_subtype.detect{|ti|
|
469
|
-
|
472
|
+
trace "considering supertype #{ti.supertype.name}"
|
470
473
|
next unless ti.provides_identification
|
471
|
-
|
474
|
+
trace "found identifying supertype of #{name}, it's #{ti.supertype.name}"
|
472
475
|
return ti.supertype
|
473
476
|
}
|
474
|
-
|
477
|
+
trace "Failed to find identifying supertype of #{name}"
|
475
478
|
return nil
|
476
479
|
end
|
477
480
|
|
@@ -551,7 +554,7 @@ module ActiveFacts
|
|
551
554
|
end
|
552
555
|
}
|
553
556
|
expanded.gsub!(/ ?- ?/, '-') # Remove single spaces around adjectives
|
554
|
-
#
|
557
|
+
#trace "Expanded '#{expanded}' using #{frequency_constraints.inspect}"
|
555
558
|
expanded
|
556
559
|
end
|
557
560
|
|
@@ -621,7 +624,7 @@ module ActiveFacts
|
|
621
624
|
def to_s
|
622
625
|
if all_allowed_range.size > 1
|
623
626
|
"[" +
|
624
|
-
|
627
|
+
all_allowed_range_sorted.map { |ar| ar.to_s(true) }*", " +
|
625
628
|
"]"
|
626
629
|
else
|
627
630
|
all_allowed_range.single.to_s
|
@@ -777,17 +780,17 @@ module ActiveFacts
|
|
777
780
|
class Query
|
778
781
|
def show
|
779
782
|
steps_shown = {}
|
780
|
-
|
783
|
+
trace :query, "Displaying full contents of Query #{concept.guid}" do
|
781
784
|
all_variable.sort_by{|jn| jn.ordinal}.each do |variable|
|
782
|
-
|
785
|
+
trace :query, "#{variable.describe}" do
|
783
786
|
variable.all_step.
|
784
787
|
each do |step|
|
785
788
|
next if steps_shown[step]
|
786
789
|
steps_shown[step] = true
|
787
|
-
|
790
|
+
trace :query, "#{step.describe}"
|
788
791
|
end
|
789
792
|
variable.all_play.each do |play|
|
790
|
-
|
793
|
+
trace :query, "role of #{play.describe} in '#{play.role.fact_type.default_reading}'"
|
791
794
|
end
|
792
795
|
end
|
793
796
|
end
|
@@ -979,9 +982,9 @@ module ActiveFacts
|
|
979
982
|
# Discount a subtype step over an object type that's not a player here,
|
980
983
|
# if we can use an objectification step to an object type that is:
|
981
984
|
if counterpart_sups.size > 0 && obj_sups.size > 0 && counterpart_sups[0] != obj_sups[0]
|
982
|
-
|
985
|
+
trace :query, "ambiguous query, could be over #{counterpart_sups[0].name} or #{obj_sups[0].name}"
|
983
986
|
if !roles.detect{|r| r.object_type == counterpart_sups[0]} and roles.detect{|r| r.object_type == obj_sups[0]}
|
984
|
-
|
987
|
+
trace :query, "discounting #{counterpart_sups[0].name} in favour of direct objectification"
|
985
988
|
counterpart_sups = []
|
986
989
|
end
|
987
990
|
end
|
@@ -9,10 +9,12 @@ module ActiveFacts
|
|
9
9
|
|
10
10
|
class AgentName < String
|
11
11
|
value_type
|
12
|
+
one_to_one :agent # See Agent.agent_name
|
12
13
|
end
|
13
14
|
|
14
15
|
class AggregateCode < String
|
15
16
|
value_type :length => 32
|
17
|
+
one_to_one :aggregate # See Aggregate.aggregate_code
|
16
18
|
end
|
17
19
|
|
18
20
|
class Assimilation < String
|
@@ -60,10 +62,15 @@ module ActiveFacts
|
|
60
62
|
|
61
63
|
class Guid < ::Guid
|
62
64
|
value_type
|
65
|
+
one_to_one :alternative_set # See AlternativeSet.guid
|
66
|
+
one_to_one :concept # See Concept.guid
|
67
|
+
one_to_one :role_sequence # See RoleSequence.guid
|
68
|
+
one_to_one :shape # See Shape.guid
|
63
69
|
end
|
64
70
|
|
65
71
|
class ImplicationRuleName < String
|
66
72
|
value_type
|
73
|
+
one_to_one :implication_rule # See ImplicationRule.implication_rule_name
|
67
74
|
end
|
68
75
|
|
69
76
|
class Length < UnsignedInteger
|
@@ -76,6 +83,9 @@ module ActiveFacts
|
|
76
83
|
|
77
84
|
class Name < String
|
78
85
|
value_type :length => 64
|
86
|
+
one_to_one :plural_named_unit, :class => "Unit", :counterpart => :plural_name # See Unit.plural_name
|
87
|
+
one_to_one :unit # See Unit.name
|
88
|
+
one_to_one :vocabulary # See Vocabulary.name
|
79
89
|
end
|
80
90
|
|
81
91
|
class Numerator < Decimal
|
@@ -295,7 +305,7 @@ module ActiveFacts
|
|
295
305
|
maybe :is_fundamental
|
296
306
|
one_to_one :name, :mandatory => true # See Name.unit
|
297
307
|
has_one :offset # See Offset.all_unit
|
298
|
-
one_to_one :plural_name, :class => Name
|
308
|
+
one_to_one :plural_name, :class => Name, :counterpart => :plural_named_unit # See Name.plural_named_unit
|
299
309
|
has_one :vocabulary, :mandatory => true # See Vocabulary.all_unit
|
300
310
|
end
|
301
311
|
|
@@ -139,10 +139,10 @@ module ActiveFacts
|
|
139
139
|
@player_by_role_ref[ref] or ref.play && @player_by_play[ref.play]
|
140
140
|
end
|
141
141
|
if existing_player
|
142
|
-
|
142
|
+
trace :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
143
|
return existing_player
|
144
144
|
else
|
145
|
-
|
145
|
+
trace :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
146
|
p = Player.new(ref.role.object_type)
|
147
147
|
@players.push(p)
|
148
148
|
p
|
@@ -162,11 +162,11 @@ module ActiveFacts
|
|
162
162
|
|
163
163
|
# Add a RoleRef to an existing Player
|
164
164
|
def add_role_player player, role_ref
|
165
|
-
#
|
165
|
+
#trace :subscript, "Adding role_ref #{role_ref.object_id} to player #{player.object_id}"
|
166
166
|
if jr = role_ref.play
|
167
167
|
add_play(player, jr)
|
168
168
|
elsif !player.role_refs.include?(role_ref)
|
169
|
-
|
169
|
+
trace :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"
|
170
170
|
player.role_refs.push(role_ref)
|
171
171
|
@player_by_role_ref[role_ref] = player
|
172
172
|
end
|
@@ -222,9 +222,9 @@ module ActiveFacts
|
|
222
222
|
end
|
223
223
|
p = existing_players[0] || player(plays[0])
|
224
224
|
debugger if plays.detect{|jr| jr.role.object_type != p.object_type }
|
225
|
-
|
225
|
+
trace :subscript, "roles are playes of #{p.describe}" do
|
226
226
|
plays.each do |play|
|
227
|
-
|
227
|
+
trace :subscript, "#{play.describe}" do
|
228
228
|
add_play p, play
|
229
229
|
end
|
230
230
|
end
|
@@ -244,7 +244,7 @@ module ActiveFacts
|
|
244
244
|
end
|
245
245
|
p = existing_players[0] || player(role_refs[0])
|
246
246
|
|
247
|
-
|
247
|
+
trace :subscript, "#{existing_players[0] ? 'Adding to existing' : 'Creating new'} player for #{role_refs.map{|rr| rr.role.object_type.name}.uniq*', '}" do
|
248
248
|
role_refs.each do |rr|
|
249
249
|
unless p.object_type == rr.role.object_type
|
250
250
|
# This happens in SubtypePI because uniqueness constraint is built without its implicit subtyping step.
|
@@ -275,10 +275,10 @@ module ActiveFacts
|
|
275
275
|
p.role_adjuncts(matching) == player.role_adjuncts(matching)
|
276
276
|
end
|
277
277
|
if dups.size == 1
|
278
|
-
|
278
|
+
trace :subscript, "No subscript needed for #{object_type.name}"
|
279
279
|
next
|
280
280
|
end
|
281
|
-
|
281
|
+
trace :subscript, "Applying subscripts to #{dups.size} occurrences of #{object_type.name}" do
|
282
282
|
s = 0
|
283
283
|
dups.
|
284
284
|
sort_by{|p| # Guarantee stable numbering
|
@@ -350,7 +350,7 @@ module ActiveFacts
|
|
350
350
|
prrs = fact_type.preferred_reading.role_sequence.all_role_ref
|
351
351
|
residual_roles = fact_type.all_role.select{|r| !@role_refs.detect{|rr| rr.role == r} }
|
352
352
|
residual_roles.each do |role|
|
353
|
-
|
353
|
+
trace :subscript, "Adding residual role for #{role.object_type.name} (in #{fact_type.default_reading}) not covered in role sequence"
|
354
354
|
preferred_role_ref = prrs.detect{|rr| rr.role == role}
|
355
355
|
if p = @player_by_role_ref[preferred_role_ref] and !p.role_refs.include?(preferred_role_ref)
|
356
356
|
raise "Adding DUPLICATE residual role for #{role.object_type.name}"
|
@@ -361,11 +361,11 @@ module ActiveFacts
|
|
361
361
|
end
|
362
362
|
|
363
363
|
def prepare_query_players query
|
364
|
-
|
364
|
+
trace :subscript, "Indexing roles of fact types in #{query.all_step.size} steps" do
|
365
365
|
steps = []
|
366
366
|
# Register all references to each variable as being for the same player:
|
367
367
|
query.all_variable.sort_by{|jn| jn.ordinal}.each do |variable|
|
368
|
-
|
368
|
+
trace :subscript, "Adding Roles of #{variable.describe}" do
|
369
369
|
plays_have_same_player(variable.all_play.to_a)
|
370
370
|
steps = steps | variable.all_step
|
371
371
|
end
|
@@ -388,11 +388,11 @@ module ActiveFacts
|
|
388
388
|
#steps.map{|js|js.fact_type}.uniq.each do |fact_type|
|
389
389
|
next if fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
390
390
|
|
391
|
-
|
391
|
+
trace :subscript, "Residual roles in '#{fact_type.default_reading}' are" do
|
392
392
|
prrs = fact_type.preferred_reading.role_sequence.all_role_ref
|
393
393
|
residual_roles = fact_type.all_role.select{|r| !r.all_role_ref.detect{|rr| rr.variable && rr.variable.query == query} }
|
394
394
|
residual_roles.each do |r|
|
395
|
-
|
395
|
+
trace :subscript, "Adding residual role for #{r.object_type.name} (in #{fact_type.default_reading}) not covered in query"
|
396
396
|
preferred_role_ref = prrs.detect{|rr| rr.role == r}
|
397
397
|
if p = @player_by_role_ref[preferred_role_ref] and !p.role_refs.include?(preferred_role_ref)
|
398
398
|
raise "Adding DUPLICATE residual role for #{r.object_type.name} not covered in query"
|
@@ -433,7 +433,7 @@ module ActiveFacts
|
|
433
433
|
reading.role_sequence.all_role_ref.each do |rr|
|
434
434
|
next unless player = @player_by_role_ref[rr]
|
435
435
|
next unless subscript = player.subscript
|
436
|
-
|
436
|
+
trace :subscript, "Need to apply subscript #{subscript} to #{rr.role.object_type.name}"
|
437
437
|
end
|
438
438
|
player_by_role = {}
|
439
439
|
@player_by_role_ref.keys.each{|rr| player_by_role[rr.role] = @player_by_role_ref[rr] if rr.role.fact_type == fact_type }
|
@@ -454,7 +454,7 @@ module ActiveFacts
|
|
454
454
|
plays = ([step.input_play, step.output_play]+step.all_incidental_play.to_a).compact
|
455
455
|
variable_by_role = plays.inject({}) { |h, play| h[play.role] = play.variable; h }
|
456
456
|
end
|
457
|
-
|
457
|
+
trace :subscript, "expanding '#{text}' with #{role_sequence.describe}" do
|
458
458
|
text.gsub(/\{(\d)\}/) do
|
459
459
|
role_ref = rrs[$1.to_i]
|
460
460
|
# REVISIT: We may need to use the step's role_refs to expand the role players here, not the reading's one (extra adjectives?)
|
@@ -471,7 +471,7 @@ module ActiveFacts
|
|
471
471
|
def subscripted_player role_ref, subscript = nil, play_name = nil, value = nil
|
472
472
|
prr = @player_by_role_ref[role_ref]
|
473
473
|
subscript ||= prr.subscript if prr
|
474
|
-
|
474
|
+
trace :subscript, "Need to apply subscript #{subscript} to #{role_ref.role.object_type.name}" if subscript
|
475
475
|
object_type = role_ref.role.object_type
|
476
476
|
(play_name ||
|
477
477
|
[
|
@@ -532,19 +532,19 @@ module ActiveFacts
|
|
532
532
|
# so just use any step involving this node, or just any step.
|
533
533
|
if next_steps
|
534
534
|
if next_step = next_steps.detect { |ns| !ns.is_objectification_step }
|
535
|
-
|
535
|
+
trace :query, "Chose new non-objectification step: #{next_step.describe}"
|
536
536
|
return next_step
|
537
537
|
end
|
538
538
|
end
|
539
539
|
|
540
540
|
if next_step = @steps.detect { |ns| !ns.is_objectification_step }
|
541
|
-
|
541
|
+
trace :query, "Chose random non-objectification step: #{next_step.describe}"
|
542
542
|
return next_step
|
543
543
|
end
|
544
544
|
|
545
545
|
next_step = @steps[0]
|
546
546
|
if next_step
|
547
|
-
|
547
|
+
trace :query, "Chose new random step from #{steps.size}: #{next_step.describe}"
|
548
548
|
if next_step.is_objectification_step
|
549
549
|
# if this objectification plays any roles (other than its FT roles) in remaining steps, use one of those first:
|
550
550
|
fact_type = next_step.fact_type.implying_role.fact_type
|
@@ -590,7 +590,7 @@ module ActiveFacts
|
|
590
590
|
end
|
591
591
|
next_reading
|
592
592
|
end
|
593
|
-
|
593
|
+
trace :query, "#{next_reading ? "'"+next_reading.expand+"'" : "No reading"} contracts against last node '#{next_node.object_type.name}'"
|
594
594
|
return [next_step, next_reading]
|
595
595
|
end
|
596
596
|
|
@@ -621,7 +621,7 @@ module ActiveFacts
|
|
621
621
|
js.input_play.variable.object_type == object_type || js.output_play.variable.object_type == object_type
|
622
622
|
}
|
623
623
|
steps << other_step
|
624
|
-
|
624
|
+
trace :query, "Emitting objectification step allows deleting #{other_step.describe}"
|
625
625
|
step_completed(other_step)
|
626
626
|
end
|
627
627
|
|
@@ -658,12 +658,12 @@ module ActiveFacts
|
|
658
658
|
exit_node = @variables.detect{|jn| jn.all_play.detect{|jr| jr.role == last_role_ref.role}}
|
659
659
|
exit_step = nil
|
660
660
|
|
661
|
-
|
661
|
+
trace :query, "Stepping over an objectification to #{exit_node.object_type.name} requires eliding the other implied steps" do
|
662
662
|
count = 0
|
663
663
|
while other_step =
|
664
664
|
@steps.
|
665
665
|
detect{|js|
|
666
|
-
|
666
|
+
trace :query, "Considering step '#{js.fact_type.default_reading}'"
|
667
667
|
next unless js.is_objectification_step
|
668
668
|
|
669
669
|
# REVISIT: This test is too weak: We need to ensure that the same variables are involved, not just the same object types:
|
@@ -671,7 +671,7 @@ module ActiveFacts
|
|
671
671
|
exit_step = js if js.output_play.variable == exit_node
|
672
672
|
true
|
673
673
|
}
|
674
|
-
|
674
|
+
trace :query, "Emitting objectified FT allows deleting #{other_step.describe}"
|
675
675
|
step_completed(other_step)
|
676
676
|
# raise "The objectification of '#{fact_type.default_reading}' should not cause the deletion of more than #{fact_type.all_role.size} other steps" if (count += 1) > fact_type.all_role.size
|
677
677
|
end
|
@@ -685,12 +685,12 @@ module ActiveFacts
|
|
685
685
|
readings = ''
|
686
686
|
next_node = @role_refs[0].play.variable # Choose a place to start
|
687
687
|
last_is_contractable = false
|
688
|
-
|
688
|
+
trace :query, "Variables are #{@variables.map{|jn| jn.describe }.inspect}, Steps are #{@steps.map{|js| js.describe }.inspect}" do
|
689
689
|
until @steps.empty?
|
690
690
|
next_reading = nil
|
691
691
|
# Choose amonst all remaining steps we can take from the next node, if any
|
692
692
|
next_steps = @steps_by_variable[next_node]
|
693
|
-
|
693
|
+
trace :query, "Next Steps from #{next_node.describe} are #{(next_steps||[]).map{|js| js.describe }.inspect}"
|
694
694
|
|
695
695
|
# See if we can find a next step that contracts against the last (if any):
|
696
696
|
next_step = nil
|
@@ -699,7 +699,7 @@ module ActiveFacts
|
|
699
699
|
end
|
700
700
|
|
701
701
|
if next_step
|
702
|
-
|
702
|
+
trace :query, "Chose #{next_step.describe} because it's contractable against last node #{next_node.object_type.name} using #{next_reading.expand}"
|
703
703
|
|
704
704
|
player_by_role =
|
705
705
|
next_step.all_play.inject({}) {|h, jr| h[jr.role] = @player_by_play[jr]; h }
|