ruby-hl7 1.0.3 → 1.1.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 +7 -0
 - data/README.rdoc +5 -5
 - data/lib/core_ext/date_time.rb +65 -0
 - data/lib/core_ext/string.rb +6 -0
 - data/lib/message.rb +272 -0
 - data/lib/message_parser.rb +75 -0
 - data/lib/ruby-hl7.rb +15 -637
 - data/lib/segment.rb +189 -0
 - data/lib/segment_default.rb +18 -0
 - data/lib/segment_fields.rb +117 -0
 - data/lib/segment_generator.rb +55 -0
 - data/lib/segment_list_storage.rb +79 -0
 - data/lib/segments/evn.rb +14 -8
 - data/lib/segments/in1.rb +54 -0
 - data/lib/segments/msh.rb +23 -17
 - data/lib/segments/obr.rb +23 -10
 - data/lib/segments/obx.rb +15 -4
 - data/lib/segments/orc.rb +19 -3
 - data/lib/segments/pid.rb +13 -6
 - data/lib/segments/prd.rb +18 -0
 - data/lib/segments/pv1.rb +6 -2
 - data/lib/segments/pv2.rb +18 -15
 - data/lib/segments/rf1.rb +22 -0
 - data/lib/segments/zcf.rb +23 -0
 - data/test_data/obxobr.hl7 +1 -1
 - metadata +94 -110
 - data/lib/string.rb +0 -5
 
    
        data/lib/segment.rb
    ADDED
    
    | 
         @@ -0,0 +1,189 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Ruby Object representation of an hl7 2.x message segment
         
     | 
| 
      
 2 
     | 
    
         
            +
            # The segments can be setup to provide aliases to specific fields with
         
     | 
| 
      
 3 
     | 
    
         
            +
            # optional validation code that is run when the field is modified
         
     | 
| 
      
 4 
     | 
    
         
            +
            # The segment field data is also accessible via the e<number> method.
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # == Defining a New Segment
         
     | 
| 
      
 7 
     | 
    
         
            +
            #  class HL7::Message::Segment::NK1 < HL7::Message::Segment
         
     | 
| 
      
 8 
     | 
    
         
            +
            #    wieght 100 # segments are sorted ascendingly
         
     | 
| 
      
 9 
     | 
    
         
            +
            #    add_field :something_you_want       # assumes :idx=>1
         
     | 
| 
      
 10 
     | 
    
         
            +
            #    add_field :something_else, :idx=>6  # :idx=>6 and field count=6
         
     | 
| 
      
 11 
     | 
    
         
            +
            #    add_field :something_more           # :idx=>7
         
     | 
| 
      
 12 
     | 
    
         
            +
            #    add_field :block_example do |value|
         
     | 
| 
      
 13 
     | 
    
         
            +
            #       raise HL7::InvalidDataError.new
         
     | 
| 
      
 14 
     | 
    
         
            +
            #                                  unless value.to_i < 100 && value.to_i > 10
         
     | 
| 
      
 15 
     | 
    
         
            +
            #      return value
         
     | 
| 
      
 16 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 17 
     | 
    
         
            +
            #    # this block will be executed when seg.block_example= is called
         
     | 
| 
      
 18 
     | 
    
         
            +
            #    # and when seg.block_example is called
         
     | 
| 
      
 19 
     | 
    
         
            +
            #
         
     | 
| 
      
 20 
     | 
    
         
            +
            class HL7::Message::Segment
         
     | 
| 
      
 21 
     | 
    
         
            +
              extend HL7::Message::SegmentListStorage
         
     | 
| 
      
 22 
     | 
    
         
            +
              include HL7::Message::SegmentFields
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              attr :segment_parent, true
         
     | 
| 
      
 25 
     | 
    
         
            +
              attr :element_delim
         
     | 
| 
      
 26 
     | 
    
         
            +
              attr :item_delim
         
     | 
| 
      
 27 
     | 
    
         
            +
              attr :segment_weight
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              METHOD_MISSING_FOR_INITIALIZER = <<-END
         
     | 
| 
      
 30 
     | 
    
         
            +
                def method_missing( sym, *args, &blk )
         
     | 
