openehr 1.2.99999 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9cb803ae534a0b21a6f32f49a6ab67f23e9a2310
4
- data.tar.gz: 83f4c97ef8df85d96c2e9a21a19ec75e11e45f78
2
+ SHA256:
3
+ metadata.gz: a8b6b9646daa3a967d9addfb4effc70408a402ff746a52fc549bff5ed150593b
4
+ data.tar.gz: 9390b872a07e6b3e3291489cfd1dc2ef87cc8eb41f3d2906aab829cfeb317937
5
5
  SHA512:
6
- metadata.gz: 2c4ec78adc29711593e9bec0adebffca790c18f5b3dcd9b80dc878347ae5466a841aa0b24df3b6c4f34f9f58ff410477a8df9cfdd1311ca25cbb027d2572054f
7
- data.tar.gz: 143ca8d16048c7865ece5de9c8a9d75bebbce386619ac0e3e324ad84b39a2608d6f7726f1e6985ca78a1dcabceb208167aadb47e87afe6ed6a6a90e0821584a7
6
+ metadata.gz: a4d0d99c554e80da635c8d4d4bbbef09c5937dede153582e68793611e4708afac008eef063b2ca4a2b57cb7d25f6e18cf0db0914e9f74bf4463b200dd60a764a
7
+ data.tar.gz: 2b57b5b3556a2d431e7643936026067438d8d1405a9ad443cc7cd237cc7cd37f9b8dbf83085f3aa4d5407d3e3957a01945664b3e00fffa82299a23ab82387a60
data/README.rdoc CHANGED
@@ -7,9 +7,9 @@ A Ruby implementation of the openEHR specifications
7
7
 
8
8
  = Requirements
9
9
 
10
- * Supports Ruby 1.9.3, 2.0.0, 2.1.0, 2.2.3 or equivalents.
11
- * Developed with CRuby 2.2.3, 2.0.0, 1.9.3 on FreeBSD and Linux.
12
- * Ruby 1.8 or earlier are no longer supported.
10
+ * Supports CRuby 2.5.0 or later.
11
+ * Developed with CRuby 3.0.0 on FreeBSD and Linux.
12
+ * Ruby 2.4 or earlier are no longer supported.
13
13
 
14
14
  =Description
15
15
 
@@ -34,7 +34,7 @@ This package excludes:
34
34
  * Terminology service(moved to openehr-terminology package)
