class HL7::Message

Ruby Object representation of an hl7 2.x message the message object is actually a “smart” collection of hl7 segments

Examples

Creating a new HL7 message

# create a message
msg = HL7::Message.new

# create a MSH segment for our new message
msh = HL7::Message::Segment::MSH.new
msh.recv_app = "ruby hl7"
msh.recv_facility = "my office"
msh.processing_id = rand(10000).to_s

msg << msh # add the MSH segment to the message

puts msg.to_s # readable version of the message

puts msg.to_hl7 # hl7 version of the message (as a string)

puts msg.to_mllp # mllp version of the message (as a string)

Parse an existing HL7 message

raw_input = open( "my_hl7_msg.txt" ).readlines
msg = HL7::Message.new( raw_input )

puts "message type: %s" % msg[:MSH].message_type

Attributes

delimiter[R]
element_delim[R]
item_delim[R]
message_parser[R]
segment_delim[R]

Public Class Methods

new( raw_msg=nil, &blk ) click to toggle source

setup a new hl7 message

raw_msg

is an optional object containing an hl7 message it can either be a string or an Enumerable object

# File lib/message.rb, line 45
def initialize( raw_msg=nil, &blk )
  @segments = []
  @segments_by_name = {}
  @item_delim = "^"
  @element_delim = '|'
  @segment_delim = "\r"
  @delimiter = HL7::Message::Delimiter.new( @element_delim,
                                            @item_delim,
                                            @segment_delim)

  @message_parser = HL7::MessageParser.new(@delimiter)

  parse( raw_msg ) if raw_msg

  if block_given?
    blk.call self
  end
end

Public Instance Methods

<<( value ) click to toggle source

add a segment or array of segments to the message

  • will force auto set_id sequencing for segments containing set_id's

# File lib/message.rb, line 129
def <<( value )
  # do nothing if value is nil
  return unless value

  if value.kind_of? Array
    value.map{|item| append(item)}
  else
    append(value)
  end
end
[]( index ) click to toggle source

access a segment of the message

index

can be a Range, Integer or anything that responds to to_sym

# File lib/message.rb, line 83
def []( index )
  ret = nil

  if index.kind_of?(Range) || index.kind_of?(Integer)
    ret = @segments[ index ]
  elsif (index.respond_to? :to_sym)
    ret = @segments_by_name[ index.to_sym ]
    ret = ret.first if ret && ret.length == 1
  end

  ret
end
[]=( index, value ) click to toggle source

modify a segment of the message

index

can be a Range, Integer or anything that responds to to_sym

value

an HL7::Message::Segment object

# File lib/message.rb, line 100
def []=( index, value )
  unless ( value && value.kind_of?(HL7::Message::Segment) )
    raise HL7::Exception.new( "attempting to assign something other than an HL7 Segment" )
  end

  if index.kind_of?(Range) || index.kind_of?(Integer)
    @segments[ index ] = value
  elsif index.respond_to?(:to_sym)
    (@segments_by_name[ index.to_sym ] ||= []) << value
  else
    raise HL7::Exception.new( "attempting to use an indice that is not a Range, Integer or to_sym providing object" )
  end

  value.segment_parent = self
end
append( value ) click to toggle source
# File lib/message.rb, line 140
def append( value )
  unless ( value && value.kind_of?(HL7::Message::Segment) )
    raise HL7::Exception.new( "attempting to append something other than an HL7 Segment" )
  end

  value.segment_parent = self unless value.segment_parent
  (@segments ||= []) << value
  name = value.class.to_s.gsub("HL7::Message::Segment::", "").to_sym
  (@segments_by_name[ name ] ||= []) << value
  sequence_segments unless defined?(@parsing) && @parsing # let's auto-set the set-id as we go
end
correction?() click to toggle source

Checks if any of the results is a correction

# File lib/message.rb, line 200
def correction?
  Array(self[:OBX]).any?(&:correction?)
end
each() { |segment| ... } click to toggle source

yield each segment in the message

# File lib/message.rb, line 153
def each # :yields: segment
  return unless @segments
  @segments.each { |s| yield s }
end
generate_segments_enumerable(enumerable) click to toggle source
# File lib/message.rb, line 74
def generate_segments_enumerable(enumerable)
  enumerable.each do |segment|
    generate_segments( message_parser.parse_string( segment.to_s ))
  end
end
index( value ) click to toggle source

return the index of the value if it exists, nil otherwise

value

is expected to be a string

# File lib/message.rb, line 118
def index( value )
  return nil unless (value && value.respond_to?(:to_sym))

  segs = @segments_by_name[ value.to_sym ]
  return nil unless segs

  @segments.index( segs.to_a.first )