| 
      
 31 
     | 
    
         
            +
                  __seg__.send( sym, args, blk )
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              END
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              # setup a new HL7::Message::Segment
         
     | 
| 
      
 36 
     | 
    
         
            +
              # raw_segment:: is an optional String or Array which will be used as the
         
     | 
| 
      
 37 
     | 
    
         
            +
              #               segment's field data
         
     | 
| 
      
 38 
     | 
    
         
            +
              # delims:: an optional array of delimiters, where
         
     | 
| 
      
 39 
     | 
    
         
            +
              #               delims[0] = element delimiter
         
     | 
| 
      
 40 
     | 
    
         
            +
              #               delims[1] = item delimiter
         
     | 
| 
      
 41 
     | 
    
         
            +
              def initialize(raw_segment="", delims=[], &blk)
         
     | 
| 
      
 42 
     | 
    
         
            +
                @segments_by_name = {}
         
     | 
| 
      
 43 
     | 
    
         
            +
                @field_total = 0
         
     | 
| 
      
 44 
     | 
    
         
            +
                @is_child = false
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                setup_delimiters delims
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                @elements = elements_from_segment(raw_segment)
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                if block_given?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  callctx = eval( "self", blk.binding )
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def callctx.__seg__(val=nil)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @__seg_val__ ||= val
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  callctx.__seg__(self)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # TODO: find out if this pollutes the calling namespace permanently...
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  eval( METHOD_MISSING_FOR_INITIALIZER, blk.binding )
         
     | 
| 
      
 59 
     | 
    
         
            +
                  yield self
         
     | 
| 
      
 60 
     | 
    
         
            +
                  eval( "class << self; remove_method :method_missing;end", blk.binding )
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              # Breaks the raw segment into elements
         
     | 
| 
      
 65 
     | 
    
         
            +
              # raw_segment:: is an optional String or Array which will be used as the
         
     | 
| 
      
 66 
     | 
    
         
            +
              #               segment's field data
         
     | 
| 
      
 67 
     | 
    
         
            +
              def elements_from_segment(raw_segment)
         
     | 
| 
      
 68 
     | 
    
         
            +
                if (raw_segment.kind_of? Array)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  elements = raw_segment
         
     | 
| 
      
 70 
     | 
    
         
            +
                else
         
     | 
| 
      
 71 
     | 
    
         
            +
                  elements = HL7::MessageParser.split_by_delimiter( raw_segment,
         
     | 
| 
      
 72 
     | 
    
         
            +
                                                                    @element_delim )
         
     | 
| 
      
 73 
     | 
    
         
            +
                  if raw_segment == ""
         
     | 
| 
      
 74 
     | 
    
         
            +
                    elements[0] = self.class.to_s.split( "::" ).last
         
     | 
| 
      
 75 
     | 
    
         
            +
                    elements << ""
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
                elements
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              def to_info
         
     | 
| 
      
 82 
     | 
    
         
            +
                "%s: empty segment >> %s" % [ self.class.to_s, @elements.inspect ]
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              # output the HL7 spec version of the segment
         
     | 
| 
      
 86 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 87 
     | 
    
         
            +
                @elements.join( @element_delim )
         
     | 
| 
      
 88 
     | 
    
         
            +
              end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
              # at the segment level there is no difference between to_s and to_hl7
         
     | 
| 
      
 91 
     | 
    
         
            +
              alias :to_hl7 :to_s
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
              # handle the e<number> field accessor
         
     | 
| 
      
 94 
     | 
    
         
            +
              # and any aliases that didn't get added to the system automatically
         
     | 
| 
      
 95 
     | 
    
         
            +
              def method_missing( sym, *args, &blk )
         
     | 
| 
      
 96 
     | 
    
         
            +
                base_str = sym.to_s.gsub( "=", "" )
         
     | 
| 
      
 97 
     | 
    
         
            +
                base_sym = base_str.to_sym
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                if self.class.fields.include?( base_sym )
         
     | 
| 
      
 100 
     | 
    
         
            +
                  # base_sym is ok, let's move on
         
     | 
