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
|
@@ -3,8 +3,8 @@ module ActiveFacts
|
|
|
3
3
|
class Compiler < ActiveFacts::CQL::Parser
|
|
4
4
|
|
|
5
5
|
class Fact < Definition
|
|
6
|
-
def initialize
|
|
7
|
-
@
|
|
6
|
+
def initialize clauses, population_name = ''
|
|
7
|
+
@clauses = clauses
|
|
8
8
|
@population_name = population_name
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -12,17 +12,15 @@ module ActiveFacts
|
|
|
12
12
|
@population = @constellation.Population(@vocabulary, @population_name)
|
|
13
13
|
|
|
14
14
|
@context = CompilationContext.new(@vocabulary)
|
|
15
|
-
@
|
|
16
|
-
@
|
|
17
|
-
@
|
|
18
|
-
@readings.each{ |reading| reading.match_existing_fact_type @context }
|
|
15
|
+
@context.bind @clauses
|
|
16
|
+
@context.left_contraction_allowed = true
|
|
17
|
+
@clauses.each{ |clause| clause.match_existing_fact_type @context }
|
|
19
18
|
|
|
20
19
|
# Figure out the simple existential facts and find fact types:
|
|
21
20
|
@bound_facts = []
|
|
22
|
-
@
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
bind_literal_or_fact_type reading
|
|
21
|
+
@unbound_clauses = all_clauses.
|
|
22
|
+
map do |clause|
|
|
23
|
+
bind_literal_or_fact_type clause
|
|
26
24
|
end.
|
|
27
25
|
compact
|
|
28
26
|
|
|
@@ -32,158 +30,157 @@ module ActiveFacts
|
|
|
32
30
|
true while bind_more_facts
|
|
33
31
|
|
|
34
32
|
# Any remaining unbound facts are a problem we can bitch about:
|
|
35
|
-
complain_incomplete unless @
|
|
33
|
+
complain_incomplete unless @unbound_clauses.empty?
|
|
36
34
|
|
|
37
35
|
@bound_facts.uniq # N.B. this includes Instance objects (existential facts)
|
|
38
36
|
end
|
|
39
37
|
|
|
40
|
-
def bind_literal_or_fact_type
|
|
38
|
+
def bind_literal_or_fact_type clause
|
|
41
39
|
# Every bound word (term) in the phrases must have a literal
|
|
42
40
|
# OR be bound to an entity type identified by the phrases
|
|
43
41
|
|
|
44
|
-
# Any clause that has one
|
|
42
|
+
# Any clause that has one variable and no other word is
|
|
45
43
|
# either a value instance or a simply-identified entity.
|
|
46
|
-
|
|
47
|
-
next unless l =
|
|
48
|
-
next if
|
|
49
|
-
player =
|
|
50
|
-
# raise "A literal may not be an objectification" if
|
|
51
|
-
# raise "Not processing facts involving
|
|
44
|
+
clause.var_refs.each do |var_ref|
|
|
45
|
+
next unless l = var_ref.literal # No literal
|
|
46
|
+
next if var_ref.variable.instance # Already bound
|
|
47
|
+
player = var_ref.variable.player
|
|
48
|
+
# raise "A literal may not be an objectification" if var_ref.role_ref.nested_clauses
|
|
49
|
+
# raise "Not processing facts involving nested clauses yet" if var_ref.role_ref
|
|
52
50
|
debug :instance, "Making #{player.class.basename} #{player.name} using #{l.inspect}" do
|
|
53
|
-
|
|
51
|
+
var_ref.variable.instance = instance_identified_by_literal(player, l)
|
|
54
52
|
end
|
|
55
|
-
|
|
53
|
+
var_ref
|
|
56
54
|
end
|
|
57
55
|
|
|
58
|
-
if
|
|
59
|
-
if
|
|
60
|
-
# Assign the objectified fact type as this
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
if clause.phrases.size == 1 and (var_ref = clause.phrases[0]).is_a?(Compiler::VarRef)
|
|
57
|
+
if var_ref.nested_clauses
|
|
58
|
+
# Assign the objectified fact type as this clause's fact type?
|
|
59
|
+
clause.fact_type = var_ref.player.fact_type
|
|
60
|
+
clause
|
|
63
61
|
else
|
|
64
62
|
# This is an existential fact (like "Name 'foo'", or "Company 'Microsoft'")
|
|
65
63
|
nil # Nothing to see here, move along
|
|
66
64
|
end
|
|
67
65
|
else
|
|
68
|
-
raise "Fact Type not found: '#{
|
|
69
|
-
# This instance will be associated with its
|
|
70
|
-
|
|
66
|
+
raise "Fact Type not found: '#{clause.display}'" unless clause.fact_type
|
|
67
|
+
# This instance will be associated with its variable by our caller
|
|
68
|
+
clause
|
|
71
69
|
end
|
|
72
70
|
end
|
|
73
71
|
|
|
74
72
|
#
|
|
75
|
-
# Try to bind this
|
|
73
|
+
# Try to bind this clause, and return true if it can be completed
|
|
76
74
|
#
|
|
77
|
-
def
|
|
78
|
-
return true if
|
|
79
|
-
|
|
80
|
-
# Find the roles of this
|
|
81
|
-
bare_roles =
|
|
82
|
-
select do |
|
|
83
|
-
next false if
|
|
84
|
-
next false if
|
|
85
|
-
|
|
75
|
+
def bind_clause clause
|
|
76
|
+
return true if clause.fact
|
|
77
|
+
|
|
78
|
+
# Find the roles of this clause that do not yet have an instance
|
|
79
|
+
bare_roles = clause.var_refs.
|
|
80
|
+
select do |var_ref|
|
|
81
|
+
next false if var_ref.variable.instance
|
|
82
|
+
next false if var_ref.literal and
|
|
83
|
+
var_ref.variable.instance = instance_identified_by_literal(var_ref.variable.player, var_ref.literal)
|
|
86
84
|
true
|
|
87
85
|
end
|
|
88
86
|
|
|
89
|
-
debug :instance, "Considering '#{
|
|
90
|
-
(bare_roles.empty? ? "no bare roles" : "bare roles: #{bare_roles.map{|
|
|
87
|
+
debug :instance, "Considering '#{clause.display}' with "+
|
|
88
|
+
(bare_roles.empty? ? "no bare roles" : "bare roles: #{bare_roles.map{|var_ref| var_ref.player.name}*", "}") do
|
|
91
89
|
|
|
92
|
-
# If all the roles are in place, we can bind the rest of this
|
|
93
|
-
return true if bare_roles.size == 0 && bind_complete_fact(
|
|
90
|
+
# If all the roles are in place, we can bind the rest of this clause:
|
|
91
|
+
return true if bare_roles.size == 0 && bind_complete_fact(clause)
|
|
94
92
|
|
|
95
93
|
progress = false
|
|
96
94
|
if bare_roles.size == 1 &&
|
|
97
|
-
(
|
|
98
|
-
(et =
|
|
99
|
-
if et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type ==
|
|
100
|
-
bind_entity_if_identifier_ready(
|
|
95
|
+
(variable = bare_roles[0].variable) &&
|
|
96
|
+
(et = variable.player).is_a?(ActiveFacts::Metamodel::EntityType)
|
|
97
|
+
if et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type == clause.fact_type} &&
|
|
98
|
+
bind_entity_if_identifier_ready(clause, et, variable)
|
|
101
99
|
progress = true
|
|
102
100
|
end
|
|
103
101
|
end
|
|
104
102
|
|
|
105
103
|
return true if progress
|
|
106
|
-
debug :instance, "Can't make progress on '#{
|
|
104
|
+
debug :instance, "Can't make progress on '#{clause.display}'"
|
|
107
105
|
nil
|
|
108
106
|
end
|
|
109
107
|
end
|
|
110
108
|
|
|
111
|
-
# Take one pass through the @
|
|
109
|
+
# Take one pass through the @unbound_clauses, processing (and removing) any that have all pre-requisites
|
|
112
110
|
def bind_more_facts
|
|
113
|
-
return false unless @
|
|
111
|
+
return false unless @unbound_clauses.size > 0
|
|
114
112
|
@pass += 1
|
|
115
113
|
|
|
116
114
|
progress = false
|
|
117
|
-
debug :instance, "Pass #{@pass} with #{@
|
|
118
|
-
@
|
|
119
|
-
@
|
|
120
|
-
action =
|
|
115
|
+
debug :instance, "Pass #{@pass} with #{@unbound_clauses.size} clauses to consider" do
|
|
116
|
+
@unbound_clauses =
|
|
117
|
+
@unbound_clauses.select do |clause|
|
|
118
|
+
action = bind_clause(clause)
|
|
121
119
|
progress = true if action
|
|
122
120
|
!action
|
|
123
121
|
end
|
|
124
|
-
debug :instance, "end of pass, unbound
|
|
122
|
+
debug :instance, "end of pass, unbound clauses are #{@unbound_clauses.map(&:display)*', '}"
|
|
125
123
|
end # debug
|
|
126
124
|
progress
|
|
127
125
|
end
|
|
128
126
|
|
|
129
|
-
# Occasionally we need to search through all the
|
|
130
|
-
def
|
|
131
|
-
@
|
|
132
|
-
[
|
|
127
|
+
# Occasionally we need to search through all the clauses:
|
|
128
|
+
def all_clauses
|
|
129
|
+
@clauses.map do |clause|
|
|
130
|
+
[clause] + clause.var_refs.map{|vr| vr.nested_clauses}
|
|
133
131
|
end.flatten.compact
|
|
134
132
|
end
|
|
135
133
|
|
|
136
|
-
def bind_complete_fact
|
|
137
|
-
return true unless
|
|
138
|
-
debug :instance, "All
|
|
139
|
-
instances =
|
|
140
|
-
debug :instance, "Instances are #{instances.map{|i| "#{i.
|
|
134
|
+
def bind_complete_fact clause
|
|
135
|
+
return true unless clause.fact_type # An bare objectification
|
|
136
|
+
debug :instance, "All variables in '#{clause.display}' contain instances; create the fact type"
|
|
137
|
+
instances = clause.var_refs.map{|vr| vr.variable.instance}
|
|
138
|
+
debug :instance, "Instances are #{instances.map{|i| "#{i.object_type.name} #{i.value.inspect}"}*", "}"
|
|
141
139
|
|
|
142
|
-
if e =
|
|
143
|
-
|
|
144
|
-
fact =
|
|
140
|
+
if e = clause.fact_type.entity_type and
|
|
141
|
+
clause.var_refs[0].variable.instance.object_type == e
|
|
142
|
+
fact = clause.var_refs[0].variable.instance.fact
|
|
145
143
|
else
|
|
146
144
|
# Check that this fact doesn't already exist
|
|
147
|
-
fact =
|
|
148
|
-
# Get the role values of this fact in the order of the
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
reading.reading.role_sequence.all_role_ref.detect{|rr| rr.role == rv.role}.ordinal
|
|
145
|
+
fact = clause.fact_type.all_fact.detect do |f|
|
|
146
|
+
# Get the role values of this fact in the order of the clause we just bound
|
|
147
|
+
role_values_in_clause_order = f.all_role_value.sort_by do |rv|
|
|
148
|
+
clause.reading.role_sequence.all_role_ref.detect{|rr| rr.role == rv.role}.ordinal
|
|
152
149
|
end
|
|
153
150
|
# If all this fact's role values are played by the bound instances, it's the same fact
|
|
154
|
-
!
|
|
151
|
+
!role_values_in_clause_order.zip(instances).detect{|rv, i| rv.instance != i }
|
|
155
152
|
end
|
|
156
153
|
end
|
|
157
154
|
if fact
|
|
158
|
-
|
|
155
|
+
clause.fact = fact
|
|
159
156
|
debug :instance, "Found existing fact type instance"
|
|
160
157
|
else
|
|
161
158
|
fact =
|
|
162
|
-
|
|
163
|
-
@constellation.Fact(:new, :fact_type =>
|
|
159
|
+
clause.fact =
|
|
160
|
+
@constellation.Fact(:new, :fact_type => clause.fact_type, :population => @population)
|
|
164
161
|
@bound_facts << fact
|
|
165
162
|
|
|
166
|
-
|
|
167
|
-
debug :instance, "New fact has #{instance.
|
|
163
|
+
clause.reading.role_sequence.all_role_ref_in_order.zip(instances).each do |rr, instance|
|
|
164
|
+
debug :instance, "New fact has #{instance.object_type.name} role #{instance.value.inspect}"
|
|
168
165
|
# REVISIT: Any residual adjectives after the fact type matching are lost here.
|
|
169
166
|
@constellation.RoleValue(:fact => fact, :instance => instance, :role => rr.role, :population => @population)
|
|
170
167
|
end
|
|
171
168
|
end
|
|
172
169
|
|
|
173
|
-
if !fact.instance &&
|
|
170
|
+
if !fact.instance && clause.fact_type.entity_type
|
|
174
171
|
# Objectified fact type; create the instance
|
|
175
|
-
# Create the instance that objectifies this fact. We don't have the
|
|
176
|
-
debug :instance, "Objectifying fact as #{
|
|
172
|
+
# Create the instance that objectifies this fact. We don't have the variable to assign it to though; that'll happen in our caller
|
|
173
|
+
debug :instance, "Objectifying fact as #{clause.fact_type.entity_type.name}"
|
|
177
174
|
instance =
|
|
178
|
-
@constellation.Instance(:new, :
|
|
175
|
+
@constellation.Instance(:new, :object_type => clause.fact_type.entity_type, :fact => fact, :population => @population)
|
|
179
176
|
@bound_facts << instance
|
|
180
177
|
end
|
|
181
178
|
|
|
182
|
-
if
|
|
183
|
-
|
|
184
|
-
instance =
|
|
185
|
-
instance.
|
|
186
|
-
|
|
179
|
+
if clause.fact and
|
|
180
|
+
clause.objectified_as and
|
|
181
|
+
instance = clause.fact.instance and
|
|
182
|
+
instance.object_type == clause.objectified_as.variable.player
|
|
183
|
+
clause.objectified_as.variable.instance = instance
|
|
187
184
|
end
|
|
188
185
|
|
|
189
186
|
true
|
|
@@ -192,21 +189,21 @@ module ActiveFacts
|
|
|
192
189
|
# If we have one bare role (no literal or instance) played by an entity type,
|
|
193
190
|
# and the bound fact type participates in the identifier, we might now be able
|
|
194
191
|
# to create the entity instance.
|
|
195
|
-
def bind_entity_if_identifier_ready
|
|
192
|
+
def bind_entity_if_identifier_ready clause, entity_type, variable
|
|
196
193
|
# Check this instance doesn't already exist already:
|
|
197
|
-
|
|
198
|
-
return false unless
|
|
199
|
-
identifying_instance =
|
|
194
|
+
identifying_variable = (clause.var_refs.map{|vr| vr.variable}-[variable])[0]
|
|
195
|
+
return false unless identifying_variable # This happens when we have a bare objectification
|
|
196
|
+
identifying_instance = identifying_variable.instance
|
|
200
197
|
preferred_identifier = entity_type.preferred_identifier
|
|
201
198
|
|
|
202
|
-
debug :instance, "This clause associates a new #{
|
|
199
|
+
debug :instance, "This clause associates a new #{variable.player.name} with a #{identifying_variable.player.name}#{identifying_instance ? " which exists" : ""}"
|
|
203
200
|
|
|
204
201
|
identifying_role_ref = preferred_identifier.role_sequence.all_role_ref.detect { |rr|
|
|
205
|
-
rr.role.fact_type ==
|
|
202
|
+
rr.role.fact_type == clause.fact_type && rr.role.object_type == identifying_variable.player
|
|
206
203
|
}
|
|
207
204
|
unless identifying_role_ref
|
|
208
|
-
# This shold never happen; we already bound all
|
|
209
|
-
debug :instance, "Failed to find a #{identifying_instance.
|
|
205
|
+
# This shold never happen; we already bound all var_refs
|
|
206
|
+
debug :instance, "Failed to find a #{identifying_instance.object_type.name}"
|
|
210
207
|
return false # We can't do this yet
|
|
211
208
|
end
|
|
212
209
|
role_value = identifying_instance.all_role_value.detect do |rv|
|
|
@@ -214,41 +211,41 @@ module ActiveFacts
|
|
|
214
211
|
end
|
|
215
212
|
if role_value
|
|
216
213
|
instance = (role_value.fact.all_role_value.to_a-[role_value])[0].instance
|
|
217
|
-
debug :instance, "Found an existing instance (of #{instance.
|
|
218
|
-
|
|
219
|
-
return true # Done with this
|
|
214
|
+
debug :instance, "Found an existing instance (of #{instance.object_type.name}) from a previous definition"
|
|
215
|
+
variable.instance = instance
|
|
216
|
+
return true # Done with this clause
|
|
220
217
|
end
|
|
221
218
|
|
|
222
219
|
pi_role_refs = preferred_identifier.role_sequence.all_role_ref
|
|
223
|
-
# For each pi role, we have to find the fact clause, which contains the
|
|
220
|
+
# For each pi role, we have to find the fact clause, which contains the variable we need.
|
|
224
221
|
# Then we have to create an instance of each fact
|
|
225
222
|
identifiers =
|
|
226
223
|
pi_role_refs.map do |rr|
|
|
227
|
-
# Find a
|
|
228
|
-
|
|
229
|
-
rr.role.fact_type ==
|
|
230
|
-
|
|
224
|
+
# Find a clause that provides the identifying_var_ref for this player:
|
|
225
|
+
identifying_clause = all_clauses.detect do |clause|
|
|
226
|
+
rr.role.fact_type == clause.fact_type &&
|
|
227
|
+
clause.var_refs.detect{|vr| vr.variable == variable}
|
|
231
228
|
end
|
|
232
|
-
return false unless
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
identifying_instance =
|
|
229
|
+
return false unless identifying_clause
|
|
230
|
+
identifying_var_ref = identifying_clause.var_refs.select{|var_ref| var_ref.variable != variable}[0]
|
|
231
|
+
identifying_variable = identifying_var_ref ? identifying_var_ref.variable : nil
|
|
232
|
+
identifying_instance = identifying_variable.instance
|
|
236
233
|
|
|
237
|
-
[rr,
|
|
234
|
+
[rr, identifying_clause, identifying_variable, identifying_instance]
|
|
238
235
|
end
|
|
239
236
|
if identifiers.detect{ |i| !i[3] } # Not all required facts are bound yet
|
|
240
|
-
debug :instance, "Can't go through with creating #{
|
|
237
|
+
debug :instance, "Can't go through with creating #{variable.player.name}; not all the identifying facts are in"
|
|
241
238
|
return false
|
|
242
239
|
end
|
|
243
240
|
|
|
244
|
-
debug :instance, "Going ahead with creating #{
|
|
245
|
-
instance = @constellation.Instance(:new, :
|
|
246
|
-
|
|
241
|
+
debug :instance, "Going ahead with creating #{variable.player.name} using #{identifiers.size} roles" do
|
|
242
|
+
instance = @constellation.Instance(:new, :object_type => entity_type, :population => @population)
|
|
243
|
+
variable.instance = instance
|
|
247
244
|
@bound_facts << instance
|
|
248
|
-
identifiers.each do |rr,
|
|
249
|
-
# This
|
|
245
|
+
identifiers.each do |rr, identifying_clause, identifying_variable, identifying_instance|
|
|
246
|
+
# This clause provides the identifying literal for the entity_type
|
|
250
247
|
id_fact =
|
|
251
|
-
|
|
248
|
+
identifying_clause.fact =
|
|
252
249
|
@constellation.Fact(:new, :fact_type => rr.role.fact_type, :population => @population)
|
|
253
250
|
@bound_facts << id_fact
|
|
254
251
|
role = (rr.role.fact_type.all_role.to_a-[rr.role])[0]
|
|
@@ -257,14 +254,14 @@ module ActiveFacts
|
|
|
257
254
|
end
|
|
258
255
|
end
|
|
259
256
|
|
|
260
|
-
true # Done with this
|
|
257
|
+
true # Done with this clause
|
|
261
258
|
end
|
|
262
259
|
|
|
263
|
-
def instance_identified_by_literal
|
|
264
|
-
if
|
|
265
|
-
entity_identified_by_literal
|
|
260
|
+
def instance_identified_by_literal object_type, literal
|
|
261
|
+
if object_type.is_a?(ActiveFacts::Metamodel::EntityType)
|
|
262
|
+
entity_identified_by_literal object_type, literal
|
|
266
263
|
else
|
|
267
|
-
debug :instance, "Making ValueType #{
|
|
264
|
+
debug :instance, "Making ValueType #{object_type.name} #{literal.inspect} #{@population.name.size>0 ? " in "+@population.name.inspect : ''}" do
|
|
268
265
|
|
|
269
266
|
is_a_string = String === literal
|
|
270
267
|
instance = @constellation.Instance.detect do |key, i|
|
|
@@ -274,14 +271,14 @@ module ActiveFacts
|
|
|
274
271
|
i.value.literal == literal &&
|
|
275
272
|
i.value.is_a_string == is_a_string
|
|
276
273
|
end
|
|
277
|
-
#instance =
|
|
274
|
+
#instance = object_type.all_instance.detect { |instance|
|
|
278
275
|
# instance.population == @population && instance.value == literal
|
|
279
276
|
#}
|
|
280
|
-
debug :instance, "This #{
|
|
277
|
+
debug :instance, "This #{object_type.name} value already exists" if instance
|
|
281
278
|
unless instance
|
|
282
279
|
instance = @constellation.Instance(
|
|
283
280
|
:new,
|
|
284
|
-
:
|
|
281
|
+
:object_type => object_type,
|
|
285
282
|
:population => @population,
|
|
286
283
|
:value => [literal.to_s, is_a_string, nil]
|
|
287
284
|
)
|
|
@@ -292,32 +289,32 @@ module ActiveFacts
|
|
|
292
289
|
end
|
|
293
290
|
end
|
|
294
291
|
|
|
295
|
-
def entity_identified_by_literal
|
|
292
|
+
def entity_identified_by_literal object_type, literal
|
|
296
293
|
# A literal that identifies an entity type means the entity type has only one identifying role
|
|
297
294
|
# That role is played either by a value type, or by another similarly single-identified entity type
|
|
298
|
-
debug "Making EntityType #{
|
|
299
|
-
identifying_role_refs =
|
|
300
|
-
raise "Single literal cannot satisfy multiple identifying roles for #{
|
|
295
|
+
debug "Making EntityType #{object_type.name} identified by '#{literal}' #{@population.name.size>0 ? " in "+@population.name.inspect : ''}" do
|
|
296
|
+
identifying_role_refs = object_type.preferred_identifier.role_sequence.all_role_ref
|
|
297
|
+
raise "Single literal cannot satisfy multiple identifying roles for #{object_type.name}" if identifying_role_refs.size > 1
|
|
301
298
|
role = identifying_role_refs.single.role
|
|
302
|
-
# This instance has no
|
|
303
|
-
identifying_instance = instance_identified_by_literal role.
|
|
299
|
+
# This instance has no variable; the variable is of the entity type not the identifying value type
|
|
300
|
+
identifying_instance = instance_identified_by_literal role.object_type, literal
|
|
304
301
|
existing_instance = nil
|
|
305
302
|
instance_rv = identifying_instance.all_role_value.detect { |rv|
|
|
306
303
|
next false unless rv.population == @population # Not this population
|
|
307
304
|
next false unless rv.fact.fact_type == role.fact_type # Not this fact type
|
|
308
305
|
other_role_value = (rv.fact.all_role_value-[rv])[0]
|
|
309
306
|
existing_instance = other_role_value.instance
|
|
310
|
-
other_role_value.instance.
|
|
307
|
+
other_role_value.instance.object_type == object_type # Is it this object_type?
|
|
311
308
|
}
|
|
312
309
|
if instance_rv
|
|
313
310
|
instance = existing_instance
|
|
314
|
-
debug :instance, "This #{
|
|
311
|
+
debug :instance, "This #{object_type.name} entity already exists"
|
|
315
312
|
else
|
|
316
|
-
# This fact has no
|
|
313
|
+
# This fact has no clause.
|
|
317
314
|
fact = @constellation.Fact(:new, :fact_type => role.fact_type, :population => @population)
|
|
318
315
|
@bound_facts << fact
|
|
319
|
-
# This instance will be associated with its
|
|
320
|
-
instance = @constellation.Instance(:new, :
|
|
316
|
+
# This instance will be associated with its variable by our caller
|
|
317
|
+
instance = @constellation.Instance(:new, :object_type => object_type, :population => @population)
|
|
321
318
|
@bound_facts << instance
|
|
322
319
|
# The identifying fact type has two roles; create both role instances:
|
|
323
320
|
@constellation.RoleValue(:instance => identifying_instance, :fact => fact, :population => @population, :role => role)
|
|
@@ -328,30 +325,30 @@ module ActiveFacts
|
|
|
328
325
|
end
|
|
329
326
|
|
|
330
327
|
def complain_incomplete
|
|
331
|
-
if @
|
|
332
|
-
# Provide a readable description of the problem here, by showing each
|
|
333
|
-
|
|
334
|
-
map do |
|
|
335
|
-
|
|
336
|
-
select do |
|
|
337
|
-
!
|
|
328
|
+
if @unbound_clauses.size > 0
|
|
329
|
+
# Provide a readable description of the problem here, by showing each variable with no instance
|
|
330
|
+
missing_variables = @unbound_clauses.
|
|
331
|
+
map do |clause|
|
|
332
|
+
clause.var_refs.
|
|
333
|
+
select do |var_refs|
|
|
334
|
+
!var_refs.variable.instance
|
|
338
335
|
end.
|
|
339
|
-
map do |
|
|
340
|
-
|
|
336
|
+
map do |var_ref|
|
|
337
|
+
var_ref.variable
|
|
341
338
|
end
|
|
342
339
|
end.
|
|
343
340
|
flatten.
|
|
344
341
|
uniq
|
|
345
342
|
|
|
346
343
|
raise "Not enough facts are given to identify #{
|
|
347
|
-
|
|
344
|
+
missing_variables.
|
|
348
345
|
sort_by{|b| b.key}.
|
|
349
346
|
map do |b|
|
|
350
347
|
player_identifier =
|
|
351
348
|
if b.player.is_a?(ActiveFacts::Metamodel::EntityType)
|
|
352
349
|
"lacking " +
|
|
353
350
|
b.player.preferred_identifier.role_sequence.all_role_ref.map do |rr|
|
|
354
|
-
[ rr.leading_adjective, rr.role.role_name || rr.role.
|
|
351
|
+
[ rr.leading_adjective, rr.role.role_name || rr.role.object_type.name, rr.trailing_adjective ].compact*" "
|
|
355
352
|
end*", "
|
|
356
353
|
else
|
|
357
354
|
"needs a value"
|
|
@@ -365,6 +362,10 @@ module ActiveFacts
|
|
|
365
362
|
end
|
|
366
363
|
end
|
|
367
364
|
|
|
365
|
+
def to_s
|
|
366
|
+
super+@clauses.map(&:to_s)*', '
|
|
367
|
+
end
|
|
368
|
+
|
|
368
369
|
end
|
|
369
370
|
end
|
|
370
371
|
end
|