activefacts 1.6.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,581 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler < ActiveFacts::CQL::Parser
4
- class Enforcement
5
- attr_reader :action, :agent
6
- def initialize action, agent
7
- @action = action
8
- @agent = agent
9
- end
10
-
11
- def compile constellation, constraint
12
- constellation.Enforcement(constraint, :enforcement_code => @action, :agent => @agent)
13
- end
14
- end
15
-
16
- class ContextNote
17
- attr_reader :context_kind, :discussion, :who, :agreed_date, :agreed_agents
18
-
19
- def initialize context_kind, discussion, who, agreed
20
- @context_kind, @discussion, @who, @agreed = context_kind, discussion, who, agreed
21
- @agreed_date, @agreed_agents = *agreed
22
- end
23
-
24
- def compile constellation, target
25
- context_note =
26
- constellation.ContextNote(
27
- :new,
28
- :context_note_kind => @context_kind,
29
- :discussion => @discussion
30
- )
31
- context_note.relevant_concept = target.concept
32
- if @agreed_date || @agreed_agents
33
- agreement = constellation.Agreement(context_note)
34
- agreement.date = @agreed_date if @agreed_date
35
- @agreed_agents.each do |agent|
36
- constellation.ContextAgreedBy(agreement, agent)
37
- end
38
- end
39
- if @who && @who.size > 0
40
- @who.each do |agent|
41
- constellation.ContextAccordingTo(context_note, agent)
42
- end
43
- end
44
- context_note
45
- end
46
- end
47
-
48
- class Constraint < Definition
49
- def initialize context_note, enforcement, clauses_lists = []
50
- if context_note.is_a?(Treetop::Runtime::SyntaxNode) && !context_note.empty?
51
- context_note = context_note.empty? ? nil : context_note.ast
52
- else
53
- context_note = nil # Perhaps a context note got attached to one of the clauses. Steal it.
54
- clauses_lists.detect do |clauses_list|
55
- if c = clauses_list.last.context_note
56
- context_note = c
57
- clauses_list.last.context_note = nil
58
- end
59
- end
60
- end
61
- @context_note = context_note
62
- @enforcement = enforcement
63
- @clauses_lists = clauses_lists
64
- end
65
-
66
- def compile
67
- @context_note.compile @constellation, @constraint if @context_note
68
- @constraint
69
- end
70
-
71
- def loose_binding
72
- # Override for constraint types that need loose binding (same role player matching with different adjectives)
73
- end
74
-
75
- def bind_clauses extra = []
76
- @context = CompilationContext.new(@vocabulary)
77
- @context.left_contraction_allowed = true
78
-
79
- @context.bind @clauses_lists, extra
80
- @clauses_lists.map do |clauses_list|
81
- @context.left_contractable_clause = nil # Don't contract outside this set of clauses
82
- clauses_list.each do |clause|
83
- fact_type = clause.match_existing_fact_type @context
84
- raise "Unrecognised fact type #{clause.inspect} in #{self.class}" unless fact_type
85
- raise "Negated fact type #{clause.inspect} in #{self.class} is not yet supported" if clause.certainty == false
86
- end
87
- end
88
-
89
- # Any constrained roles will be first identified here.
90
- # This means that they can't introduce role names.
91
- loose_binding
92
-
93
- # Ok, we have bound all players by subscript/role_name, by adjectives, and by loose binding,
94
- # and matched all the fact types that matter. Now assemble a query (with all steps) for
95
- # each query list, and build an array of the bindings that are involved in the steps.
96
- @bindings_by_list =
97
- @clauses_lists.map do |clauses_list|
98
- all_bindings_in_clauses(clauses_list)
99
- end
100
-
101
- warn_ignored_queries
102
- end
103
-
104
- def warn_ignored_queries
105
- # Warn about ignored queries
106
- @clauses_lists.each do |clauses_list|
107
- fact_types = clauses_list.map{|clauses| (rr = clauses.refs[0].role_ref) && rr.role.fact_type}.compact.uniq
108
- if fact_types.size > 1
109
- raise "------->>>> join ignored in #{self.class}: #{fact_types.map{|ft| ft.preferred_reading.expand}*' and '}"
110
- end
111
- end
112
- end
113
-
114
- def loose_bind_wherever_possible
115
- # Apply loose binding over applicable roles:
116
- trace :binding, "Loose binding on #{self.class.name}" do
117
- @clauses_lists.each do |clauses_list|
118
- clauses_list.each do |clause|
119
- clause.refs.each_with_index do |ref, i|
120
- next if ref.binding.refs.size > 1
121
- # if clause.side_effects && !clause.side_effects.role_side_effects[i].residual_adjectives
122
- # trace :binding, "Discounting #{ref.inspect} as needing loose binding because it has no residual_adjectives"
123
- # next
124
- # end
125
- # This ref didn't match any other ref. Have a scout around for a suitable partner
126
- candidates = @context.bindings.
127
- select do |key, binding|
128
- binding.player == ref.binding.player and
129
- binding != ref.binding and
130
- binding.role_name == ref.binding.role_name and # Both will be nil if they match
131
- # REVISIT: Don't bind to a binding with a role occurrence in the same clause
132
- !binding.refs.detect{|vr|
133
- x = vr.clause == clause
134
- # puts "Discounting binding #{binding.inspect} as a match for #{ref.inspect} because it's already bound to a player in #{ref.clause.inspect}" if x
135
- x
136
- }
137
- end.map{|k,b| b}
138
- next if candidates.size != 1 # Fail
139
- trace :binding, "Loose binding #{ref.inspect} to #{candidates[0].inspect}"
140
- ref.rebind_to(@context, candidates[0].refs[0])
141
- end
142
- end
143
- end
144
- end
145
- end
146
-
147
- def loose_bind
148
- # Apply loose binding over applicable @roles:
149
- trace :binding, "Check for loose bindings on #{@roles.size} roles in #{self.class.name}" do
150
- @roles.each do |ref|
151
- if ref.binding.refs.size < @clauses_lists.size+1
152
- trace :binding, "Insufficient bindings for #{ref.inspect} (#{ref.binding.refs.size}, expected #{@clauses_lists.size+1}), attempting loose binding" do
153
- @clauses_lists.each do |clauses_list|
154
- candidates = []
155
- next if clauses_list.
156
- detect do |clause|
157
- trace :binding, "Checking #{clause.inspect}"
158
- clause.refs.
159
- detect do |vr|
160
- already_bound = vr.binding == ref.binding
161
- if !already_bound && vr.player == ref.player
162
- candidates << vr
163
- end
164
- already_bound
165
- end
166
- end
167
- trace :binding, "Attempting loose binding for #{ref.inspect} in #{clauses_list.inspect}, from the following candidates: #{candidates.inspect}"
168
-
169
- if candidates.size == 1
170
- trace :binding, "Rebinding #{candidates[0].inspect} to #{ref.inspect}"
171
- candidates[0].rebind_to(@context, ref)
172
- end
173
- end
174
- end
175
- end
176
- end
177
- end
178
- end
179
-
180
- def common_bindings
181
- @common_bindings ||= @bindings_by_list[1..-1].inject(@bindings_by_list[0]) { |r, b| r & b }
182
- raise "#{self.class} must cover some of the same roles, see #{@bindings_by_list.inspect}" unless @common_bindings.size > 0
183
- @common_bindings
184
- end
185
-
186
- def to_s
187
- "#{self.class.name.sub(/.*::/,'')}" + (@clauses_lists.size > 0 ? " over #{@clauses_lists.inspect}" : '')
188
- end
189
- end
190
-
191
- class PresenceConstraint < Constraint
192
- def initialize context_note, enforcement, clauses_lists, refs, quantifier
193
- super context_note, enforcement, clauses_lists
194
- @refs = refs || []
195
- @quantifier = quantifier
196
- end
197
-
198
- def compile
199
- @clauses = @clauses_lists.map do |clauses_list|
200
- raise "REVISIT: join presence constraints not supported yet" if clauses_list.size > 1 or
201
- clauses_list.detect{|clause| clause.refs.detect{|vr| vr.nested_clauses } }
202
- clauses_list[0]
203
- end
204
-
205
- bind_clauses @refs
206
-
207
- if @refs.size > 0
208
- bind_constrained_roles
209
- else
210
- cb = common_bindings
211
- raise "Either/or must have only one duplicated role, not #{cb.inspect}" unless cb.size == 1
212
- @refs = cb[0].refs.reverse # REVISIT: Should have order these by clause, not like this
213
- end
214
-
215
- role_sequence = @constellation.RoleSequence(:new)
216
- @refs.each do |ref|
217
- raise "The constrained role #{ref.inspect} was not found in the invoked fact types" if ref.binding.refs.size == 1
218
- (ref.binding.refs-[ref]).each do |ref|
219
- role = (ref.role_ref && ref.role_ref.role) || ref.role
220
- raise "FactType role not found for #{ref.inspect}" unless role
221
- @constellation.RoleRef(role_sequence, role_sequence.all_role_ref.size, :role => role)
222
- end
223
- end
224
-
225
- @constraint =
226
- @constellation.PresenceConstraint(
227
- :new,
228
- :name => '',
229
- :vocabulary => @vocabulary,
230
- :role_sequence => role_sequence,
231
- :min_frequency => @quantifier.min,
232
- :max_frequency => @quantifier.max,
233
- :is_preferred_identifier => false,
234
- :is_mandatory => @quantifier.min && @quantifier.min > 0
235
- )
236
- if @quantifier.pragmas
237
- @quantifier.pragmas.each do |p|
238
- @constellation.ConceptAnnotation(:concept => @constraint.concept, :mapping_annotation => p)
239
- end
240
- end
241
- @enforcement.compile(@constellation, @constraint) if @enforcement
242
- trace :constraint, "Made new PC GUID=#{@constraint.concept.guid} min=#{@quantifier.min.inspect} max=#{@quantifier.max.inspect} over #{role_sequence.describe}"
243
- super
244
- end
245
-
246
- # In a PresenceConstraint, each role in "each XYZ" must occur in exactly one clauses_list
247
- def loose_binding
248
- # loose_bind_wherever_possible
249
- end
250
-
251
- def bind_constrained_roles
252
- @refs.each do |ref|
253
- if ref.binding.refs.size == 1
254
- # Apply loose binding over the constrained roles
255
- candidates =
256
- @clauses.map do |clause|
257
- clause.refs.select{ |vr| vr.player == ref.player }
258
- end.flatten
259
- if candidates.size == 1
260
- trace :binding, "Rebinding #{ref.inspect} to #{candidates[0].inspect} in presence constraint"
261
- ref.rebind_to(@context, candidates[0])
262
- end
263
- end
264
- end
265
- end
266
-
267
- def to_s
268
- "#{super} #{@quantifier.min}-#{@quantifier.max} over (#{@refs.map{|vr| vr.inspect}*', '})"
269
- end
270
- end
271
-
272
- class SetConstraint < Constraint
273
- def initialize context_note, enforcement, clauses_lists
274
- super context_note, enforcement, clauses_lists
275
- end
276
-
277
- def warn_ignored_queries
278
- # No warnings needed here any more
279
- end
280
-
281
- def role_sequences_for_common_bindings ignore_trailing_steps = false
282
- @clauses_lists.
283
- zip(@bindings_by_list).
284
- map do |clauses_list, bindings|
285
- # Does this clauses_list involve a query?
286
- if clauses_list.size > 1 or
287
- clauses_list.detect do |clause|
288
- clause.refs.detect{|ref| ref.nested_clauses } or
289
- clause.includes_literals
290
- end
291
-
292
- trace :query, "Building query for #{clauses_list.inspect}" do
293
- trace :query, "Constrained bindings are #{@common_bindings.inspect}"
294
- # Every Binding in these clauses becomes a Variable,
295
- # and every clause becomes a Step (and a RoleSequence).
296
- # The returned RoleSequences contains the RoleRefs for the common_bindings.
297
-
298
- # Create a query with a variable for every binding and all steps:
299
- query = build_variables(clauses_list)
300
- roles_by_binding = build_all_steps(clauses_list)
301
- query.validate
302
-
303
- # Create the projected RoleSequence for the constraint:
304
- role_sequence = @constellation.RoleSequence(:new)
305
- @common_bindings.each do |binding|
306
- role, play = *roles_by_binding[binding]
307
- @constellation.RoleRef(role_sequence, role_sequence.all_role_ref.size, :role => role, :play => play)
308
- end
309
-
310
- role_sequence
311
- end
312
- else
313
- # There's no query in this clauses_list, just create a role_sequence
314
- role_sequence = @constellation.RoleSequence(:new)
315
- query_bindings = bindings-@common_bindings
316
- unless query_bindings.empty? or ignore_trailing_steps && query_bindings.size <= 1
317
- trace :constraint, "REVISIT: #{self.class}: Ignoring query from #{@common_bindings.inspect} to #{query_bindings.inspect} in #{clauses_list.inspect}"
318
- end
319
- @common_bindings.each do |binding|
320
- roles = clauses_list.
321
- map do |clause|
322
- clause.refs.detect{|vr| vr.binding == binding }
323
- end.
324
- compact. # A query clause will probably not have the common binding
325
- map do |ref|
326
- ref.role_ref && ref.role_ref.role or ref.role
327
- end.
328
- compact
329
- # REVISIT: Should use clause side effects to preserve residual adjectives here.
330
- @constellation.RoleRef(role_sequence, role_sequence.all_role_ref.size, :role => roles[0])
331
- end
332
- role_sequence
333
- end
334
- end
335
- end
336
- end
337
-
338
- class SubsetConstraint < SetConstraint
339
- def initialize context_note, enforcement, clauses_lists
340
- super context_note, enforcement, clauses_lists
341
- @subset_clauses = @clauses_lists[0]
342
- @superset_clauses = @clauses_lists[1]
343
- end
344
-
345
- def compile
346
- bind_clauses
347
- common_bindings
348
-
349
- role_sequences =
350
- role_sequences_for_common_bindings
351
-
352
- @constraint =
353
- @constellation.SubsetConstraint(
354
- :new,
355
- :vocabulary => @vocabulary,
356
- :subset_role_sequence => role_sequences[0],
357
- :superset_role_sequence => role_sequences[1]
358
- )
359
- @enforcement.compile(@constellation, @constraint) if @enforcement
360
- super
361
- end
362
-
363
- def loose_binding
364
- loose_bind_wherever_possible
365
- end
366
- end
367
-
368
- class SetComparisonConstraint < SetConstraint
369
- def initialize context_note, enforcement, clauses_lists
370
- super context_note, enforcement, clauses_lists
371
- end
372
- end
373
-
374
- class SetExclusionConstraint < SetComparisonConstraint
375
- def initialize context_note, enforcement, clauses_lists, roles, quantifier
376
- super context_note, enforcement, clauses_lists
377
- @roles = roles || []
378
- @quantifier = quantifier
379
- end
380
-
381
- def compile
382
- bind_clauses @roles
383
- common_bindings
384
-
385
- role_sequences =
386
- role_sequences_for_common_bindings
387
-
388
- @constraint = @constellation.SetExclusionConstraint(
389
- :new,
390
- :vocabulary => @vocabulary,
391
- :is_mandatory => @quantifier.min == 1
392
- )
393
- if @quantifier.pragmas
394
- @quantifier.pragmas.each do |p|
395
- @constellation.ConceptAnnotation(:concept => @constraint.concept, :mapping_annotation => p)
396
- end
397
- end
398
- @enforcement.compile(@constellation, @constraint) if @enforcement
399
- role_sequences.each_with_index do |role_sequence, i|
400
- @constellation.SetComparisonRoles(@constraint, i, :role_sequence => role_sequence)
401
- end
402
- super
403
- end
404
-
405
- # In a SetExclusionConstraint, each role in "for each XYZ" must occur in each clauses_list
406
- def loose_binding
407
- if @roles.size == 0
408
- loose_bind_wherever_possible
409
- else
410
- loose_bind
411
- end
412
- end
413
-
414
- end
415
-
416
- class SetEqualityConstraint < SetComparisonConstraint
417
- def initialize context_note, enforcement, clauses_lists
418
- super context_note, enforcement, clauses_lists
419
- end
420
-
421
- def compile
422
- bind_clauses
423
- common_bindings
424
-
425
- role_sequences =
426
- role_sequences_for_common_bindings
427
-
428
- @constraint = @constellation.SetEqualityConstraint(
429
- :new,
430
- :vocabulary => @vocabulary
431
- )
432
- @enforcement.compile(@constellation, @constraint) if @enforcement
433
- role_sequences.each_with_index do |role_sequence, i|
434
- @constellation.SetComparisonRoles(@constraint, i, :role_sequence => role_sequence)
435
- end
436
- super
437
- end
438
-
439
- def loose_binding
440
- loose_bind_wherever_possible
441
- end
442
- end
443
-
444
- class RingConstraint < Constraint
445
- Types = %w{acyclic intransitive stronglyintransitive symmetric asymmetric transitive antisymmetric irreflexive reflexive}
446
- Pairs = {
447
- :stronglyintransitive => [:acyclic, :asymmetric, :symmetric],
448
- :intransitive => [:acyclic, :asymmetric, :symmetric],
449
- :transitive => [:acyclic],
450
- :acyclic => [:transitive],
451
- :irreflexive => [:symmetric]
452
- }
453
-
454
- def initialize role_sequence, qualifiers
455
- super nil, nil
456
- @role_sequence = role_sequence
457
- @rings, rest = qualifiers.partition{|q| Types.include?(q) }
458
- qualifiers.replace rest
459
- end
460
-
461
- def compile
462
- # Process the ring constraints:
463
- return if @rings.empty?
464
-
465
- role_refs = @role_sequence.all_role_ref_in_order.to_a
466
- supertypes_by_position = role_refs.
467
- map do |role_ref|
468
- role_ref.role.object_type.supertypes_transitive
469
- end
470
- role_pairs = []
471
- supertypes_by_position.each_with_index do |sts, i|
472
- (i+1...supertypes_by_position.size).each do |j|
473
- common_supertype = (sts & supertypes_by_position[j])[0]
474
- role_pairs << [role_refs[i], role_refs[j], common_supertype] if common_supertype
475
- end
476
- end
477
- if role_pairs.size > 1
478
- # REVISIT: Verbalise the role_refs better:
479
- raise "ambiguous #{@rings*' '} ring constraint, consider #{role_pairs.map{|rp| "#{rp[0].inspect}<->#{rp[1].inspect}"}*', '}"
480
- end
481
- if role_pairs.size == 0
482
- raise "No matching role pair found for #{@rings*' '} ring constraint over #{role_refs.map(&:role).map(&:object_type).map(&:name).inspect}"
483
- end
484
-
485
- rp = role_pairs[0]
486
-
487
- # Ensure that the keys in Pairs follow others:
488
- @rings = @rings.partition{|rc| !Pairs.keys.include?(rc.downcase.to_sym) }.flatten
489
-
490
- if @rings.size > 1 and !(p = Pairs[@rings[-1].to_sym]) and !p.include?(@rings[0].to_sym)
491
- raise "incompatible ring constraint types (#{@rings*", "})"
492
- end
493
- ring_type = @rings.map{|c| c.capitalize}*""
494
-
495
- @constraint = @constellation.RingConstraint(
496
- :new,
497
- :vocabulary => @vocabulary,
498
- # :name => name, # Create a name for Ring Constraints?
499
- :role => rp[0].role,
500
- :other_role => rp[1].role,
501
- :ring_type => ring_type
502
- )
503
-
504
- trace :constraint, "Added #{@constraint.verbalise}"
505
- super
506
- end
507
-
508
- def to_s
509
- "#{super} #{@rings*','} over #{@clauses_lists.inspect}"
510
- end
511
- end
512
-
513
- class ValueConstraint < Constraint
514
- def initialize ast, enforcement
515
- super nil, enforcement
516
- @value_ranges = ast[:ranges]
517
- @units = ast[:units]
518
- @regular_expression = ast[:regular_expression]
519
- end
520
-
521
- def assert_value(val)
522
- if val.is_a?(String)
523
- @constellation.Value(eval(val), true, nil)
524
- elsif val
525
- @constellation.Value(val.to_s, false , nil)
526
- else
527
- nil
528
- end
529
- end
530
-
531
- def compile
532
- @constraint = @constellation.ValueConstraint(:new)
533
- raise "Units on value constraints are not yet processed (at line #{'REVISIT'})" if @units
534
- # @string.line_of(node.interval.first)
535
-
536
- if @value_ranges
537
- @value_ranges.each do |range|
538
- min, max = Array === range ? range : [range, range]
539
- v_range = @constellation.ValueRange(
540
- min && @constellation.Bound(:value => assert_value(min), :is_inclusive => true),
541
- max && @constellation.Bound(:value => assert_value(max), :is_inclusive => true))
542
- ar = @constellation.AllowedRange(@constraint, v_range)
543
- end
544
- else
545
- @constraint.regular_expression = @regular_expression
546
- end
547
- @enforcement.compile(@constellation, @constraint) if @enforcement
548
- super
549
- end
550
-
551
- def vrto_s vr
552
- if Array === vr
553
- min = vr[0]
554
- max = vr[1]
555
- if Numeric === min or Numeric === max
556
- infinite = 1.0/0
557
- min ||= -infinite
558
- max ||= infinite
559
- else
560
- min ||= 'MIN'
561
- max ||= 'MAX'
562
- end
563
- Range.new(min, max)
564
- else
565
- vr
566
- end
567
- end
568
-
569
- def to_s
570
- "#{super} to " +
571
- (@value_ranges ?
572
- "(#{@value_ranges.map{|vr| vrto_s(vr) }.inspect })#{ @units ? " in #{@units.inspect}" : ''}" :
573
- @regular_expression
574
- )
575
- end
576
- end
577
-
578
- end
579
- end
580
- end
581
-