| 
      
 101 
     | 
    
         
            +
                elsif /e([0-9]+)/.match( base_str )
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # base_sym should actually be $1, since we're going by
         
     | 
| 
      
 103 
     | 
    
         
            +
                  # element id number
         
     | 
| 
      
 104 
     | 
    
         
            +
                  base_sym = $1.to_i
         
     | 
| 
      
 105 
     | 
    
         
            +
                else
         
     | 
| 
      
 106 
     | 
    
         
            +
                  super
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                if sym.to_s.include?( "=" )
         
     | 
| 
      
 110 
     | 
    
         
            +
                  write_field( base_sym, args )
         
     | 
| 
      
 111 
     | 
    
         
            +
                else
         
     | 
| 
      
 112 
     | 
    
         
            +
                  if args.length > 0
         
     | 
| 
      
 113 
     | 
    
         
            +
                    write_field( base_sym, args.flatten.select { |arg| arg } )
         
     | 
| 
      
 114 
     | 
    
         
            +
                  else
         
     | 
| 
      
 115 
     | 
    
         
            +
                    read_field( base_sym )
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              # sort-compare two Segments, 0 indicates equality
         
     | 
| 
      
 121 
     | 
    
         
            +
              def <=>( other )
         
     | 
| 
      
 122 
     | 
    
         
            +
                return nil unless other.kind_of?(HL7::Message::Segment)
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                # per Comparable docs: http://www.ruby-doc.org/core/classes/Comparable.html
         
     | 
| 
      
 125 
     | 
    
         
            +
                diff = self.weight - other.weight
         
     | 
| 
      
 126 
     | 
    
         
            +
                return -1 if diff > 0
         
     | 
| 
      
 127 
     | 
    
         
            +
                return 1 if diff < 0
         
     | 
| 
      
 128 
     | 
    
         
            +
                return 0
         
     | 
| 
      
 129 
     | 
    
         
            +
              end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              # get the defined sort-weight of this segment class
         
     | 
| 
      
 132 
     | 
    
         
            +
              # an alias for self.weight
         
     | 
| 
      
 133 
     | 
    
         
            +
              def weight
         
     | 
| 
      
 134 
     | 
    
         
            +
                self.class.weight
         
     | 
| 
      
 135 
     | 
    
         
            +
              end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
              # return true if the segment has a parent
         
     | 
| 
      
 138 
     | 
    
         
            +
              def is_child_segment?
         
     | 
| 
      
 139 
     | 
    
         
            +
                (@is_child_segment ||= false)
         
     | 
| 
      
 140 
     | 
    
         
            +
              end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
              # indicate whether or not the segment has a parent
         
     | 
| 
      
 143 
     | 
    
         
            +
              def is_child_segment=(val)
         
     | 
| 
      
 144 
     | 
    
         
            +
                @is_child_segment = val
         
     | 
| 
      
 145 
     | 
    
         
            +
              end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
              # get the length of the segment (number of fields it contains)
         
     | 
| 
      
 148 
     | 
    
         
            +
              def length
         
     | 
| 
      
 149 
     | 
    
         
            +
                0 unless @elements
         
     | 
| 
      
 150 
     | 
    
         
            +
                @elements.length
         
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
              def has_children?
         
     | 
| 
      
 154 
     | 
    
         
            +
                self.respond_to?(:children)
         
     | 
| 
      
 155 
     | 
    
         
            +
              end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
              private
         
     | 
| 
      
 158 
     | 
    
         
            +
              def self.singleton #:nodoc:
         
     | 
| 
      
 159 
     | 
    
         
            +
                class << self; self end
         
     | 
| 
      
 160 
     | 
    
         
            +
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
              def setup_delimiters(delims)
         
     | 
| 
      
 163 
     | 
    
         
            +
                delims = [ delims ].flatten
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                @element_delim = ( delims.length>0 ) ? delims[0] : "|"
         
     | 
| 
      
 166 
     | 
    
         
            +
                @item_delim = ( delims.length>1 ) ? delims[1] : "^"
         
     | 
| 
      
 167 
     | 
    
         
            +
              end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
              # DSL element to define a segment's sort weight
         
     | 
