lib/segment.rb in ruby-hl7-1.3.3 vs lib/segment.rb in ruby-hl7-1.4.0

- old
+ new

@@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Ruby Object representation of an hl7 2.x message segment # The segments can be setup to provide aliases to specific fields with # optional validation code that is run when the field is modified # The segment field data is also accessible via the e<number> method. # @@ -17,16 +19,16 @@ # # this block will be executed when seg.block_example= is called # # and when seg.block_example is called # class HL7::Message::Segment extend HL7::Message::SegmentListStorage + extend TimeFormatterHelper + include HL7::Message::SegmentFields attr_accessor :segment_parent - attr_reader :element_delim - attr_reader :item_delim - attr_reader :segment_weight + attr_reader :element_delim, :item_delim, :segment_weight METHOD_MISSING_FOR_INITIALIZER = <<-END def method_missing( sym, *args, &blk ) __seg__.send( sym, args, blk ) end @@ -36,98 +38,97 @@ # raw_segment:: is an optional String or Array which will be used as the # segment's field data # delims:: an optional array of delimiters, where # delims[0] = element delimiter # delims[1] = item delimiter - def initialize(raw_segment="", delims=[], &blk) + def initialize(raw_segment = "", delims = [], &blk) @segments_by_name = {} @field_total = 0 @is_child = false setup_delimiters delims @elements = elements_from_segment(raw_segment) - if block_given? - callctx = eval( "self", blk.binding ) - def callctx.__seg__(val=nil) - @__seg_val__ ||= val - end - callctx.__seg__(self) - # TODO: find out if this pollutes the calling namespace permanently... + return unless block_given? - eval( METHOD_MISSING_FOR_INITIALIZER, blk.binding ) - yield self - eval( "class << self; remove_method :method_missing;end", blk.binding ) + callctx = eval("self", blk.binding, __FILE__, __LINE__) + def callctx.__seg__(val = nil) + @__seg_val__ ||= val end + callctx.__seg__(self) + # TODO: find out if this pollutes the calling namespace permanently... + + eval(METHOD_MISSING_FOR_INITIALIZER, blk.binding) + yield self + eval("class << self; remove_method :method_missing;end", blk.binding, __FILE__, __LINE__) end # Breaks the raw segment into elements # raw_segment:: is an optional String or Array which will be used as the # segment's field data def elements_from_segment(raw_segment) - if (raw_segment.kind_of? Array) + if raw_segment.is_a? Array elements = raw_segment else - elements = HL7::MessageParser.split_by_delimiter( raw_segment, - @element_delim ) + elements = HL7::MessageParser.split_by_delimiter(raw_segment, + @element_delim) if raw_segment == "" - elements[0] = self.class.to_s.split( "::" ).last + elements[0] = self.class.to_s.split("::").last elements << "" end end elements end def to_info - "%s: empty segment >> %s" % [ self.class.to_s, @elements.inspect ] + format("%s: empty segment >> %s", self.class.to_s, @elements.inspect) end # output the HL7 spec version of the segment def to_s - @elements.join( @element_delim ) + @elements.join(@element_delim) end # at the segment level there is no difference between to_s and to_hl7 - alias :to_hl7 :to_s + alias_method :to_hl7, :to_s # handle the e<number> field accessor # and any aliases that didn't get added to the system automatically - def method_missing( sym, *args, &blk ) - base_str = sym.to_s.gsub( "=", "" ) + def method_missing(sym, *args, &blk) + base_str = sym.to_s.delete("=") base_sym = base_str.to_sym - if self.class.fields.include?( base_sym ) + if self.class.fields.include?(base_sym) # base_sym is ok, let's move on - elsif /e([0-9]+)/.match( base_str ) + elsif /e([0-9]+)/ =~ base_str # base_sym should actually be $1, since we're going by # element id number base_sym = $1.to_i else super end - if sym.to_s.include?( "=" ) - write_field( base_sym, args ) + if sym.to_s.include?("=") + write_field(base_sym, args) + elsif args.length.positive? + write_field(base_sym, args.flatten.select {|arg| arg }) else - if args.length > 0 - write_field( base_sym, args.flatten.select { |arg| arg } ) - else - read_field( base_sym ) - end + read_field(base_sym) end end # sort-compare two Segments, 0 indicates equality - def <=>( other ) - return nil unless other.kind_of?(HL7::Message::Segment) + def <=>(other) + return nil unless other.is_a?(HL7::Message::Segment) # per Comparable docs: http://www.ruby-doc.org/core/classes/Comparable.html - diff = self.weight - other.weight - return -1 if diff > 0 - return 1 if diff < 0 - return 0 + diff = weight - other.weight + return -1 if diff.positive? + return 1 if diff.negative? + + 0 end # get the defined sort-weight of this segment class # an alias for self.weight def weight @@ -145,51 +146,66 @@ end # yield each element in the segment def each # :yields: element return unless @elements + @elements.each { |e| yield e } end # get the length of the segment (number of fields it contains) def length 0 unless @elements @elements.length end def has_children? - self.respond_to?(:children) + respond_to?(:children) end - private - def self.singleton #:nodoc: +private + + def self.singleton # :nodoc: class << self; self end end def setup_delimiters(delims) - delims = [ delims ].flatten + delims = [delims].flatten - @element_delim = ( delims.length>0 ) ? delims[0] : "|" - @item_delim = ( delims.length>1 ) ? delims[1] : "^" + @element_delim = delims.length.positive? ? delims[0] : "|" + @item_delim = delims.length > 1 ? delims[1] : "^" end # DSL element to define a segment's sort weight # returns the segment's current weight by default # segments are sorted ascending - def self.weight(new_weight=nil) + def self.weight(new_weight = nil) if new_weight singleton.module_eval do @my_weight = new_weight end end singleton.module_eval do return 999 unless @my_weight + @my_weight end end - def self.convert_to_ts(value) #:nodoc: - value.respond_to?(:to_hl7) ? value.to_hl7 : value + def self.convert_to_ts(value) # :nodoc: + if value.is_a?(Time) || value.is_a?(DateTime) + hl7_formatted_timestamp(value) + elsif value.is_a?(Date) + hl7_formatted_date(value) + else + value + end end + def self.sanitize_admin_sex!(value) + raise HL7::InvalidDataError, "bad administrative sex value (not F|M|O|U|A|N|C)" unless /^[FMOUANC]$/.match(value) || value.nil? || value == "" + + value ||= "" + value + end end