lib/stupidedi/writer/default.rb
module Stupidedi
using Refinements
module Writer
class Default
# @return [Reader::Separators]
attr_reader :separators
def initialize(zipper, separators = Reader::Separators.empty)
@zipper, @separators =
zipper, separators
end
# @return out
def write(out = "")
unless @zipper.node.transmission? or @zipper.node.interchange?
common = @separators.characters & @zipper.node.characters
message = common.to_a.map(&:inspect).join(", ")
if common.present?
raise Exceptions::OutputError,
"separator characters #{message} occur as data"
end
end
out.tap { recurse(@zipper.node, @separators, out) }
end
private
def recurse(value, separators, out)
return if value.invalid?
if value.segment?
segment(value, separators, out)
else
if value.interchange?
unless separators.merge(value.separators) == separators
common = separators.characters & value.characters
message = common.to_a.map(&:inspect).join(", ")
if common.present?
raise Exceptions::OutputError,
"separator characters #{message} occur as data"
end
# Change ISA11 and ISA16
value = value.replace_separators(separators)
end
separators = value.separators
raise Exceptions::OutputError,
"separators.segment cannot be blank" if separators.segment.blank?
raise Exceptions::OutputError,
"separators.element cannot be blank" if separators.element.blank?
end
value.children.each{|c| recurse(c, separators, out) }
end
end
def segment(s, separators, out)
# It's likely annoying for the user to need to check for at least
# one non-blank element before generating a segment. Instead, we
# can check that after the segment was generated and supress any
# empty segments here.
return if s.empty?
out << s.id.to_s
# Trailing empty elements (including component elements) can be omitted,
# so "NM1*XX*1:2::::*****~" should be abbreviated to "NM1*XX*1:2~".
elements = s.children.
reverse.drop_while(&:empty?).reverse # Remove the trailing empties
elements.each do |e|
out << separators.element
element(e, separators, out)
end
out << separators.segment
end
def element(e, separators, out)
if e.simple?
out << e.to_x12
elsif e.composite?
components = e.children.
reverse.drop_while(&:empty?).reverse
unless components.empty?
out << components.head.to_x12
end
components.tail.each do |c|
out << separators.component
out << c.to_x12
end
elsif e.repeated?
occurrences = e.children.
reverse.drop_while(&:empty?).reverse
unless occurrences.empty?
element(occurrences.head, separators, out)
end
occurrences.tail.each do |o|
out << separators.repetition
element(o, separators, out)
end
end
end
end
end
end