lib/segment_fields.rb
# SegmentFields
# class HL7::Message::Segment::NK1 < HL7::Message::Segment
# wieght 100 # segments are sorted ascendingly
# add_field :something_you_want # assumes :idx=>1
# add_field :something_else, :idx=>6 # :idx=>6 and field count=6
module HL7::Message::SegmentFields
def self.included(base)
base.extend(ClassMethods)
end
@elements = []
module ClassMethods
# define a field alias
# * name is the alias itself (required)
# * options is a hash of parameters
# * :id is the field number to reference (optional, auto-increments from 1
# by default)
# * :blk is a validation proc (optional, overrides the second argument)
# * blk is an optional validation/convertion proc which MUST
# take a parameter and always return a value for the field (it will be
# used on read/write calls)
def add_field( name, options={}, &blk )
options = { :idx =>-1, :blk =>blk}.merge!( options )
name ||= :id
namesym = name.to_sym
@field_cnt ||= 1
if options[:idx] == -1
options[:idx] = @field_cnt # provide default auto-incrementing
end
@field_cnt = options[:idx].to_i + 1
singleton.module_eval do
@fields ||= {}
@fields[ namesym ] = options
end
self.class_eval <<-END
def #{name}(val=nil)
unless val
read_field( :#{namesym} )
else
write_field( :#{namesym}, val )
val # this matches existing n= method functionality
end
end
def #{name}=(value)
write_field( :#{namesym}, value )
end
END
end
def fields #:nodoc:
singleton.module_eval do
(@fields ||= [])
end
end
end
def field_info( name ) #:nodoc:
field_blk = nil
idx = name # assume we've gotten a fixnum
unless name.kind_of?( Fixnum )
fld_info = self.class.fields[ name ]
idx = fld_info[:idx].to_i
field_blk = fld_info[:blk]
end
[ idx, field_blk ]
end
def read_field( name ) #:nodoc:
idx, field_blk = field_info( name )
return nil unless idx
return nil if (idx >= @elements.length)
ret = @elements[ idx ]
ret = ret.first if (ret.kind_of?(Array) && ret.length == 1)
ret = field_blk.call( ret ) if field_blk
ret
end
def write_field( name, value ) #:nodoc:
idx, field_blk = field_info( name )
return nil unless idx
if (idx >= @elements.length)
# make some space for the incoming field, missing items are assumed to
# be empty, so this is valid per the spec -mg
missing = ("," * (idx-@elements.length)).split(',',-1)
@elements += missing
end
value = value.first if (value && value.kind_of?(Array) && value.length == 1)
value = field_blk.call( value ) if field_blk
@elements[ idx ] = value.to_s
end
end