| 
      
 170 
     | 
    
         
            +
              # returns the segment's current weight by default
         
     | 
| 
      
 171 
     | 
    
         
            +
              # segments are sorted ascending
         
     | 
| 
      
 172 
     | 
    
         
            +
              def self.weight(new_weight=nil)
         
     | 
| 
      
 173 
     | 
    
         
            +
                if new_weight
         
     | 
| 
      
 174 
     | 
    
         
            +
                  singleton.module_eval do
         
     | 
| 
      
 175 
     | 
    
         
            +
                    @my_weight = new_weight
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                singleton.module_eval do
         
     | 
| 
      
 180 
     | 
    
         
            +
                  return 999 unless @my_weight
         
     | 
| 
      
 181 
     | 
    
         
            +
                  @my_weight
         
     | 
| 
      
 182 
     | 
    
         
            +
                end
         
     | 
| 
      
 183 
     | 
    
         
            +
              end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
              def self.convert_to_ts(value) #:nodoc:
         
     | 
| 
      
 186 
     | 
    
         
            +
                value.respond_to?(:to_hl7) ? value.to_hl7 : value
         
     | 
| 
      
 187 
     | 
    
         
            +
              end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Provide a catch-all information preserving segment
         
     | 
| 
      
 2 
     | 
    
         
            +
            # * nb: aliases are not provided BUT you can use the numeric element accessor
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            #  seg = HL7::Message::Segment::Default.new
         
     | 
| 
      
 5 
     | 
    
         
            +
            #  seg.e0 = "NK1"
         
     | 
| 
      
 6 
     | 
    
         
            +
            #  seg.e1 = "SOMETHING ELSE"
         
     | 
| 
      
 7 
     | 
    
         
            +
            #  seg.e2 = "KIN HERE"
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            class HL7::Message::Segment::Default < HL7::Message::Segment
         
     | 
| 
      
 10 
     | 
    
         
            +
              def initialize(raw_segment="", delims=[])
         
     | 
| 
      
 11 
     | 
    
         
            +
                segs = [] if (raw_segment == "")
         
     | 
| 
      
 12 
     | 
    
         
            +
                segs ||= raw_segment
         
     | 
| 
      
 13 
     | 
    
         
            +
                super( segs, delims )
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            # load our segments
         
     | 
| 
      
 18 
     | 
    
         
            +
            Dir["#{File.dirname(__FILE__)}/segments/*.rb"].each { |ext| load ext }
         
     | 
| 
         @@ -0,0 +1,117 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #  SegmentFields
         
     | 
| 
      
 2 
     | 
    
         
            +
            #  class HL7::Message::Segment::NK1 < HL7::Message::Segment
         
     | 
| 
      
 3 
     | 
    
         
            +
            #    wieght 100 # segments are sorted ascendingly
         
     | 
| 
      
 4 
     | 
    
         
            +
            #    add_field :something_you_want       # assumes :idx=>1
         
     | 
| 
      
 5 
     | 
    
         
            +
            #    add_field :something_else, :idx=>6  # :idx=>6 and field count=6
         
     | 
| 
      
 6 
     | 
    
         
            +
            module HL7::Message::SegmentFields
         
     | 
| 
      
 7 
     | 
    
         
            +
              def self.included(base)
         
     | 
| 
      
 8 
     | 
    
         
            +
                base.extend(ClassMethods)
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              @elements = []
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              module ClassMethods
         
     | 
| 
      
 14 
     | 
    
         
            +
                # define a field alias
         
     | 
| 
      
 15 
     | 
    
         
            +
                # * name is the alias itself (required)
         
     | 
