activefacts-cql 1.8.1 → 1.8.2
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 +4 -4
- data/.gitignore +1 -0
- data/Gemfile +6 -5
- data/activefacts-cql.gemspec +4 -3
- data/lib/activefacts/cql/compiler.rb +29 -22
- data/lib/activefacts/cql/compiler/clause.rb +86 -84
- data/lib/activefacts/cql/compiler/constraint.rb +53 -53
- data/lib/activefacts/cql/compiler/entity_type.rb +28 -28
- data/lib/activefacts/cql/compiler/expression.rb +27 -27
- data/lib/activefacts/cql/compiler/fact.rb +37 -37
- data/lib/activefacts/cql/compiler/fact_type.rb +91 -85
- data/lib/activefacts/cql/compiler/informal.rb +48 -0
- data/lib/activefacts/cql/compiler/query.rb +52 -52
- data/lib/activefacts/cql/compiler/shared.rb +17 -17
- data/lib/activefacts/cql/compiler/value_type.rb +11 -11
- data/lib/activefacts/cql/parser/CQLParser.treetop +76 -56
- data/lib/activefacts/cql/parser/Context.treetop +15 -17
- data/lib/activefacts/cql/parser/Expressions.treetop +21 -21
- data/lib/activefacts/cql/parser/FactTypes.treetop +216 -216
- data/lib/activefacts/cql/parser/Language/English.treetop +136 -131
- data/lib/activefacts/cql/parser/Language/French.treetop +118 -118
- data/lib/activefacts/cql/parser/Language/Mandarin.treetop +111 -111
- data/lib/activefacts/cql/parser/LexicalRules.treetop +45 -45
- data/lib/activefacts/cql/parser/ObjectTypes.treetop +120 -120
- data/lib/activefacts/cql/parser/Terms.treetop +63 -63
- data/lib/activefacts/cql/parser/ValueTypes.treetop +71 -71
- data/lib/activefacts/cql/require.rb +8 -8
- data/lib/activefacts/cql/verbaliser.rb +88 -88
- data/lib/activefacts/cql/version.rb +1 -1
- data/lib/activefacts/input/cql.rb +7 -7
- metadata +12 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc4fec528ea30db43664caba24b4eae5b394d59b
|
4
|
+
data.tar.gz: 670db8c27a33bf2a3777127fd3d41babd0641718
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d57cf6ed6d728b03c4f4b644e4a1866e313d53fef2315674be23f1f0695b7294b3ef388196c7bf95aca581a54b4da29b0ce65a79fe9944b17d128c0441e092d6
|
7
|
+
data.tar.gz: 46e7553490bd3bcaf73c65b5006d7c1f13e38fbaf46e41f4d1a32ce6afaa0066c9e15e723ea2a48f22af887fb562c4fb6e26a8a954c66f57e6d67a9669a3ced1
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -2,9 +2,10 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
this_file = File.absolute_path(__FILE__)
|
6
|
+
if this_file =~ %r{\A#{ENV['HOME']}}i
|
7
|
+
dir = File.dirname(File.dirname(this_file))
|
8
|
+
$stderr.puts "Using work area gems in #{dir} from activefacts-cql"
|
9
|
+
gem 'activefacts-api', path: dir+'/api'
|
10
|
+
gem 'activefacts-metamodel', path: dir+'/metamodel'
|
10
11
|
end
|
data/activefacts-cql.gemspec
CHANGED
@@ -18,12 +18,13 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.bindir = "exe"
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
|
+
spec.extensions << 'lib/activefacts/cql/Rakefile'
|
21
22
|
|
22
|
-
spec.add_development_dependency "bundler", ">= 1.10"
|
23
|
+
spec.add_development_dependency "bundler", ">= 1.10"
|
23
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
25
|
spec.add_development_dependency "rspec", "~> 3.3"
|
25
26
|
|
26
|
-
spec.add_runtime_dependency "activefacts-metamodel", "
|
27
|
-
spec.add_runtime_dependency
|
27
|
+
spec.add_runtime_dependency "activefacts-metamodel", "~> 1", ">= 1.9.5"
|
28
|
+
spec.add_runtime_dependency "treetop", [">= 1.4.14", "~> 1.4"]
|
28
29
|
end
|
29
30
|
|
@@ -13,6 +13,7 @@ require 'activefacts/cql/compiler/expression'
|
|
13
13
|
require 'activefacts/cql/compiler/fact'
|
14
14
|
require 'activefacts/cql/compiler/constraint'
|
15
15
|
require 'activefacts/cql/compiler/query'
|
16
|
+
require 'activefacts/cql/compiler/informal'
|
16
17
|
|
17
18
|
module ActiveFacts
|
18
19
|
module CQL
|
@@ -28,6 +29,7 @@ module ActiveFacts
|
|
28
29
|
@filename = a.shift || "stdio"
|
29
30
|
super *a
|
30
31
|
@constellation = ActiveFacts::API::Constellation.new(ActiveFacts::Metamodel)
|
32
|
+
@constellation.loggers << proc{|*k| trace :apilog, k.inspect} if trace(:apilog)
|
31
33
|
@language = nil
|
32
34
|
trace :file, "Parsing '#{@filename}'"
|
33
35
|
end
|
@@ -58,11 +60,11 @@ module ActiveFacts
|
|
58
60
|
|
59
61
|
# Mark any new Concepts as belonging to this topic
|
60
62
|
def topic_flood
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
@constellation.Concept.each do |key, concept|
|
64
|
+
next if concept.topic
|
65
|
+
trace :topic, "Colouring #{concept.describe} with #{@topic.topic_name}"
|
66
|
+
concept.topic = @topic
|
67
|
+
end
|
66
68
|
end
|
67
69
|
|
68
70
|
def compile input
|
@@ -74,7 +76,7 @@ module ActiveFacts
|
|
74
76
|
# parse_all returns an array of the block's non-nil return values.
|
75
77
|
ok = parse_all(@string, :definition) do |node|
|
76
78
|
trace :parse, "Parsed '#{node.text_value.gsub(/\s+/,' ').strip}'" do
|
77
|
-
|
79
|
+
trace :lex, (proc { node.inspect })
|
78
80
|
begin
|
79
81
|
ast = node.ast
|
80
82
|
next unless ast
|
@@ -84,14 +86,14 @@ module ActiveFacts
|
|
84
86
|
ast.vocabulary = @vocabulary
|
85
87
|
value = compile_definition ast
|
86
88
|
trace :definition, "Compiled to #{value.is_a?(Array) ? value.map{|v| v.verbalise}*', ' : value.verbalise}" if value
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
if value.is_a?(ActiveFacts::Metamodel::Topic)
|
90
|
+
topic_flood if @topic
|
91
|
+
@topic = value
|
92
|
+
elsif ast.is_a?(Compiler::Vocabulary)
|
93
|
+
topic_flood if @topic
|
94
|
+
@vocabulary = value
|
95
|
+
@topic = @constellation.Topic(@vocabulary.name)
|
96
|
+
end
|
95
97
|
rescue => e
|
96
98
|
# Augment the exception message, but preserve the backtrace
|
97
99
|
start_line = @string.line_of(node.interval.first)
|
@@ -102,7 +104,7 @@ module ActiveFacts
|
|
102
104
|
raise ne
|
103
105
|
end
|
104
106
|
end
|
105
|
-
|
107
|
+
topic_flood if @topic
|
106
108
|
end
|
107
109
|
raise failure_reason unless ok
|
108
110
|
vocabulary
|
@@ -115,16 +117,16 @@ module ActiveFacts
|
|
115
117
|
saved_input_length = @input_length
|
116
118
|
saved_topic = @topic
|
117
119
|
old_filename = @filename
|
118
|
-
@filename =
|
120
|
+
@filename = import_filename(old_filename, file)
|
119
121
|
|
120
122
|
# REVISIT: Save and use another @vocabulary for this file?
|
121
123
|
File.open(@filename) do |f|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
topic_flood if @topic
|
125
|
+
@topic = @constellation.Topic(File.basename(@filename, '.cql'))
|
126
|
+
trace :import, "Importing #{@filename} as #{@topic.topic_name}" do
|
127
|
+
ok = parse_all(f.read, nil, &@block)
|
128
|
+
end
|
129
|
+
@topic = saved_topic
|
128
130
|
end
|
129
131
|
|
130
132
|
rescue => e
|
@@ -140,6 +142,11 @@ module ActiveFacts
|
|
140
142
|
nil
|
141
143
|
end
|
142
144
|
|
145
|
+
# import_filename may be redefined in subclass
|
146
|
+
def import_filename(old_filename, file)
|
147
|
+
File.dirname(old_filename)+'/'+file+'.cql'
|
148
|
+
end
|
149
|
+
|
143
150
|
def compile_definition ast
|
144
151
|
ast.compile
|
145
152
|
end
|
@@ -52,34 +52,34 @@ module ActiveFacts
|
|
52
52
|
# else 'definitely '
|
53
53
|
end
|
54
54
|
}#{
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
55
|
+
(
|
56
|
+
phrases.map do |phrase|
|
57
|
+
case phrase
|
58
|
+
when String
|
59
|
+
'"' + phrase.to_s + '"'
|
60
|
+
when Reference
|
61
|
+
phrase.to_s +
|
62
|
+
if phrase.nested_clauses
|
63
|
+
' (in which ' +
|
64
|
+
phrase.nested_clauses.map do |c|
|
65
|
+
((j = c.conjunction) ? j+' ' : '') +
|
66
|
+
c.to_s
|
67
|
+
end*' ' +
|
68
|
+
')'
|
69
|
+
else
|
70
|
+
''
|
71
|
+
end
|
72
|
+
when Operation
|
73
|
+
phrase.inspect
|
74
|
+
when Literal
|
75
|
+
phrase.inspect
|
76
|
+
#when FunctionCallChain # REVISIT: Add something here when I re-add functions
|
77
|
+
# phrase.inspect
|
78
|
+
else
|
79
|
+
raise "Unexpected phrase type in clause: #{phrase.class}"
|
80
|
+
end
|
81
|
+
end * ' '
|
82
|
+
).gsub(/" "/, ' ')
|
83
83
|
}#{
|
84
84
|
@context_note && ' ' + @context_note.inspect
|
85
85
|
}"
|
@@ -121,8 +121,8 @@ module ActiveFacts
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
-
|
125
|
-
|
124
|
+
# This method is used in matching unary fact types in entity identification
|
125
|
+
# It disregards literals, which are not allowed in this context.
|
126
126
|
def phrases_match(phrases)
|
127
127
|
@phrases.zip(phrases).each do |mine, theirs|
|
128
128
|
return false if mine.is_a?(Reference) != theirs.is_a?(Reference)
|
@@ -145,20 +145,20 @@ module ActiveFacts
|
|
145
145
|
raise "Cannot match a clause that contains no object types" if refs.size == 0
|
146
146
|
raise "Internal error, clause already matched, should not match again" if @fact_type
|
147
147
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
148
|
+
if is_naked_object_type
|
149
|
+
ref = refs[0] # "There can be only one"
|
150
|
+
return true unless ref.nested_clauses
|
151
|
+
ref.nested_clauses.each do |nested|
|
152
|
+
ft = nested.match_existing_fact_type(context)
|
153
|
+
raise "Unrecognised fact type #{nested.display} nested under #{inspect}" unless ft
|
154
|
+
if (ft.entity_type == ref.player)
|
155
|
+
ref.objectification_of = ft
|
156
|
+
nested.objectified_as = ref
|
157
|
+
end
|
158
|
+
end
|
159
|
+
raise "#{ref.inspect} contains objectification steps that do not objectify it" unless ref.objectification_of
|
160
|
+
return true
|
161
|
+
end
|
162
162
|
|
163
163
|
# If we fail to match, try a left contraction (or save this for a subsequent left contraction):
|
164
164
|
left_contract_this_onto = context.left_contractable_clause
|
@@ -267,9 +267,9 @@ module ActiveFacts
|
|
267
267
|
next if role.fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
268
268
|
next if role.fact_type.all_role.size != players.size # Wrong number of players
|
269
269
|
|
270
|
-
|
271
|
-
|
272
|
-
|
270
|
+
compatible_readings = role.fact_type.compatible_readings(player_related_types)
|
271
|
+
next unless compatible_readings.size > 0
|
272
|
+
trace :matching_fails, "These readings are compatible: #{compatible_readings.map(&:expand).inspect}"
|
273
273
|
true
|
274
274
|
end.
|
275
275
|
map{ |role| role.fact_type}
|
@@ -437,13 +437,13 @@ module ActiveFacts
|
|
437
437
|
if la = role_ref.leading_adjective and !la.empty?
|
438
438
|
# The leading adjectives must match, one way or another
|
439
439
|
la = la.split(/\s+/)
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
440
|
+
if (la[0, intervening_words.size] == intervening_words) # Exact match
|
441
|
+
iw = intervening_words
|
442
|
+
else
|
443
|
+
# We may have hyphenated adjectives. Break them up to check:
|
444
|
+
iw = intervening_words.map{|w| w.split(/-/)}.flatten
|
445
|
+
return nil unless la[0,iw.size] == iw
|
446
|
+
end
|
447
447
|
|
448
448
|
# Any intervening_words matched, see what remains
|
449
449
|
la.slice!(0, iw.size)
|
@@ -933,7 +933,9 @@ module ActiveFacts
|
|
933
933
|
def identify_player context
|
934
934
|
@player || begin
|
935
935
|
@player = context.object_type @term
|
936
|
-
|
936
|
+
unless @player
|
937
|
+
raise "ObjectType #{@term} unrecognised"
|
938
|
+
end
|
937
939
|
context.player_by_role_name[@role_name] = player if @role_name
|
938
940
|
@player
|
939
941
|
end
|
@@ -953,8 +955,8 @@ module ActiveFacts
|
|
953
955
|
t = @trailing_adjective
|
954
956
|
key = [!l || l.empty? ? nil : l, @term, !t || t.empty? ? nil : t]
|
955
957
|
end
|
956
|
-
|
957
|
-
|
958
|
+
key += [:literal, literal.literal] if @literal
|
959
|
+
key
|
958
960
|
end
|
959
961
|
|
960
962
|
def bind context
|
@@ -972,27 +974,27 @@ module ActiveFacts
|
|
972
974
|
role_name = @term
|
973
975
|
end
|
974
976
|
end
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
977
|
+
k = key
|
978
|
+
@binding = context.bindings[k]
|
979
|
+
if !@binding
|
980
|
+
if !literal
|
981
|
+
# Find a binding that has a literal, and bind to it if it's the only one
|
982
|
+
candidates = context.bindings.map do |binding_key, binding|
|
983
|
+
binding_key[0...k.size] == k &&
|
984
|
+
binding_key[-2] == :literal ? binding : nil
|
985
|
+
end.compact
|
986
|
+
raise "Uncertain binding reference for #{to_s}, could be any of #{candidates.inspect}" if candidates.size > 1
|
987
|
+
@binding = candidates[0]
|
988
|
+
else
|
989
|
+
# New binding has a literal, look for one without:
|
990
|
+
@binding = context.bindings[k[0...-2]]
|
991
|
+
end
|
992
|
+
end
|
993
|
+
|
994
|
+
if !@binding
|
995
|
+
@binding = Binding.new(@player, role_name)
|
996
|
+
context.bindings[k] = @binding
|
997
|
+
end
|
996
998
|
@binding.add_ref self
|
997
999
|
@binding
|
998
1000
|
end
|
@@ -1079,11 +1081,11 @@ module ActiveFacts
|
|
1079
1081
|
:max_frequency => @quantifier.max,
|
1080
1082
|
:min_frequency => @quantifier.min
|
1081
1083
|
)
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1084
|
+
if @quantifier.pragmas
|
1085
|
+
@quantifier.pragmas.each do |p|
|
1086
|
+
constellation.ConceptAnnotation(:concept => constraint.concept, :mapping_annotation => p)
|
1087
|
+
end
|
1088
|
+
end
|
1087
1089
|
trace :constraint, "Made new embedded PC GUID=#{constraint.concept.guid} min=#{@quantifier.min.inspect} max=#{@quantifier.max.inspect} over #{(e = fact_type.entity_type) ? e.name : role_sequence.describe} in #{fact_type.describe}"
|
1088
1090
|
@quantifier.enforcement.compile(constellation, constraint) if @quantifier.enforcement
|
1089
1091
|
@embedded_presence_constraint = constraint
|
@@ -1110,7 +1112,7 @@ module ActiveFacts
|
|
1110
1112
|
@max = max
|
1111
1113
|
@enforcement = enforcement
|
1112
1114
|
@context_note = context_note
|
1113
|
-
|
1115
|
+
@pragmas = pragmas
|
1114
1116
|
end
|
1115
1117
|
|
1116
1118
|
def is_unique
|
@@ -14,10 +14,10 @@ module ActiveFacts
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class ContextNote
|
17
|
-
attr_reader :context_kind, :
|
17
|
+
attr_reader :context_kind, :description, :who, :agreed_date, :agreed_agents
|
18
18
|
|
19
|
-
def initialize context_kind,
|
20
|
-
@context_kind, @
|
19
|
+
def initialize context_kind, description, who, agreed
|
20
|
+
@context_kind, @description, @who, @agreed = context_kind, description, who, agreed
|
21
21
|
@agreed_date, @agreed_agents = *agreed
|
22
22
|
end
|
23
23
|
|
@@ -26,7 +26,7 @@ module ActiveFacts
|
|
26
26
|
constellation.ContextNote(
|
27
27
|
:new,
|
28
28
|
:context_note_kind => @context_kind,
|
29
|
-
:
|
29
|
+
:description => @description
|
30
30
|
)
|
31
31
|
context_note.relevant_concept = target.concept
|
32
32
|
if @agreed_date || @agreed_agents
|
@@ -49,14 +49,14 @@ module ActiveFacts
|
|
49
49
|
def initialize context_note, enforcement, clauses_lists = []
|
50
50
|
if context_note.is_a?(Treetop::Runtime::SyntaxNode) && !context_note.empty?
|
51
51
|
context_note = context_note.empty? ? nil : context_note.ast
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
60
|
end
|
61
61
|
@context_note = context_note
|
62
62
|
@enforcement = enforcement
|
@@ -233,13 +233,13 @@ module ActiveFacts
|
|
233
233
|
:is_preferred_identifier => false,
|
234
234
|
:is_mandatory => @quantifier.min && @quantifier.min > 0
|
235
235
|
)
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
236
|
+
if @quantifier.pragmas
|
237
|
+
@quantifier.pragmas.each do |p|
|
238
|
+
@constellation.ConceptAnnotation(:concept => @constraint.concept, :mapping_annotation => p)
|
239
|
+
end
|
240
|
+
end
|
241
241
|
@enforcement.compile(@constellation, @constraint) if @enforcement
|
242
|
-
|
242
|
+
trace :constraint, "Made new PC GUID=#{@constraint.concept.guid} min=#{@quantifier.min.inspect} max=#{@quantifier.max.inspect} over #{role_sequence.describe}"
|
243
243
|
super
|
244
244
|
end
|
245
245
|
|
@@ -285,9 +285,9 @@ module ActiveFacts
|
|
285
285
|
# Does this clauses_list involve a query?
|
286
286
|
if clauses_list.size > 1 or
|
287
287
|
clauses_list.detect do |clause|
|
288
|
-
|
289
|
-
|
290
|
-
|
288
|
+
clause.refs.detect{|ref| ref.nested_clauses } or
|
289
|
+
clause.includes_literals
|
290
|
+
end
|
291
291
|
|
292
292
|
trace :query, "Building query for #{clauses_list.inspect}" do
|
293
293
|
trace :query, "Constrained bindings are #{@common_bindings.inspect}"
|
@@ -390,11 +390,11 @@ module ActiveFacts
|
|
390
390
|
:vocabulary => @vocabulary,
|
391
391
|
:is_mandatory => @quantifier.min == 1
|
392
392
|
)
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
393
|
+
if @quantifier.pragmas
|
394
|
+
@quantifier.pragmas.each do |p|
|
395
|
+
@constellation.ConceptAnnotation(:concept => @constraint.concept, :mapping_annotation => p)
|
396
|
+
end
|
397
|
+
end
|
398
398
|
@enforcement.compile(@constellation, @constraint) if @enforcement
|
399
399
|
role_sequences.each_with_index do |role_sequence, i|
|
400
400
|
@constellation.SetComparisonRoles(@constraint, i, :role_sequence => role_sequence)
|
@@ -518,35 +518,35 @@ module ActiveFacts
|
|
518
518
|
@regular_expression = ast[:regular_expression]
|
519
519
|
end
|
520
520
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
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
530
|
|
531
531
|
def compile
|
532
532
|
@constraint = @constellation.ValueConstraint(:new)
|
533
533
|
raise "Units on value constraints are not yet processed (at line #{'REVISIT'})" if @units
|
534
534
|
# @string.line_of(node.interval.first)
|
535
535
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
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
550
|
|
551
551
|
def vrto_s vr
|
552
552
|
if Array === vr
|
@@ -568,10 +568,10 @@ module ActiveFacts
|
|
568
568
|
|
569
569
|
def to_s
|
570
570
|
"#{super} to " +
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
571
|
+
(@value_ranges ?
|
572
|
+
"(#{@value_ranges.map{|vr| vrto_s(vr) }.inspect })#{ @units ? " in #{@units.inspect}" : ''}" :
|
573
|
+
@regular_expression
|
574
|
+
)
|
575
575
|
end
|
576
576
|
end
|
577
577
|
|