ruby-hl7 1.3.3 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|