| 
      
 16 
     | 
    
         
            +
                # * options is a hash of parameters
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   * :id is the field number to reference (optional, auto-increments from 1
         
     | 
| 
      
 18 
     | 
    
         
            +
                #      by default)
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   * :blk is a validation proc (optional, overrides the second argument)
         
     | 
| 
      
 20 
     | 
    
         
            +
                # * blk is an optional validation/convertion proc which MUST
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   take a parameter and always return a value for the field (it will be
         
     | 
| 
      
 22 
     | 
    
         
            +
                #    used on read/write calls)
         
     | 
| 
      
 23 
     | 
    
         
            +
                def add_field( name, options={}, &blk )
         
     | 
| 
      
 24 
     | 
    
         
            +
                  options = { :idx =>-1, :blk =>blk}.merge!( options )
         
     | 
| 
      
 25 
     | 
    
         
            +
                  name ||= :id
         
     | 
| 
      
 26 
     | 
    
         
            +
                  namesym = name.to_sym
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @field_cnt ||= 1
         
     | 
| 
      
 28 
     | 
    
         
            +
                  if options[:idx] == -1
         
     | 
| 
      
 29 
     | 
    
         
            +
                    options[:idx] = @field_cnt # provide default auto-incrementing
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @field_cnt = options[:idx].to_i + 1
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  singleton.module_eval do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @fields ||= {}
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @fields[ namesym ] = options
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  self.class_eval <<-END
         
     | 
| 
      
 39 
     | 
    
         
            +
                    def #{name}(val=nil)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      unless val
         
     | 
| 
      
 41 
     | 
    
         
            +
                        read_field( :#{namesym} )
         
     | 
| 
      
 42 
     | 
    
         
            +
                      else
         
     | 
| 
      
 43 
     | 
    
         
            +
                        write_field( :#{namesym}, val )
         
     | 
| 
      
 44 
     | 
    
         
            +
                        val # this matches existing n= method functionality
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    def #{name}=(value)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      write_field( :#{namesym}, value )
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  END
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def fields #:nodoc:
         
     | 
| 
      
 55 
     | 
    
         
            +
                  singleton.module_eval do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    (@fields ||= [])
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def alias_field(new_field_name, old_field_name)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  self.class_eval <<-END
         
     | 
| 
      
 62 
     | 
    
         
            +
                    def #{new_field_name}(val=nil)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      raise HL7::InvalidDataError.new unless self.class.fields[:#{old_field_name}]
         
     | 
| 
      
 64 
     | 
    
         
            +
                      unless val
         
     | 
| 
      
 65 
     | 
    
         
            +
                        read_field( :#{old_field_name} )
         
     | 
| 
      
 66 
     | 
    
         
            +
                      else
         
     | 
| 
      
 67 
     | 
    
         
            +
                        write_field( :#{old_field_name}, val )
         
     | 
| 
      
 68 
     | 
    
         
            +
                        val # this matches existing n= method functionality
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    def #{new_field_name}=(value)
         
     | 
| 
      
 73 
     | 
    
         
            +
                      write_field( :#{old_field_name}, value )
         
     | 
| 
      
 74 
     | 
    
         
            +
                    end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  END
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              def field_info( name ) #:nodoc:
         
     | 
| 
      
 80 
     | 
    
         
            +
                field_blk = nil
         
     | 
| 
      
 81 
     | 
    
         
            +
                idx = name # assume we've gotten a fixnum
         
     | 
| 
      
 82 
     | 
    
         
            +
                unless name.kind_of?( Fixnum )
         
     | 
| 
      
 83 
     | 
    
         
            +
                  fld_info = self.class.fields[ name ]
         
     | 
| 
      
 84 
     | 
    
         
            +
                  idx = fld_info[:idx].to_i
         
     | 
| 
      
 85 
     | 
    
         
            +
                  field_blk = fld_info[:blk]
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                [ idx, field_blk ]
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
              def read_field( name ) #:nodoc:
         
     | 
| 
      
 92 
     | 
    
         
            +
                idx, field_blk = field_info( name )
         
     | 
| 
      
 93 
     | 
    
         
            +
                return nil unless idx
         
     | 
| 
      
 94 
     | 
    
         
            +
                return nil if (idx >= @elements.length)
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                ret = @elements[ idx ]
         
     | 
| 
      
 97 
     | 
    
         
            +
                ret = ret.first if (ret.kind_of?(Array) && ret.length == 1)
         
     | 
| 
      
 98 
     | 
    
         
            +
                ret = field_blk.call( ret ) if field_blk
         
     | 
| 
      
 99 
     | 
    
         
            +
                ret
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
              def write_field( name, value ) #:nodoc:
         
     | 
| 
      
 103 
     | 
    
         
            +
                idx, field_blk = field_info( name )
         
     | 
| 
      
 104 
     | 
    
         
            +
                return nil unless idx
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                if (idx >= @elements.length)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  # make some space for the incoming field, missing items are assumed to
         
     | 
| 
      
 108 
     | 
    
         
            +
                  # be empty, so this is valid per the spec -mg
         
     | 
| 
      
 109 
     | 
    
         
            +
                  missing = ("," * (idx-@elements.length)).split(',',-1)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  @elements += missing
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                value = value.first if (value && value.kind_of?(Array) && value.length == 1)
         
     | 
| 
      
 114 
     | 
    
         
            +
                value = field_blk.call( value ) if field_blk
         
     | 
| 
      
 115 
     | 
    
         
            +
                @elements[ idx ] = value.to_s
         
     | 
| 
      
 116 
     | 
    
         
            +
              end
         
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Class for grouping the messages delimiter
         
     | 
| 
      
 2 
     | 
    
         
            +
            class HL7::Message::Delimiter
         
     | 
| 
      
 3 
     | 
    
         
            +
              attr_accessor :item, :element, :segment
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def initialize(element_delim, item_delim, segment_delim)
         
     | 
| 
      
 6 
     | 
    
         
            +
                @element = element_delim
         
     | 
| 
      
 7 
     | 
    
         
            +
                @item = item_delim
         
     | 
| 
      
 8 
     | 
    
         
            +
                @segment = segment_delim
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            # Methods for creating segments in Message
         
     | 
| 
      
 13 
     | 
    
         
            +
            class HL7::Message::SegmentGenerator
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              attr_reader :element, :last_seg
         
     | 
| 
      
 16 
     | 
    
         
            +
              attr_reader :delimiter
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              attr_accessor :seg_parts, :seg_name
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def initialize(element, last_seg, delimiter)
         
     | 
| 
      
 21 
     | 
    
         
            +
                @element = element
         
     | 
| 
      
 22 
     | 
    
         
            +
                @last_seg = last_seg
         
     | 
| 
      
 23 
     | 
    
         
            +
                @delimiter = delimiter
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                @seg_parts = HL7::MessageParser.split_by_delimiter( element,
         
     | 
| 
      
 26 
     | 
    
         
            +
                                                                    delimiter.element )
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              def valid_segments_parts?
         
     | 
| 
      
 30 
     | 
    
         
            +
                return true if @seg_parts && @seg_parts.length > 0
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                if HL7.ParserConfig[:empty_segment_is_error]
         
     | 
| 
      
 33 
     | 
    
         
            +
                  raise HL7::EmptySegmentNotAllowed
         
     | 
| 
      
 34 
     | 
    
         
            +
                else
         
     | 
| 
      
 35 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def build
         
     | 
| 
      
 40 
     | 
    
         
            +
                klass = get_segment_class
         
     | 
| 
      
 41 
     | 
    
         
            +
                new_seg = klass.new( @element, [@delimiter.element, @delimiter.item] )
         
     | 
| 
      
 42 
     | 
    
         
            +
                new_seg
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def get_segment_class
         
     | 
| 
      
 46 
     | 
    
         
            +
                segment_to_search = @seg_name.to_sym
         
     | 
| 
      
 47 
     | 
    
         
            +
                segment_to_search = @seg_name if RUBY_VERSION < "1.9"
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                if HL7::Message::Segment.constants.index(segment_to_search)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  eval("HL7::Message::Segment::%s" % @seg_name)
         
     | 
| 
      
 51 
     | 
    
         
            +
                else
         
     | 
| 
      
 52 
     | 
    
         
            +
                  HL7::Message::Segment::Default
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,79 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # This module includes methods for storing segments inside segments.
         
     | 
| 
      
 2 
     | 
    
         
            +
            # has_children(child_types) defines three methods dynamically.
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module HL7::Message::SegmentListStorage
         
     | 
| 
      
 5 
     | 
    
         
            +
              attr_reader :child_types
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def add_child_type(child_type)
         
     | 
| 
      
 8 
     | 
    
         
            +
                if @child_types
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @child_types << child_type.to_sym
         
     | 
| 
      
 10 
     | 
    
         
            +
                else
         
     | 
| 
      
 11 
     | 
    
         
            +
                  has_children [ child_type.to_sym ]
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              private
         
     | 
| 
      
 16 
     | 
    
         
            +
              # allows a segment to store other segment objects
         
     | 
| 
      
 17 
     | 
    
         
            +
              # used to handle associated lists like one OBR to many OBX segments
         
     | 
| 
      
 18 
     | 
    
         
            +
              def has_children(child_types)
         
     | 
| 
      
 19 
     | 
    
         
            +
                @child_types = child_types
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                define_method_child_types
         
     | 
| 
      
 22 
     | 
    
         
            +
                define_method_children
         
     | 
| 
      
 23 
     | 
    
         
            +
                define_method_accepts
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def define_method_child_types
         
     | 
| 
      
 27 
     | 
    
         
            +
                define_method(:child_types) do
         
     | 
| 
      
 28 
     | 
    
         
            +
                  self.class.child_types
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              def define_method_accepts
         
     | 
| 
      
 33 
     | 
    
         
            +
                self.class_eval do
         
     | 
| 
      
 34 
     | 
    
         
            +
                  define_method('accepts?') do |t|
         
     | 
| 
      
 35 
     | 
    
         
            +
                    t = t.to_sym if t.respond_to?(:to_sym)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    !!child_types.index(t)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def define_method_children
         
     | 
| 
      
 42 
     | 
    
         
            +
                self.class_eval do
         
     | 
| 
      
 43 
     | 
    
         
            +
                  define_method(:children) do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    unless @my_children
         
     | 
| 
      
 45 
     | 
    
         
            +
                      p = self
         
     | 
| 
      
 46 
     | 
    
         
            +
                      @my_children ||= []
         
     | 
| 
      
 47 
     | 
    
         
            +
                      @my_children.instance_eval do
         
     | 
| 
      
 48 
     | 
    
         
            +
                        @parental = p
         
     | 
| 
      
 49 
     | 
    
         
            +
                        alias :old_append :<<
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                        def <<( value )
         
     | 
| 
      
 52 
     | 
    
         
            +
                          # do nothing if value is nil
         
     | 
| 
      
 53 
     | 
    
         
            +
                          return unless value
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                          # make sure it's an array
         
     | 
| 
      
 56 
     | 
    
         
            +
                          value = [value].flatten
         
     | 
| 
      
 57 
     | 
    
         
            +
                          value.map{|item| append(item)}
         
     | 
| 
      
 58 
     | 
    
         
            +
                        end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                        def append(value)
         
     | 
| 
      
 61 
     | 
    
         
            +
                          unless (value && value.kind_of?(HL7::Message::Segment))
         
     | 
| 
      
 62 
     | 
    
         
            +
                            raise HL7::Exception.new( "attempting to append non-segment to a segment list" )
         
     | 
| 
      
 63 
     | 
    
         
            +
                          end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                          value.segment_parent = @parental
         
     | 
| 
      
 66 
     | 
    
         
            +
                          k = @parental
         
     | 
| 
      
 67 
     | 
    
         
            +
                          while (k && k.segment_parent && !k.segment_parent.kind_of?(HL7::Message))
         
     | 
| 
      
 68 
     | 
    
         
            +
                            k = k.segment_parent
         
     | 
| 
      
 69 
     | 
    
         
            +
                          end
         
     | 
| 
      
 70 
     | 
    
         
            +
                          k.segment_parent << value if k && k.segment_parent
         
     | 
| 
      
 71 
     | 
    
         
            +
                          old_append( value )
         
     | 
| 
      
 72 
     | 
    
         
            +
                        end
         
     | 
| 
      
 73 
     | 
    
         
            +
                      end
         
     | 
| 
      
 74 
     | 
    
         
            +
                    end
         
     | 
| 
      
 75 
     | 
    
         
            +
                    @my_children
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     |