end
length() click to toggle source

return the segment count

# File lib/message.rb, line 159
def length
  0 unless @segments
  @segments.length
end
parse( inobj ) click to toggle source
# File lib/message.rb, line 64
def parse( inobj )
  if inobj.kind_of?(String)
    generate_segments( message_parser.parse_string( inobj ))
  elsif inobj.respond_to?(:each)
    generate_segments_enumerable(inobj)
  else
    raise HL7::ParseError.new( "object to parse should be string or enumerable" )
  end
end
sequence_segments(base=nil) click to toggle source

auto-set the set_id fields of any message segments that provide it and have more than one instance in the message

# File lib/message.rb, line 182
def sequence_segments(base=nil)
  last = nil
  segs = @segments
  segs = base.children if base

  segs.each do |s|
    if s.kind_of?( last.class ) && s.respond_to?( :set_id )
      last.set_id = 1 unless last.set_id && last.set_id.to_i > 0
      s.set_id = last.set_id.to_i + 1
    end

    sequence_segments( s ) if s.has_children?

    last = s
  end
end
to_hl7() click to toggle source

provide a HL7 spec version of the message

# File lib/message.rb, line 170
def to_hl7
  @segments.collect { |s| s if s.to_s.length > 0 }.join( @delimiter.segment )
end
to_mllp() click to toggle source

provide the HL7 spec version of the message wrapped in MLLP

# File lib/message.rb, line 175
def to_mllp
  pre_mllp = to_hl7
  "\x0b" + pre_mllp + "\x1c\r"
end
to_s() click to toggle source

provide a screen-readable version of the message

# File lib/message.rb, line 165
def to_s
  @segments.collect { |s| s if s.to_s.length > 0 }.join( "\n" )
end

Private Instance Methods

choose_segment_from(segment_stack, new_seg, seg_name) click to toggle source
# File lib/message.rb, line 240
def choose_segment_from(segment_stack, new_seg, seg_name)

  # Segments have been previously seen
  while(segment_stack.length > 0)
    if segment_stack.last && segment_stack.last.has_children? && segment_stack.last.accepts?( seg_name )
      # If a previous segment can accept the current segment as a child,
      # add it to the previous segments children
      segment_stack.last.children << new_seg
      new_seg.is_child_segment = true
      segment_stack << new_seg
      break;
    else
      segment_stack.pop
    end
  end

  # Root of segment 'tree'
  if segment_stack.length == 0
    @segments << new_seg
    segment_stack << new_seg
    setup_segment_lookup_by_name( seg_name, new_seg)
  end
end
generate_segment( elm, segment_stack ) click to toggle source
# File lib/message.rb, line 226
def generate_segment( elm, segment_stack )
  segment_generator = HL7::Message::SegmentGenerator.new( elm,
                                                          segment_stack,
                                                          @delimiter )

  return nil unless segment_generator.valid_segments_parts?
  segment_generator.seg_name = segment_generator.seg_parts[0]

  new_seg = segment_generator.build
  new_seg.segment_parent = self

  choose_segment_from(segment_stack, new_seg, segment_generator.seg_name)
end
generate_segments( ary ) click to toggle source
# File lib/message.rb, line 205
def generate_segments( ary )
  raise HL7::ParseError.new( "no array to generate segments" ) unless ary.length > 0

  @parsing = true
  segment_stack = []
  ary.each do |elm|
    if elm.slice(0,3) == "MSH"
      update_delimiters(elm)
    end
    last_seg = generate_segment( elm, segment_stack ) || last_seg
  end
  @parsing = nil
end
get_symbol_from_name(seg_name) click to toggle source
# File lib/message.rb, line 273
def get_symbol_from_name(seg_name)
  seg_name.to_s.strip.length > 0 ? seg_name.to_sym : nil
end
setup_segment_lookup_by_name(seg_name, new_seg) click to toggle source

Allow segment lookup by name

# File lib/message.rb, line 265
def setup_segment_lookup_by_name(seg_name, new_seg)
  seg_sym = get_symbol_from_name(seg_name)
  if seg_sym
    @segments_by_name[ seg_sym ] ||= []
    @segments_by_name[ seg_sym ] << new_seg
  end
end
update_delimiters(elm) click to toggle source
# File lib/message.rb, line 219
def update_delimiters(elm)
  @item_delim = message_parser.parse_item_delim(elm)
  @element_delim = message_parser.parse_element_delim(elm)
  @delimiter.item = @item_delim
  @delimiter.element = @element_delim
end