35
35
  * Rails plugin(moved to openehr-rails package
36
36
 
37
- Almost all classes passed the test constructed by RSpec2. These spec
37
+ Almost all classes passed the test constructed by RSpec23 These spec
38
38
  files are under /spec.
39
39
 
40
40
  Some specifications are not well determined yet, such as rm/security
@@ -66,7 +66,7 @@ All Rights Reserved.
66
66
 
67
67
  This product is released under Apache 2.0 license
68
68
 
69
- Copyright [2012-2014] openEHR Ruby implementation project.
69
+ Copyright [2012-2020] openEHR Ruby implementation project.
70
70
 
71
71
  Licensed under the Apache License, Version 2.0 (the "License");
72
72
  you may not use this file except in compliance with the License.
@@ -100,6 +100,12 @@ module OpenEHR
100
100
  return archetype
101
101
  end
102
102
 
103
+ def to_rm
104
+ ::OpenEHR::RM::Factory.create(definition.rm_type_name,
105
+ archetype_node_id: definition.archetype_node_id,
106
+ name: definition
107
+ )
108
+ end
103
109
  end # end of Archetype
104
110
  # original file:
105
111
  # ref_imple_eiffel/components/adl_parser/src/interface/adl_definition.e
@@ -1,49 +1,80 @@
1
+ require_relative 'archetype'
2
+
1
3
  module OpenEHR
2
4
  module AM
3
5
  module Template
4
- class OperationalTemplate
5
- attr_reader :uid, :concept, :language, :description, :template_id, :definition, :component_terminologies
6
+ # OPERATIONAL_TEMPLATE class represents a "compiled" template derived from
7
+ # a source TEMPLATE by a "flattening" process, used for generating and
8
+ # validating reference model instance data.
9
+ # According to openEHR AOM2 specification, it inherits from AUTHORED_ARCHETYPE.
10
+ class OperationalTemplate < OpenEHR::AM::Archetype::Archetype
11
+ attr_reader :component_terminologies, :terminology_extracts, :template_id
6
12
 
7
13
  def initialize(args = {})
8
- self.uid = args[:uid]
9
- self.concept = args[:concept]
14
+ # Initialize parent archetype with template-specific archetype_id
15
+ template_args = args.dup
16
+ template_args[:archetype_id] = args[:template_id] if args[:template_id] && !args[:archetype_id]
17
+
18
+ super(template_args)
19
+
10
20
  self.template_id = args[:template_id]
11
- self.language = args[:language]
12
- self.description = args[:description]
13
- self.definition = args[:definition]
14
- self.component_terminologies = args[:component_terminologies]
21
+ self.component_terminologies = args[:component_terminologies] || {}
22
+ self.terminology_extracts = args[:terminology_extracts] || {}
15
23
  end
16
24
 
17
- def uid=(uid)
18
- @uid = uid
25
+ def template_id=(template_id)
26
+ if template_id.nil?
27
+ raise ArgumentError, 'template_id is mandatory for operational template'
28
+ end
29
+ @template_id = template_id
30
+ # Update archetype_id to match template_id for consistency
31
+ @archetype_id = template_id if template_id
19
32
  end
20
33
 
21
- def concept=(concept)
22
- raise ArgumentError if concept.nil?
23
- @concept = concept
34
+ def component_terminologies=(component_terminologies)
35
+ @component_terminologies = component_terminologies || {}
24
36
  end
25
37
 
26
- def language=(language)
27
- @language = language
38
+ def terminology_extracts=(terminology_extracts)
39
+ @terminology_extracts = terminology_extracts || {}
28
40
  end
29
41
 
30
- def template_id=(template_id)
31
- raise ArgumentError if template_id.nil?
32
- @template_id = template_id
42
+ # Returns true if this is a valid operational template
43
+ def is_valid_operational_template?
44
+ return false if template_id.nil?
45
+ return false if definition.nil?
46
+ return false if component_terminologies.nil?
47
+ true
33
48
  end
34
49
 
35
- def description=(description)
36
- raise ArgumentError if description.nil?
37
- @description=description
50
+ # Returns whether the template is specialized (should be true for operational templates)
51
+ def is_specialized?
52
+ !parent_archetype_id.nil?
38
53
  end
39
54
 
40
- def definition=(definition)
41
- raise ArgumentError if definition.nil?
42
- @definition = definition
55
+ # Get all archetype identifiers referenced in this operational template
56
+ def referenced_archetype_ids
57
+ component_terminologies.keys
43
58
  end
44
59
 
45
- def component_terminologies=(component_terminologies)
46
- @component_terminologies = component_terminologies
60
+ # Get terminology for a specific archetype
61
+ def terminology_for_archetype(archetype_id)
62
+ component_terminologies[archetype_id]
63
+ end
64
+
65
+ # Override concept to use template concept or fallback to archetype concept
66
+ def concept
67
+ @concept || (archetype_id ? archetype_id.concept_name : nil)
68
+ end
69
+
70
+ # Compatibility method for backward compatibility with existing tests
71
+ def language
72
+ original_language
73
+ end
74
+
75
+ # Compatibility setter for language (maps to original_language)
76
+ def language=(language)
77
+ self.original_language = language
47
78
  end
48
79
  end
49
80
  end
@@ -25,6 +25,10 @@ module OpenEHR
25
25
  arch_identification.adl_version
26
26
  end
27
27
 
28
+ def uid
29
+ arch_identification.uid
30
+ end
31
+
28
32
  def concept
29
33
  arch_concept.value
30
34
  end
@@ -61,6 +65,10 @@ module OpenEHR
61
65
  head.value[:adl_version]
62
66
  end
63
67
 
68
+ def uid
69
+ head.value[:uid]
70
+ end
71
+
64
72
  def is_controlled?
65
73
  head.value[:is_controlled?]
66
74
  end
@@ -89,11 +97,10 @@ module OpenEHR
89
97
  end
90
98
 
91
99
  rule arch_meta_data_items
92
- item:arch_meta_data_item other_item:(';' arch_meta_data_item)* {
100
+ item:arch_meta_data_item other_items:(';' white_space arch_meta_data_item)* {
93
101
  def value
94
102
  v = item.value
95
- other_item.elements.map {|i| i.arch_meta_data_item.value}
96
- v
103
+ other_items.elements.map {|m| m.arch_meta_data_item.value }.inject(v, :update)
97
104
  end
98
105
  }
99
106
  end
@@ -104,9 +111,14 @@ module OpenEHR
104
111
  {:adl_version => ver.value}
105
112
  end
106
113
  }
114
+ / SYM_UID SYM_EQ uid:V_HIER_OBJECT space {
115
+ def value
116
+ { :uid => uid.value }
117
+ end
118
+ }
107
119
  / SYM_IS_CONTROLED space {
108
120
  def value
109
- {:is_controled? => true} # if elements[0]
121
+ { :is_controled? => true } # If elements[0]
110
122
  end
111
123
  }
112
124
  end
@@ -562,7 +574,7 @@ module OpenEHR
562
574
  path = node.path + id.value
563
575
  elsif node.id
564
576
  path = node.path + "[#{node.id}]/" + id.value
565
- elsif
577
+ else
566
578
  path = node.path + '/' + id.value
567
579
  end
568
580
  OpenEHR::AM::Archetype::ConstraintModel::CMultipleAttribute.new(
@@ -578,7 +590,7 @@ module OpenEHR
578
590
  path = node.path + id.value
579
591
  elsif node.id
580
592
  path = node.path + "[#{node.id}]/" + id.value
581
- elsif
593
+ else
582
594
  path = node.path + '/' + id.value
583
595
  end
584
596
  OpenEHR::AM::Archetype::ConstraintModel::CSingleAttribute.new(
@@ -2880,6 +2892,10 @@ module OpenEHR
2880
2892
  [a-zA-Z0-9]
2881
2893
  end
2882
2894
 
2895
+ rule HEXADECIMAL
2896
+ [a-fA-F0-9]
2897
+ end
2898
+
2883
2899
  rule IDCHAR
2884
2900
  [a-zA-Z0-9_]
2885
2901
  end
@@ -3144,6 +3160,10 @@ module OpenEHR
3144
3160
  [Aa] [Dd] [Ll] '_' [Vv] [Ee] [Rr] [Ss] [Ii] [Oo] [Nn] space
3145
3161
  end
3146
3162
 
3163
+ rule SYM_UID
3164
+ [Uu] [Ii] [Dd] space
3165
+ end
3166
+
3147
3167
  rule SYM_IS_CONTROLLED
3148
3168
  [Cc] [Oo] [Nn] [Tt] [Rr] [Oo] [Ll] [Ll] [Ee] [Dd] space
3149
3169
  end
@@ -3208,6 +3228,14 @@ module OpenEHR
3208
3228
  }
3209
3229
  end
3210
3230
 
3231
+ rule V_HIER_OBJECT
3232
+ HEXADECIMAL 8..8 '-' (HEXADECIMAL 4..4 '-') 3..3 HEXADECIMAL 12..12 {
3233
+ def value
3234
+ text_value
3235
+ end
3236
+ }
3237
+ end
3238
+
3211
3239
  rule V_URI
3212
3240
  [a-z]+ '://' [^<>|\\{}^~"\[\] ]* {
3213
3241
  def value
@@ -3353,7 +3381,7 @@ module OpenEHR
3353
3381
  end
3354
3382
  }
3355
3383
  end
3356
-
3384
+
3357
3385
  rule V_CHAR
3358
3386
  [^\\\n\"] {
3359
3387
  def value
@@ -25,7 +25,7 @@ module OpenEHR
25
25
 
26
26
  def parsed_data
27
27
  filestream = File.open(@filename, 'rb:bom|utf-8')
28
- @parsed_data ||= adl_grammar_parser.parse(filestream.read)
28
+ @parsed_data ||= adl_grammar_parser.parse(filestream.read.scrub)
29
29
  filestream.close
30
30
  unless @parsed_data
31
31
  puts adl_grammar_parser.failure_reason
@@ -59,6 +59,10 @@ module OpenEHR
59
59
  parsed_data.adl_version
60
60
  end
61
61
 
62
+ def uid
63
+ OpenEHR::RM::Support::Identification::HierObjectID.new(value: parsed_data.uid) if parsed_data.uid
64
+ end
65
+
62
66
  def concept
63
67
  parsed_data.concept
64
68
  end
@@ -78,6 +82,7 @@ module OpenEHR
78
82
  def archetype
79
83
  OpenEHR::AM::Archetype::Archetype.new(:archetype_id => archetype_id,
80
84
  :adl_version => adl_version,
85
+ :uid => uid,
81
86
  :concept => concept,
82
87
  :original_language => original_language,
83
88
  :translations => translations,
@@ -27,6 +27,8 @@ module OpenEHR
27
27
  '/template/description/details/misuse'
28
28
  DESC_DETAILS_COPYRIGHT_PATH =
29
29
  '/template/description/details/copyright'
30
+ DESC_OTHER_DETAILS_PATH =
31
+ '/template/description/other_details'
30
32
  DEFINITION_PATH = '/template/definition'
31
33
  OCCURRENCE_PATH = '/occurrences'
32
34
 
@@ -37,9 +39,24 @@ module OpenEHR
37
39
  def parse
38
40
  @opt = Nokogiri::XML::Document.parse(File.open(@filename))
39
41
  @opt.remove_namespaces!
42
+
40
43
  uid = OpenEHR::RM::Support::Identification::UIDBasedID.new(value: text_on_path(@opt, UID_PATH))
41
44
  defs = definition
42
- OpenEHR::AM::Template::OperationalTemplate.new(uid: uid, concept: concept, language: language, description: description, template_id: template_id, definition: defs, component_terminologies: @component_terminologies)
45
+
46
+ # Create operational template with archetype-compatible parameters
47
+ OpenEHR::AM::Template::OperationalTemplate.new(
48
+ uid: uid,
49
+ concept: concept,
50
+ original_language: language,
51
+ description: description,
52
+ template_id: template_id,
53
+ archetype_id: template_id, # Use template_id as archetype_id for compatibility
54
+ definition: defs,
55
+ ontology: create_template_ontology,
56
+ component_terminologies: @component_terminologies || {},
57
+ terminology_extracts: @component_terminologies || {},
58
+ adl_version: "1.4"
59
+ )
43
60
  end
44
61
 
45
62
  private
@@ -59,7 +76,7 @@ module OpenEHR
59
76
  def description
60
77
  original_author = text_on_path(@opt, DESC_ORIGINAL_AUTHOR_PATH)
61
78
  lifecycle_state = text_on_path(@opt, DESC_LIFECYCLE_STATE_PATH)
62
- OpenEHR::RM::Common::Resource::ResourceDescription.new(original_author: original_author, lifecycle_state: lifecycle_state, details: [description_details])
79
+ OpenEHR::RM::Common::Resource::ResourceDescription.new(original_author: original_author, lifecycle_state: lifecycle_state, details: [description_details], other_details: description_other_details)
63
80
  end
64
81
 
65
82
  def description_details
@@ -73,15 +90,15 @@ module OpenEHR
73
90
  OpenEHR::RM::Common::Resource::ResourceDescriptionItem.new(language: language, purpose: purpose, keywords: keywords, use: use, misuse: misuse, copyright: copyright)
74
91
  end
75
92
 
93
+ def description_other_details
94
+ @opt.xpath(DESC_OTHER_DETAILS_PATH).inject({}) do |hash, detail|
95
+ hash[detail.attributes['id'].value] = detail.text
96
+ hash
97
+ end
98
+ end
99
+
76
100
  def definition
77
- root_rm_type = text_on_path(@opt, DEFINITION_PATH + '/rm_type_name')
78
- root_node = Node.new
79
- root_node.id = text_on_path(@opt, DEFINITION_PATH + '/node_id')
80
- root_occurrences = occurrences(@opt.xpath(DEFINITION_PATH + OCCURRENCE_PATH))
81
- root_archetype_id = OpenEHR::RM::Support::Identification::ArchetypeID.new(value: text_on_path(@opt, DEFINITION_PATH+'/archetype_id/value'))
82
- root_node.path = "/[#{root_archetype_id.value}]"
83
- component_terminologies(root_archetype_id, @opt.xpath(DEFINITION_PATH))
84
- OpenEHR::AM::Archetype::ConstraintModel::CArchetypeRoot.new(rm_type_name: root_rm_type, node_id: root_node.id, path: root_node.path, occurrences: root_occurrences, archetype_id: root_archetype_id, attributes: attributes(@opt.xpath(DEFINITION_PATH+'/attributes'), root_node))
101
+ c_archetype_root @opt.xpath(DEFINITION_PATH)
85
102
  end
86
103
 
87
104
  def component_terminologies(archetype_id, nodes)
@@ -90,6 +107,30 @@ module OpenEHR
90
107
  archetype_terminology(nodes)
91
108
  end
92
109
 
110
+ def create_template_ontology
111
+ # Create a basic ontology for the template using the main concept
112
+ concept_code = 'at0000'
113
+ original_lang = language
114
+
115
+ term_definitions = {
116
+ original_lang.code_string => [
117
+ OpenEHR::AM::Archetype::Terminology::ArchetypeTerm.new(
118
+ code: concept_code,
119
+ items: {
120
+ 'text' => concept || 'Template',
121
+ 'description' => 'Operational template'
122
+ }
123
+ )
124
+ ]
125
+ }
126
+
127
+ OpenEHR::AM::Archetype::Terminology::ArchetypeTerminology.new(
128
+ concept_code: concept_code,
129
+ original_language: original_lang,
130
+ term_definitions: term_definitions
131
+ )
132
+ end
133
+
93
134
  def archetype_terminology(nodes)
94
135
  td = term_definitions(nodes)
95
136
  concept_code = td[language.code_string][0]
@@ -111,12 +152,6 @@ module OpenEHR
111
152
  { language.code_string => term_items }
112
153
  end
113
154
 
114
- def children(children_xml, node)
115
- children_xml.map do |child|
116
- send child.attributes['type'].text.downcase, child, node
117
- end
118
- end
119
-
120
155
  def c_archetype_root(xml, node = Node.new)
121
156
  rm_type_name = text_on_path(xml, './rm_type_name')
122
157
  id = text_on_path(xml, './node_id')
@@ -124,9 +159,9 @@ module OpenEHR
124
159
  occurrences = occurrences(xml.xpath('./occurrences'))
125
160
  archetype_id = OpenEHR::RM::Support::Identification::ArchetypeID.new(value: text_on_path(xml, './archetype_id/value'))
126
161
  if node.root? or node.id.nil?
127
- node.path = "/[#{archetype_id.value}]"
128
- else
129
- node.path += "/[#{archetype_id.value}]"
162
+ node.path = "/"
163
+ # else
164
+ # node.path += "/" #"/[#{archetype_id.value}]"
130
165
  end
131
166
  component_terminologies(archetype_id, xml)
132
167
  OpenEHR::AM::Archetype::ConstraintModel::CArchetypeRoot.new(rm_type_name: rm_type_name, node_id: node.id, path: node.path, occurrences: occurrences, archetype_id: archetype_id, attributes: attributes(xml.xpath('./attributes'), node))
@@ -137,55 +172,64 @@ module OpenEHR
137
172
  node_id = xml.xpath('./node_id').text
138
173
  unless node_id.nil? or node_id.empty?
139
174
  node.id = node_id
140
- node.path += "[#{node_id}]"
175
+ node.path = "#{node.path}[#{node.id}]"
141
176
  end
142
177
  OpenEHR::AM::Archetype::ConstraintModel::CComplexObject.new(rm_type_name: rm_type_name, node_id: node.id, path: node.path, occurrences: occurrences(xml.xpath('./occurrences')), attributes: attributes(xml.xpath('./attributes'), node))
143
178
  end
144
179
 
145
180
  def attributes(attributes_xml, node)
146
181
  attributes_xml.map do |attr|
147
- send attr.attributes['type'].text.downcase, attr, node
182
+ rm_attribute_name = attr.at('rm_attribute_name').text
183
+ if node.root?
184
+ path = "/#{rm_attribute_name}"
185
+ # elsif node.id
186
+ # path = "#{node.path}[#{node.id}]/#{rm_attribute_name}"
187
+ else
188
+ path = "#{node.path}/#{rm_attribute_name}"
189
+ end
190
+ child_node = Node.new(node)
191
+ child_node.path = path
192
+ child_node.id = node.id
193
+ send attr.attributes['type'].text.downcase, attr, child_node
194
+ end
195
+ end
196
+
197
+ def children(children_xml, node)
198
+ children_xml.map do |child|
199
+ send child.attributes['type'].text.downcase, child, node
148
200
  end
149
201
  end
150
202
 
151
203
  def c_single_attribute(attr_xml, node)
152
204
  rm_attribute_name = attr_xml.at('rm_attribute_name').text
153
205
  existence = occurrences(attr_xml.at('existence'))
154
- if node.root?
155
- path = "/#{rm_attribute_name}"
156
- elsif node.id
157
- path = "#{node.path}[#{node.id}]/#{rm_attribute_name}"
158
- else
159
- path = "#{node.path}/#{rm_attribute_name}"
160
- end
161
- child_node = Node.new(node)
162
- child_node.path = node.path
163
- child_node.id = node.id
164
- OpenEHR::AM::Archetype::ConstraintModel::CSingleAttribute.new(rm_attribute_name: rm_attribute_name, existence: existence, path: path, children: children(attr_xml.xpath('./children'), child_node))
206
+ OpenEHR::AM::Archetype::ConstraintModel::CSingleAttribute.new(rm_attribute_name: rm_attribute_name, existence: existence, path: node.path, children: children(attr_xml.xpath('./children'), node))
165
207
  end
166
208
 
167
209
  def c_multiple_attribute(attr_xml, node)
168
210
  rm_attribute_name = attr_xml.at('rm_attribute_name').text
169
211
  existence = occurrences(attr_xml.at('existence'))
170
- if node.root?
171
- path = "/#{rm_attribute_name}"
172
- elsif node.id
173
- path = "#{node.path}[#{node.id}]/#{rm_attribute_name}"
174
- else
175
- path = "#{node.path}/#{rm_attribute_name}"
176
- end
177
- child_node = Node.new(node)
178
- child_node.path = node.path
179
- child_node.id = node.id
180
- OpenEHR::AM::Archetype::ConstraintModel::CMultipleAttribute.new(rm_attribute_name: rm_attribute_name, existence: existence, path: path, children: children(attr_xml.xpath('./children'), child_node))
212
+ OpenEHR::AM::Archetype::ConstraintModel::CMultipleAttribute.new(rm_attribute_name: rm_attribute_name, existence: existence, path: node.path, cardinality: cardinality(attr_xml), children: children(attr_xml.xpath('./children'), node))
181
213
  end
182
214
 
183
215
  def c_code_phrase(attr_xml, node)
184
- terminology_id = OpenEHR::RM::Support::Identification::TerminologyID.new(value: attr_xml.at('terminology_id/value').text.strip)
185
- path = node.path
186
- code_list = attr_xml.xpath('code_list').text.strip
187
- occurrences = occurrences(attr_xml.at('occurrences'))
188
- OpenEHR::AM::OpenEHRProfile::DataTypes::Text::CCodePhrase.new(terminology_id: terminology_id, code_list: [code_list], path: path, occurrences: occurrences, rm_type_name: 'CodePhrase')
216
+ terminology_id_node = attr_xml.at('terminology_id/value')
217
+ terminology_id = terminology_id_node ? OpenEHR::RM::Support::Identification::TerminologyID.new(value: terminology_id_node.text.strip) : nil
218
+
219
+ code_list_nodes = attr_xml.xpath('code_list')
220
+ code_list = code_list_nodes.map { |code_node| code_node.text.strip }
221
+ code_list = [code_list.first] if code_list.size == 1 && code_list.first.empty?
222
+
223
+ occurrences_node = attr_xml.at('occurrences')
224
+ occurrences_obj = occurrences_node ? occurrences(occurrences_node) : nil
225
+
226
+ OpenEHR::AM::OpenEHRProfile::DataTypes::Text::CCodePhrase.new(
227
+ terminology_id: terminology_id,
228
+ code_list: code_list,
229
+ path: node.path,
230
+ occurrences: occurrences_obj,
231
+ rm_type_name: 'CODE_PHRASE'
232
+ )
189
233
  end
190
234
 
191
235
  def archetype_slot(attr_xml,node)
@@ -201,15 +245,59 @@ module OpenEHR
201
245
  end
202
246
 
203
247
  def occurrences(occurrence_xml)
248
+ return nil if occurrence_xml.nil?
249
+
204
250
  lower_node = occurrence_xml.at('lower')
205
251
  upper_node = occurrence_xml.at('upper')
206
- lower = lower_node.text.to_i if lower_node
207
- upper = upper_node.text.to_i if upper_node
208
- lower_included = to_bool(occurrence_xml.at('lower_included'))
209
- upper_included = to_bool(occurrence_xml.at('upper_included'))
210
- OpenEHR::AssumedLibraryTypes::Interval.new(lower: lower, upper: upper, lower_included: lower_included, upper_included: upper_included)
252
+ lower_included_node = occurrence_xml.at('lower_included')
253
+ upper_included_node = occurrence_xml.at('upper_included')
254
+ lower_unbounded_node = occurrence_xml.at('lower_unbounded')
255
+ upper_unbounded_node = occurrence_xml.at('upper_unbounded')
256
+
257
+ lower = lower_node ? lower_node.text.to_i : nil
258
+ upper = upper_node ? upper_node.text.to_i : nil
259
+ lower_included = lower_included_node ? to_bool(lower_included_node.text) : (lower.nil? ? nil : true)
260
+ upper_included = upper_included_node ? to_bool(upper_included_node.text) : (upper.nil? ? nil : true)
261
+ lower_unbounded = lower_unbounded_node ? to_bool(lower_unbounded_node.text) : false
262
+ upper_unbounded = upper_unbounded_node ? to_bool(upper_unbounded_node.text) : false
263
+
264
+ # Handle unbounded intervals properly
265
+ if upper_unbounded || upper.nil?
266
+ upper = nil
267
+ upper_included = nil
268
+ end
269
+
270
+ if lower_unbounded || lower.nil?
271
+ lower = nil
272
+ lower_included = nil
273
+ end
274
+
275
+ OpenEHR::AssumedLibraryTypes::Interval.new(
276
+ lower: lower,
277
+ upper: upper,
278
+ lower_included: lower_included,
279
+ upper_included: upper_included
280
+ )
211
281
  end
212
282
 
283
+ def cardinality(xml)
284
+ return nil if xml.nil?
285
+
286
+ order_node = xml.at('is_ordered')
287
+ unique_node = xml.at('is_unique')
288
+ interval_node = xml.at('interval')
289
+
290
+ order = order_node ? to_bool(order_node.text) : false
291
+ unique = unique_node ? to_bool(unique_node.text) : false
292
+ interval = interval_node ? occurrences(interval_node) : nil
293
+
294
+ OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new(
295
+ is_ordered: order,
296
+ is_unique: unique,
297
+ interval: interval
298
+ )
299
+ end
300
+
213
301
  def constraint_ref(attr_xml, node)
214
302
  rm_type_name = attr_xml.at('rm_type_name').text
215
303
  reference = attr_xml.at('reference').text
@@ -248,12 +336,19 @@ module OpenEHR
248
336
  def c_primitive_object(attr_xml, node)
249
337
  rm_type_name = attr_xml.at('rm_type_name').text
250
338
  occurrences = occurrences(attr_xml.at('occurrences'))
251
- OpenEHR::AM::Archetype::ConstraintModel::CPrimitiveObject.new(rm_type_name: rm_type_name, occurrences: occurrences, node_id: node.id)
339
+ item = send attr_xml.at('item')['type'].downcase, attr_xml.at('item')
340
+ OpenEHR::AM::Archetype::ConstraintModel::CPrimitiveObject.new(rm_type_name: rm_type_name, occurrences: occurrences, node_id: node.id, item: item)
252
341
  end
253
-
342
+
254
343
  def c_string(attr_xml)
255
- pattern = attr_xml.at('pattern').text
256
- OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new(pattern: pattern)
344
+ if attr_xml.at('pattern')
345
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new(pattern: attr_xml.at('pattern').text)
346
+ else
347
+ list = attr_xml.xpath('.//list').map do |str|
348
+ str.text
349
+ end
350
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new(list: list)
351
+ end
257
352
  end
258
353
 
259
354
  def c_dv_quantity(attr_xml, node)
@@ -271,6 +366,59 @@ module OpenEHR
271
366
  OpenEHR::AM::OpenEHRProfile::DataTypes::Quantity::CDvQuantity.new(rm_type_name: rm_type_name, occurrences: occurrences, list: list, property: property)
272
367
  end
273
368
 
369
+ def c_date(xml)
370
+ pattern = xml.at('pattern')
371
+ range = xml.at('range')
372
+ if pattern
373
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDate.new(pattern: pattern.text)
374
+ elsif range
375
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDate.new(range: occurrences(range))
376
+ else
377
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDate.new
378
+ end
379
+ end
380
+
381
+ def c_date_time(xml)
382
+ pattern = xml.at('pattern')
383
+ range = xml.at('range')
384
+ if pattern
385
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDateTime.new(pattern: pattern.text)
386
+ elsif range
387
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDateTime.new(range: occurrences(range))
388
+ else
389
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDateTime.new
390
+ end
391
+ end
392
+
393
+ def c_integer(xml)
394
+ range = xml.at('range')
395
+ list = xml.xpath('list')
396
+ if range
397
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CInteger.new(range: occurrences(range))
398
+ elsif !list.empty?
399
+ list_values = list.map { |item| item.text.to_i }
400
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CInteger.new(list: list_values)
401
+ else
402
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CInteger.new
403
+ end
404
+ end
405
+
406
+ def c_boolean(xml)
407
+ true_valid = xml.at('true_valid')
408
+ false_valid = xml.at('false_valid')
409
+ assumed_value = xml.at('assumed_value')
410
+
411
+ true_valid_value = true_valid ? to_bool(true_valid.text) : nil
412
+ false_valid_value = false_valid ? to_bool(false_valid.text) : nil
413
+ assumed_value_value = assumed_value ? to_bool(assumed_value.text) : nil
414
+
415
+ OpenEHR::AM::Archetype::ConstraintModel::Primitive::CBoolean.new(
416
+ true_valid: true_valid_value,
417
+ false_valid: false_valid_value,
418
+ assumed_value: assumed_value_value
419
+ )
420
+ end
421
+
274
422
  def string(attr_xml)
275
423
  attr_xml.text
276
424
  end
@@ -288,12 +436,11 @@ module OpenEHR
288
436
  end
289
437
 
290
438
  def to_bool(str)
291
- if str =~ /true/i
292
- return true
293
- elsif str =~ /false/i
294
- return false
295
- end
296
- return nil
439
+ return nil if str.nil?
440
+ str = str.text if str.respond_to?(:text)
441
+ return true if /true/i =~ str.to_s
442
+ return false if /false/i =~ str.to_s
443
+ nil
297
444
  end
298
445
  end
299
446
  end
@@ -95,7 +95,7 @@ module OpenEHR
95
95
  attr_reader :archetype_id, :rm_version
96
96
  attr_accessor :template_id
97
97
 
98
- def initialize(args = { })
98
+ def initialize(**args)
99
99
  self.archetype_id = args[:archetype_id]
100
100
  self.rm_version = args[:rm_version]
101
101
  self.template_id = args[:template_id]
@@ -31,9 +31,13 @@ module OpenEHR
31
31
 
32
32
  def value=(value)
33
33
  raise ArgumentError, "value must not be nil" if value.nil?
34
- if value == true or value =~ /TRUE/i
34
+ if value == true
35
35
  @value = true
36
- else
36
+ elsif value == false
37
+ @value = false
38
+ elsif /TRUE/i =~ value
39
+ @value = true
40
+ elsif /FALSE/i =~ value
37
41
  @value = false
38
42
  end
39
43
  end
@@ -24,7 +24,6 @@ module URI
24
24
  true
25
25
  end
26
26
  end
27
- @@schemes['EHR'] = EHR
28
27
  end
29
28
 
30
29
  module OpenEHR
@@ -3,9 +3,56 @@ require 'active_support/inflector'
3
3
  module OpenEHR
4
4
  module RM
5
5
  class Factory
6
- def self.create(type, *param)
7
- type = type.downcase.camelize if type.include? '_'
8
- class_eval("#{type}Factory").create(*param)
6
+ def initialize(cobject)
7
+ @cobject = cobject
8
+ end
9
+
10
+ class << self
11
+ def create(type, **param)
12
+ if type.include? '_'
13
+ type = type.downcase.camelize
14
+ else
15
+ type = type.capitalize
16
+ end
17
+ class_eval("#{type}Factory").create(params(param))
18
+ end
19
+
20
+ def params(param)
21
+ param.each_with_object({}) do |item, parameters|
22
+ key = item.shift
23
+ value = item.shift
24
+ if value.instance_of? Hash
25
+ parameters[key] = Factory.create(value[:_type], **value)
26
+ else
27
+ parameters[key] = value
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def build
34
+ Factory.create(type, params)
35
+ end
36
+
37
+ private
38
+ def type
39
+ @cobject.rm_type_name
40
+ end
41
+
42
+ def name
43
+ OpenEHR::RM::DataTypes::Text::DvText.new(value: ' ')
44
+ end
45
+
46
+ def params
47
+ @cobject.attributes.inject({}) do |hash, attribute|
48
+ if attribute.children
49
+ hash[attribute.rm_attribute_name.to_sym] =
50
+ attribute.children.map { |child| Factory.new(child).build }
51
+ end
52
+ hash
53
+ end.merge(
54
+ { archetype_node_id: @cobject.node_id,
55
+ occurrences: @cobject.occurrences })
9
56
  end
10
57
  end
11
58
 
@@ -124,63 +171,140 @@ module OpenEHR
124
171
  end
125
172
 
126
173
  class DvDateFactory
127
- def self.create(*param)
128
- OpenEHR::RM::DataTypes::Quantity::DateTime::DvDate.new(*param)
174
+ def self.create(param)
175
+ OpenEHR::RM::DataTypes::Quantity::DateTime::DvDate.new(param)
129
176
  end
130
177
  end
131
178
 
132
179
  class DvTimeFactory
133
- def self.create(*param)
134
- DataTypes::Quantity::DateTime::DvTime.new(*param)
180
+ def self.create(param)
181
+ DataTypes::Quantity::DateTime::DvTime.new(param)
135
182
  end
136
183
  end
137
184
 
138
185
  class DvDateTimeFactory
139
- def self.create(*param)
140
- DataTypes::Quantity::DateTime::DvDateTime.new(*param)
186
+ def self.create(param)
187
+ DataTypes::Quantity::DateTime::DvDateTime.new(param)
141
188
  end
142
189
  end
143
190
 
144
191
  class DvDurationFactory
145
- def self.create(*param)
146
- DataTypes::Quantity::DateTime::DvDuration.new(*param)
192
+ def self.create(param)
193
+ DataTypes::Quantity::DateTime::DvDuration.new(param)
147
194
  end
148
195
  end
149
196
 
150
197
  class DvEncapsulatedFactory
151
- def self.create(*param)
152
- DataTypes::Encapsulated::DvEncapsulated.new(*param)
198
+ def self.create(param)
199
+ DataTypes::Encapsulated::DvEncapsulated.new(param)
153
200
  end
154
201
  end
155
202
 
156
203
  class DvMultimediaFactory
157
- def self.create(*param)
158
- DataTypes::Encapsulated::DvMultimedia.new(*param)
204
+ def self.create(param)
205
+ DataTypes::Encapsulated::DvMultimedia.new(param)
159
206
  end
160
207
  end
161
208
 
162
209
  class DvParsableFactory
163
- def self.create(*param)
164
- DataTypes::Encapsulated::DvParsable.new(*param)
210
+ def self.create(param)
211
+ DataTypes::Encapsulated::DvParsable.new(param)
165
212
  end
166
213
  end
167
214
 
168
215
  class DvUriFactory
169
- def self.create(*param)
170
- DataTypes::URI::DvUri.new(*param)
216
+ def self.create(param)
217
+ DataTypes::URI::DvUri.new(param)
171
218
  end
172
219
  end
173
220
 
174
221
  class DvEhrUriFactory
175
- def self.create(*param)
176
- DataTypes::URI::DvEhrUri.new(*param)
222
+ def self.create(param)
223
+ DataTypes::URI::DvEhrUri.new(param)
177
224
  end
178
225
  end
179
226
 
180
- class OBSERVATIONFactory
181
- def self.create(*param)
182
- Composition::Content::Entry::Observation.new(*param)
227
+ class ObservationFactory
228
+ def self.create(param)
229
+ Composition::Content::Entry::Observation.new(param)
230
+ end
231
+ end
232
+
233
+ class SectionFactory
234
+ def self.create(param)
235
+ Composition::Content::Navigation::Section.new(param)
236
+ end
237
+ end
238
+
239
+ class ClusterFactory
240
+ def self.create(param)
241
+ DataStructures::ItemStructure::Representation::Cluster.new(param)
242
+ end
243
+ end
244
+
245
+ class ArchetypedFactory
246
+ def self.create(param)
247
+ OpenEHR::RM::Common::Archetyped::Archetyped.new(**param)
248
+ end
249
+ end
250
+
251
+ class ArchetypeIdFactory
252
+ def self.create(param)
253
+ OpenEHR::RM::Support::Identification::ArchetypeID.new(param)
254
+ end
255
+ end
256
+
257
+ class TemplateIdFactory
258
+ def self.create(param)
259
+ OpenEHR::RM::Support::Identification::TemplateID.new(param)
260
+ end
261
+ end
262
+
263
+ class TerminologyIdFactory
264
+ def self.create(param)
265
+ OpenEHR::RM::Support::Identification::TerminologyID.new(param)
266
+ end
267
+ end
268
+
269
+ class GenericIdFactory
270
+ def self.create(param)
271
+ OpenEHR::RM::Support::Identification::GenericID.new(param)
272
+ end
273
+ end
274
+
275
+ class PartyRefFactory
276
+ def self.create(param)
277
+ OpenEHR::RM::Support::Identification::PartyRef.new(param)
278
+ end
279
+ end
280
+
281
+ class PartyIdentifiedFactory
282
+ def self.create(param)
283
+ OpenEHR::RM::Common::Generic::PartyIdentified.new(param)
284
+ end
285
+ end
286
+
287
+ class EventContextFactory
288
+ def self.create(param)
289
+ OpenEHR::RM::Composition::EventContext.new(param)
290
+ end
291
+ end
292
+
293
+ class TermMappingFactory
294
+ def self.create(param)
295
+ OpenEHR::RM::DataTypes::Text::TermMapping.new(param)
296
+ end
297
+ end
298
+
299
+ class CompositionFactory < Factory
300
+ class << self
301
+ def create_from_json(json)
302
+ hash = JSON.parse(json, max_nesting: false, symbolize_names: true)
303
+ OpenEHR::RM::Composition::Composition.new(params(hash))
304
+ end
183
305
  end
184
306
  end
185
307
  end
186
308
  end
309
+
310
+
data/lib/openehr/rm.rb CHANGED
@@ -42,6 +42,5 @@ require_relative 'rm/demographic'
42
42
  #Integration Information Model
43
43
  require_relative 'rm/integration'
44
44
 
45
-
45
+ #factory and builder
46
46
  require_relative 'rm/factory'
47
-
@@ -14,6 +14,10 @@ module OpenEHR
14
14
  def serialize
15
15
  return self.merge
16
16
  end
17
+
18
+ private
19
+ def merge
20
+ end
17
21
  end
18
22
 
19
23
  class ADLSerializer < BaseSerializer
@@ -249,6 +253,22 @@ module OpenEHR
249
253
  return archetype
250
254
  end
251
255
  end
256
+
257
+ class OPTSerializer < BaseSerializer
258
+ def initialize(opt, format:)
259
+ @opt = OpenEHR::Parser::OPTParser.new(opt).parse
260
+ end
261
+
262
+ def name
263
+ @opt.definition.archetype_id.concept_name
264
+ end
265
+
266
+ def header
267
+
268
+ end
269
+
270
+
271
+ end
252
272
  end
253
273
  end
254
274
 
@@ -1,3 +1,3 @@
1
1
  module OpenEHR
2
- VERSION = "1.2.99999"
2
+ VERSION = "1.3.0"
3
3
  end
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: 1.2.99999
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shinji KOBAYASHI
@@ -9,10 +9,9 @@ authors:
9
9
  - Michael Deryugin
10
10
  - Dmitry Lavrov
11
11
  - Evgeny Strokov
12
- autorequire:
13
12
  bindir: bin
14
13
  cert_chain: []
15
- date: 2015-10-06 00:00:00.000000000 Z
14
+ date: 1980-01-02 00:00:00.000000000 Z
16
15
  dependencies:
17
16
  - !ruby/object:Gem::Dependency
18
17
  name: rake
@@ -211,7 +210,7 @@ dependencies:
211
210
  - !ruby/object:Gem::Version
212
211
  version: '0'
213
212
  - !ruby/object:Gem::Dependency
214
- name: guard-spork
213
+ name: simplecov
215
214
  requirement: !ruby/object:Gem::Requirement
216
215
  requirements:
217
216
  - - ">="
@@ -225,7 +224,7 @@ dependencies:
225
224
  - !ruby/object:Gem::Version
226
225
  version: '0'
227
226
  - !ruby/object:Gem::Dependency
228
- name: simplecov
227
+ name: libnotify
229
228
  requirement: !ruby/object:Gem::Requirement
230
229
  requirements:
231
230
  - - ">="
@@ -239,7 +238,35 @@ dependencies:
239
238
  - !ruby/object:Gem::Version
240
239
  version: '0'
241
240
  - !ruby/object:Gem::Dependency
242
- name: libnotify
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
243
270
  requirement: !ruby/object:Gem::Requirement
244
271
  requirements:
245
272
  - - ">="
@@ -319,7 +346,6 @@ homepage: http://openehr.jp
319
346
  licenses:
320
347
  - Apache 2.0
321
348
  metadata: {}
322
- post_install_message:
323
349
  rdoc_options: []
324
350
  require_paths:
325
351
  - lib
@@ -334,9 +360,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
334
360
  - !ruby/object:Gem::Version
335
361
  version: '0'
336
362
  requirements: []
337
- rubyforge_project:
338
- rubygems_version: 2.4.8
339
- signing_key:
363
+ rubygems_version: 3.6.7
340
364
  specification_version: 4
341
365
  summary: Ruby implementation of the openEHR specification
342
366
  test_files: []