ruby-hl7 1.3.3 → 1.4.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/lib/configuration.rb +30 -0
- data/lib/core_ext/date_time.rb +19 -15
- data/lib/core_ext/string.rb +2 -0
- data/lib/helpers/time_formatter_helper.rb +42 -0
- data/lib/message.rb +72 -75
- data/lib/message_parser.rb +17 -15
- data/lib/ruby-hl7.rb +26 -16
- data/lib/segment.rb +63 -47
- data/lib/segment_default.rb +6 -4
- data/lib/segment_fields.rb +27 -25
- data/lib/segment_generator.rb +12 -15
- data/lib/segment_list_storage.rb +15 -14
- data/lib/segments/aig.rb +2 -0
- data/lib/segments/ail.rb +2 -0
- data/lib/segments/aip.rb +2 -0
- data/lib/segments/ais.rb +2 -0
- data/lib/segments/dg1.rb +2 -10
- data/lib/segments/err.rb +2 -0
- data/lib/segments/evn.rb +2 -1
- data/lib/segments/ft1.rb +13 -13
- data/lib/segments/fts.rb +2 -0
- data/lib/segments/gt1.rb +4 -6
- data/lib/segments/in1.rb +2 -1
- data/lib/segments/mfe.rb +2 -0
- data/lib/segments/mfi.rb +2 -0
- data/lib/segments/mrg.rb +2 -0
- data/lib/segments/msa.rb +2 -2
- data/lib/segments/msh.rb +3 -2
- data/lib/segments/nk1.rb +48 -8
- data/lib/segments/nte.rb +6 -5
- data/lib/segments/obr.rb +4 -3
- data/lib/segments/obx.rb +2 -1
- data/lib/segments/orc.rb +8 -10
- data/lib/segments/oru.rb +2 -1
- data/lib/segments/pid.rb +19 -10
- data/lib/segments/prd.rb +2 -1
- data/lib/segments/prt.rb +23 -0
- data/lib/segments/pv1.rb +2 -1
- data/lib/segments/pv2.rb +64 -51
- data/lib/segments/qrd.rb +2 -1
- data/lib/segments/qrf.rb +2 -1
- data/lib/segments/rf1.rb +2 -1
- data/lib/segments/rgs.rb +2 -0
- data/lib/segments/rol.rb +22 -0
- data/lib/segments/sch.rb +2 -0
- data/lib/segments/sft.rb +2 -0
- data/lib/segments/spm.rb +2 -0
- data/lib/segments/tq1.rb +2 -0
- data/lib/segments/txa.rb +2 -0
- data/lib/test/hl7_messages.rb +118 -117
- data/lib/version.rb +5 -0
- metadata +14 -163
- data/.gitignore +0 -7
- data/.rubocop.yml +0 -127
- data/.travis.yml +0 -20
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -65
- data/LICENSE +0 -19
- data/NOTES.md +0 -151
- data/README.rdoc +0 -47
- data/Rakefile +0 -76
- data/VERSION +0 -1
- data/VERSION.yml +0 -4
- data/examples/proxy_server.rb +0 -26
- data/ruby-hl7.gemspec +0 -39
- data/spec/ail_segment_spec.rb +0 -28
- data/spec/aip_segment_spec.rb +0 -31
- data/spec/basic_parsing_spec.rb +0 -319
- data/spec/batch_parsing_spec.rb +0 -52
- data/spec/child_segment_spec.rb +0 -66
- data/spec/core_ext/date_time_spec.rb +0 -43
- data/spec/default_segment_spec.rb +0 -31
- data/spec/dg1_spec.rb +0 -42
- data/spec/dynamic_segment_def_spec.rb +0 -37
- data/spec/err_segment_spec.rb +0 -26
- data/spec/evn_segment_spec.rb +0 -23
- data/spec/ft1_segment_spec.rb +0 -35
- data/spec/fts_segment_spec.rb +0 -19
- data/spec/gt1_segment_spec.rb +0 -32
- data/spec/in1_segment_spec.rb +0 -34
- data/spec/message_spec.rb +0 -53
- data/spec/messages_spec.rb +0 -24
- data/spec/mfe_segment_spec.rb +0 -28
- data/spec/mfi_segment_spec.rb +0 -28
- data/spec/msa_segment_spec.rb +0 -27
- data/spec/msh_segment_spec.rb +0 -28
- data/spec/nk1_segment_spec.rb +0 -26
- data/spec/obr_segment_spec.rb +0 -45
- data/spec/obx_segment_spec.rb +0 -68
- data/spec/orc_segment_spec.rb +0 -27
- data/spec/pid_segment_spec.rb +0 -78
- data/spec/prd_segment_spec.rb +0 -29
- data/spec/pv1_segment_spec.rb +0 -23
- data/spec/rf1_segment_spec.rb +0 -29
- data/spec/sch_segment_spec.rb +0 -32
- data/spec/segment_field_spec.rb +0 -110
- data/spec/segment_generator_spec.rb +0 -32
- data/spec/segment_list_storage_spec.rb +0 -47
- data/spec/segment_spec.rb +0 -38
- data/spec/sft_segment_spec.rb +0 -26
- data/spec/spec_helper.rb +0 -13
- data/spec/speed_parsing_spec.rb +0 -19
- data/spec/spm_segment_spec.rb +0 -26
- data/spec/txa_segment_spec.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 035f9636e28515eae6fbc2a678ce86b39263c48cd1568b8b97c7ce4152bef4a7
|
4
|
+
data.tar.gz: d8773a865c2ec350577dcafb478a077de96ad591b35dfc3660feca586d037631
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bc0af59178fe08d1dd5eec8a1452e94a30d0fefc499f5ccba3571fb20e3c55131904bf7ee3692f586c9f8a5cc4665d45352e87f335d403b25966c2480de06c6
|
7
|
+
data.tar.gz: 6af3309af2c11db2a8d51541e709dcd70f941e03b16323492443c58a83aca3908df1eab3083b255bb765d7192010bfc9aafd6031d91110fe1dc51991749f73be
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HL7
|
4
|
+
# This class enables detailed configuration of the HL7 parser services.
|
5
|
+
#
|
6
|
+
# By calling
|
7
|
+
#
|
8
|
+
# HL7.configuration # => instance of HL7::Configuration
|
9
|
+
#
|
10
|
+
# or
|
11
|
+
# HL7.configure do |config|
|
12
|
+
# config # => instance of HL7::Configuration
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# you are able to perform configuration updates.
|
16
|
+
#
|
17
|
+
# Setting the keys with this Configuration
|
18
|
+
#
|
19
|
+
# HL7.configure do |config|
|
20
|
+
# config.empty_segment_is_error = false
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class Configuration
|
24
|
+
attr_accessor :empty_segment_is_error
|
25
|
+
|
26
|
+
def initialize # :nodoc:
|
27
|
+
@empty_segment_is_error = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/core_ext/date_time.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HL7Time
|
2
4
|
# Get a HL7 timestamp (type TS) for a Time instance.
|
3
5
|
#
|
@@ -7,16 +9,18 @@ module HL7Time
|
|
7
9
|
# => "20091202012300"
|
8
10
|
# Time.now.to_hl7(3)
|
9
11
|
# => "20091202153652.302"
|
10
|
-
def to_hl7(
|
11
|
-
strftime(
|
12
|
+
def to_hl7(fraction_digits = 0)
|
13
|
+
strftime("%Y%m%d%H%M%S") + hl7_fractions(fraction_digits)
|
12
14
|
end
|
13
15
|
|
14
16
|
private
|
17
|
+
|
15
18
|
def hl7_fractions(fraction_digits = 0)
|
16
|
-
return
|
19
|
+
return "" unless fraction_digits.positive?
|
20
|
+
|
17
21
|
time_fraction = hl7_time_fraction
|
18
|
-
answer = ".#{
|
19
|
-
answer +=
|
22
|
+
answer = ".#{format("%06d", time_fraction)}"
|
23
|
+
answer += "0" * ((fraction_digits - 6)).abs if fraction_digits > 6
|
20
24
|
answer[0, 1 + fraction_digits]
|
21
25
|
end
|
22
26
|
|
@@ -24,7 +28,7 @@ private
|
|
24
28
|
if respond_to? :usec
|
25
29
|
usec
|
26
30
|
else
|
27
|
-
sec_fraction.to_f *
|
31
|
+
sec_fraction.to_f * 1_000_000
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
@@ -36,7 +40,7 @@ class Date
|
|
36
40
|
# Date.parse('2009-12-02').to_hl7
|
37
41
|
# => "20091202"
|
38
42
|
def to_hl7
|
39
|
-
strftime(
|
43
|
+
strftime("%Y%m%d")
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
@@ -52,14 +56,14 @@ end
|
|
52
56
|
|
53
57
|
# TODO
|
54
58
|
# parse an hl7 formatted date
|
55
|
-
#def Date.from_hl7( hl7_date )
|
56
|
-
#end
|
59
|
+
# def Date.from_hl7( hl7_date )
|
60
|
+
# end
|
57
61
|
|
58
|
-
#def Date.to_hl7_short( ruby_date )
|
59
|
-
#end
|
62
|
+
# def Date.to_hl7_short( ruby_date )
|
63
|
+
# end
|
60
64
|
|
61
|
-
#def Date.to_hl7_med( ruby_date )
|
62
|
-
#end
|
65
|
+
# def Date.to_hl7_med( ruby_date )
|
66
|
+
# end
|
63
67
|
|
64
|
-
#def Date.to_hl7_long( ruby_date )
|
65
|
-
#end
|
68
|
+
# def Date.to_hl7_long( ruby_date )
|
69
|
+
# end
|
data/lib/core_ext/string.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TimeFormatterHelper
|
4
|
+
class ValueTypeNotSupportedError < StandardError; end
|
5
|
+
|
6
|
+
# Get an HL7 timestamp (type TS) for a Time or DateTime instance.
|
7
|
+
#
|
8
|
+
# fraction_digits:: specifies a number of digits of fractional seconds.
|
9
|
+
# Its default value is 0.
|
10
|
+
# hl7_formatted_timestamp(Time.parse('01:23'))
|
11
|
+
# => "20091202012300"
|
12
|
+
# hl7_formatted_timestamp(Time.now, 3)
|
13
|
+
# => "20091202153652.302"
|
14
|
+
def hl7_formatted_timestamp(value, fraction_digits = 0)
|
15
|
+
raise ValueTypeNotSupportedError, "Value must be an instance of Time or DateTime" unless value.is_a?(Time) || value.is_a?(DateTime)
|
16
|
+
|
17
|
+
value.strftime("%Y%m%d%H%M%S") + hl7_formatted_fractions(value, fraction_digits)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get an HL7 timestamp (type TS) for a Date instance.
|
21
|
+
def hl7_formatted_date(value)
|
22
|
+
raise ValueTypeNotSupportedError, "Value must be an instance of Date" unless value.is_a?(Date)
|
23
|
+
|
24
|
+
value.strftime("%Y%m%d")
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def hl7_formatted_fractions(value, fraction_digits = 0)
|
30
|
+
return "" unless fraction_digits.positive?
|
31
|
+
|
32
|
+
time_fraction = if value.respond_to?(:usec)
|
33
|
+
value.usec
|
34
|
+
else
|
35
|
+
value.sec_fraction.to_f * 1_000_000
|
36
|
+
end
|
37
|
+
|
38
|
+
answer = ".#{format("%06d", time_fraction)}"
|
39
|
+
answer += "0" * ((fraction_digits - 6)).abs if fraction_digits > 6
|
40
|
+
answer[0, 1 + fraction_digits]
|
41
|
+
end
|
42
|
+
end
|
data/lib/message.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Ruby Object representation of an hl7 2.x message
|
2
4
|
# the message object is actually a "smart" collection of hl7 segments
|
3
5
|
# == Examples
|
@@ -33,60 +35,56 @@ class HL7::Message
|
|
33
35
|
include Enumerable # we treat an hl7 2.x message as a collection of segments
|
34
36
|
extend HL7::MessageBatchParser
|
35
37
|
|
36
|
-
attr_reader :message_parser
|
37
|
-
attr_reader :element_delim
|
38
|
-
attr_reader :item_delim
|
39
|
-
attr_reader :segment_delim
|
40
|
-
attr_reader :delimiter
|
38
|
+
attr_reader :message_parser, :element_delim, :item_delim, :segment_delim, :delimiter
|
41
39
|
|
42
40
|
# setup a new hl7 message
|
43
41
|
# raw_msg:: is an optional object containing an hl7 message
|
44
42
|
# it can either be a string or an Enumerable object
|
45
|
-
def initialize(
|
43
|
+
def initialize(raw_msg = nil, &blk)
|
46
44
|
@segments = []
|
47
45
|
@segments_by_name = {}
|
48
46
|
@item_delim = "^"
|
49
|
-
@element_delim =
|
47
|
+
@element_delim = "|"
|
50
48
|
@segment_delim = "\r"
|
51
|
-
@delimiter = HL7::Message::Delimiter.new(
|
52
|
-
|
53
|
-
|
49
|
+
@delimiter = HL7::Message::Delimiter.new(@element_delim,
|
50
|
+
@item_delim,
|
51
|
+
@segment_delim)
|
54
52
|
|
55
53
|
@message_parser = HL7::MessageParser.new(@delimiter)
|
56
54
|
|
57
|
-
parse(
|
55
|
+
parse(raw_msg) if raw_msg
|
58
56
|
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
return unless block_given?
|
58
|
+
|
59
|
+
yield self
|
62
60
|
end
|
63
61
|
|
64
|
-
def parse(
|
65
|
-
if inobj.
|
66
|
-
generate_segments(
|
62
|
+
def parse(inobj)
|
63
|
+
if inobj.is_a?(String)
|
64
|
+
generate_segments(message_parser.parse_string(inobj))
|
67
65
|
elsif inobj.respond_to?(:each)
|
68
66
|
generate_segments_enumerable(inobj)
|
69
67
|
else
|
70
|
-
raise HL7::ParseError
|
68
|
+
raise HL7::ParseError, "object to parse should be string or enumerable"
|
71
69
|
end
|
72
70
|
end
|
73
71
|
|
74
72
|
def generate_segments_enumerable(enumerable)
|
75
73
|
enumerable.each do |segment|
|
76
|
-
generate_segments(
|
74
|
+
generate_segments(message_parser.parse_string(segment.to_s))
|
77
75
|
end
|
78
76
|
end
|
79
77
|
|
80
78
|
# access a segment of the message
|
81
79
|
# index:: can be a Range, Integer or anything that
|
82
80
|
# responds to to_sym
|
83
|
-
def [](
|
81
|
+
def [](index)
|
84
82
|
ret = nil
|
85
83
|
|
86
|
-
if index.
|
87
|
-
ret = @segments[
|
88
|
-
elsif
|
89
|
-
ret = @segments_by_name[
|
84
|
+
if index.is_a?(Range) || index.is_a?(Integer)
|
85
|
+
ret = @segments[index]
|
86
|
+
elsif index.respond_to? :to_sym
|
87
|
+
ret = @segments_by_name[index.to_sym]
|
90
88
|
ret = ret.first if ret && ret.length == 1
|
91
89
|
end
|
92
90
|
|
@@ -97,17 +95,17 @@ class HL7::Message
|
|
97
95
|
# index:: can be a Range, Integer or anything that
|
98
96
|
# responds to to_sym
|
99
97
|
# value:: an HL7::Message::Segment object
|
100
|
-
def []=(
|
101
|
-
unless
|
102
|
-
raise HL7::Exception
|
98
|
+
def []=(index, value)
|
99
|
+
unless value.is_a?(HL7::Message::Segment)
|
100
|
+
raise HL7::Exception, "attempting to assign something other than an HL7 Segment"
|
103
101
|
end
|
104
102
|
|
105
|
-
if index.
|
106
|
-
@segments[
|
103
|
+
if index.is_a?(Range) || index.is_a?(Integer)
|
104
|
+
@segments[index] = value
|
107
105
|
elsif index.respond_to?(:to_sym)
|
108
|
-
(@segments_by_name[
|
106
|
+
(@segments_by_name[index.to_sym] ||= []) << value
|
109
107
|
else
|
110
|
-
raise HL7::Exception
|
108
|
+
raise HL7::Exception, "attempting to use an indice that is not a Range, Integer or to_sym providing object"
|
111
109
|
end
|
112
110
|
|
113
111
|
value.segment_parent = self
|
@@ -115,43 +113,44 @@ class HL7::Message
|
|
115
113
|
|
116
114
|
# return the index of the value if it exists, nil otherwise
|
117
115
|
# value:: is expected to be a string
|
118
|
-
def index(
|
119
|
-
return nil unless
|
116
|
+
def index(value)
|
117
|
+
return nil unless value.respond_to?(:to_sym)
|
120
118
|
|
121
|
-
segs = @segments_by_name[
|
119
|
+
segs = @segments_by_name[value.to_sym]
|
122
120
|
return nil unless segs
|
123
121
|
|
124
|
-
@segments.index(
|
122
|
+
@segments.index(segs.to_a.first)
|
125
123
|
end
|
126
124
|
|
127
125
|
# add a segment or array of segments to the message
|
128
126
|
# * will force auto set_id sequencing for segments containing set_id's
|
129
|
-
def <<(
|
127
|
+
def <<(value)
|
130
128
|
# do nothing if value is nil
|
131
129
|
return unless value
|
132
130
|
|
133
|
-
if value.
|
134
|
-
value.map{|item| append(item)}
|
131
|
+
if value.is_a? Array
|
132
|
+
value.map {|item| append(item) }
|
135
133
|
else
|
136
134
|
append(value)
|
137
135
|
end
|
138
136
|
end
|
139
137
|
|
140
|
-
def append(
|
141
|
-
unless
|
142
|
-
raise HL7::Exception
|
138
|
+
def append(value)
|
139
|
+
unless value.is_a?(HL7::Message::Segment)
|
140
|
+
raise HL7::Exception, "attempting to append something other than an HL7 Segment"
|
143
141
|
end
|
144
142
|
|
145
143
|
value.segment_parent = self unless value.segment_parent
|
146
144
|
(@segments ||= []) << value
|
147
145
|
name = value.class.to_s.gsub("HL7::Message::Segment::", "").to_sym
|
148
|
-
(@segments_by_name[
|
146
|
+
(@segments_by_name[name] ||= []) << value
|
149
147
|
sequence_segments unless defined?(@parsing) && @parsing # let's auto-set the set-id as we go
|
150
148
|
end
|
151
149
|
|
152
150
|
# yield each segment in the message
|
153
151
|
def each # :yields: segment
|
154
152
|
return unless @segments
|
153
|
+
|
155
154
|
@segments.each { |s| yield s }
|
156
155
|
end
|
157
156
|
|
@@ -163,34 +162,34 @@ class HL7::Message
|
|
163
162
|
|
164
163
|
# provide a screen-readable version of the message
|
165
164
|
def to_s
|
166
|
-
@segments.collect {
|
165
|
+
@segments.collect {|s| s if s.to_s.length.positive? }.join("\n")
|
167
166
|
end
|
168
167
|
|
169
168
|
# provide a HL7 spec version of the message
|
170
169
|
def to_hl7
|
171
|
-
@segments.collect {
|
170
|
+
@segments.collect {|s| s if s.to_s.length.positive? }.join(@delimiter.segment)
|
172
171
|
end
|
173
172
|
|
174
173
|
# provide the HL7 spec version of the message wrapped in MLLP
|
175
174
|
def to_mllp
|
176
175
|
pre_mllp = to_hl7
|
177
|
-
"\
|
176
|
+
"\v#{pre_mllp}\u001C\r"
|
178
177
|
end
|
179
178
|
|
180
179
|
# auto-set the set_id fields of any message segments that
|
181
180
|
# provide it and have more than one instance in the message
|
182
|
-
def sequence_segments(base=nil)
|
181
|
+
def sequence_segments(base = nil)
|
183
182
|
last = nil
|
184
183
|
segs = @segments
|
185
184
|
segs = base.children if base
|
186
185
|
|
187
186
|
segs.each do |s|
|
188
|
-
if s.
|
189
|
-
last.set_id = 1 unless last.set_id
|
187
|
+
if s.is_a?(last.class) && s.respond_to?(:set_id)
|
188
|
+
last.set_id = 1 unless last.set_id&.to_i&.positive?
|
190
189
|
s.set_id = last.set_id.to_i + 1
|
191
190
|
end
|
192
191
|
|
193
|
-
sequence_segments(
|
192
|
+
sequence_segments(s) if s.has_children?
|
194
193
|
|
195
194
|
last = s
|
196
195
|
end
|
@@ -201,17 +200,16 @@ class HL7::Message
|
|
201
200
|
Array(self[:OBX]).any?(&:correction?)
|
202
201
|
end
|
203
202
|
|
204
|
-
|
205
|
-
|
206
|
-
|
203
|
+
private
|
204
|
+
|
205
|
+
def generate_segments(ary)
|
206
|
+
raise HL7::ParseError, "no array to generate segments" unless ary.length.positive?
|
207
207
|
|
208
208
|
@parsing = true
|
209
209
|
segment_stack = []
|
210
210
|
ary.each do |elm|
|
211
|
-
if elm.slice(0,3) == "MSH"
|
212
|
-
|
213
|
-
end
|
214
|
-
last_seg = generate_segment( elm, segment_stack ) || last_seg
|
211
|
+
update_delimiters(elm) if elm.slice(0, 3) == "MSH"
|
212
|
+
generate_segment(elm, segment_stack)
|
215
213
|
end
|
216
214
|
@parsing = nil
|
217
215
|
end
|
@@ -223,12 +221,13 @@ class HL7::Message
|
|
223
221
|
@delimiter.element = @element_delim
|
224
222
|
end
|
225
223
|
|
226
|
-
def generate_segment(
|
227
|
-
segment_generator = HL7::Message::SegmentGenerator.new(
|
228
|
-
|
229
|
-
|
224
|
+
def generate_segment(elm, segment_stack)
|
225
|
+
segment_generator = HL7::Message::SegmentGenerator.new(elm,
|
226
|
+
segment_stack,
|
227
|
+
@delimiter)
|
230
228
|
|
231
229
|
return nil unless segment_generator.valid_segments_parts?
|
230
|
+
|
232
231
|
segment_generator.seg_name = segment_generator.seg_parts[0]
|
233
232
|
|
234
233
|
new_seg = segment_generator.build
|
@@ -238,40 +237,38 @@ class HL7::Message
|
|
238
237
|
end
|
239
238
|
|
240
239
|
def choose_segment_from(segment_stack, new_seg, seg_name)
|
241
|
-
|
242
240
|
# Segments have been previously seen
|
243
|
-
while
|
244
|
-
if segment_stack.last
|
241
|
+
while segment_stack.length.positive?
|
242
|
+
if segment_stack.last&.has_children? && segment_stack.last&.accepts?(seg_name)
|
245
243
|
# If a previous segment can accept the current segment as a child,
|
246
244
|
# add it to the previous segments children
|
247
245
|
segment_stack.last.children << new_seg
|
248
246
|
new_seg.is_child_segment = true
|
249
247
|
segment_stack << new_seg
|
250
|
-
break
|
248
|
+
break
|
251
249
|
else
|
252
250
|
segment_stack.pop
|
253
251
|
end
|
254
252
|
end
|
255
253
|
|
256
254
|
# Root of segment 'tree'
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
255
|
+
return unless segment_stack.empty?
|
256
|
+
|
257
|
+
@segments << new_seg
|
258
|
+
segment_stack << new_seg
|
259
|
+
setup_segment_lookup_by_name(seg_name, new_seg)
|
262
260
|
end
|
263
261
|
|
264
262
|
# Allow segment lookup by name
|
265
263
|
def setup_segment_lookup_by_name(seg_name, new_seg)
|
266
264
|
seg_sym = get_symbol_from_name(seg_name)
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
265
|
+
return unless seg_sym
|
266
|
+
|
267
|
+
@segments_by_name[seg_sym] ||= []
|
268
|
+
@segments_by_name[seg_sym] << new_seg
|
271
269
|
end
|
272
270
|
|
273
271
|
def get_symbol_from_name(seg_name)
|
274
|
-
seg_name.to_s.strip.length
|
272
|
+
seg_name.to_s.strip.length.positive? ? seg_name.to_sym : nil
|
275
273
|
end
|
276
|
-
|
277
274
|
end
|
data/lib/message_parser.rb
CHANGED
@@ -1,29 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HL7::MessageBatchParser
|
2
4
|
def parse_batch(batch) # :yields: message
|
3
|
-
raise HL7::ParseError,
|
5
|
+
raise HL7::ParseError, "badly_formed_batch_message" unless
|
4
6
|
batch.hl7_batch?
|
5
7
|
|
6
8
|
batch = clean_batch_for_jruby batch
|
7
9
|
|
8
|
-
raise HL7::ParseError,
|
10
|
+
raise HL7::ParseError, "empty_batch_message" unless
|
9
11
|
match = /\rMSH/.match(batch)
|
10
12
|
|
11
|
-
match.post_match.split(
|
13
|
+
match.post_match.split("\rMSH").each do |_msg|
|
12
14
|
if md = /\rBTS/.match(_msg)
|
13
15
|
# TODO: Validate the message count in the BTS segment
|
14
16
|
# should == index + 1
|
15
17
|
_msg = md.pre_match
|
16
18
|
end
|
17
19
|
|
18
|
-
yield
|
20
|
+
yield "MSH#{_msg}"
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
24
|
# parse a String or Enumerable object into an HL7::Message if possible
|
23
25
|
# * returns a new HL7::Message if successful
|
24
|
-
def parse(
|
26
|
+
def parse(inobj)
|
25
27
|
HL7::Message.new do |msg|
|
26
|
-
msg.parse(
|
28
|
+
msg.parse(inobj)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -35,10 +37,10 @@ module HL7::MessageBatchParser
|
|
35
37
|
# characters, only in sample messages from here documents. The
|
36
38
|
# expensive copy is only incurred when the batch message has a
|
37
39
|
# newline character in it.
|
38
|
-
|
40
|
+
private
|
39
41
|
|
40
42
|
def clean_batch_for_jruby(batch)
|
41
|
-
batch.
|
43
|
+
batch.tr("\n", "\r") if batch.include?("\n")
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
@@ -47,7 +49,7 @@ class HL7::MessageParser
|
|
47
49
|
attr_reader :delimiter
|
48
50
|
|
49
51
|
def self.split_by_delimiter(element, delimiter)
|
50
|
-
element.split(
|
52
|
+
element.split(delimiter, -1)
|
51
53
|
end
|
52
54
|
|
53
55
|
def initialize(delimiter)
|
@@ -55,21 +57,21 @@ class HL7::MessageParser
|
|
55
57
|
end
|
56
58
|
|
57
59
|
# parse the provided String or Enumerable object into this message
|
58
|
-
def parse_string(
|
60
|
+
def parse_string(instr)
|
59
61
|
post_mllp = instr
|
60
|
-
if /\x0b((:?.|\r|\n)+)\x1c\r
|
61
|
-
post_mllp = $1 #strip the mllp bytes
|
62
|
+
if /\x0b((:?.|\r|\n)+)\x1c\r/ =~ instr
|
63
|
+
post_mllp = $1 # strip the mllp bytes
|
62
64
|
end
|
63
65
|
HL7::MessageParser.split_by_delimiter(post_mllp, @delimiter.segment)
|
64
66
|
end
|
65
67
|
|
66
68
|
# Get the element delimiter from an MSH segment
|
67
69
|
def parse_element_delim(str)
|
68
|
-
|
70
|
+
str.is_a?(String) ? str.slice(3, 1) : "|"
|
69
71
|
end
|
70
72
|
|
71
73
|
# Get the item delimiter from an MSH segment
|
72
74
|
def parse_item_delim(str)
|
73
|
-
|
75
|
+
str.is_a?(String) ? str.slice(4, 1) : "^"
|
74
76
|
end
|
75
|
-
end
|
77
|
+
end
|
data/lib/ruby-hl7.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#= ruby-hl7.rb
|
3
4
|
# Ruby HL7 is designed to provide a simple, easy to use library for
|
4
5
|
# parsing and generating HL7 (2.x) messages.
|
@@ -16,14 +17,23 @@
|
|
16
17
|
# see the LICENSE file
|
17
18
|
#
|
18
19
|
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
20
|
+
require "rubygems"
|
21
|
+
require "stringio"
|
22
|
+
require "date"
|
23
|
+
require "configuration"
|
24
|
+
require "helpers/time_formatter_helper"
|
22
25
|
|
23
26
|
module HL7 # :nodoc:
|
24
|
-
|
25
|
-
def self.
|
26
|
-
@
|
27
|
+
# Gives access to the current Configuration.
|
28
|
+
def self.configuration
|
29
|
+
@configuration ||= Configuration.new
|
30
|
+
end
|
31
|
+
|
32
|
+
# Allows easy setting of multiple configuration options. See Configuration
|
33
|
+
# for all available options.
|
34
|
+
def self.configure
|
35
|
+
config = configuration
|
36
|
+
yield(config)
|
27
37
|
end
|
28
38
|
end
|
29
39
|
|
@@ -48,13 +58,13 @@ end
|
|
48
58
|
class HL7::EmptySegmentNotAllowed < HL7::ParseError
|
49
59
|
end
|
50
60
|
|
51
|
-
require
|
52
|
-
require
|
53
|
-
require
|
54
|
-
require
|
55
|
-
require
|
56
|
-
require
|
57
|
-
require
|
61
|
+
require "message_parser"
|
62
|
+
require "message"
|
63
|
+
require "segment_list_storage"
|
64
|
+
require "segment_generator"
|
65
|
+
require "segment_fields"
|
66
|
+
require "segment"
|
67
|
+
require "segment_default"
|
58
68
|
|
59
|
-
require
|
60
|
-
require
|
69
|
+
require "core_ext/date_time"
|
70
|
+
require "core_ext/string"
|