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