activefacts 0.8.5 → 0.8.6
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/lib/activefacts/cql/CQLParser.treetop +20 -11
- data/lib/activefacts/cql/Concepts.treetop +10 -2
- data/lib/activefacts/cql/Context.treetop +2 -2
- data/lib/activefacts/cql/FactTypes.treetop +10 -4
- data/lib/activefacts/cql/Language/English.treetop +12 -6
- data/lib/activefacts/cql/ValueTypes.treetop +4 -3
- data/lib/activefacts/cql/compiler.rb +26 -19
- data/lib/activefacts/cql/parser.rb +8 -0
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/metamodel.rb +19 -19
- data/spec/absorption_ruby_spec.rb +1 -1
- data/spec/cql/context_spec.rb +10 -10
- data/spec/cql/unit_spec.rb +8 -10
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/norma_tables_spec.rb +1 -1
- metadata +3 -3
@@ -75,30 +75,39 @@ module ActiveFacts
|
|
75
75
|
# REVISIT: / value_constraint
|
76
76
|
end
|
77
77
|
|
78
|
+
rule enforcement
|
79
|
+
s '(' s otherwise s action s agent? s ')' s
|
80
|
+
{ def value; [action.text_value, agent.empty? ? nil : agent.text_value]; end }
|
81
|
+
/
|
82
|
+
''
|
83
|
+
{ def value; []; end }
|
84
|
+
end
|
85
|
+
|
78
86
|
# presence constraint:
|
79
87
|
rule presence_constraint
|
80
|
-
s 'each' s ('combination' S)? role_list s 'occurs' s quantifier s 'time' s 'in' s
|
88
|
+
s 'each' s ('combination' S)? role_list s 'occurs' s quantifier s 'time' s enforcement 'in' s
|
81
89
|
readings_list s
|
82
90
|
c:context? ';' s
|
83
|
-
{ def value; [ nil, [ :constraint, :presence, role_list.roles, quantifier.value, readings_list.value, c.empty? ? nil : c.value ] ]; end }
|
91
|
+
{ def value; [ nil, [ :constraint, :presence, role_list.roles, quantifier.value, readings_list.value, c.empty? ? nil : c.value, enforcement.value ] ]; end }
|
84
92
|
end
|
85
93
|
|
86
94
|
# set (exclusion, mandatory exclusion, complex equality) constraint
|
87
95
|
rule set_constraint
|
88
|
-
s 'for' s 'each' s role_list s quantifier s 'of' s 'these' s 'holds' s ':' s
|
96
|
+
s 'for' s 'each' s role_list s quantifier s 'of' s 'these' s 'holds' s enforcement ':' s
|
89
97
|
readings_list s
|
90
98
|
c:context? ';' s
|
91
|
-
{ def value; [ nil, [ :constraint, :set, role_list.roles, quantifier.value, readings_list.value, c.empty? ? nil : c.value
|
99
|
+
{ def value; [ nil, [ :constraint, :set, role_list.roles, quantifier.value, readings_list.value, c.empty? ? nil : c.value, enforcement.value ] ]; end }
|
92
100
|
/
|
93
|
-
s either? s r1:readings s or s r2:readings exclusion:(but s not s both s)? c:context? ';' s
|
101
|
+
s either? s r1:readings s or s r2:readings exclusion:(but s not s both s)? c:context? enforcement ';' s
|
94
102
|
{ def value;
|
95
103
|
[ nil, [ :constraint, :set,
|
96
104
|
nil, # No roles names, rely on the join
|
97
105
|
exclusion.text_value.empty? ?
|
98
|
-
[1, nil] :
|
106
|
+
[1, nil] : # At least one (meaning 1 or 2/more)
|
99
107
|
[1,1], # Exactly one (1 and only 1)
|
100
108
|
[r1.value, r2.value],
|
101
|
-
c.empty? ? nil : c.value
|
109
|
+
c.empty? ? nil : c.value,
|
110
|
+
enforcement.value
|
102
111
|
] ];
|
103
112
|
end
|
104
113
|
}
|
@@ -106,14 +115,14 @@ module ActiveFacts
|
|
106
115
|
|
107
116
|
rule subset_constraint
|
108
117
|
s readings s only s if s r2:readings s
|
109
|
-
c:context? ';' s
|
110
|
-
{ def value; [ nil, [ :constraint, :subset, [readings.value, r2.value], c.empty? ? nil : c.value ] ]; end }
|
118
|
+
c:context? enforcement ';' s
|
119
|
+
{ def value; [ nil, [ :constraint, :subset, [readings.value, r2.value], c.empty? ? nil : c.value, enforcement.value ] ]; end }
|
111
120
|
end
|
112
121
|
|
113
122
|
rule equality_constraint
|
114
123
|
s readings s tail:( if s and s only s if s readings s)+
|
115
|
-
c:context? ';' s
|
116
|
-
{ def value; [ nil, [ :constraint, :equality, [readings.value] + tail.elements.map{|e| e.readings.value }, c.empty? ? nil : c.value ]]; end }
|
124
|
+
c:context? enforcement ';' s
|
125
|
+
{ def value; [ nil, [ :constraint, :equality, [readings.value] + tail.elements.map{|e| e.readings.value }, c.empty? ? nil : c.value, enforcement.value ]]; end }
|
117
126
|
end
|
118
127
|
|
119
128
|
rule readings_list
|
@@ -69,8 +69,16 @@ module ActiveFacts
|
|
69
69
|
|
70
70
|
rule identification
|
71
71
|
# REVISIT: Consider distinguishing "-Id" from just "Id", and not prepending the entity type name if no "-"
|
72
|
-
identified_by its s id value_type_parameters
|
73
|
-
|
72
|
+
identified_by its s id value_type_parameters
|
73
|
+
r:(restriction enforcement)? # Reference Mode; restriction may be needed for the ValueType
|
74
|
+
{ def value
|
75
|
+
{ :mode => id.value,
|
76
|
+
:restriction => (r.text_value.empty? ? nil : r.restriction.ranges),
|
77
|
+
:enforcement => (r.text_value.empty? ? nil : r.enforcement.value),
|
78
|
+
:parameters => value_type_parameters.values
|
79
|
+
}
|
80
|
+
end
|
81
|
+
}
|
74
82
|
/
|
75
83
|
identified_by role_list
|
76
84
|
{ def value; {:roles => role_list.roles }; end }
|
@@ -123,18 +123,21 @@ module ActiveFacts
|
|
123
123
|
# When we have an expression, we will come down here perhaps multiple times,
|
124
124
|
# but find no way out as soon as we hit the trailing non_role.
|
125
125
|
rule role
|
126
|
-
q:quantifier?
|
126
|
+
q:(quantifier enforcement)?
|
127
127
|
adj0:(a:role_word '-' s)?
|
128
128
|
player:role_word !'-' s?
|
129
129
|
adj1:( '-' a:(a:role_word s)? )?
|
130
130
|
func:function_call?
|
131
131
|
role_id:(role_name / subscript )?
|
132
|
-
lr:( literal / restriction )?
|
132
|
+
lr:( literal / restriction enforcement )?
|
133
133
|
!non_role
|
134
134
|
{
|
135
135
|
def value
|
136
136
|
r = {}
|
137
|
-
|
137
|
+
if !q.empty?
|
138
|
+
quantifier = q.quantifier.value # "some" quantifier has nil value
|
139
|
+
r[:quantifier_restriction] = q.enforcement.value
|
140
|
+
end
|
138
141
|
|
139
142
|
r[:quantifier] = quantifier if quantifier
|
140
143
|
r[:leading_adjective] = adj0.a.value unless adj0.empty?
|
@@ -144,7 +147,10 @@ module ActiveFacts
|
|
144
147
|
r[:trailing_adjective] = adj1.a.a.value unless adj1.empty?
|
145
148
|
r[:function] = func.value if !func.empty?
|
146
149
|
r[:role_name] = role_id.value unless role_id.empty?
|
147
|
-
|
150
|
+
if !lr.empty? && lr.respond_to?(:restriction)
|
151
|
+
r[:restriction] = lr.restriction.ranges
|
152
|
+
r[:restriction_enforcement] = lr.enforcement.value
|
153
|
+
end
|
148
154
|
r[:literal] = lr.value if !lr.empty? && lr.respond_to?(:value)
|
149
155
|
|
150
156
|
r
|
@@ -68,8 +68,8 @@ module ActiveFacts
|
|
68
68
|
end
|
69
69
|
|
70
70
|
rule as_agreed_by
|
71
|
-
s as s 'agreed' s d:('on' S date)? by s
|
72
|
-
{ def value; [ d.empty? ? nil : d.date.value,
|
71
|
+
s as s 'agreed' s d:('on' S date)? by s agents
|
72
|
+
{ def value; [ d.empty? ? nil : d.date.value, agents.value ]; end }
|
73
73
|
end
|
74
74
|
|
75
75
|
rule date
|
@@ -77,15 +77,20 @@ module ActiveFacts
|
|
77
77
|
{ def value; d.text_value.strip; end }
|
78
78
|
end
|
79
79
|
|
80
|
-
rule
|
81
|
-
s h:
|
82
|
-
{ def value; [h.text_value] + t.elements.map{|e| e.
|
80
|
+
rule agents
|
81
|
+
s h:agent s t:(',' s !context_type agent s)*
|
82
|
+
{ def value; [h.text_value] + t.elements.map{|e| e.agent.text_value }; end }
|
83
83
|
end
|
84
84
|
|
85
|
-
rule
|
85
|
+
rule agent
|
86
86
|
id (s id)*
|
87
87
|
end
|
88
88
|
|
89
|
+
# An enforcement action, like SMS, email, log, alarm, etc.
|
90
|
+
rule action
|
91
|
+
id
|
92
|
+
end
|
93
|
+
|
89
94
|
rule acyclic 'acyclic' !alphanumeric end
|
90
95
|
rule alias 'alias' !alphanumeric end
|
91
96
|
rule all 'all' !alphanumeric end
|
@@ -126,6 +131,7 @@ module ActiveFacts
|
|
126
131
|
rule one 'one' !alphanumeric end
|
127
132
|
rule only 'only' !alphanumeric end
|
128
133
|
rule or 'or' !alphanumeric end
|
134
|
+
rule otherwise 'otherwise' !alphanumeric end
|
129
135
|
rule partitioned 'partitioned' !alphanumeric end
|
130
136
|
rule personal 'personal' !alphanumeric end
|
131
137
|
rule restricted 'restricted' !alphanumeric end
|
@@ -14,7 +14,7 @@ module ActiveFacts
|
|
14
14
|
base:id s
|
15
15
|
value_type_parameters
|
16
16
|
units
|
17
|
-
r:restriction?
|
17
|
+
r:(restriction enforcement)?
|
18
18
|
mapping_pragmas
|
19
19
|
s ';' s
|
20
20
|
{
|
@@ -24,8 +24,9 @@ module ActiveFacts
|
|
24
24
|
base.value,
|
25
25
|
value_type_parameters.values,
|
26
26
|
units.value,
|
27
|
-
(!r.empty? ? r.ranges : []),
|
28
|
-
mapping_pragmas.value
|
27
|
+
(!r.empty? ? r.restriction.ranges : []),
|
28
|
+
mapping_pragmas.value,
|
29
|
+
(!r.empty? ? r.enforcement.value : nil)
|
29
30
|
]
|
30
31
|
end
|
31
32
|
|
@@ -69,7 +69,7 @@ module ActiveFacts
|
|
69
69
|
end
|
70
70
|
|
71
71
|
private
|
72
|
-
def value_type(name, base_type_name, parameters, unit, ranges, mapping_pragmas)
|
72
|
+
def value_type(name, base_type_name, parameters, unit, ranges, mapping_pragmas, enforcement)
|
73
73
|
length, scale = *parameters
|
74
74
|
|
75
75
|
# Create the base type:
|
@@ -91,11 +91,11 @@ module ActiveFacts
|
|
91
91
|
# REVISIT: Find and apply the units
|
92
92
|
|
93
93
|
if ranges.size != 0
|
94
|
-
vt.value_restriction = value_restriction
|
94
|
+
vt.value_restriction = value_restriction(ranges, enforcement)
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
def value_restriction(ranges)
|
98
|
+
def value_restriction(ranges, enforcement)
|
99
99
|
vr = @constellation.ValueRestriction(:new)
|
100
100
|
ranges.each do |range|
|
101
101
|
min, max = Array === range ? range : [range, range]
|
@@ -105,9 +105,15 @@ module ActiveFacts
|
|
105
105
|
)
|
106
106
|
ar = @constellation.AllowedRange(vr, v_range)
|
107
107
|
end
|
108
|
+
apply_enforcement(vr, enforcement) if enforcement
|
108
109
|
vr
|
109
110
|
end
|
110
111
|
|
112
|
+
def apply_enforcement(constraint, enforcement)
|
113
|
+
constraint.enforcement = enforcement[0]
|
114
|
+
constraint.enforcement.agent = enforcement[1] if enforcement[1]
|
115
|
+
end
|
116
|
+
|
111
117
|
def entity_type(name, supertypes, identification, mapping_pragmas, clauses)
|
112
118
|
#puts "Entity Type #{name}, supertypes #{supertypes.inspect}, id #{identification.inspect}, clauses = #{clauses.inspect}"
|
113
119
|
debug :entity, "Defining Entity Type #{name}" do
|
@@ -139,7 +145,7 @@ module ActiveFacts
|
|
139
145
|
end
|
140
146
|
# REVISIT: If we do this, it gets emitted twice when we generate CQL. The generator should detect that the restriction is the same and not emit it.
|
141
147
|
#if (ranges = identification[:restriction])
|
142
|
-
# vt.value_restriction = value_restriction(ranges)
|
148
|
+
# vt.value_restriction = value_restriction(ranges, identification[:enforcement])
|
143
149
|
#end
|
144
150
|
end
|
145
151
|
|
@@ -269,7 +275,7 @@ player, binding = @symbols.bind(names)
|
|
269
275
|
|
270
276
|
# REVISIT: The restriction applies only to the value role. There is good reason to apply it above to the value type as well.
|
271
277
|
if (ranges = identification[:restriction])
|
272
|
-
value_role.role_value_restriction = value_restriction(ranges)
|
278
|
+
value_role.role_value_restriction = value_restriction(ranges, identification[:enforcement])
|
273
279
|
end
|
274
280
|
|
275
281
|
# Forward reading, if it doesn't already exist:
|
@@ -315,10 +321,9 @@ player, binding = @symbols.bind(names)
|
|
315
321
|
debug :mode, "Using existing EntityType role sequence"
|
316
322
|
end
|
317
323
|
if (rs0.all_presence_constraint.size == 0)
|
318
|
-
@constellation.PresenceConstraint(
|
324
|
+
constraint = @constellation.PresenceConstraint(
|
319
325
|
:new,
|
320
326
|
:name => '',
|
321
|
-
:enforcement => '',
|
322
327
|
:vocabulary => @vocabulary,
|
323
328
|
:role_sequence => rs0,
|
324
329
|
:min_frequency => 1,
|
@@ -344,10 +349,9 @@ player, binding = @symbols.bind(names)
|
|
344
349
|
debug :mode, "Using existing ValueType role sequence"
|
345
350
|
end
|
346
351
|
if (rs1.all_presence_constraint.size == 0)
|
347
|
-
@constellation.PresenceConstraint(
|
352
|
+
constraint = @constellation.PresenceConstraint(
|
348
353
|
:new,
|
349
354
|
:name => '',
|
350
|
-
:enforcement => '',
|
351
355
|
:vocabulary => @vocabulary,
|
352
356
|
:role_sequence => rs1,
|
353
357
|
:min_frequency => 0,
|
@@ -870,7 +874,7 @@ player, binding = @symbols.bind(names)
|
|
870
874
|
role_sequences
|
871
875
|
end
|
872
876
|
|
873
|
-
def presence_constraint(constrained_role_names, quantifier, phrases_list, context)
|
877
|
+
def presence_constraint(constrained_role_names, quantifier, phrases_list, context, enforcement)
|
874
878
|
raise "REVISIT: Join presence constraints not supported yet" if phrases_list[0].size > 1
|
875
879
|
phrases_list = phrases_list.map{|r| r[0] }
|
876
880
|
#p phrases_list
|
@@ -929,10 +933,9 @@ player, binding = @symbols.bind(names)
|
|
929
933
|
|
930
934
|
# REVISIT: Check that no existing PC spans the same roles (nor a superset nor subset?)
|
931
935
|
|
932
|
-
@constellation.PresenceConstraint(
|
936
|
+
constraint = @constellation.PresenceConstraint(
|
933
937
|
:new,
|
934
938
|
:name => '',
|
935
|
-
:enforcement => '',
|
936
939
|
:vocabulary => @vocabulary,
|
937
940
|
:role_sequence => rs,
|
938
941
|
:min_frequency => quantifier[0],
|
@@ -940,9 +943,10 @@ player, binding = @symbols.bind(names)
|
|
940
943
|
:is_preferred_identifier => false,
|
941
944
|
:is_mandatory => quantifier[0] && quantifier[0] > 0
|
942
945
|
)
|
946
|
+
apply_enforcement(constraint, enforcement) if enforcement
|
943
947
|
end
|
944
948
|
|
945
|
-
def set_constraint(constrained_roles, quantifier, joins_list, context)
|
949
|
+
def set_constraint(constrained_roles, quantifier, joins_list, context, enforcement)
|
946
950
|
role_sequences = bind_joins_as_role_sequences(joins_list)
|
947
951
|
|
948
952
|
if quantifier[1] == nil
|
@@ -953,10 +957,9 @@ player, binding = @symbols.bind(names)
|
|
953
957
|
second_role_ref = @constellation.RoleRef(:role_sequence => role_sequences[0], :ordinal => 1, :role => second_role)
|
954
958
|
@constellation.deny(role_sequences[1].all_role_ref.single)
|
955
959
|
@constellation.deny(role_sequences[1])
|
956
|
-
@constellation.PresenceConstraint(
|
960
|
+
constraint = @constellation.PresenceConstraint(
|
957
961
|
:new,
|
958
962
|
:name => '',
|
959
|
-
:enforcement => '',
|
960
963
|
:vocabulary => @vocabulary,
|
961
964
|
:role_sequence => role_sequences[0],
|
962
965
|
:min_frequency => quantifier[0],
|
@@ -964,6 +967,7 @@ player, binding = @symbols.bind(names)
|
|
964
967
|
:is_preferred_identifier => false,
|
965
968
|
:is_mandatory => true
|
966
969
|
)
|
970
|
+
apply_enforcement(constraint, enforcement) if enforcement
|
967
971
|
else
|
968
972
|
# Create a normal (mandatory) exclusion constraint:
|
969
973
|
constraint = @constellation.SetExclusionConstraint(:new)
|
@@ -971,11 +975,12 @@ player, binding = @symbols.bind(names)
|
|
971
975
|
role_sequences.each_with_index do |rs, i|
|
972
976
|
@constellation.SetComparisonRoles(constraint, i, :role_sequence => rs)
|
973
977
|
end
|
978
|
+
apply_enforcement(constraint, enforcement) if enforcement
|
974
979
|
constraint.is_mandatory = quantifier[0] == 1
|
975
980
|
end
|
976
981
|
end
|
977
982
|
|
978
|
-
def subset_constraint(joins_list, context)
|
983
|
+
def subset_constraint(joins_list, context, enforcement)
|
979
984
|
role_sequences = bind_joins_as_role_sequences(joins_list)
|
980
985
|
|
981
986
|
#puts "subset_constraint:\n\t#{subset_readings.inspect}\n\t#{superset_readings.inspect}"
|
@@ -990,10 +995,11 @@ player, binding = @symbols.bind(names)
|
|
990
995
|
#constraint.enforcement =
|
991
996
|
constraint.subset_role_sequence = role_sequences[0]
|
992
997
|
constraint.superset_role_sequence = role_sequences[1]
|
998
|
+
apply_enforcement(constraint, enforcement) if enforcement
|
993
999
|
end
|
994
1000
|
|
995
|
-
def equality_constraint(joins_list, context)
|
996
|
-
#puts "
|
1001
|
+
def equality_constraint(joins_list, context, enforcement)
|
1002
|
+
#puts "equality\n\t#{joins_list.map{|rl| rl.inspect}*"\n\tif and only if\n\t"}"
|
997
1003
|
|
998
1004
|
role_sequences = bind_joins_as_role_sequences(joins_list)
|
999
1005
|
|
@@ -1003,6 +1009,7 @@ player, binding = @symbols.bind(names)
|
|
1003
1009
|
role_sequences.each_with_index do |rs, i|
|
1004
1010
|
@constellation.SetComparisonRoles(constraint, i, :role_sequence => rs)
|
1005
1011
|
end
|
1012
|
+
apply_enforcement(constraint, enforcement) if enforcement
|
1006
1013
|
end
|
1007
1014
|
|
1008
1015
|
# Search the supertypes of 'subtype' looking for an inheritance path to 'supertype',
|
@@ -1195,7 +1202,7 @@ player, binding = @symbols.bind(names)
|
|
1195
1202
|
|
1196
1203
|
# Save a role value restriction
|
1197
1204
|
if (ranges = role_phrase[:restriction])
|
1198
|
-
role.role_value_restriction = value_restriction(ranges)
|
1205
|
+
role.role_value_restriction = value_restriction(ranges, role_phrase[:restriction_enforcement])
|
1199
1206
|
end
|
1200
1207
|
|
1201
1208
|
roles << role
|
data/lib/activefacts/version.rb
CHANGED
@@ -7,6 +7,10 @@ module ActiveFacts
|
|
7
7
|
value_type :length => 64
|
8
8
|
end
|
9
9
|
|
10
|
+
class AgentName < String
|
11
|
+
value_type
|
12
|
+
end
|
13
|
+
|
10
14
|
class Assimilation < String
|
11
15
|
value_type
|
12
16
|
restrict 'partitioned', 'separate'
|
@@ -37,7 +41,7 @@ module ActiveFacts
|
|
37
41
|
value_type
|
38
42
|
end
|
39
43
|
|
40
|
-
class
|
44
|
+
class EnforcementCode < String
|
41
45
|
value_type :length => 16
|
42
46
|
end
|
43
47
|
|
@@ -85,10 +89,6 @@ module ActiveFacts
|
|
85
89
|
value_type :length => 32
|
86
90
|
end
|
87
91
|
|
88
|
-
class PersonName < String
|
89
|
-
value_type
|
90
|
-
end
|
91
|
-
|
92
92
|
class Pronoun < String
|
93
93
|
value_type :length => 20
|
94
94
|
restrict 'feminine', 'masculine', 'neuter', 'personal'
|
@@ -114,8 +114,9 @@ module ActiveFacts
|
|
114
114
|
value_type
|
115
115
|
end
|
116
116
|
|
117
|
-
class
|
118
|
-
|
117
|
+
class Agent
|
118
|
+
identified_by :agent_name
|
119
|
+
one_to_one :agent_name, :mandatory => true # See AgentName.agent
|
119
120
|
end
|
120
121
|
|
121
122
|
class Coefficient
|
@@ -143,6 +144,12 @@ module ActiveFacts
|
|
143
144
|
has_one :fact_type # See FactType.all_context_note
|
144
145
|
end
|
145
146
|
|
147
|
+
class Enforcement
|
148
|
+
identified_by :enforcement_code
|
149
|
+
has_one :agent # See Agent.all_enforcement
|
150
|
+
one_to_one :enforcement_code, :mandatory => true # See EnforcementCode.enforcement
|
151
|
+
end
|
152
|
+
|
146
153
|
class Fact
|
147
154
|
identified_by :fact_id
|
148
155
|
one_to_one :fact_id, :mandatory => true # See FactId.fact
|
@@ -164,11 +171,6 @@ module ActiveFacts
|
|
164
171
|
has_one :value # See Value.all_instance
|
165
172
|
end
|
166
173
|
|
167
|
-
class Person
|
168
|
-
identified_by :person_name
|
169
|
-
one_to_one :person_name, :mandatory => true # See PersonName.person
|
170
|
-
end
|
171
|
-
|
172
174
|
class PresenceConstraint < Constraint
|
173
175
|
maybe :is_mandatory
|
174
176
|
maybe :is_preferred_identifier
|
@@ -239,9 +241,7 @@ module ActiveFacts
|
|
239
241
|
has_one :unit # See Unit.all_value
|
240
242
|
end
|
241
243
|
|
242
|
-
class ValueRestriction
|
243
|
-
identified_by :value_restriction_id
|
244
|
-
one_to_one :value_restriction_id, :mandatory => true # See ValueRestrictionId.value_restriction
|
244
|
+
class ValueRestriction < Constraint
|
245
245
|
end
|
246
246
|
|
247
247
|
class Vocabulary
|
@@ -270,15 +270,15 @@ module ActiveFacts
|
|
270
270
|
end
|
271
271
|
|
272
272
|
class ContextAccordingTo
|
273
|
-
identified_by :context_note, :
|
273
|
+
identified_by :context_note, :agent
|
274
|
+
has_one :agent, :mandatory => true # See Agent.all_context_according_to
|
274
275
|
has_one :context_note, :mandatory => true # See ContextNote.all_context_according_to
|
275
|
-
has_one :person, :mandatory => true # See Person.all_context_according_to
|
276
276
|
end
|
277
277
|
|
278
278
|
class ContextAgreedBy
|
279
|
-
identified_by :agreement, :
|
279
|
+
identified_by :agreement, :agent
|
280
|
+
has_one :agent, :mandatory => true # See Agent.all_context_agreed_by
|
280
281
|
has_one :agreement, :mandatory => true # See Agreement.all_context_agreed_by
|
281
|
-
has_one :person, :mandatory => true # See Person.all_context_agreed_by
|
282
282
|
end
|
283
283
|
|
284
284
|
class Derivation
|
@@ -15,7 +15,7 @@ include ActiveFacts
|
|
15
15
|
describe "Column lists from absorption compared with Ruby's" do
|
16
16
|
ABSORPTION_RUBY_FAILURES = {
|
17
17
|
"Metamodel" => "Overlaps with ActiveFacts Metamodel",
|
18
|
-
"
|
18
|
+
"MetamodelNext" => "Overlaps with ActiveFacts Metamodel",
|
19
19
|
"ServiceDirector" => "Lacks standard AutoTimestamp class"
|
20
20
|
}
|
21
21
|
|
data/spec/cql/context_spec.rb
CHANGED
@@ -15,39 +15,39 @@ describe "Business Context Notes" do
|
|
15
15
|
Notes = [
|
16
16
|
# Constraints:
|
17
17
|
[ 'each Person occurs one time in Person is employed, Person is unemployed (because it can be no other way!);',
|
18
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :presence, [["Person"]], [1, 1], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"unemployed"}]]], [nil, "because", "it can be no other way!", []]]]]
|
18
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :presence, [["Person"]], [1, 1], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"unemployed"}]]], [nil, "because", "it can be no other way!", []], []]]]
|
19
19
|
],
|
20
20
|
[ 'each Person occurs one time in Person is employed, Person is unemployed (as opposed to blah!);',
|
21
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :presence, [["Person"]], [1, 1], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"unemployed"}]]], [nil, "as_opposed_to", " blah!", []]]]]
|
21
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :presence, [["Person"]], [1, 1], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"unemployed"}]]], [nil, "as_opposed_to", " blah!", []], []]]]
|
22
22
|
],
|
23
23
|
[ 'for each Person at least one of these holds: Person is employed, Person is a bad credit risk (so that blah);',
|
24
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [nil, "so_that", " blah", []]]]]
|
24
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [nil, "so_that", " blah", []], []]]]
|
25
25
|
],
|
26
26
|
[ 'Person is good credit risk only if Person is employed (to avoid lending to people who can\'t repay);',
|
27
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :subset, [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"good"}, {:word=>"credit"}, {:word=>"risk"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]]], [nil, "to_avoid", " lending to people who can't repay", []]]]]
|
27
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :subset, [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"good"}, {:word=>"credit"}, {:word=>"risk"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]]], [nil, "to_avoid", " lending to people who can't repay", []], []]]]
|
28
28
|
],
|
29
29
|
[ 'Person is good credit risk if and only if Person is employed (to avoid lending to people who can\'t repay);',
|
30
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :equality, [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"good"}, {:word=>"credit"}, {:word=>"risk"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]]], [nil, "to_avoid", " lending to people who can't repay", []]]]]
|
30
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :equality, [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"good"}, {:word=>"credit"}, {:word=>"risk"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]]], [nil, "to_avoid", " lending to people who can't repay", []], []]]]
|
31
31
|
],
|
32
32
|
# Entity and Fact types
|
33
33
|
[ 'Foo is identified by Bar [independent] where Foo has one Bar (so that we have an id);',
|
34
|
-
[["Person", [:value_type, "Person", [], [], [], []]], ["Foo", [:entity_type, [], {:roles=>[["Bar"]]}, ["independent"], [[:fact_clause, [], [{:word=>"Foo"}, {:word=>"has"}, {:
|
34
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], ["Foo", [:entity_type, [], {:roles=>[["Bar"]]}, ["independent"], [[:fact_clause, [], [{:word=>"Foo"}, {:word=>"has"}, {:quantifier=>[1, 1], :quantifier_restriction=>[], :word=>"Bar"}], [nil, "so_that", " we have an id", []]]]]]]
|
35
35
|
],
|
36
36
|
[ 'Foo has one Bar (so that we have an id), Bar is of one Foo (because we need that);',
|
37
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Foo"}, {:word=>"has"}, {:
|
37
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Foo"}, {:word=>"has"}, {:quantifier=>[1, 1], :quantifier_restriction=>[], :word=>"Bar"}], [nil, "so_that", " we have an id", []]], [:fact_clause, [], [{:word=>"Bar"}, {:word=>"is"}, {:word=>"of"}, {:quantifier=>[1, 1], :quantifier_restriction=>[], :word=>"Foo"}], [nil, "because", "we need that", []]]], []]]]
|
38
38
|
],
|
39
39
|
# REVISIT: No context notes on quantifiers yet
|
40
40
|
# As agreed by:
|
41
41
|
[ 'for each Person at least one of these holds: Person is employed, Person is a bad credit risk (so that blah, as agreed by Jim);',
|
42
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [nil, "so_that", " blah", [nil, ["Jim"]]]]]]
|
42
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [nil, "so_that", " blah", [nil, ["Jim"]]], []]]]
|
43
43
|
],
|
44
44
|
# REVISIT: Populate an "as agreed by" with a date
|
45
45
|
[ 'for each Person at least one of these holds: Person is employed, Person is a bad credit risk (so that blah, as agreed on 29 March by Jim);',
|
46
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [nil, "so_that", " blah", ["29 March", ["Jim"]]]]]]
|
46
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [nil, "so_that", " blah", ["29 March", ["Jim"]]], []]]]
|
47
47
|
],
|
48
48
|
# According to:
|
49
49
|
[ 'for each Person at least one of these holds: Person is employed, Person is a bad credit risk (according to jim, so that blah);',
|
50
|
-
[["Person", [:value_type, "Person", [], [], [], []]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [["jim"], "so_that", " blah", []]]]]
|
50
|
+
[["Person", [:value_type, "Person", [], [], [], [], nil]], [nil, [:constraint, :set, [["Person"]], [1, nil], [[[{:word=>"Person"}, {:word=>"is"}, {:word=>"employed"}]], [[{:word=>"Person"}, {:word=>"is"}, {:word=>"a"}, {:word=>"bad"}, {:word=>"credit"}, {:word=>"risk"}]]], [["jim"], "so_that", " blah", []], []]]]
|
51
51
|
],
|
52
52
|
]
|
53
53
|
|
data/spec/cql/unit_spec.rb
CHANGED
@@ -167,7 +167,7 @@ end
|
|
167
167
|
describe "Value Types" do
|
168
168
|
ValueTypes = [
|
169
169
|
[ "a is written as b(1, 2) inch restricted to { 3 .. 4 } inch ;",
|
170
|
-
[["a", [:value_type, "b", [
|
170
|
+
[["a", [:value_type, "b", [1, 2], [["inch", 1]], [[3, 4]], [], []]]]
|
171
171
|
],
|
172
172
|
# [ "a c is written as b(1, 2) inch restricted to { 3 .. 4 } inch ;",
|
173
173
|
# [["a c", [:value_type, "b", [1, 2], "inch", [[3, 4]]]]]
|
@@ -195,16 +195,16 @@ end
|
|
195
195
|
describe "Entity Types" do
|
196
196
|
EntityTypes_RefMode = [
|
197
197
|
[ "a is identified by its id;", # Entity type declaration with reference mode
|
198
|
-
[["a", [:entity_type, [], {:mode=>"id", :parameters=>
|
198
|
+
[["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :restriction=>nil}, [], nil]]]
|
199
199
|
],
|
200
200
|
[ "a is identified by its number(12);", # Entity type declaration with reference mode
|
201
|
-
[["a", [:entity_type, [], {:mode=>"number", :parameters
|
201
|
+
[["a", [:entity_type, [], {:enforcement=>nil, :mode=>"number", :parameters=>[12], :restriction=>nil}, [], nil]]]
|
202
202
|
],
|
203
203
|
[ "a is identified by its id:c;", # Entity type declaration with reference mode and fact type(s)
|
204
|
-
[["a", [:entity_type, [], {:mode=>"id", :parameters=>
|
204
|
+
[["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :restriction=>nil}, [], [[:fact_clause, [], [{:word=>"c"}], nil]]]]]
|
205
205
|
],
|
206
206
|
[ "a is identified by its id where c;", # Entity type declaration with reference mode and where
|
207
|
-
[["a", [:entity_type, [], {:mode=>"id", :parameters=>
|
207
|
+
[["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :restriction=>nil}, [], [[:fact_clause, [], [{:word=>"c"}], nil]]]]]
|
208
208
|
],
|
209
209
|
]
|
210
210
|
|
@@ -222,12 +222,10 @@ describe "Entity Types" do
|
|
222
222
|
[["a", [:entity_type, [], {:roles=>[["b"], ["c"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
|
223
223
|
],
|
224
224
|
[ "a is written as b(); c is identified by a:d;",
|
225
|
-
[["a", [:value_type, "b", [], [], [], []]],
|
226
|
-
["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
|
225
|
+
[["a", [:value_type, "b", [], [], [], [], nil]], ["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
|
227
226
|
],
|
228
227
|
[ " a is written as b ( ) ; c is identified by a : d ; ",
|
229
|
-
[["a", [:value_type, "b", [], [], [], []]],
|
230
|
-
["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
|
228
|
+
[["a", [:value_type, "b", [], [], [], [], nil]], ["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
|
231
229
|
],
|
232
230
|
[ "a is identified by c:maybe d;",
|
233
231
|
[["a", [:entity_type, [], {:roles=>[["c"]]}, [], [[:fact_clause, ["maybe"], [{:word=>"d"}], nil]]]]]
|
@@ -343,7 +341,7 @@ describe "Fact Types" do
|
|
343
341
|
|
344
342
|
Constraints = [
|
345
343
|
[ "each combination FamilyName, GivenName occurs at most one time in Competitor has FamilyName, Competitor has GivenName;",
|
346
|
-
[nil, [:constraint, :presence, [["FamilyName"], ["GivenName"]], [nil, 1], [[[{:word=>"Competitor"}, {:word=>"has"}, {:word=>"FamilyName"}]], [[{:word=>"Competitor"}, {:word=>"has"}, {:word=>"GivenName"}]]], nil]]
|
344
|
+
[nil, [:constraint, :presence, [["FamilyName"], ["GivenName"]], [nil, 1], [[[{:word=>"Competitor"}, {:word=>"has"}, {:word=>"FamilyName"}]], [[{:word=>"Competitor"}, {:word=>"has"}, {:word=>"GivenName"}]]], nil, []]]
|
347
345
|
],
|
348
346
|
]
|
349
347
|
|
data/spec/cql_cql_spec.rb
CHANGED
@@ -16,12 +16,12 @@ describe "CQL Loader" do
|
|
16
16
|
cql_failures = {
|
17
17
|
"Airline" => "Contains queries, unsupported",
|
18
18
|
"CompanyQuery" => "Contains queries, unsupported",
|
19
|
+
"MetamodelNext" => "Fails due to weak adjective/role matching",
|
19
20
|
"OrienteeringER" => "Doesn't parse due to difficult fact type match",
|
20
21
|
"ServiceDirector" => "Doesn't parse some constraints due to mis-matched adjectives"
|
21
22
|
}
|
22
23
|
cql_cql_failures = {
|
23
24
|
"Insurance" => "Misses a subtype join in a constraint verbalisation",
|
24
|
-
"MetamodelTerms" => "Fails due to weak adjective/role matching",
|
25
25
|
# "OddIdentifier" => "Doesn't support identification of object fact types using mixed external/internal roles",
|
26
26
|
}
|
27
27
|
# Generate and return the CQL for the given vocabulary
|
data/spec/norma_tables_spec.rb
CHANGED
@@ -20,7 +20,7 @@ Exceptions = {
|
|
20
20
|
"Blog" => ["Author", "Comment", "Paragraph", "Post", "Topic"],
|
21
21
|
"JoinEquality" => ["Event", "Seat", "Ticket", "Venue"],
|
22
22
|
"Metamodel" => ["AllowedRange", "Concept", "Constraint", "ContextAccordingTo", "ContextAgreedBy", "ContextNote", "Derivation", "Fact", "FactType", "Instance", "Join", "ParamValue", "Reading", "Role", "RoleRef", "RoleSequence", "RoleValue", "SetComparisonRoles", "Unit", "ValueRestriction" ],
|
23
|
-
"
|
23
|
+
"MetamodelNext" => ["AllowedRange", "Constraint", "ContextAccordingTo", "ContextAgreedBy", "ContextNote", "Derivation", "Fact", "FactType", "Instance", "Join", "ParamValue", "Reading", "Role", "RoleRef", "RoleSequence", "RoleValue", "SetComparisonRoles", "Term", "Unit", "ValueConstraint"],
|
24
24
|
"OilSupply" => ["AcceptableSubstitutes", "Month", "ProductionForecast", "RegionalDemand", "TransportRoute"],
|
25
25
|
"Orienteering" => ["Club", "Entry", "Event", "EventControl", "EventScoringMethod", "Map", "Person", "Punch", "PunchPlacement", "Series", "Visit"],
|
26
26
|
"SeparateSubtype" => ["Claim", "VehicleIncident"],
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activefacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clifford Heath
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-04-09 00:00:00 +10:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 2.3.
|
43
|
+
version: 2.3.3
|
44
44
|
version:
|
45
45
|
description: |
|
46
46
|
|