openehr 2.0.1 → 2.1.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 +3 -3
- data/lib/openehr/am/archetype/constraint_model.rb +1 -1
- data/lib/openehr/assumed_library_types.rb +20 -17
- data/lib/openehr/parser/adl_grammar.tt +0 -4
- data/lib/openehr/parser/adl_parser.rb +0 -5
- data/lib/openehr/parser/opt_parser.rb +0 -4
- data/lib/openehr/rm/common/generic.rb +2 -2
- data/lib/openehr/rm/common/resource.rb +0 -1
- data/lib/openehr/rm/data_structures/item_structure.rb +0 -1
- data/lib/openehr/rm/data_types/basic.rb +3 -12
- data/lib/openehr/rm/data_types/encapsulated.rb +2 -2
- data/lib/openehr/rm/data_types/quantity/date_time.rb +36 -29
- data/lib/openehr/rm/data_types/quantity.rb +2 -1
- data/lib/openehr/rm/data_types/text.rb +1 -1
- data/lib/openehr/rm/data_types/time_specification.rb +101 -27
- data/lib/openehr/rm/data_types/uri.rb +0 -8
- data/lib/openehr/rm/factory.rb +64 -10
- data/lib/openehr/rm/security.rb +3 -1
- data/lib/openehr/rm/type_name.rb +0 -1
- data/lib/openehr/serializer/adl_serializer.rb +92 -74
- data/lib/openehr/serializer/base.rb +2 -0
- data/lib/openehr/serializer/rm_json_serializer.rb +0 -1
- data/lib/openehr/serializer/xml_serializer.rb +6 -4
- data/lib/openehr/version.rb +1 -1
- metadata +5 -144
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9e728b70dac1326f832dd44e631442ae3e9ed8b3a3c81a2b5300c23e01a9068e
|
|
4
|
+
data.tar.gz: 0003101647c193f7d35d575a3eef1a92a8e34038a849719a0598e34109f92a52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 334d9390f1e59a2a68a812fda1c946ddf3a74504b4234f6363dddee9e42d8763b01d8bbee50fed8c894318c4bec794b4ba743310961e4ba482164ccf9ec660e7
|
|
7
|
+
data.tar.gz: 611283bb569b4bc0672a502d09b6c485db8ca47131dd8393fdb6ac67589bbdfeb305d0a98a628997a6091ffd6dda03d57695560a61308104f96c06f7e95a9c98
|
data/README.rdoc
CHANGED
|
@@ -7,9 +7,9 @@ A Ruby implementation of the openEHR specifications
|
|
|
7
7
|
|
|
8
8
|
= Requirements
|
|
9
9
|
|
|
10
|
-
* Supports
|
|
11
|
-
* Developed with CRuby 4.0.6 on Linux; CI covers 3.
|
|
12
|
-
*
|
|
10
|
+
* Supports the Ruby versions currently maintained upstream by Ruby core: 3.2, 3.4, and 4.0.
|
|
11
|
+
* Developed with CRuby 4.0.6 on Linux; CI covers 3.2, 3.4, and 4.0.
|
|
12
|
+
* Other versions, including 3.1 and 3.3, are not supported.
|
|
13
13
|
|
|
14
14
|
=Description
|
|
15
15
|
|
|
@@ -254,8 +254,8 @@ module OpenEHR
|
|
|
254
254
|
end
|
|
255
255
|
|
|
256
256
|
def to_days
|
|
257
|
-
days = nilthenzero(@year)*TimeDefinitions::NOMINAL_DAYS_IN_YEAR +
|
|
258
|
-
nilthenzero(@month)*TimeDefinitions::NOMINAL_DAYS_IN_MONTH +
|
|
257
|
+
days = (nilthenzero(@year)*TimeDefinitions::NOMINAL_DAYS_IN_YEAR) +
|
|
258
|
+
(nilthenzero(@month)*TimeDefinitions::NOMINAL_DAYS_IN_MONTH) +
|
|
259
259
|
nilthenzero(@day)
|
|
260
260
|
return days
|
|
261
261
|
end
|
|
@@ -406,7 +406,7 @@ module OpenEHR
|
|
|
406
406
|
end
|
|
407
407
|
|
|
408
408
|
def to_second
|
|
409
|
-
second = (nilthenzero(@hour)*60 + nilthenzero(@minute))*60 +
|
|
409
|
+
second = (((nilthenzero(@hour)*60) + nilthenzero(@minute))*60) +
|
|
410
410
|
nilthenzero(@second) +
|
|
411
411
|
nilthenzero(@fractional_second)
|
|
412
412
|
return second
|
|
@@ -472,18 +472,21 @@ module OpenEHR
|
|
|
472
472
|
end
|
|
473
473
|
# A timezone is optional in ISO 8601; its absence does not make an
|
|
474
474
|
# otherwise-valid time invalid.
|
|
475
|
-
unless tz
|
|
476
|
-
|
|
477
|
-
if timezone.hour < 0 or timezone.hour >= HOURS_IN_DAY
|
|
478
|
-
return false
|
|
479
|
-
end
|
|
480
|
-
if timezone.minute < 0 or timezone.minute >= MINUTES_IN_HOUR
|
|
481
|
-
return false
|
|
482
|
-
end
|
|
483
|
-
end
|
|
475
|
+
return false unless valid_timezone_part?(tz)
|
|
476
|
+
|
|
484
477
|
return true
|
|
485
478
|
end
|
|
486
479
|
end
|
|
480
|
+
|
|
481
|
+
def self.valid_timezone_part?(tz)
|
|
482
|
+
return true if tz.nil?
|
|
483
|
+
|
|
484
|
+
timezone = Timezone.new(tz)
|
|
485
|
+
return false if timezone.hour < 0 or timezone.hour >= HOURS_IN_DAY
|
|
486
|
+
return false if timezone.minute < 0 or timezone.minute >= MINUTES_IN_HOUR
|
|
487
|
+
|
|
488
|
+
true
|
|
489
|
+
end
|
|
487
490
|
end # end of ISO8601_TIME
|
|
488
491
|
|
|
489
492
|
module ISO8601DateTimeModule
|
|
@@ -571,7 +574,7 @@ module OpenEHR
|
|
|
571
574
|
|
|
572
575
|
protected
|
|
573
576
|
def magnitude
|
|
574
|
-
return self.to_days*HOURS_IN_DAY*MINUTES_IN_HOUR*SECONDS_IN_MINUTE +
|
|
577
|
+
return (self.to_days*HOURS_IN_DAY*MINUTES_IN_HOUR*SECONDS_IN_MINUTE) +
|
|
575
578
|
self.to_second
|
|
576
579
|
end
|
|
577
580
|
end
|
|
@@ -719,11 +722,11 @@ module OpenEHR
|
|
|
719
722
|
end
|
|
720
723
|
|
|
721
724
|
def to_seconds
|
|
722
|
-
days = nilthenzero(@years)*TimeDefinitions::DAYS_IN_YEAR +
|
|
723
|
-
nilthenzero(@months)*TimeDefinitions::DAYS_IN_MONTH +
|
|
724
|
-
nilthenzero(@weeks)*TimeDefinitions::DAYS_IN_WEEK +
|
|
725
|
+
days = (nilthenzero(@years)*TimeDefinitions::DAYS_IN_YEAR) +
|
|
726
|
+
(nilthenzero(@months)*TimeDefinitions::DAYS_IN_MONTH) +
|
|
727
|
+
(nilthenzero(@weeks)*TimeDefinitions::DAYS_IN_WEEK) +
|
|
725
728
|
nilthenzero(@days)
|
|
726
|
-
seconds_with_fractional = (((days*TimeDefinitions::HOURS_IN_DAY + nilthenzero(@hours))*TimeDefinitions::MINUTES_IN_HOUR)+nilthenzero(@minutes))*TimeDefinitions::SECONDS_IN_MINUTE +
|
|
729
|
+
seconds_with_fractional = (((((days*TimeDefinitions::HOURS_IN_DAY) + nilthenzero(@hours))*TimeDefinitions::MINUTES_IN_HOUR)+nilthenzero(@minutes))*TimeDefinitions::SECONDS_IN_MINUTE) +
|
|
727
730
|
nilthenzero(@seconds) +
|
|
728
731
|
@fractional_second.to_f
|
|
729
732
|
return negative? ? -seconds_with_fractional : seconds_with_fractional
|
|
@@ -3140,10 +3140,6 @@ module OpenEHR
|
|
|
3140
3140
|
[Uu] [Nn] [Ii] [Qq] [Uu] [Ee] space
|
|
3141
3141
|
end
|
|
3142
3142
|
|
|
3143
|
-
rule SYM_INFINITY
|
|
3144
|
-
[Ii] [Nn] [Ff] [Ii] [Nn] [Ii] [Tt] [Yy] space
|
|
3145
|
-
end
|
|
3146
|
-
|
|
3147
3143
|
rule SYM_USE_NODE
|
|
3148
3144
|
[Uu] [Ss] [Ee] '_' [Nn] [Oo] [Dd] [Ee] space
|
|
3149
3145
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'treetop'
|
|
2
2
|
#require 'polyglot'
|
|
3
3
|
|
|
4
|
-
require_relative '../parser'
|
|
5
4
|
#require_relative './adl_grammar'
|
|
6
5
|
|
|
7
6
|
module OpenEHR
|
|
@@ -9,10 +8,6 @@ module OpenEHR
|
|
|
9
8
|
class ADLParser < ::OpenEHR::Parser::Base
|
|
10
9
|
Treetop.load(File.join(File.dirname(__FILE__), 'adl_grammar.tt'))
|
|
11
10
|
|
|
12
|
-
def initialize(filename)
|
|
13
|
-
super
|
|
14
|
-
end
|
|
15
|
-
|
|
16
11
|
def parse(validate: false)
|
|
17
12
|
archetype.tap do |a|
|
|
18
13
|
ArchetypeValidator.new(a).validate! if validate
|
|
@@ -31,10 +31,6 @@ module OpenEHR
|
|
|
31
31
|
'/template/description/other_details'
|
|
32
32
|
DEFINITION_PATH = '/template/definition'
|
|
33
33
|
OCCURRENCE_PATH = '/occurrences'
|
|
34
|
-
|
|
35
|
-
def initialize(filename)
|
|
36
|
-
super(filename)
|
|
37
|
-
end
|
|
38
34
|
|
|
39
35
|
def parse
|
|
40
36
|
@opt = Nokogiri::XML::Document.parse(File.open(@filename))
|
|
@@ -194,8 +194,8 @@ module OpenEHR
|
|
|
194
194
|
end
|
|
195
195
|
|
|
196
196
|
class Attestation < AuditDetails
|
|
197
|
-
attr_reader :reason
|
|
198
|
-
attr_accessor :proof, :attested_view, :is_pending
|
|
197
|
+
attr_reader :reason, :items
|
|
198
|
+
attr_accessor :proof, :attested_view, :is_pending
|
|
199
199
|
|
|
200
200
|
def initialize(args = { })
|
|
201
201
|
super(args)
|
|
@@ -25,20 +25,11 @@ module OpenEHR
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
class DvBoolean < DataValue
|
|
28
|
-
def initialize(args)
|
|
29
|
-
super(args)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
28
|
def value=(value)
|
|
33
29
|
raise ArgumentError, "value must not be nil" if value.nil?
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@value = false
|
|
38
|
-
elsif /TRUE/i =~ value
|
|
39
|
-
@value = true
|
|
40
|
-
elsif /FALSE/i =~ value
|
|
41
|
-
@value = false
|
|
30
|
+
case value
|
|
31
|
+
when true, /TRUE/i then @value = true
|
|
32
|
+
when false, /FALSE/i then @value = false
|
|
42
33
|
end
|
|
43
34
|
end
|
|
44
35
|
|
|
@@ -55,20 +55,8 @@ module OpenEHR
|
|
|
55
55
|
else
|
|
56
56
|
past, future = self, other
|
|
57
57
|
end
|
|
58
|
-
year
|
|
59
|
-
|
|
60
|
-
day = future.day - past.day
|
|
61
|
-
else
|
|
62
|
-
month = -1
|
|
63
|
-
previous_month = future.month - 1
|
|
64
|
-
if previous_month == 0
|
|
65
|
-
previous_month = 12
|
|
66
|
-
end
|
|
67
|
-
day = DAYS_IN_MONTH[previous_month] + future.day - past.day
|
|
68
|
-
if leapyear?(future.year) && (previous_month == 2)
|
|
69
|
-
day += 1
|
|
70
|
-
end
|
|
71
|
-
end
|
|
58
|
+
year = 0
|
|
59
|
+
month, day = day_borrow(past, future)
|
|
72
60
|
week = day / 7
|
|
73
61
|
if (future.month >= past.month)
|
|
74
62
|
month += future.month - past.month
|
|
@@ -82,11 +70,26 @@ module OpenEHR
|
|
|
82
70
|
end
|
|
83
71
|
year += future.year - past.year
|
|
84
72
|
return DvDuration.new(:value =>
|
|
85
|
-
'P' + year.to_s + 'Y' + month.to_s + 'M' +
|
|
73
|
+
'P' + year.to_s + 'Y' + month.to_s + 'M' +
|
|
86
74
|
week.to_s + 'W' + day.to_s + 'D')
|
|
87
75
|
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
# Returns [month_adjustment, day] for diff: when future's
|
|
80
|
+
# day-of-month is behind past's, a month is borrowed from
|
|
81
|
+
# future's calendar to make day non-negative.
|
|
82
|
+
def day_borrow(past, future)
|
|
83
|
+
return [0, future.day - past.day] if future.day >= past.day
|
|
84
|
+
|
|
85
|
+
previous_month = future.month - 1
|
|
86
|
+
previous_month = 12 if previous_month == 0
|
|
87
|
+
day = DAYS_IN_MONTH[previous_month] + future.day - past.day
|
|
88
|
+
day += 1 if leapyear?(future.year) && previous_month == 2
|
|
89
|
+
[-1, day]
|
|
90
|
+
end
|
|
88
91
|
end
|
|
89
|
-
|
|
92
|
+
|
|
90
93
|
class DvTime < DvTemporal
|
|
91
94
|
include OpenEHR::AssumedLibraryTypes::ISO8601TimeModule
|
|
92
95
|
|
|
@@ -104,19 +107,19 @@ module OpenEHR
|
|
|
104
107
|
if @fractional_second.nil? && @second.nil? && @minute.nil?
|
|
105
108
|
return @hour * 60 * 60
|
|
106
109
|
elsif @fractional_second.nil? && @second.nil?
|
|
107
|
-
return @hour * 60 * 60 + @minute * 60
|
|
110
|
+
return (@hour * 60 * 60) + (@minute * 60)
|
|
108
111
|
elsif @fractional_second.nil?
|
|
109
|
-
return @hour * 60 * 60 + @minute * 60 + @second
|
|
112
|
+
return (@hour * 60 * 60) + (@minute * 60) + @second
|
|
110
113
|
else
|
|
111
|
-
return @hour*60*60
|
|
114
|
+
return (@hour*60*60)+(@minute* 60) + @second + @fractional_second
|
|
112
115
|
end
|
|
113
116
|
end
|
|
114
117
|
|
|
115
118
|
def diff(other)
|
|
116
119
|
diff = (other.magnitude - self.magnitude).abs
|
|
117
120
|
hour = (diff / 60 / 60).to_i
|
|
118
|
-
minute = ((diff - hour*60*60)/60).to_i
|
|
119
|
-
second = (diff - hour * 60 *60 - minute * 60).to_i
|
|
121
|
+
minute = ((diff - (hour*60*60))/60).to_i
|
|
122
|
+
second = (diff - (hour * 60 * 60) - (minute * 60)).to_i
|
|
120
123
|
fractional_second = ((diff - diff.to_i)*1000000.0).to_i/1000000.0
|
|
121
124
|
str = 'P0Y0M0W0DT' + hour.to_s + 'H' +
|
|
122
125
|
minute.to_s + 'M' + second.to_s
|
|
@@ -156,11 +159,11 @@ module OpenEHR
|
|
|
156
159
|
minute += @timezone.minute
|
|
157
160
|
end
|
|
158
161
|
end
|
|
159
|
-
seconds = (((@year * 365.24 +
|
|
160
|
-
@month * 30.42 +
|
|
161
|
-
@day) * 24 +
|
|
162
|
-
hour) * 60 +
|
|
163
|
-
minute) * 60 + @second
|
|
162
|
+
seconds = (((((((@year * 365.24) +
|
|
163
|
+
(@month * 30.42) +
|
|
164
|
+
@day) * 24) +
|
|
165
|
+
hour) * 60) +
|
|
166
|
+
minute) * 60) + @second
|
|
164
167
|
if @fractional_second.nil?
|
|
165
168
|
return seconds
|
|
166
169
|
else
|
|
@@ -168,6 +171,9 @@ module OpenEHR
|
|
|
168
171
|
end
|
|
169
172
|
end
|
|
170
173
|
|
|
174
|
+
# rubocop:disable Metrics/AbcSize -- dense calendar arithmetic; refactoring
|
|
175
|
+
# without broader leap-year/borrow coverage (only 1 example exercises this
|
|
176
|
+
# method) is riskier than the lint value gained
|
|
171
177
|
def diff(other)
|
|
172
178
|
if self.magnitude >= other.magnitude
|
|
173
179
|
past, future = other, self
|
|
@@ -183,12 +189,12 @@ module OpenEHR
|
|
|
183
189
|
end
|
|
184
190
|
date_duration = past_date.diff(future_date)
|
|
185
191
|
hour = (time_diff / 60 / 60).to_i
|
|
186
|
-
minute = ((time_diff - hour*60*60)/60).to_i
|
|
187
|
-
second = (time_diff - hour * 60 *60 - minute * 60).to_i
|
|
192
|
+
minute = ((time_diff - (hour*60*60))/60).to_i
|
|
193
|
+
second = (time_diff - (hour * 60 * 60) - (minute * 60)).to_i
|
|
188
194
|
str = date_duration.value + 'T' + hour.to_s + 'H' +
|
|
189
195
|
minute.to_s + 'M' + second.to_s
|
|
190
196
|
if @fractional_second.nil?
|
|
191
|
-
return DvDuration.new(:value => str +'S')
|
|
197
|
+
return DvDuration.new(:value => str + 'S')
|
|
192
198
|
else
|
|
193
199
|
fractional_second =
|
|
194
200
|
((time_diff - time_diff.to_i)*1000000.0).to_i/1000000.0
|
|
@@ -196,6 +202,7 @@ module OpenEHR
|
|
|
196
202
|
fractional_second.to_s[1..-1] + 'S')
|
|
197
203
|
end
|
|
198
204
|
end
|
|
205
|
+
# rubocop:enable Metrics/AbcSize
|
|
199
206
|
|
|
200
207
|
private
|
|
201
208
|
def split_date_time(date_time)
|
|
@@ -11,7 +11,8 @@ module OpenEHR
|
|
|
11
11
|
|
|
12
12
|
class DvOrdered < OpenEHR::RM::DataTypes::Basic::DataValue
|
|
13
13
|
include Comparable
|
|
14
|
-
attr_accessor :normal_range, :
|
|
14
|
+
attr_accessor :normal_range, :normal_status
|
|
15
|
+
attr_reader :other_reference_ranges
|
|
15
16
|
|
|
16
17
|
def initialize(args = {})
|
|
17
18
|
super(args)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# This module is related to the ticket #47
|
|
2
2
|
require_relative 'basic'
|
|
3
|
+
require_relative 'quantity/date_time'
|
|
3
4
|
|
|
4
5
|
module OpenEHR
|
|
5
6
|
module RM
|
|
@@ -8,19 +9,24 @@ module OpenEHR
|
|
|
8
9
|
class DvTimeSpecification < OpenEHR::RM::DataTypes::Basic::DataValue
|
|
9
10
|
attr_reader :value
|
|
10
11
|
|
|
11
|
-
def initialize(value)
|
|
12
|
-
self.value=(value)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
12
|
def value=(value)
|
|
16
13
|
raise ArgumentError, 'value must be not nil' if value.nil?
|
|
14
|
+
unless value.respond_to?(:formalism) && value.respond_to?(:value)
|
|
15
|
+
raise ArgumentError, 'value must be a DV_PARSABLE'
|
|
16
|
+
end
|
|
17
17
|
@value = value
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
def calendar_alignment
|
|
21
21
|
raise NotImplementedError, "calendar_alignment must be implemented"
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
# Legacy misspelling, deliberately kept (pinned by spec). Defined
|
|
25
|
+
# as a delegating method rather than `alias` so a subclass
|
|
26
|
+
# override of calendar_alignment is still reached through it.
|
|
27
|
+
def calender_alignment
|
|
28
|
+
calendar_alignment
|
|
29
|
+
end
|
|
24
30
|
|
|
25
31
|
def event_alignment
|
|
26
32
|
raise NotImplementedError, "event_alignment must be implemented"
|
|
@@ -35,39 +41,107 @@ module OpenEHR
|
|
|
35
41
|
# because I could not obtain HL7 specification related them.
|
|
36
42
|
|
|
37
43
|
class DvGeneralTimeSpecification < DvTimeSpecification
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
super(value)
|
|
41
|
-
end
|
|
44
|
+
FORMALISM = 'HL7:GTS'
|
|
45
|
+
|
|
42
46
|
def value=(value)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def value_valid(value)
|
|
47
|
+
unless value.respond_to?(:formalism) && value.formalism == FORMALISM
|
|
48
|
+
raise ArgumentError, "formalism must be #{FORMALISM}"
|
|
49
|
+
end
|
|
50
|
+
super
|
|
48
51
|
end
|
|
52
|
+
# calendar_alignment / event_alignment / institution_specified
|
|
53
|
+
# remain NotImplementedError (inherited from DvTimeSpecification):
|
|
54
|
+
# deriving them requires parsing the full HL7 GTS set-algebra
|
|
55
|
+
# (union/intersection/exclusion of interval sets), which is
|
|
56
|
+
# explicitly out of scope here.
|
|
49
57
|
end
|
|
50
58
|
|
|
51
59
|
class DvPeriodicTimeSpecification < DvTimeSpecification
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
PIVL_FORMALISM = 'HL7:PIVL'
|
|
61
|
+
EIVL_FORMALISM = 'HL7:EIVL'
|
|
62
|
+
|
|
63
|
+
# Single-literal PIVL: [phase_low(;phase_high)?]/(period)@ALIGN? IST?
|
|
64
|
+
# e.g. "[200004181100;200004181110]/(7d)@DW IST"
|
|
65
|
+
PIVL_PATTERN = %r{\A\[(?<phase_low>\d+)(?:;(?<phase_high>\d+))?\]/
|
|
66
|
+
\((?<period>\d+(?:\.\d+)?)(?<unit>[a-z]+)\)
|
|
67
|
+
(?:@(?<alignment>[A-Z]{2}))?(?<ist>\ ?IST)?\z}x
|
|
68
|
+
|
|
69
|
+
# Single-literal EIVL: EVENT([+-]offset)? e.g. "ACM+10min"
|
|
70
|
+
EIVL_PATTERN = /\A(?<event>[A-Z]+)(?:(?<sign>[+-])(?<offset>\d+(?:\.\d+)?)(?<unit>[a-z]+))?\z/
|
|
71
|
+
|
|
72
|
+
# HL7 CalendarCycle codes (DW=day of week, HD=hour of day, ...)
|
|
73
|
+
CALENDAR_CYCLE_CODES = %w[CY MY CM CW WY DM CD DY DW HD CH NH CN SN CS].freeze
|
|
74
|
+
# HL7 TimingEvent codes (HS=bedtime, ACM=before breakfast, ...)
|
|
75
|
+
TIMING_EVENT_CODES = %w[HS WAKE C CM CD CV AC ACM ACD ACV PC PCM PCD PCV].freeze
|
|
76
|
+
# HL7 physical-quantity time units -> ISO8601 duration templates
|
|
77
|
+
PERIOD_UNIT_TO_ISO8601 = { 's' => 'PT%sS', 'min' => 'PT%sM', 'h' => 'PT%sH',
|
|
78
|
+
'd' => 'P%sD', 'wk' => 'P%sW', 'mo' => 'P%sM',
|
|
79
|
+
'a' => 'P%sY' }.freeze
|
|
80
|
+
|
|
81
|
+
attr_reader :period, :calendar_alignment, :event_alignment
|
|
82
|
+
|
|
57
83
|
def value=(value)
|
|
58
|
-
unless value.
|
|
59
|
-
|
|
84
|
+
unless value.respond_to?(:formalism) &&
|
|
85
|
+
[PIVL_FORMALISM, EIVL_FORMALISM].include?(value.formalism)
|
|
86
|
+
raise ArgumentError, "formalism must be #{PIVL_FORMALISM} or #{EIVL_FORMALISM}"
|
|
87
|
+
end
|
|
88
|
+
if value.formalism == PIVL_FORMALISM
|
|
89
|
+
parse_pivl(value.value)
|
|
90
|
+
else
|
|
91
|
+
parse_eivl(value.value)
|
|
60
92
|
end
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
93
|
+
super
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def institution_specified
|
|
97
|
+
@institution_specified
|
|
98
|
+
end
|
|
99
|
+
alias institution_specified? institution_specified
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def parse_pivl(raw)
|
|
104
|
+
match = PIVL_PATTERN.match(raw)
|
|
105
|
+
raise ArgumentError, 'value does not match HL7:PIVL syntax' unless match
|
|
106
|
+
|
|
107
|
+
unit = match[:unit]
|
|
108
|
+
unless PERIOD_UNIT_TO_ISO8601.key?(unit)
|
|
109
|
+
raise ArgumentError, "unknown HL7 PIVL period unit #{unit.inspect}"
|
|
64
110
|
end
|
|
65
|
-
|
|
111
|
+
|
|
112
|
+
alignment = match[:alignment]
|
|
113
|
+
if alignment && !CALENDAR_CYCLE_CODES.include?(alignment)
|
|
114
|
+
raise ArgumentError, "unknown HL7 CalendarCycle code #{alignment.inspect}"
|
|
66
115
|
end
|
|
116
|
+
|
|
117
|
+
@period = DataTypes::Quantity::DateTime::DvDuration.new(:value => period_from(match[:period], unit))
|
|
118
|
+
@calendar_alignment = alignment
|
|
119
|
+
@event_alignment = nil
|
|
120
|
+
@institution_specified = !match[:ist].nil?
|
|
67
121
|
end
|
|
68
122
|
|
|
69
|
-
def
|
|
123
|
+
def parse_eivl(raw)
|
|
124
|
+
match = EIVL_PATTERN.match(raw)
|
|
125
|
+
raise ArgumentError, 'value does not match HL7:EIVL syntax' unless match
|
|
126
|
+
|
|
127
|
+
event = match[:event]
|
|
128
|
+
unless TIMING_EVENT_CODES.include?(event)
|
|
129
|
+
raise ArgumentError, "unknown HL7 TimingEvent code #{event.inspect}"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
unit = match[:unit]
|
|
133
|
+
if unit && !PERIOD_UNIT_TO_ISO8601.key?(unit)
|
|
134
|
+
raise ArgumentError, "unknown HL7 EIVL offset unit #{unit.inspect}"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
@event_alignment = event
|
|
138
|
+
@calendar_alignment = nil
|
|
139
|
+
@period = nil
|
|
140
|
+
@institution_specified = false
|
|
141
|
+
end
|
|
70
142
|
|
|
143
|
+
def period_from(quantity, unit)
|
|
144
|
+
format(PERIOD_UNIT_TO_ISO8601[unit], quantity)
|
|
71
145
|
end
|
|
72
146
|
end
|
|
73
147
|
end
|
|
@@ -31,10 +31,6 @@ module OpenEHR
|
|
|
31
31
|
module DataTypes
|
|
32
32
|
module URI
|
|
33
33
|
class DvUri < OpenEHR::RM::DataTypes::Basic::DataValue
|
|
34
|
-
def initialize(args = {})
|
|
35
|
-
self.value = args[:value]
|
|
36
|
-
end
|
|
37
|
-
|
|
38
34
|
def value
|
|
39
35
|
@value
|
|
40
36
|
end
|
|
@@ -69,10 +65,6 @@ module OpenEHR
|
|
|
69
65
|
end
|
|
70
66
|
|
|
71
67
|
class DvEhrUri < DvUri
|
|
72
|
-
def initialize(value)
|
|
73
|
-
super
|
|
74
|
-
end
|
|
75
|
-
|
|
76
68
|
def value=(value)
|
|
77
69
|
raise ArgumentError, "scheme must be ehr" if !(value =~ /^ehr/i)
|
|
78
70
|
parse(value)
|
data/lib/openehr/rm/factory.rb
CHANGED
|
@@ -3,6 +3,23 @@ require 'active_support/inflector'
|
|
|
3
3
|
module OpenEHR
|
|
4
4
|
module RM
|
|
5
5
|
class Factory
|
|
6
|
+
# Attribute keys whose openEHR RM type is always exactly one
|
|
7
|
+
# concrete class (never actually polymorphic), so a real-world
|
|
8
|
+
# canonical-JSON serializer may legally omit _type for them - e.g.
|
|
9
|
+
# openehr-rails's own CanonicalSerializer does. Consulted only as
|
|
10
|
+
# a fallback when _type is absent; see convert_hash below.
|
|
11
|
+
#
|
|
12
|
+
# Deliberately does NOT include attributes whose declared type is
|
|
13
|
+
# abstract (e.g. LOCATABLE.uid : UID_BASED_ID, which could be an
|
|
14
|
+
# ObjectVersionID or a HierObjectID; OBJECT_REF.id : OBJECT_ID,
|
|
15
|
+
# similarly abstract) - guessing there would silently build the
|
|
16
|
+
# wrong object instead of failing loudly.
|
|
17
|
+
NON_POLYMORPHIC_TYPE_FOR_KEY = {
|
|
18
|
+
archetype_id: 'ARCHETYPE_ID',
|
|
19
|
+
template_id: 'TEMPLATE_ID',
|
|
20
|
+
terminology_id: 'TERMINOLOGY_ID'
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
6
23
|
def initialize(cobject)
|
|
7
24
|
@cobject = cobject
|
|
8
25
|
end
|
|
@@ -21,30 +38,49 @@ module OpenEHR
|
|
|
21
38
|
param.each_with_object({}) do |item, parameters|
|
|
22
39
|
key = item.shift
|
|
23
40
|
value = item.shift
|
|
24
|
-
parameters[key] = convert_value(value)
|
|
41
|
+
parameters[key] = convert_value(key, value)
|
|
25
42
|
end
|
|
26
43
|
end
|
|
27
44
|
|
|
28
45
|
private
|
|
29
46
|
|
|
30
47
|
# A canonical-JSON attribute value is either a typed sub-object
|
|
31
|
-
# (Hash with _type
|
|
48
|
+
# (Hash, normally with _type - see convert_hash for the
|
|
49
|
+
# _type-less case), a List<...> of those (Array - openEHR RM
|
|
32
50
|
# multiplicity 0..*/1..* attributes, e.g. COMPOSITION.content,
|
|
33
51
|
# HISTORY.events, ITEM_TREE.items), or a plain value (String,
|
|
34
|
-
# Numeric, ...). Arrays recurse
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
|
|
52
|
+
# Numeric, ...). Arrays recurse (passing the same attribute key
|
|
53
|
+
# down, since none of NON_POLYMORPHIC_TYPE_FOR_KEY's keys are
|
|
54
|
+
# ever Array-valued) so nested multiplicities (e.g. a CLUSTER's
|
|
55
|
+
# own items) convert too; non-Hash array elements (there is no
|
|
56
|
+
# List<String>/List<Numeric> attribute in this RM, but doubles/
|
|
57
|
+
# pre-built objects show up in specs) pass through unchanged.
|
|
58
|
+
def convert_value(key, value)
|
|
40
59
|
if value.instance_of? Hash
|
|
41
|
-
|
|
60
|
+
convert_hash(key, value)
|
|
42
61
|
elsif value.instance_of? Array
|
|
43
|
-
value.map { |element| convert_value(element) }
|
|
62
|
+
value.map { |element| convert_value(key, element) }
|
|
44
63
|
else
|
|
45
64
|
value
|
|
46
65
|
end
|
|
47
66
|
end
|
|
67
|
+
|
|
68
|
+
# _type is how a Hash normally says what RM class to become;
|
|
69
|
+
# when it's absent, fall back to NON_POLYMORPHIC_TYPE_FOR_KEY.
|
|
70
|
+
# Anything else raises with the attribute name rather than
|
|
71
|
+
# silently guessing or passing a raw Hash through where an RM
|
|
72
|
+
# object is expected (downstream code - e.g. Locatable#concept
|
|
73
|
+
# calling archetype_id.concept_name - would then fail far from
|
|
74
|
+
# the real cause).
|
|
75
|
+
def convert_hash(key, value)
|
|
76
|
+
type = value[:_type] || NON_POLYMORPHIC_TYPE_FOR_KEY[key]
|
|
77
|
+
unless type
|
|
78
|
+
raise ArgumentError,
|
|
79
|
+
"cannot determine the RM type for attribute #{key.inspect}: its Hash value has no _type key " \
|
|
80
|
+
"and #{key.inspect} is not a known non-polymorphic attribute (keys: #{value.keys.inspect})"
|
|
81
|
+
end
|
|
82
|
+
Factory.create(type, **value)
|
|
83
|
+
end
|
|
48
84
|
end
|
|
49
85
|
|
|
50
86
|
def build
|
|
@@ -241,6 +277,24 @@ module OpenEHR
|
|
|
241
277
|
end
|
|
242
278
|
end
|
|
243
279
|
|
|
280
|
+
class DvTimeSpecificationFactory
|
|
281
|
+
def self.create(param)
|
|
282
|
+
DataTypes::TimeSpecification::DvTimeSpecification.new(param)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
class DvGeneralTimeSpecificationFactory
|
|
287
|
+
def self.create(param)
|
|
288
|
+
DataTypes::TimeSpecification::DvGeneralTimeSpecification.new(param)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
class DvPeriodicTimeSpecificationFactory
|
|
293
|
+
def self.create(param)
|
|
294
|
+
DataTypes::TimeSpecification::DvPeriodicTimeSpecification.new(param)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
244
298
|
class ObservationFactory
|
|
245
299
|
def self.create(param)
|
|
246
300
|
Composition::Content::Entry::Observation.new(param)
|
data/lib/openehr/rm/security.rb
CHANGED
data/lib/openehr/rm/type_name.rb
CHANGED
|
@@ -1,66 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'base'
|
|
2
4
|
|
|
3
5
|
module OpenEHR
|
|
4
6
|
module Serializer
|
|
5
7
|
class ADLSerializer < BaseSerializer
|
|
6
8
|
def header
|
|
7
|
-
hd = 'archetype'
|
|
9
|
+
hd = +'archetype'
|
|
8
10
|
unless @archetype.adl_version.nil?
|
|
9
11
|
hd << " (adl_version = #{@archetype.adl_version})"
|
|
10
12
|
end
|
|
11
|
-
hd << NL+INDENT + "#{@archetype.archetype_id.value}"+NL*2
|
|
12
|
-
hd << 'concept'+NL+ INDENT+"[#{@archetype.concept}]"+NL
|
|
13
|
-
hd << NL+'language'+NL+INDENT+'original_language = <['+
|
|
13
|
+
hd << (NL+INDENT + "#{@archetype.archetype_id.value}"+(NL*2))
|
|
14
|
+
hd << ('concept'+NL+ INDENT+"[#{@archetype.concept}]"+NL)
|
|
15
|
+
hd << (NL+'language'+NL+INDENT+'original_language = <['+
|
|
14
16
|
@archetype.original_language.terminology_id.value+'::'+
|
|
15
|
-
@archetype.original_language.code_string+']>'+NL
|
|
17
|
+
@archetype.original_language.code_string+']>'+NL)
|
|
16
18
|
return hd
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def description
|
|
20
|
-
desc = ''
|
|
22
|
+
desc = +''
|
|
21
23
|
if @archetype.description
|
|
22
24
|
ad = @archetype.description
|
|
23
|
-
desc << 'description' + NL
|
|
24
|
-
desc << INDENT + 'original_author = <' + NL
|
|
25
|
+
desc << ('description' + NL)
|
|
26
|
+
desc << (INDENT + 'original_author = <' + NL)
|
|
25
27
|
ad.original_author.each do |k,v|
|
|
26
|
-
desc << INDENT+INDENT+'["'+k+'"] = <"'+v+'">'+NL
|
|
28
|
+
desc << (INDENT+INDENT+'["'+k+'"] = <"'+v+'">'+NL)
|
|
27
29
|
end
|
|
28
|
-
desc << INDENT+'>'+NL
|
|
29
|
-
desc << INDENT+'lifecycle_state = <"'+ad.lifecycle_state+'">'+NL
|
|
30
|
-
desc << INDENT+'details = <'+NL
|
|
30
|
+
desc << (INDENT+'>'+NL)
|
|
31
|
+
desc << (INDENT+'lifecycle_state = <"'+ad.lifecycle_state+'">'+NL)
|
|
32
|
+
desc << (INDENT+'details = <'+NL)
|
|
31
33
|
ad.details.each do |lang,item|
|
|
32
|
-
desc <<
|
|
33
|
-
desc << INDENT*3+'language = <['+
|
|
34
|
-
item.language.terminology_id.value+'::'+
|
|
35
|
-
item.language.code_string+']>'+NL
|
|
36
|
-
desc << INDENT*3+'purpose = <"'+item.purpose+'">'+NL
|
|
37
|
-
if item.keywords then
|
|
38
|
-
desc << INDENT*3+'keywords = <'
|
|
39
|
-
item.keywords.each do |word|
|
|
40
|
-
desc << '"'+word+'",'
|
|
41
|
-
end
|
|
42
|
-
desc.chop! << '>'+NL
|
|
43
|
-
end
|
|
44
|
-
desc << INDENT*3+'use = <"'+item.use+'">'+NL if item.use
|
|
45
|
-
desc << INDENT*3+'misuse = <"'+item.misuse+'">'+NL if item.misuse
|
|
46
|
-
desc << INDENT*3+'copyright = <"'+item.copyright+'">'+NL if item.copyright
|
|
47
|
-
if item.original_resource_uri
|
|
48
|
-
desc << INDENT*3 + 'original_resource_uri = <'
|
|
49
|
-
item.original_resource_uri.each do |k,v|
|
|
50
|
-
desc << INDENT*4+'["'+k+'"] = <"'+v+'">'+NL
|
|
51
|
-
end
|
|
52
|
-
desc << INDENT*3+'>'+NL
|
|
53
|
-
end
|
|
54
|
-
if item.other_details
|
|
55
|
-
desc << INDENT*3 + 'other_details = <'
|
|
56
|
-
item.other_details.each do |k,v|
|
|
57
|
-
desc << INDENT*4+'["'+k+'"] = <"'+v+'">'+NL
|
|
58
|
-
end
|
|
59
|
-
desc << INDENT*3+'>'+NL
|
|
60
|
-
end
|
|
61
|
-
desc << INDENT*2+'>'+NL
|
|
34
|
+
desc << description_details_item(lang, item)
|
|
62
35
|
end
|
|
63
|
-
desc << INDENT+'>'+NL
|
|
36
|
+
desc << (INDENT+'>'+NL)
|
|
64
37
|
end
|
|
65
38
|
return desc
|
|
66
39
|
end
|
|
@@ -74,21 +47,7 @@ module OpenEHR
|
|
|
74
47
|
ontology = 'ontology'+NL
|
|
75
48
|
ontology << string_list_line('languages_available', ao.languages_available)
|
|
76
49
|
ontology << string_list_line('terminologies_available', ao.terminologies_available)
|
|
77
|
-
ontology <<
|
|
78
|
-
ao.term_definitions.each do |lang, items|
|
|
79
|
-
ontology << INDENT*2 + "[\"#{lang}\"] = <" + NL
|
|
80
|
-
ontology << INDENT*3 + 'items = <' + NL
|
|
81
|
-
items.each do |code, item|
|
|
82
|
-
ontology << INDENT*4 + "[\"#{code}\"] = <" + NL
|
|
83
|
-
item.items.each do |name, desc|
|
|
84
|
-
ontology << INDENT*5 + "#{name} = <\"#{desc}\">" +NL
|
|
85
|
-
end
|
|
86
|
-
ontology << INDENT*4 + '>'+NL
|
|
87
|
-
end
|
|
88
|
-
ontology << INDENT*3 + '>' + NL
|
|
89
|
-
ontology << INDENT*2 + '>' + NL
|
|
90
|
-
end
|
|
91
|
-
ontology << INDENT + '>' + NL
|
|
50
|
+
ontology << term_definitions_block(ao.term_definitions)
|
|
92
51
|
ontology << term_bindings_block(ao.term_bindings)
|
|
93
52
|
ontology
|
|
94
53
|
end
|
|
@@ -109,21 +68,80 @@ module OpenEHR
|
|
|
109
68
|
INDENT + "#{keyword} = <" + values.map { |v| "\"#{v}\"" }.join(', ') + '>' + NL
|
|
110
69
|
end
|
|
111
70
|
|
|
71
|
+
def description_details_item(lang, item)
|
|
72
|
+
block = (INDENT*2)+'["'+lang+'"] = <'+NL
|
|
73
|
+
block << description_language_line(item.language)
|
|
74
|
+
block << ((INDENT*3)+'purpose = <"'+item.purpose+'">'+NL)
|
|
75
|
+
block << description_keywords_line(item) if item.keywords
|
|
76
|
+
block << optional_field_line('use', item.use)
|
|
77
|
+
block << optional_field_line('misuse', item.misuse)
|
|
78
|
+
block << optional_field_line('copyright', item.copyright)
|
|
79
|
+
block << keyed_map_block('original_resource_uri', item.original_resource_uri) if item.original_resource_uri
|
|
80
|
+
block << keyed_map_block('other_details', item.other_details) if item.other_details
|
|
81
|
+
block << ((INDENT*2)+'>'+NL)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def description_language_line(language)
|
|
85
|
+
(INDENT*3)+'language = <['+
|
|
86
|
+
language.terminology_id.value+'::'+
|
|
87
|
+
language.code_string+']>'+NL
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def optional_field_line(keyword, value)
|
|
91
|
+
return '' if value.nil?
|
|
92
|
+
|
|
93
|
+
(INDENT*3)+"#{keyword} = <\"#{value}\">"+NL
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def description_keywords_line(item)
|
|
97
|
+
block = (INDENT*3)+'keywords = <'
|
|
98
|
+
item.keywords.each do |word|
|
|
99
|
+
block << ('"'+word+'",')
|
|
100
|
+
end
|
|
101
|
+
block.chop! << ('>'+NL)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def keyed_map_block(keyword, hash)
|
|
105
|
+
block = (INDENT*3) + "#{keyword} = <"
|
|
106
|
+
hash.each do |k,v|
|
|
107
|
+
block << ((INDENT*4)+'["'+k+'"] = <"'+v+'">'+NL)
|
|
108
|
+
end
|
|
109
|
+
block << ((INDENT*3)+'>'+NL)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def term_definitions_block(term_definitions)
|
|
113
|
+
block = INDENT + 'term_definitions = <' + NL
|
|
114
|
+
term_definitions.each do |lang, items|
|
|
115
|
+
block << ((INDENT*2) + "[\"#{lang}\"] = <" + NL)
|
|
116
|
+
block << ((INDENT*3) + 'items = <' + NL)
|
|
117
|
+
items.each do |code, item|
|
|
118
|
+
block << ((INDENT*4) + "[\"#{code}\"] = <" + NL)
|
|
119
|
+
item.items.each do |name, desc|
|
|
120
|
+
block << ((INDENT*5) + "#{name} = <\"#{desc}\">" + NL)
|
|
121
|
+
end
|
|
122
|
+
block << ((INDENT*4) + '>'+NL)
|
|
123
|
+
end
|
|
124
|
+
block << ((INDENT*3) + '>' + NL)
|
|
125
|
+
block << ((INDENT*2) + '>' + NL)
|
|
126
|
+
end
|
|
127
|
+
block << (INDENT + '>' + NL)
|
|
128
|
+
end
|
|
129
|
+
|
|
112
130
|
def term_bindings_block(term_bindings)
|
|
113
131
|
return '' if term_bindings.nil? || term_bindings.empty?
|
|
114
132
|
|
|
115
133
|
block = INDENT + 'term_bindings = <' + NL
|
|
116
134
|
term_bindings.each do |terminology, codes|
|
|
117
|
-
block << INDENT*2 + "[\"#{terminology}\"] = <" + NL
|
|
118
|
-
block << INDENT*3 + 'items = <' + NL
|
|
135
|
+
block << ((INDENT*2) + "[\"#{terminology}\"] = <" + NL)
|
|
136
|
+
block << ((INDENT*3) + 'items = <' + NL)
|
|
119
137
|
codes.each do |code, bindings|
|
|
120
138
|
code_phrase = Array(bindings).first
|
|
121
|
-
block << INDENT*4 + "[\"#{code}\"] = <[#{code_phrase.terminology_id.value}::#{code_phrase.code_string}]>" + NL
|
|
139
|
+
block << ((INDENT*4) + "[\"#{code}\"] = <[#{code_phrase.terminology_id.value}::#{code_phrase.code_string}]>" + NL)
|
|
122
140
|
end
|
|
123
|
-
block << INDENT*3 + '>' + NL
|
|
124
|
-
block << INDENT*2 + '>' + NL
|
|
141
|
+
block << ((INDENT*3) + '>' + NL)
|
|
142
|
+
block << ((INDENT*2) + '>' + NL)
|
|
125
143
|
end
|
|
126
|
-
block << INDENT + '>' + NL
|
|
144
|
+
block << (INDENT + '>' + NL)
|
|
127
145
|
end
|
|
128
146
|
|
|
129
147
|
# Recursive cADL emitter for a single C_OBJECT node, dispatching
|
|
@@ -151,12 +169,12 @@ module OpenEHR
|
|
|
151
169
|
head + ' matches {*}' + NL
|
|
152
170
|
else
|
|
153
171
|
body = node.attributes.map { |a| emit_c_attribute(a, depth + 1) }.join
|
|
154
|
-
head + ' matches {' + NL + body + INDENT*depth + '}' + NL
|
|
172
|
+
head + ' matches {' + NL + body + (INDENT*depth) + '}' + NL
|
|
155
173
|
end
|
|
156
174
|
end
|
|
157
175
|
|
|
158
176
|
def complex_object_head(node, depth)
|
|
159
|
-
head = INDENT*depth + node.rm_type_name
|
|
177
|
+
head = (INDENT*depth) + node.rm_type_name
|
|
160
178
|
head += "[#{node.node_id}]" if node.node_id
|
|
161
179
|
head += " occurrences matches {#{interval_literal(node.occurrences)}}" if show_interval?(node.occurrences)
|
|
162
180
|
head
|
|
@@ -177,12 +195,12 @@ module OpenEHR
|
|
|
177
195
|
head + " matches {#{inline_body(children.first)}}" + NL
|
|
178
196
|
else
|
|
179
197
|
body = children.map { |c| emit_c_object(c, depth + 1) }.join
|
|
180
|
-
head + ' matches {' + NL + body + INDENT*depth + '}' + NL
|
|
198
|
+
head + ' matches {' + NL + body + (INDENT*depth) + '}' + NL
|
|
181
199
|
end
|
|
182
200
|
end
|
|
183
201
|
|
|
184
202
|
def attribute_head(attribute, depth)
|
|
185
|
-
head = INDENT*depth + attribute.rm_attribute_name
|
|
203
|
+
head = (INDENT*depth) + attribute.rm_attribute_name
|
|
186
204
|
head += " existence matches {#{interval_literal(attribute.existence)}}" if show_interval?(attribute.existence)
|
|
187
205
|
head += " cardinality matches {#{cardinality_literal(attribute.cardinality)}}" if attribute.is_a?(CMultipleAttribute)
|
|
188
206
|
head
|
|
@@ -208,30 +226,30 @@ module OpenEHR
|
|
|
208
226
|
end
|
|
209
227
|
|
|
210
228
|
def emit_archetype_slot(node, depth)
|
|
211
|
-
head = INDENT*depth + 'allow_archetype ' + node.rm_type_name
|
|
229
|
+
head = (INDENT*depth) + 'allow_archetype ' + node.rm_type_name
|
|
212
230
|
head += "[#{node.node_id}]" if node.node_id
|
|
213
231
|
head += " occurrences matches {#{interval_literal(node.occurrences)}}" if show_interval?(node.occurrences)
|
|
214
232
|
lines = [head + ' matches {' + NL]
|
|
215
233
|
lines << assertion_block(node.includes, 'include', depth + 1)
|
|
216
234
|
lines << assertion_block(node.excludes, 'exclude', depth + 1)
|
|
217
|
-
lines << INDENT*depth + '}' + NL
|
|
235
|
+
lines << ((INDENT*depth) + '}' + NL)
|
|
218
236
|
lines.join
|
|
219
237
|
end
|
|
220
238
|
|
|
221
239
|
def assertion_block(assertions, keyword, depth)
|
|
222
240
|
return '' if assertions.nil?
|
|
223
241
|
|
|
224
|
-
lines = [INDENT*depth + keyword + NL]
|
|
225
|
-
assertions.each { |a| lines << INDENT*(depth+1) + a.string_expression + NL }
|
|
242
|
+
lines = [(INDENT*depth) + keyword + NL]
|
|
243
|
+
assertions.each { |a| lines << ((INDENT*(depth+1)) + a.string_expression + NL) }
|
|
226
244
|
lines.join
|
|
227
245
|
end
|
|
228
246
|
|
|
229
247
|
def emit_internal_ref(node, depth)
|
|
230
|
-
INDENT*depth + "use_node #{node.rm_type_name} #{node.target_path}" + NL
|
|
248
|
+
(INDENT*depth) + "use_node #{node.rm_type_name} #{node.target_path}" + NL
|
|
231
249
|
end
|
|
232
250
|
|
|
233
251
|
def emit_constraint_ref(node, depth)
|
|
234
|
-
INDENT*depth + "[#{node.reference}]" + NL
|
|
252
|
+
(INDENT*depth) + "[#{node.reference}]" + NL
|
|
235
253
|
end
|
|
236
254
|
|
|
237
255
|
def primitive_body(item)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'rexml/document'
|
|
2
4
|
require 'builder'
|
|
3
5
|
require_relative 'base'
|
|
@@ -6,7 +8,7 @@ module OpenEHR
|
|
|
6
8
|
module Serializer
|
|
7
9
|
class XMLSerializer < BaseSerializer
|
|
8
10
|
def header
|
|
9
|
-
header = ''
|
|
11
|
+
header = +''
|
|
10
12
|
xml = Builder::XmlMarkup.new(:indent => 2, :target => header)
|
|
11
13
|
xml.archetype_id do
|
|
12
14
|
xml.value @archetype.archetype_id.value
|
|
@@ -22,7 +24,7 @@ module OpenEHR
|
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def description
|
|
25
|
-
desc = ''
|
|
27
|
+
desc = +''
|
|
26
28
|
xml = Builder::XmlMarkup.new(:indent => 2, :target => desc)
|
|
27
29
|
ad = @archetype.description
|
|
28
30
|
if ad
|
|
@@ -66,7 +68,7 @@ module OpenEHR
|
|
|
66
68
|
end
|
|
67
69
|
|
|
68
70
|
def definition
|
|
69
|
-
definition = ''
|
|
71
|
+
definition = +''
|
|
70
72
|
xml = Builder::XmlMarkup.new(:indent => 2, :target => definition)
|
|
71
73
|
xml.definition do
|
|
72
74
|
emit_c_object_body(xml, @archetype.definition)
|
|
@@ -75,7 +77,7 @@ module OpenEHR
|
|
|
75
77
|
end
|
|
76
78
|
|
|
77
79
|
def ontology
|
|
78
|
-
ontology = ''
|
|
80
|
+
ontology = +''
|
|
79
81
|
ao = @archetype.ontology
|
|
80
82
|
xml = Builder::XmlMarkup.new(:indent => 2, :target => ontology)
|
|
81
83
|
xml.ontology do
|
data/lib/openehr/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openehr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shinji KOBAYASHI
|
|
@@ -139,146 +139,6 @@ dependencies:
|
|
|
139
139
|
- - ">="
|
|
140
140
|
- !ruby/object:Gem::Version
|
|
141
141
|
version: '0'
|
|
142
|
-
- !ruby/object:Gem::Dependency
|
|
143
|
-
name: rspec
|
|
144
|
-
requirement: !ruby/object:Gem::Requirement
|
|
145
|
-
requirements:
|
|
146
|
-
- - ">="
|
|
147
|
-
- !ruby/object:Gem::Version
|
|
148
|
-
version: '0'
|
|
149
|
-
type: :development
|
|
150
|
-
prerelease: false
|
|
151
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
152
|
-
requirements:
|
|
153
|
-
- - ">="
|
|
154
|
-
- !ruby/object:Gem::Version
|
|
155
|
-
version: '0'
|
|
156
|
-
- !ruby/object:Gem::Dependency
|
|
157
|
-
name: rspec-expectations
|
|
158
|
-
requirement: !ruby/object:Gem::Requirement
|
|
159
|
-
requirements:
|
|
160
|
-
- - ">="
|
|
161
|
-
- !ruby/object:Gem::Version
|
|
162
|
-
version: '0'
|
|
163
|
-
type: :development
|
|
164
|
-
prerelease: false
|
|
165
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
166
|
-
requirements:
|
|
167
|
-
- - ">="
|
|
168
|
-
- !ruby/object:Gem::Version
|
|
169
|
-
version: '0'
|
|
170
|
-
- !ruby/object:Gem::Dependency
|
|
171
|
-
name: rspec-collection_matchers
|
|
172
|
-
requirement: !ruby/object:Gem::Requirement
|
|
173
|
-
requirements:
|
|
174
|
-
- - ">="
|
|
175
|
-
- !ruby/object:Gem::Version
|
|
176
|
-
version: '0'
|
|
177
|
-
type: :development
|
|
178
|
-
prerelease: false
|
|
179
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
180
|
-
requirements:
|
|
181
|
-
- - ">="
|
|
182
|
-
- !ruby/object:Gem::Version
|
|
183
|
-
version: '0'
|
|
184
|
-
- !ruby/object:Gem::Dependency
|
|
185
|
-
name: guard
|
|
186
|
-
requirement: !ruby/object:Gem::Requirement
|
|
187
|
-
requirements:
|
|
188
|
-
- - ">="
|
|
189
|
-
- !ruby/object:Gem::Version
|
|
190
|
-
version: '0'
|
|
191
|
-
type: :development
|
|
192
|
-
prerelease: false
|
|
193
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
194
|
-
requirements:
|
|
195
|
-
- - ">="
|
|
196
|
-
- !ruby/object:Gem::Version
|
|
197
|
-
version: '0'
|
|
198
|
-
- !ruby/object:Gem::Dependency
|
|
199
|
-
name: guard-rspec
|
|
200
|
-
requirement: !ruby/object:Gem::Requirement
|
|
201
|
-
requirements:
|
|
202
|
-
- - ">="
|
|
203
|
-
- !ruby/object:Gem::Version
|
|
204
|
-
version: '0'
|
|
205
|
-
type: :development
|
|
206
|
-
prerelease: false
|
|
207
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
208
|
-
requirements:
|
|
209
|
-
- - ">="
|
|
210
|
-
- !ruby/object:Gem::Version
|
|
211
|
-
version: '0'
|
|
212
|
-
- !ruby/object:Gem::Dependency
|
|
213
|
-
name: simplecov
|
|
214
|
-
requirement: !ruby/object:Gem::Requirement
|
|
215
|
-
requirements:
|
|
216
|
-
- - ">="
|
|
217
|
-
- !ruby/object:Gem::Version
|
|
218
|
-
version: '0'
|
|
219
|
-
type: :development
|
|
220
|
-
prerelease: false
|
|
221
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
222
|
-
requirements:
|
|
223
|
-
- - ">="
|
|
224
|
-
- !ruby/object:Gem::Version
|
|
225
|
-
version: '0'
|
|
226
|
-
- !ruby/object:Gem::Dependency
|
|
227
|
-
name: libnotify
|
|
228
|
-
requirement: !ruby/object:Gem::Requirement
|
|
229
|
-
requirements:
|
|
230
|
-
- - ">="
|
|
231
|
-
- !ruby/object:Gem::Version
|
|
232
|
-
version: '0'
|
|
233
|
-
type: :development
|
|
234
|
-
prerelease: false
|
|
235
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
236
|
-
requirements:
|
|
237
|
-
- - ">="
|
|
238
|
-
- !ruby/object:Gem::Version
|
|
239
|
-
version: '0'
|
|
240
|
-
- !ruby/object:Gem::Dependency
|
|
241
|
-
name: rubocop
|
|
242
|
-
requirement: !ruby/object:Gem::Requirement
|
|
243
|
-
requirements:
|
|
244
|
-
- - ">="
|
|
245
|
-
- !ruby/object:Gem::Version
|
|
246
|
-
version: '0'
|
|
247
|
-
type: :development
|
|
248
|
-
prerelease: false
|
|
249
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
250
|
-
requirements:
|
|
251
|
-
- - ">="
|
|
252
|
-
- !ruby/object:Gem::Version
|
|
253
|
-
version: '0'
|
|
254
|
-
- !ruby/object:Gem::Dependency
|
|
255
|
-
name: meowcop
|
|
256
|
-
requirement: !ruby/object:Gem::Requirement
|
|
257
|
-
requirements:
|
|
258
|
-
- - ">="
|
|
259
|
-
- !ruby/object:Gem::Version
|
|
260
|
-
version: '0'
|
|
261
|
-
type: :development
|
|
262
|
-
prerelease: false
|
|
263
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
264
|
-
requirements:
|
|
265
|
-
- - ">="
|
|
266
|
-
- !ruby/object:Gem::Version
|
|
267
|
-
version: '0'
|
|
268
|
-
- !ruby/object:Gem::Dependency
|
|
269
|
-
name: better_errors
|
|
270
|
-
requirement: !ruby/object:Gem::Requirement
|
|
271
|
-
requirements:
|
|
272
|
-
- - ">="
|
|
273
|
-
- !ruby/object:Gem::Version
|
|
274
|
-
version: '0'
|
|
275
|
-
type: :development
|
|
276
|
-
prerelease: false
|
|
277
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
278
|
-
requirements:
|
|
279
|
-
- - ">="
|
|
280
|
-
- !ruby/object:Gem::Version
|
|
281
|
-
version: '0'
|
|
282
142
|
description: This project is an implementation of the openEHR specification on Ruby.
|
|
283
143
|
email: skoba@moss.gr.jp
|
|
284
144
|
executables: []
|
|
@@ -373,7 +233,8 @@ files:
|
|
|
373
233
|
homepage: http://openehr.jp
|
|
374
234
|
licenses:
|
|
375
235
|
- Apache 2.0
|
|
376
|
-
metadata:
|
|
236
|
+
metadata:
|
|
237
|
+
rubygems_mfa_required: 'true'
|
|
377
238
|
rdoc_options: []
|
|
378
239
|
require_paths:
|
|
379
240
|
- lib
|
|
@@ -381,14 +242,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
381
242
|
requirements:
|
|
382
243
|
- - ">="
|
|
383
244
|
- !ruby/object:Gem::Version
|
|
384
|
-
version: '3.
|
|
245
|
+
version: '3.2'
|
|
385
246
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
386
247
|
requirements:
|
|
387
248
|
- - ">="
|
|
388
249
|
- !ruby/object:Gem::Version
|
|
389
250
|
version: '0'
|
|
390
251
|
requirements: []
|
|
391
|
-
rubygems_version: 4.0.
|
|
252
|
+
rubygems_version: 4.0.16
|
|
392
253
|
specification_version: 4
|
|
393
254
|
summary: Ruby implementation of the openEHR specification
|
|
394
255
|
test_files: []
|