openehr 1.2.999999 → 2.0.0
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/README.rdoc +95 -14
- data/lib/openehr/am/archetype/constraint_model/primitive.rb +204 -6
- data/lib/openehr/am/archetype/constraint_model.rb +228 -4
- data/lib/openehr/am/archetype/ontology.rb +2 -2
- data/lib/openehr/am/archetype.rb +101 -2
- data/lib/openehr/am/openehr_profile/data_types/basic.rb +28 -0
- data/lib/openehr/am/openehr_profile/data_types/quantity.rb +88 -0
- data/lib/openehr/am/openehr_profile/data_types/text.rb +23 -0
- data/lib/openehr/am/template.rb +77 -24
- data/lib/openehr/aql/engine/binding.rb +13 -0
- data/lib/openehr/aql/engine/contains_resolver.rb +161 -0
- data/lib/openehr/aql/engine/dataset.rb +122 -0
- data/lib/openehr/aql/engine/path_evaluator.rb +137 -0
- data/lib/openehr/aql/engine/predicate_evaluator.rb +65 -0
- data/lib/openehr/aql/engine.rb +119 -0
- data/lib/openehr/aql/errors.rb +27 -0
- data/lib/openehr/aql/lexer.rb +295 -0
- data/lib/openehr/aql/model/containment.rb +45 -0
- data/lib/openehr/aql/model/from_clause.rb +35 -0
- data/lib/openehr/aql/model/function_call.rb +56 -0
- data/lib/openehr/aql/model/identified_path.rb +20 -0
- data/lib/openehr/aql/model/literal.rb +15 -0
- data/lib/openehr/aql/model/object_path.rb +34 -0
- data/lib/openehr/aql/model/order_by_and_limit.rb +50 -0
- data/lib/openehr/aql/model/predicate.rb +84 -0
- data/lib/openehr/aql/model/query.rb +24 -0
- data/lib/openehr/aql/model/select_clause.rb +29 -0
- data/lib/openehr/aql/model/where_clause.rb +105 -0
- data/lib/openehr/aql/model.rb +14 -0
- data/lib/openehr/aql/parser.rb +484 -0
- data/lib/openehr/aql/result_set.rb +54 -0
- data/lib/openehr/aql.rb +28 -0
- data/lib/openehr/assumed_library_types.rb +68 -17
- data/lib/openehr/parser/adl_grammar.tt +29 -13
- data/lib/openehr/parser/adl_parser.rb +18 -4
- data/lib/openehr/parser/archetype_validator.rb +126 -0
- data/lib/openehr/parser/exception.rb +13 -0
- data/lib/openehr/parser/opt_parser.rb +306 -27
- data/lib/openehr/parser.rb +2 -0
- data/lib/openehr/path.rb +195 -0
- data/lib/openehr/rm/common/archetyped.rb +117 -7
- data/lib/openehr/rm/common/change_control.rb +3 -8
- data/lib/openehr/rm/common/directory.rb +4 -0
- data/lib/openehr/rm/common/generic.rb +24 -10
- data/lib/openehr/rm/composition/content/entry.rb +24 -5
- data/lib/openehr/rm/composition/content/navigation.rb +2 -1
- data/lib/openehr/rm/composition.rb +19 -2
- data/lib/openehr/rm/data_structures/history.rb +3 -0
- data/lib/openehr/rm/data_structures/item_structure/representation.rb +13 -9
- data/lib/openehr/rm/data_structures/item_structure.rb +28 -15
- data/lib/openehr/rm/data_types/encapsulated.rb +23 -3
- data/lib/openehr/rm/data_types/quantity/date_time.rb +9 -1
- data/lib/openehr/rm/data_types/quantity.rb +66 -14
- data/lib/openehr/rm/data_types/text.rb +8 -0
- data/lib/openehr/rm/data_types/time_specification.rb +5 -4
- data/lib/openehr/rm/data_types/uri.rb +0 -1
- data/lib/openehr/rm/demographic.rb +4 -3
- data/lib/openehr/rm/ehr.rb +20 -1
- data/lib/openehr/rm/factory.rb +345 -36
- data/lib/openehr/rm/integration.rb +1 -0
- data/lib/openehr/rm/support/identification.rb +37 -8
- data/lib/openehr/rm/support/measurement.rb +32 -0
- data/lib/openehr/rm/type_name.rb +90 -0
- data/lib/openehr/rm.rb +3 -0
- data/lib/openehr/serializer/adl_serializer.rb +335 -0
- data/lib/openehr/serializer/base.rb +20 -0
- data/lib/openehr/serializer/opt_serializer.rb +49 -0
- data/lib/openehr/serializer/rm_json_serializer.rb +62 -0
- data/lib/openehr/serializer/xml_serializer.rb +260 -0
- data/lib/openehr/serializer.rb +5 -291
- data/lib/openehr/terminology_service.rb +44 -0
- data/lib/openehr/version.rb +1 -1
- data/lib/openehr.rb +5 -2
- metadata +36 -11
- data/lib/openehr/parser/validator.rb +0 -18
- data/lib/openehr/parser/xml_parser.rb +0 -13
- data/lib/openehr/rm/data_types/charset_extract.rb +0 -24
- data/lib/openehr/writer.rb +0 -12
|
@@ -71,6 +71,35 @@ module OpenEHR
|
|
|
71
71
|
(@lower_included == value.lower_included?) &&
|
|
72
72
|
(@upper_included == value.upper_included?)
|
|
73
73
|
end
|
|
74
|
+
|
|
75
|
+
# True if every value this interval has is also had by other (a
|
|
76
|
+
# standard subset test, e.g. for conformance checks: does a
|
|
77
|
+
# constraint's occurrences/existence/cardinality interval fit
|
|
78
|
+
# within its parent's).
|
|
79
|
+
def subset_of?(other)
|
|
80
|
+
return false if other.nil?
|
|
81
|
+
|
|
82
|
+
lower_ok = if lower_unbounded?
|
|
83
|
+
other.lower_unbounded?
|
|
84
|
+
elsif other.lower_unbounded? || lower > other.lower
|
|
85
|
+
true
|
|
86
|
+
elsif lower == other.lower
|
|
87
|
+
!lower_included? || other.lower_included?
|
|
88
|
+
else
|
|
89
|
+
false
|
|
90
|
+
end
|
|
91
|
+
upper_ok = if upper_unbounded?
|
|
92
|
+
other.upper_unbounded?
|
|
93
|
+
elsif other.upper_unbounded? || upper < other.upper
|
|
94
|
+
true
|
|
95
|
+
elsif upper == other.upper
|
|
96
|
+
!upper_included? || other.upper_included?
|
|
97
|
+
else
|
|
98
|
+
false
|
|
99
|
+
end
|
|
100
|
+
lower_ok && upper_ok
|
|
101
|
+
end
|
|
102
|
+
|
|
74
103
|
private
|
|
75
104
|
|
|
76
105
|
def check_lower_upper(lower, upper)
|
|
@@ -441,6 +470,8 @@ module OpenEHR
|
|
|
441
470
|
return false
|
|
442
471
|
end
|
|
443
472
|
end
|
|
473
|
+
# A timezone is optional in ISO 8601; its absence does not make an
|
|
474
|
+
# otherwise-valid time invalid.
|
|
444
475
|
unless tz.nil?
|
|
445
476
|
timezone = Timezone.new(tz)
|
|
446
477
|
if timezone.hour < 0 or timezone.hour >= HOURS_IN_DAY
|
|
@@ -449,10 +480,8 @@ module OpenEHR
|
|
|
449
480
|
if timezone.minute < 0 or timezone.minute >= MINUTES_IN_HOUR
|
|
450
481
|
return false
|
|
451
482
|
end
|
|
452
|
-
return true
|
|
453
|
-
else
|
|
454
|
-
return false
|
|
455
483
|
end
|
|
484
|
+
return true
|
|
456
485
|
end
|
|
457
486
|
end
|
|
458
487
|
end # end of ISO8601_TIME
|
|
@@ -589,6 +618,19 @@ module OpenEHR
|
|
|
589
618
|
include TimeDefinitions
|
|
590
619
|
attr_reader :years, :months, :weeks, :days
|
|
591
620
|
attr_reader :hours, :minutes, :seconds, :fractional_second
|
|
621
|
+
# RM 1.1.0 (SPECRM-96): a leading '-' before 'P' negates the whole
|
|
622
|
+
# duration (e.g. "-P10D", 10 days before an unstated origin point).
|
|
623
|
+
# Components stay non-negative magnitudes - the sign applies to
|
|
624
|
+
# the duration as a whole, not each field - so it's tracked here.
|
|
625
|
+
attr_reader :negative
|
|
626
|
+
|
|
627
|
+
def negative=(negative)
|
|
628
|
+
@negative = negative ? true : false
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
def negative?
|
|
632
|
+
@negative == true
|
|
633
|
+
end
|
|
592
634
|
|
|
593
635
|
def years=(years)
|
|
594
636
|
unless years.nil? || years >= 0
|
|
@@ -647,7 +689,7 @@ module OpenEHR
|
|
|
647
689
|
end
|
|
648
690
|
|
|
649
691
|
def as_string
|
|
650
|
-
str = 'P'
|
|
692
|
+
str = negative? ? '-P' : 'P'
|
|
651
693
|
unless @years.nil?
|
|
652
694
|
str += @years.to_s + 'Y'
|
|
653
695
|
end
|
|
@@ -681,27 +723,36 @@ module OpenEHR
|
|
|
681
723
|
nilthenzero(@months)*TimeDefinitions::DAYS_IN_MONTH +
|
|
682
724
|
nilthenzero(@weeks)*TimeDefinitions::DAYS_IN_WEEK +
|
|
683
725
|
nilthenzero(@days)
|
|
684
|
-
seconds_with_fractional = (((days*TimeDefinitions::HOURS_IN_DAY + nilthenzero(@hours))*TimeDefinitions::MINUTES_IN_HOUR)+nilthenzero(@minutes))*TimeDefinitions::SECONDS_IN_MINUTE +
|
|
726
|
+
seconds_with_fractional = (((days*TimeDefinitions::HOURS_IN_DAY + nilthenzero(@hours))*TimeDefinitions::MINUTES_IN_HOUR)+nilthenzero(@minutes))*TimeDefinitions::SECONDS_IN_MINUTE +
|
|
685
727
|
nilthenzero(@seconds) +
|
|
686
728
|
@fractional_second.to_f
|
|
687
|
-
return seconds_with_fractional
|
|
729
|
+
return negative? ? -seconds_with_fractional : seconds_with_fractional
|
|
688
730
|
end
|
|
689
731
|
end
|
|
690
732
|
|
|
691
733
|
class ISO8601Duration
|
|
692
734
|
include ISO8601DurationModule, Comparable
|
|
693
735
|
def initialize(str)
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
self.
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
736
|
+
# A leading '-' negates the whole duration (RM 1.1.0, SPECRM-96);
|
|
737
|
+
# stripped before the main match so the existing capture group
|
|
738
|
+
# numbering below doesn't need to shift.
|
|
739
|
+
self.negative = str.start_with?('-')
|
|
740
|
+
duration_str = negative? ? str[1..-1] : str
|
|
741
|
+
md = /^P((\d+)[Yy])?((\d+)[Mm])?((\d+)[Ww])?((\d+)[dD])?(T((\d+)[Hh])?((\d+)[Mm])?((\d+)(\.\d+)?[Ss])?)?$/.match(duration_str)
|
|
742
|
+
if md.nil?
|
|
743
|
+
raise ArgumentError, 'invalid ISO8601 duration format'
|
|
744
|
+
end
|
|
745
|
+
# Absent components stay nil rather than being coerced to 0, so
|
|
746
|
+
# as_string can round-trip a partially-specified duration and
|
|
747
|
+
# "unset" is distinguishable from "explicitly zero".
|
|
748
|
+
self.years = md[2] && md[2].to_i
|
|
749
|
+
self.months = md[4] && md[4].to_i
|
|
750
|
+
self.weeks = md[6] && md[6].to_i
|
|
751
|
+
self.days = md[8] && md[8].to_i
|
|
752
|
+
self.hours = md[11] && md[11].to_i
|
|
753
|
+
self.minutes = md[13] && md[13].to_i
|
|
754
|
+
self.seconds = md[15] && md[15].to_i
|
|
755
|
+
self.fractional_second = md[16] && md[16].to_f
|
|
705
756
|
end
|
|
706
757
|
|
|
707
758
|
def <=>(other)
|
|
@@ -15,7 +15,7 @@ module OpenEHR
|
|
|
15
15
|
lang:(arch_language)?
|
|
16
16
|
desc:(arch_description)?
|
|
17
17
|
arch_definition
|
|
18
|
-
arch_invariant?
|
|
18
|
+
inv:(arch_invariant)?
|
|
19
19
|
arch_ontology {
|
|
20
20
|
def archetype_id
|
|
21
21
|
arch_identification.archetype_id
|
|
@@ -52,6 +52,14 @@ module OpenEHR
|
|
|
52
52
|
def ontology
|
|
53
53
|
arch_ontology.value
|
|
54
54
|
end
|
|
55
|
+
|
|
56
|
+
def parent_archetype_id
|
|
57
|
+
spec.archetype_id unless spec.empty?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def invariants
|
|
61
|
+
inv.value unless inv.empty?
|
|
62
|
+
end
|
|
55
63
|
}
|
|
56
64
|
end
|
|
57
65
|
|
|
@@ -116,9 +124,9 @@ module OpenEHR
|
|
|
116
124
|
{ :uid => uid.value }
|
|
117
125
|
end
|
|
118
126
|
}
|
|
119
|
-
/
|
|
127
|
+
/ SYM_IS_CONTROLLED space {
|
|
120
128
|
def value
|
|
121
|
-
{ :
|
|
129
|
+
{ :is_controlled? => true } # If elements[0]
|
|
122
130
|
end
|
|
123
131
|
}
|
|
124
132
|
end
|
|
@@ -194,7 +202,11 @@ module OpenEHR
|
|
|
194
202
|
end
|
|
195
203
|
|
|
196
204
|
rule arch_invariant
|
|
197
|
-
SYM_INVARIANT V_ASSERTION_TEXT space
|
|
205
|
+
SYM_INVARIANT text:V_ASSERTION_TEXT space {
|
|
206
|
+
def value
|
|
207
|
+
text.value
|
|
208
|
+
end
|
|
209
|
+
}
|
|
198
210
|
end
|
|
199
211
|
|
|
200
212
|
rule arch_ontology
|
|
@@ -327,7 +339,7 @@ module OpenEHR
|
|
|
327
339
|
rule c_complex_object_body
|
|
328
340
|
c_any '' {
|
|
329
341
|
def value(node)
|
|
330
|
-
Hash[:attributes =>
|
|
342
|
+
Hash[:attributes => nil]
|
|
331
343
|
end
|
|
332
344
|
}
|
|
333
345
|
/ c_attributes '' {
|
|
@@ -386,10 +398,10 @@ module OpenEHR
|
|
|
386
398
|
}
|
|
387
399
|
/ V_C_DOMAIN_TYPE '' {
|
|
388
400
|
def value(node = nil)
|
|
389
|
-
|
|
401
|
+
raise OpenEHR::Parser::ParseError,
|
|
402
|
+
"generic C_DOMAIN_TYPE constraints (e.g. C_DV_STATE) are not yet supported by the ADL parser: #{text_value}"
|
|
390
403
|
end
|
|
391
404
|
}
|
|
392
|
-
# / ERR_V_C_DOMAIN_TYPE
|
|
393
405
|
end
|
|
394
406
|
|
|
395
407
|
rule archetype_internal_ref
|
|
@@ -1460,7 +1472,7 @@ module OpenEHR
|
|
|
1460
1472
|
def value
|
|
1461
1473
|
if (id && !id.empty?)
|
|
1462
1474
|
OpenEHR::AM::Archetype::Assertion::Assertion.new(
|
|
1463
|
-
:tag => id.value, :expression => boolean_expression.value,
|
|
1475
|
+
:tag => id.elements[0].value, :expression => boolean_expression.value,
|
|
1464
1476
|
:string_expression => id.text_value + boolean_expression.text_value)
|
|
1465
1477
|
else
|
|
1466
1478
|
OpenEHR::AM::Archetype::Assertion::Assertion.new(
|
|
@@ -1726,7 +1738,7 @@ module OpenEHR
|
|
|
1726
1738
|
}
|
|
1727
1739
|
/ integer_value '' {
|
|
1728
1740
|
def value
|
|
1729
|
-
OpenEHR::AM::Archetype::
|
|
1741
|
+
OpenEHR::AM::Archetype::Assertion::ExprLeaf.new(
|
|
1730
1742
|
:type => 'Integer',
|
|
1731
1743
|
:item => integer_value.value,
|
|
1732
1744
|
:reference_type => 'CONSTANT')
|
|
@@ -1734,7 +1746,7 @@ module OpenEHR
|
|
|
1734
1746
|
}
|
|
1735
1747
|
/ real_value '' {
|
|
1736
1748
|
def value
|
|
1737
|
-
OpenEHR::AM::Archetype::
|
|
1749
|
+
OpenEHR::AM::Archetype::Assertion::ExprLeaf.new(
|
|
1738
1750
|
:type => 'Real',
|
|
1739
1751
|
:item => real_value.value,
|
|
1740
1752
|
:reference_type => 'CONSTANT')
|
|
@@ -1742,7 +1754,7 @@ module OpenEHR
|
|
|
1742
1754
|
}
|
|
1743
1755
|
/ absolute_path space {
|
|
1744
1756
|
def value
|
|
1745
|
-
OpenEHR::AM::Archetype::
|
|
1757
|
+
OpenEHR::AM::Archetype::Assertion::ExprLeaf.new(
|
|
1746
1758
|
:type => 'String',
|
|
1747
1759
|
:item => absolute_path.value,
|
|
1748
1760
|
:reference_type => 'CONSTANT')
|
|
@@ -2168,9 +2180,9 @@ module OpenEHR
|
|
|
2168
2180
|
type_identifier.value
|
|
2169
2181
|
end
|
|
2170
2182
|
}
|
|
2171
|
-
/ V_ATTRIBUTE_IDENTIFIER '' {
|
|
2183
|
+
/ id:V_ATTRIBUTE_IDENTIFIER '' {
|
|
2172
2184
|
def value
|
|
2173
|
-
|
|
2185
|
+
id.value
|
|
2174
2186
|
end
|
|
2175
2187
|
}
|
|
2176
2188
|
end
|
|
@@ -3004,6 +3016,10 @@ module OpenEHR
|
|
|
3004
3016
|
'=' white_space
|
|
3005
3017
|
end
|
|
3006
3018
|
|
|
3019
|
+
rule SYM_NE
|
|
3020
|
+
'!=' white_space
|
|
3021
|
+
end
|
|
3022
|
+
|
|
3007
3023
|
rule SYM_GE
|
|
3008
3024
|
('=>' / '>=') white_space
|
|
3009
3025
|
end
|
|
@@ -13,8 +13,10 @@ module OpenEHR
|
|
|
13
13
|
super
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def parse
|
|
17
|
-
archetype
|
|
16
|
+
def parse(validate: false)
|
|
17
|
+
archetype.tap do |a|
|
|
18
|
+
ArchetypeValidator.new(a).validate! if validate
|
|
19
|
+
end
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
private
|
|
@@ -67,6 +69,16 @@ module OpenEHR
|
|
|
67
69
|
parsed_data.concept
|
|
68
70
|
end
|
|
69
71
|
|
|
72
|
+
def parent_archetype_id
|
|
73
|
+
if parsed_data.parent_archetype_id
|
|
74
|
+
OpenEHR::RM::Support::Identification::ArchetypeID.new(:value => parsed_data.parent_archetype_id)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def invariants
|
|
79
|
+
parsed_data.invariants
|
|
80
|
+
end
|
|
81
|
+
|
|
70
82
|
def description
|
|
71
83
|
parsed_data.description
|
|
72
84
|
end
|
|
@@ -82,13 +94,15 @@ module OpenEHR
|
|
|
82
94
|
def archetype
|
|
83
95
|
OpenEHR::AM::Archetype::Archetype.new(:archetype_id => archetype_id,
|
|
84
96
|
:adl_version => adl_version,
|
|
85
|
-
:uid => uid,
|
|
97
|
+
:uid => uid,
|
|
86
98
|
:concept => concept,
|
|
87
99
|
:original_language => original_language,
|
|
88
100
|
:translations => translations,
|
|
89
101
|
:description => description,
|
|
90
102
|
:definition => definition,
|
|
91
|
-
:ontology => ontology
|
|
103
|
+
:ontology => ontology,
|
|
104
|
+
:parent_archetype_id => parent_archetype_id,
|
|
105
|
+
:invariants => invariants)
|
|
92
106
|
end
|
|
93
107
|
end
|
|
94
108
|
end # of Parser
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require_relative 'exception'
|
|
2
|
+
|
|
3
|
+
module OpenEHR
|
|
4
|
+
module Parser
|
|
5
|
+
# Post-parse semantic validator, checking a parsed archetype
|
|
6
|
+
# against the VARID..VDFPT rules (Beale07, p.100). VARID/VARDF/
|
|
7
|
+
# VARON/VDFAI are already enforced structurally by the RM/AM
|
|
8
|
+
# object model itself (their setters raise on construction), so
|
|
9
|
+
# they can never actually fail here - they're still checked
|
|
10
|
+
# explicitly, both for rule-traceability and so a validator run
|
|
11
|
+
# against a duck-typed object (not necessarily a real
|
|
12
|
+
# OpenEHR::AM::Archetype::Archetype) stays honest.
|
|
13
|
+
class ArchetypeValidator
|
|
14
|
+
Validation = Exception::Validation
|
|
15
|
+
|
|
16
|
+
def initialize(archetype)
|
|
17
|
+
@archetype = archetype
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def errors
|
|
21
|
+
RULES.filter_map { |rule| send(rule) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def valid?
|
|
25
|
+
errors.empty?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def validate!
|
|
29
|
+
error = errors.first
|
|
30
|
+
raise error if error
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Checks +rm_root+ against the archetype's definition, returning
|
|
34
|
+
# a path-annotated OpenEHR::Parser::Exception::Validation::
|
|
35
|
+
# InstanceNonConformant for the first violation found (path
|
|
36
|
+
# resolved via rm_root.path_of_item, the PATHABLE navigation
|
|
37
|
+
# method), or [] when rm_root fully conforms.
|
|
38
|
+
def validate_instance(rm_root)
|
|
39
|
+
return [] if @archetype.definition.valid_value?(rm_root)
|
|
40
|
+
|
|
41
|
+
_node, value = @archetype.definition.find_violation(rm_root)
|
|
42
|
+
message = "value does not conform to #{@archetype.archetype_id.value}"
|
|
43
|
+
[Validation::InstanceNonConformant.new(message, resolve_path(rm_root, value))]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def resolve_path(rm_root, value)
|
|
49
|
+
return nil unless rm_root.respond_to?(:path_of_item)
|
|
50
|
+
|
|
51
|
+
rm_root.path_of_item(value)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def varid
|
|
55
|
+
Validation::VARID.new(Validation::VARID::MESSAGE) if @archetype.archetype_id.nil?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def vardf
|
|
59
|
+
Validation::VARDF.new(Validation::VARDF::MESSAGE) if @archetype.definition.nil?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def varon
|
|
63
|
+
Validation::VARON.new(Validation::VARON::MESSAGE) if @archetype.ontology.nil?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def varcn
|
|
67
|
+
return if @archetype.concept.nil?
|
|
68
|
+
return if @archetype.ontology.term_codes.include?(@archetype.concept)
|
|
69
|
+
|
|
70
|
+
Validation::VARCN.new(Validation::VARCN::MESSAGE)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def vardt
|
|
74
|
+
definition_type = @archetype.definition.rm_type_name.to_s.upcase
|
|
75
|
+
id_type = @archetype.archetype_id.rm_entity.to_s.upcase
|
|
76
|
+
return if definition_type == id_type
|
|
77
|
+
|
|
78
|
+
Validation::VARDT.new(Validation::VARDT::MESSAGE)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def vatdf
|
|
82
|
+
Validation::VATDF.new(Validation::VATDF::MESSAGE) unless @archetype.node_ids_valid?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def vacdf
|
|
86
|
+
Validation::VACDF.new(Validation::VACDF::MESSAGE) unless @archetype.constraint_references_valid?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# In practice this can never actually fail through this gem's own
|
|
90
|
+
# object model: CArchetypeRoot#archetype_id= already rejects
|
|
91
|
+
# anything but a well-typed ArchetypeID at construction time.
|
|
92
|
+
# Still checked genuinely (rather than a hardcoded pass) in case
|
|
93
|
+
# +archetype+ is a duck-typed object built some other way.
|
|
94
|
+
def vdfai
|
|
95
|
+
return if archetype_roots(@archetype.definition).all? do |id|
|
|
96
|
+
id.is_a?(OpenEHR::RM::Support::Identification::ArchetypeID)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
Validation::VDFAI.new(Validation::VDFAI::MESSAGE)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def archetype_roots(node, found = [])
|
|
103
|
+
return found if node.nil?
|
|
104
|
+
|
|
105
|
+
found << node.archetype_id if node.is_a?(OpenEHR::AM::Archetype::ConstraintModel::CArchetypeRoot)
|
|
106
|
+
if node.respond_to?(:attributes) && node.attributes
|
|
107
|
+
node.attributes.each { |attribute| archetype_roots(attribute, found) }
|
|
108
|
+
end
|
|
109
|
+
if node.respond_to?(:children) && node.children
|
|
110
|
+
node.children.each { |child| archetype_roots(child, found) }
|
|
111
|
+
end
|
|
112
|
+
found
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def vdfpt
|
|
116
|
+
return if @archetype.internal_references_valid? &&
|
|
117
|
+
@archetype.physical_paths.all? { |path| OpenEHR::Path.valid?(path) }
|
|
118
|
+
|
|
119
|
+
Validation::VDFPT.new(Validation::VDFPT::MESSAGE)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
RULES = %i[varid vardf varon varcn vardt vatdf vacdf vdfai vdfpt].freeze
|
|
123
|
+
private_constant :RULES
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -60,6 +60,19 @@ module OpenEHR
|
|
|
60
60
|
class VDFPT < Base
|
|
61
61
|
MESSAGE = "Any path mentioned in the definition section must be valid syntactically, and a valid path with respect to the hierarchical structure of the definition section."
|
|
62
62
|
end
|
|
63
|
+
|
|
64
|
+
# Raised by ArchetypeValidator#validate_instance for an RM
|
|
65
|
+
# instance that does not conform to an archetype's definition;
|
|
66
|
+
# not one of the VARID..VDFPT archetype-structure rules, since
|
|
67
|
+
# this checks an RM instance against the archetype instead.
|
|
68
|
+
class InstanceNonConformant < Base
|
|
69
|
+
attr_reader :path
|
|
70
|
+
|
|
71
|
+
def initialize(message, path = nil)
|
|
72
|
+
super(message)
|
|
73
|
+
@path = path
|
|
74
|
+
end
|
|
75
|
+
end
|
|
63
76
|
end
|
|
64
77
|
|
|
65
78
|
end
|