activefacts 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 }
|