simple_hl7 0.1.2
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +188 -0
- data/Rakefile +2 -0
- data/lib/simple_hl7.rb +15 -0
- data/lib/simple_hl7/component.rb +11 -0
- data/lib/simple_hl7/component_container.rb +11 -0
- data/lib/simple_hl7/composite.rb +170 -0
- data/lib/simple_hl7/field.rb +23 -0
- data/lib/simple_hl7/message.rb +74 -0
- data/lib/simple_hl7/msh_segment.rb +38 -0
- data/lib/simple_hl7/segment.rb +23 -0
- data/lib/simple_hl7/separator_characters.rb +8 -0
- data/lib/simple_hl7/subcomponent.rb +27 -0
- data/lib/simple_hl7/version.rb +3 -0
- data/simple_hl7.gemspec +20 -0
- data/spec/simple_hl7/component_container_spec.rb +22 -0
- data/spec/simple_hl7/component_spec.rb +30 -0
- data/spec/simple_hl7/composite_spec.rb +0 -0
- data/spec/simple_hl7/field_spec.rb +15 -0
- data/spec/simple_hl7/message_spec.rb +37 -0
- data/spec/simple_hl7/msh_segment_spec.rb +13 -0
- data/spec/simple_hl7/segment_spec.rb +23 -0
- data/spec/simple_hl7/subcomponent_spec.rb +32 -0
- metadata +110 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Rome Portlock
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# SimpleHl7
|
2
|
+
|
3
|
+
SimpleHL7 is a library that manages HL7 v2.x documents for interfacing with
|
4
|
+
health care systems. The goal of SimpleHL7 is to make it easy to create basic
|
5
|
+
HL7 messages while also having the power to create more complex ones. SimpleHL7
|
6
|
+
is agnostic of message and segment types, it works only with the basic
|
7
|
+
structure of HL7 documents.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'simple_hl7'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install simple_hl7
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
SimpleHL7 can be used for either message creation or parsing.
|
26
|
+
|
27
|
+
### Message Creation
|
28
|
+
|
29
|
+
A simple example:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
msg = SimpleHL7::Message.new
|
33
|
+
msg.msh[9][1] = "ADT"
|
34
|
+
msg.msh[9][2] = "A04"
|
35
|
+
msg.msh[10] = "12345678"
|
36
|
+
msg.msh[11] = "D"
|
37
|
+
msg.msh[12] = "2.5"
|
38
|
+
|
39
|
+
msg.pid[3] = "454545"
|
40
|
+
msg.pid[5][1] = "Doe"
|
41
|
+
msg.pid[5][2] = "John"
|
42
|
+
|
43
|
+
msg.pv1[2] = "O"
|
44
|
+
|
45
|
+
msg.to_hl7
|
46
|
+
```
|
47
|
+
|
48
|
+
Would generate the following HL7 string.
|
49
|
+
|
50
|
+
```
|
51
|
+
MSH|^~\&|||||||ADT^A04|12345678|D|2.5
|
52
|
+
PID|||454545||Doe^John
|
53
|
+
PV1||O
|
54
|
+
```
|
55
|
+
|
56
|
+
This is the easiest way to use SimpleHL7, however most of the methods used
|
57
|
+
above are syntactic sugar for underlying methods that are explained in detail
|
58
|
+
later.
|
59
|
+
|
60
|
+
### Adding a segment
|
61
|
+
|
62
|
+
The easiest way to add a segment to a new message is by calling its three
|
63
|
+
letter segment name as a method on the message. For example to create a PID
|
64
|
+
segment, do the following:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
msg = SimpleHL7::Message.new
|
68
|
+
msg.pid
|
69
|
+
```
|
70
|
+
|
71
|
+
Note that since the MSH segment is always required it is created automatically.
|
72
|
+
So if to_hl7 was called on the message above, the result would be
|
73
|
+
|
74
|
+
```
|
75
|
+
MSH|^~\&|
|
76
|
+
PID
|
77
|
+
```
|
78
|
+
|
79
|
+
### Repeating segments
|
80
|
+
|
81
|
+
Using the segment name is the easiest way to create a new segment, but if you
|
82
|
+
have more than one segment with the same name it won't work. The first name
|
83
|
+
method call will create a segment, but subsequent calls will just reference
|
84
|
+
that first created segment.
|
85
|
+
|
86
|
+
To create multiple segments of the same type use the underlying `add_segment`
|
87
|
+
method.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
obx1 = msg.add_segment('obx')
|
91
|
+
obx2 = msg.add_segment('obx')
|
92
|
+
```
|
93
|
+
|
94
|
+
To later retreive a certain segment use the `segment` method.
|
95
|
+
|
96
|
+
```
|
97
|
+
obx2 = msg.segment('obx', 2)
|
98
|
+
```
|
99
|
+
|
100
|
+
### Adding components, subcomponents, fields etc.
|
101
|
+
|
102
|
+
To add values to the message just specifiy the index in brackets
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
msg = SimpleHL7::Message.new
|
106
|
+
msg.msh[12] = '2.5'
|
107
|
+
```
|
108
|
+
|
109
|
+
To specifiy a certain component use more brackets.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
msg = SimpleHL7::Message.new
|
113
|
+
msg.msh[9][1] = "ADT"
|
114
|
+
msg.msh[9][2] = "A04"
|
115
|
+
```
|
116
|
+
|
117
|
+
It is important to note that under the hood the the bracket syntax actually
|
118
|
+
adds the value to the first subcomponent of the first componenet of the first
|
119
|
+
repition in the specified field.
|
120
|
+
|
121
|
+
This means that:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
msg.msh[9] = "ADT"
|
125
|
+
msg.msh[9][1] = "ADT"
|
126
|
+
msg.msh[9][1][1] = "ADT"
|
127
|
+
```
|
128
|
+
|
129
|
+
are all equivalent.
|
130
|
+
|
131
|
+
### Repeating fields
|
132
|
+
|
133
|
+
Since repeating fields are less common in HL7 they require a little bit of
|
134
|
+
extra work to create using SimpleHL7. Use the `r(index)` method to create
|
135
|
+
repeats.
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
msg.pid[13] = '123-4567'
|
139
|
+
msg.pid[13].r(2)[1] = '876-5432'
|
140
|
+
```
|
141
|
+
|
142
|
+
Creates the following PID segment
|
143
|
+
|
144
|
+
```
|
145
|
+
PID|||||||||||||123-4567~876-5432
|
146
|
+
```
|
147
|
+
|
148
|
+
### HL7 Escaping
|
149
|
+
|
150
|
+
HL7 special characters are automatically escaped properly when generating HL7,
|
151
|
+
without doing any extra work.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
msg = SimpleHL7::Message.new
|
155
|
+
msg.nte[3] = "Testing & escaping notes"
|
156
|
+
msg.to_hl7
|
157
|
+
```
|
158
|
+
|
159
|
+
Outputs:
|
160
|
+
|
161
|
+
```
|
162
|
+
MSH|^~\&|
|
163
|
+
NTE|||Testing \T\ escaping notes
|
164
|
+
```
|
165
|
+
|
166
|
+
### Parsing
|
167
|
+
|
168
|
+
To parse HL7 string use the parse method
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
hl7_str = "MSH|^~\\&|||||||ADT^A04|12345678|D|2.5\rPID|||454545||Doe^John"
|
172
|
+
msg = SimpleHL7::Message.parse(hl7_str)
|
173
|
+
```
|
174
|
+
|
175
|
+
Once the message is parsed use to_s to pull out values
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
msg.pid[5][1].to_s
|
179
|
+
=> "Doe"
|
180
|
+
```
|
181
|
+
|
182
|
+
## Contributing
|
183
|
+
|
184
|
+
1. Fork it
|
185
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
186
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
187
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
188
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/simple_hl7.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "simple_hl7/version"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
# Your code goes here...
|
5
|
+
end
|
6
|
+
|
7
|
+
require "simple_hl7/separator_characters"
|
8
|
+
require "simple_hl7/composite"
|
9
|
+
require "simple_hl7/subcomponent"
|
10
|
+
require "simple_hl7/component"
|
11
|
+
require "simple_hl7/component_container"
|
12
|
+
require "simple_hl7/field"
|
13
|
+
require "simple_hl7/segment"
|
14
|
+
require "simple_hl7/msh_segment"
|
15
|
+
require "simple_hl7/message"
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module SimpleHL7
|
2
|
+
# Generic building block of a HL7 message. The parts of the message
|
3
|
+
# subclass this, and this class does most of the work.
|
4
|
+
class Composite
|
5
|
+
# Constructor
|
6
|
+
#
|
7
|
+
# @param value [String] a value that is passed down to the subclass
|
8
|
+
# constructor. This allows us to set values on top level components that
|
9
|
+
# are passed down to the lowest component. Default nil.
|
10
|
+
def initialize(value = nil)
|
11
|
+
@subcomposites = {}
|
12
|
+
cls = self.class
|
13
|
+
unless value.nil?
|
14
|
+
@subcomposites[cls.start_index] = cls.subcomposite_class.new(value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set the value of the specified subcomposite.
|
19
|
+
# The value is actually passed down to the first subcomposite of the
|
20
|
+
# specified subcomposite and so on until it reaches a Subcomponent
|
21
|
+
# composite.
|
22
|
+
#
|
23
|
+
# @param index [Integer] the subcomposite index.
|
24
|
+
# @param value [String] the value to set.
|
25
|
+
def []=(index, value)
|
26
|
+
set_subcomposite(index, self.class.subcomposite_class.new(value))
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get a specific subcomposite.
|
30
|
+
#
|
31
|
+
# @param index [Integer] The index of the subcomposite.
|
32
|
+
# @return [Subcomposite] The subcomposite at index or a new subcomposite
|
33
|
+
# if none exists. Note that this returns the Subcomposite object and not
|
34
|
+
# the string value. This differs from how []= works, but it seems to make
|
35
|
+
# the most sense when dealing with HL7 messages.
|
36
|
+
def [](index)
|
37
|
+
get_subcomposite(index)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Alias for []
|
41
|
+
def get_subcomposite(index)
|
42
|
+
subcomposite = @subcomposites[index]
|
43
|
+
if subcomposite.nil?
|
44
|
+
subcomposite = self.class.subcomposite_class.new
|
45
|
+
set_subcomposite(index, subcomposite)
|
46
|
+
end
|
47
|
+
subcomposite
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sets a specific subcomposite
|
51
|
+
#
|
52
|
+
# @param index [Integer] the indexs of the subcomposite, if there is an
|
53
|
+
# existing compsite at the location it is replaced.
|
54
|
+
# @param value [Subcomposite] the new subcomposite object for the
|
55
|
+
# specified location.
|
56
|
+
def set_subcomposite(index, value)
|
57
|
+
@subcomposites[index] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
# Calls the specified block once for each index between the start index
|
61
|
+
# and the max specified subcomposite index.
|
62
|
+
#
|
63
|
+
# @yeild [subcomposite] Gives the subcomposite at the current index to the
|
64
|
+
# block. If there isn't a subcomposite specified for the index then nil
|
65
|
+
# is passed.
|
66
|
+
def each
|
67
|
+
start = self.class.start_index
|
68
|
+
(start..max_index).each { |i| yield @subcomposites[i] } if max_index
|
69
|
+
end
|
70
|
+
|
71
|
+
# Calls the specified block once for each index between the start index
|
72
|
+
# and the max specified subcomposite index and returns an array resulting
|
73
|
+
# from the return values of each block.
|
74
|
+
#
|
75
|
+
# @yeild [subcomposite] Gives the subcomposite at the current index to the
|
76
|
+
# block. If there isn't a subcomposite specified for the index then nil
|
77
|
+
# is passed.
|
78
|
+
def map
|
79
|
+
start = self.class.start_index
|
80
|
+
(start..max_index).map { |i| yield @subcomposites[i] } if max_index
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get a HL7 string representation of this Composite.
|
84
|
+
#
|
85
|
+
# @separator_chars [SeparatorChars] The separator characters to be used
|
86
|
+
# when converting this Composite to a string of HL7.
|
87
|
+
def to_hl7(separator_chars)
|
88
|
+
sep_char = self.class.current_separator_char(separator_chars)
|
89
|
+
map { |subc| subc.to_hl7(separator_chars) if subc }.join(sep_char)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Get the value stored at the first Subcomponent below this Composite
|
93
|
+
def to_s
|
94
|
+
@subcomposites[self.class.start_index].to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get all the subcomposites as an array. Note that this array has the
|
98
|
+
# actual subcomposite object and not clones, so any changes will affect
|
99
|
+
# this class as well.
|
100
|
+
def to_a
|
101
|
+
a = []
|
102
|
+
each {|subc| a << subc}
|
103
|
+
a
|
104
|
+
end
|
105
|
+
|
106
|
+
# The index where the first subcomposite is located. This is usually either
|
107
|
+
# 1 or 0 depending on the specific Composite.
|
108
|
+
def self.start_index
|
109
|
+
1
|
110
|
+
end
|
111
|
+
|
112
|
+
# @abstract The character that is used to separate the subcomposites when
|
113
|
+
# generating a HL7 string.
|
114
|
+
#
|
115
|
+
# @param separator_chars [SeparatorChars] The separator characters in use
|
116
|
+
# during the HL7 string conversion.
|
117
|
+
def self.current_separator_char(separator_chars)
|
118
|
+
raise Exception.new("Subclass Responsibility")
|
119
|
+
end
|
120
|
+
|
121
|
+
# @abstract The class that is used for subcomposites.
|
122
|
+
def self.subcomposite_class
|
123
|
+
raise Exception.new("Subclass Responsibility")
|
124
|
+
end
|
125
|
+
|
126
|
+
# Create a composite from a HL7 string.
|
127
|
+
#
|
128
|
+
# @param str [String] The string of HL7.
|
129
|
+
# @param separator_chars [SeparatorChars] The separator characters used
|
130
|
+
# in the HL7 string.
|
131
|
+
# @return [Composite] The parsed composite.
|
132
|
+
def self.parse(str, separator_chars)
|
133
|
+
composite = new
|
134
|
+
parse_subcomposite_hash(str, separator_chars).each do |index, subc|
|
135
|
+
composite.set_subcomposite(start_index + index, subc)
|
136
|
+
end
|
137
|
+
composite
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def max_index
|
143
|
+
@subcomposites.keys.max
|
144
|
+
end
|
145
|
+
|
146
|
+
class << self
|
147
|
+
private
|
148
|
+
|
149
|
+
# Parses the subcomposites of a HL7 string into a hash
|
150
|
+
#
|
151
|
+
# @param str [String] The HL7 string to parse.
|
152
|
+
# @param separator_chars [SeparatorChars] The separator characters used in
|
153
|
+
# the HL7 string.
|
154
|
+
# @return A hash of composites, one for each subcomposite in the string
|
155
|
+
# that actually had a value. Empty subcomposites are left out of the
|
156
|
+
# hash.
|
157
|
+
def parse_subcomposite_hash(str, separator_chars)
|
158
|
+
subc_strs = str.split(current_separator_char(separator_chars))
|
159
|
+
subc_h = {}
|
160
|
+
subc_strs.each_with_index do |subc_str, index|
|
161
|
+
unless subc_str.empty?
|
162
|
+
subc_h[index] = subcomposite_class.parse(subc_str, separator_chars)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
subc_h
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SimpleHL7
|
2
|
+
class Field < Composite
|
3
|
+
def self.current_separator_char(separator_chars)
|
4
|
+
separator_chars.repetition
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.subcomposite_class
|
8
|
+
ComponentContainer
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(index, value)
|
12
|
+
get_subcomposite(1)[index] = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](index)
|
16
|
+
get_subcomposite(1)[index]
|
17
|
+
end
|
18
|
+
|
19
|
+
def r(index)
|
20
|
+
get_subcomposite(index)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SimpleHL7
|
2
|
+
class Message
|
3
|
+
def initialize(default_msh = true)
|
4
|
+
@segments = []
|
5
|
+
@segments << MSHSegment.new if default_msh
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(meth, *args, &block)
|
9
|
+
if meth.to_s =~ /^[a-zA-Z][a-zA-Z0-9]{2}$/
|
10
|
+
get_named_segment(meth)
|
11
|
+
elsif meth.to_s =~ /^[a-zA-Z][a-zA-Z0-9]{2}_all$/
|
12
|
+
seg_name = meth[0..3]
|
13
|
+
all_segments(seg_name)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hl7
|
20
|
+
separator_chars = get_named_segment('MSH').separator_chars
|
21
|
+
@segments.map {|s| s.to_hl7(separator_chars)}.join("\r")
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_a
|
25
|
+
@segments.reduce([]) {|a, s| a << s.to_a}
|
26
|
+
end
|
27
|
+
|
28
|
+
def segment(name, index=1)
|
29
|
+
all = all_segments(name)
|
30
|
+
seg = nil
|
31
|
+
seg = all[index - 1] if all.size >= index
|
32
|
+
seg
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_segment(name)
|
36
|
+
segment = Segment.new(name)
|
37
|
+
@segments << segment
|
38
|
+
segment
|
39
|
+
end
|
40
|
+
|
41
|
+
def append_segment(segment)
|
42
|
+
@segments << segment
|
43
|
+
segment
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def all_segments(name)
|
49
|
+
@segments.select {|seg| seg.name == name}
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def get_named_segment(name)
|
54
|
+
name_str = name.to_s.upcase
|
55
|
+
segment = @segments.select {|seg| seg.name == name_str}.first
|
56
|
+
unless segment
|
57
|
+
segment = Segment.new(name_str)
|
58
|
+
@segments << segment
|
59
|
+
end
|
60
|
+
segment
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.parse(str)
|
64
|
+
msg = new(false)
|
65
|
+
segment_strs = str.split("\r")
|
66
|
+
msh = MSHSegment.parse(segment_strs[0])
|
67
|
+
msg.append_segment(msh)
|
68
|
+
segment_strs[1, segment_strs.length].each do |seg_str|
|
69
|
+
msg.append_segment(Segment.parse(seg_str, msh.separator_chars))
|
70
|
+
end
|
71
|
+
msg
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module SimpleHL7
|
2
|
+
class MSHSegment < Segment
|
3
|
+
def initialize
|
4
|
+
super('MSH')
|
5
|
+
self[1] = '|'
|
6
|
+
self[2] = '^~\&'
|
7
|
+
end
|
8
|
+
|
9
|
+
def separator_chars
|
10
|
+
enc_chars = @subcomposites[2].to_s
|
11
|
+
SeparatorCharacters.new(@subcomposites[1].to_s,
|
12
|
+
enc_chars[0],
|
13
|
+
enc_chars[1],
|
14
|
+
enc_chars[2],
|
15
|
+
enc_chars[3])
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse(str)
|
19
|
+
msh = new
|
20
|
+
msh[1] = str[3]
|
21
|
+
msh[2] = str[4..7]
|
22
|
+
|
23
|
+
fields = parse_subcomposite_hash(str[9, str.length], msh.separator_chars)
|
24
|
+
fields.each { |index, subc| msh.set_subcomposite(index + 3, subc) }
|
25
|
+
msh
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hl7(separator_chars)
|
29
|
+
sep_char = self.class.current_separator_char(separator_chars)
|
30
|
+
base_msh = "#{name}#{self[1]}#{self[2]}"
|
31
|
+
max_index = @subcomposites.keys.max
|
32
|
+
rest_msh = (3..max_index).map { |i|
|
33
|
+
@subcomposites[i].to_hl7(separator_chars) if @subcomposites[i]
|
34
|
+
}.join(sep_char)
|
35
|
+
[base_msh, rest_msh].join(sep_char)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SimpleHL7
|
2
|
+
class Segment < Composite
|
3
|
+
def self.start_index
|
4
|
+
0
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.subcomposite_class
|
8
|
+
Field
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.current_separator_char(separator_chars)
|
12
|
+
separator_chars.field
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
self[0].to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_a
|
20
|
+
super.insert(0, name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SimpleHL7
|
2
|
+
class Subcomponent < Struct.new(:value)
|
3
|
+
def to_hl7(separator_chars)
|
4
|
+
hl7 = value
|
5
|
+
hl7.gsub!(separator_chars.escape, "\\E\\")
|
6
|
+
hl7.gsub!(separator_chars.field, "\\F\\")
|
7
|
+
hl7.gsub!(separator_chars.repetition, "\\R\\")
|
8
|
+
hl7.gsub!(separator_chars.component, "\\S\\")
|
9
|
+
hl7.gsub!(separator_chars.subcomponent, "\\T\\")
|
10
|
+
hl7
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
value
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse(str, separator_chars)
|
18
|
+
value = str
|
19
|
+
value.gsub!("\\E\\", separator_chars.escape)
|
20
|
+
value.gsub!("\\F\\", separator_chars.field)
|
21
|
+
value.gsub!("\\R\\", separator_chars.repetition)
|
22
|
+
value.gsub!("\\S\\", separator_chars.component)
|
23
|
+
value.gsub!("\\T\\", separator_chars.subcomponent)
|
24
|
+
Subcomponent.new(value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/simple_hl7.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/simple_hl7/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Rome Portlock"]
|
6
|
+
gem.email = ["rome@alivecor.com"]
|
7
|
+
gem.description = %q{Parse and generate hl7 messages for interfacing with health care systems}
|
8
|
+
gem.summary = %q{Parse and generate hl7 messages}
|
9
|
+
gem.homepage = "https://github.com/alivecor/simple_hl7"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "simple_hl7"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = SimpleHL7::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency "pry", "~> 0.9"
|
19
|
+
gem.add_development_dependency "rspec", "~> 2.14"
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "simple_hl7"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
describe ComponentContainer do
|
5
|
+
describe "#to_hl7" do
|
6
|
+
it "generates proper hl7 for a field with subfields" do
|
7
|
+
container = ComponentContainer.new
|
8
|
+
container[1] = "foo"
|
9
|
+
container[2] = "bar"
|
10
|
+
container.to_hl7(SeparatorCharacters.defaults).should == "foo^bar"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "generates proper hl7 for a field with components and subfields" do
|
14
|
+
container = ComponentContainer.new
|
15
|
+
container[1] = "foo"
|
16
|
+
container[1][2] = "bar"
|
17
|
+
container[2] = "baz"
|
18
|
+
container.to_hl7(SeparatorCharacters.defaults).should == "foo&bar^baz"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "simple_hl7"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
describe Component do
|
5
|
+
describe "#to_hl7" do
|
6
|
+
it "generates proper hl7 for a field with subfields" do
|
7
|
+
field = Component.new
|
8
|
+
field[1] = "foo"
|
9
|
+
field[2] = "bar"
|
10
|
+
field.to_hl7(SeparatorCharacters.defaults).should == "foo&bar"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "[]" do
|
15
|
+
it "gets the proper value" do
|
16
|
+
field = Component.new
|
17
|
+
field[1] = "foo"
|
18
|
+
field[1].to_s.should == "foo"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#parse" do
|
23
|
+
it "parse hl7 correctly" do
|
24
|
+
component = Component.parse("foo&bar", SeparatorCharacters.defaults)
|
25
|
+
component[1].to_s.should == "foo"
|
26
|
+
component[2].to_s.should == "bar"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "simple_hl7"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
describe Field do
|
5
|
+
describe "#to_hl7" do
|
6
|
+
it "generates proper hl7 for a field with subfields" do
|
7
|
+
field = Field.new
|
8
|
+
field[1] = "foo"
|
9
|
+
field[2] = "baz"
|
10
|
+
field.r(2)[1] = "bar"
|
11
|
+
field.to_hl7(SeparatorCharacters.defaults).should == 'foo^baz~bar'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "simple_hl7"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
describe Message do
|
5
|
+
describe "#to_hl7" do
|
6
|
+
it "generates an hl7 message" do
|
7
|
+
msg = Message.new
|
8
|
+
msg.msh[6] = "accountid"
|
9
|
+
msg.pid[5] = "User"
|
10
|
+
msg.pid[5][2] = "Test"
|
11
|
+
msg.to_hl7.should == "MSH|^~\\&||||accountid\rPID|||||User^Test"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#add_segment" do
|
16
|
+
it "adds segments properly" do
|
17
|
+
msg = Message.new
|
18
|
+
obx_1 = msg.add_segment('OBX')
|
19
|
+
obx_1[1] = "1"
|
20
|
+
obx_2 = msg.add_segment('OBX')
|
21
|
+
obx_2[1] = "2"
|
22
|
+
msg.segment('OBX', 1)[1].to_s.should == "1"
|
23
|
+
msg.segment('OBX', 2)[1].to_s.should == "2"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#parse" do
|
28
|
+
it "properly parses a hl7 string" do
|
29
|
+
msg = Message.parse("MSH|^~\\&||||accountid\rPID|||||User^Test~Repeat")
|
30
|
+
msg.msh[6].to_s.should == "accountid"
|
31
|
+
msg.pid[5].to_s.should == "User"
|
32
|
+
msg.pid[5][2].to_s.should == "Test"
|
33
|
+
msg.pid[5].r(2)[1].to_s.should == "Repeat"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "simple_hl7"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
describe MSHSegment do
|
5
|
+
describe "#parse" do
|
6
|
+
it "parses a hl7 string correctly" do
|
7
|
+
msh = MSHSegment.parse('MSH|^~\\&|||test')
|
8
|
+
msh.separator_chars.field.should == '|'
|
9
|
+
msh[5].to_s.should == 'test'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "simple_hl7"
|
3
|
+
|
4
|
+
module SimpleHL7
|
5
|
+
describe Segment do
|
6
|
+
describe "#to_hl7" do
|
7
|
+
it "generates a message using the specified separator chars" do
|
8
|
+
sep_chars = SeparatorCharacters.defaults
|
9
|
+
seg = Segment.new('PID')
|
10
|
+
seg[5] = 'test'
|
11
|
+
seg.to_hl7(sep_chars).should == 'PID|||||test'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#parse" do
|
16
|
+
it "parses a hl7 string correctly" do
|
17
|
+
sep_chars = SeparatorCharacters.defaults
|
18
|
+
seg = Segment.parse('PID|||||test', sep_chars)
|
19
|
+
seg[5].to_s.should == 'test'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "simple_hl7"
|
2
|
+
|
3
|
+
module SimpleHL7
|
4
|
+
describe Subcomponent do
|
5
|
+
describe "#to_hl7" do
|
6
|
+
it "returns the value" do
|
7
|
+
subf = Subcomponent.new('test')
|
8
|
+
subf.to_hl7(SeparatorCharacters.defaults).should == 'test'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "escapes special characters in a string" do
|
12
|
+
subc = Subcomponent.new('peas&carrots')
|
13
|
+
subc.to_hl7(SeparatorCharacters.defaults).should == 'peas\T\carrots'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "escapes all special characters" do
|
17
|
+
subc = Subcomponent.new('\\&^~|')
|
18
|
+
default_chars = SeparatorCharacters.defaults
|
19
|
+
subc.to_hl7(default_chars).should == "\\E\\\\T\\\\S\\\\R\\\\F\\"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#parse" do
|
24
|
+
it "should unescape the special characters" do
|
25
|
+
str = "\\E\\\\T\\\\S\\\\R\\\\F\\"
|
26
|
+
default_chars = SeparatorCharacters.defaults
|
27
|
+
parsed = Subcomponent.parse(str, default_chars)
|
28
|
+
parsed.to_s.should == '\\&^~|'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_hl7
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rome Portlock
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-02-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.9'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.9'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.14'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.14'
|
46
|
+
description: Parse and generate hl7 messages for interfacing with health care systems
|
47
|
+
email:
|
48
|
+
- rome@alivecor.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- lib/simple_hl7.rb
|
59
|
+
- lib/simple_hl7/component.rb
|
60
|
+
- lib/simple_hl7/component_container.rb
|
61
|
+
- lib/simple_hl7/composite.rb
|
62
|
+
- lib/simple_hl7/field.rb
|
63
|
+
- lib/simple_hl7/message.rb
|
64
|
+
- lib/simple_hl7/msh_segment.rb
|
65
|
+
- lib/simple_hl7/segment.rb
|
66
|
+
- lib/simple_hl7/separator_characters.rb
|
67
|
+
- lib/simple_hl7/subcomponent.rb
|
68
|
+
- lib/simple_hl7/version.rb
|
69
|
+
- simple_hl7.gemspec
|
70
|
+
- spec/simple_hl7/component_container_spec.rb
|
71
|
+
- spec/simple_hl7/component_spec.rb
|
72
|
+
- spec/simple_hl7/composite_spec.rb
|
73
|
+
- spec/simple_hl7/field_spec.rb
|
74
|
+
- spec/simple_hl7/message_spec.rb
|
75
|
+
- spec/simple_hl7/msh_segment_spec.rb
|
76
|
+
- spec/simple_hl7/segment_spec.rb
|
77
|
+
- spec/simple_hl7/subcomponent_spec.rb
|
78
|
+
homepage: https://github.com/alivecor/simple_hl7
|
79
|
+
licenses: []
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.8.24
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Parse and generate hl7 messages
|
102
|
+
test_files:
|
103
|
+
- spec/simple_hl7/component_container_spec.rb
|
104
|
+
- spec/simple_hl7/component_spec.rb
|
105
|
+
- spec/simple_hl7/composite_spec.rb
|
106
|
+
- spec/simple_hl7/field_spec.rb
|
107
|
+
- spec/simple_hl7/message_spec.rb
|
108
|
+
- spec/simple_hl7/msh_segment_spec.rb
|
109
|
+
- spec/simple_hl7/segment_spec.rb
|
110
|
+
- spec/simple_hl7/subcomponent_spec.rb
|