notes/builder
Appending to Syntax Tree
b = Stupidedi::Builder::BuilderDsl.new
b.ISA("00", b.blank,
"01", "SECRET",
"ZZ", "SUBMITTERS ID",
"ZZ", "RECEIVERS ID",
Date.current, Time.current,
"U", "00401",
"000000905", "1", "T", b.default)
b.GS("HC",
"SENDER CODE",
"RECEIVER CODE",
Date.current, Time.current,
b.default,
"X", "004010X098")
b.ST("837", b.default).
BHT("0019", "00", "0123", Date.current, Time.current, "CH").
NM1("41", "2", "CRAMMER, DOLE, PALMER, AND JOHANSON",
b.blank, b.blank, b.blank, b.blank, "46", "W7933THU").
N2("N ASSOCIATES, INC").
PER("IC", "JANE DOE", "TE", "9005555555")
...
b.CLM("A37YH556", 500, b.blank, b.blank,
b.composite(11, b.blank, 1),
"Y", "A", "Y", "Y", "C")
# Unlike the TokenReader, Ruby evaluates the elements before evaluating
# the segment. That means we can't really validate the correctness of
# each element as the value is constructed -- we have to do it in the
# method that builds segments.
...
b.IEA(b.default, b.default)
Shorthand
# These methods could be implemented to capture the caller's stack trace,
# but we probably don't need very fine granularity. Knowing the location
# that generated the segment would suffice, and any element-level errors
# can be noted with the element descriptor: CLM05-02
b.composite
b.repeated
b.blank
b.default
# Proxy/Thunk
# x = b.default
# x.class #=> DefaultVal
# ...
# x.force!
# x.to_s #=> "ABCDEF"
# x.class #=> StringVal
Current State
b.current.interchange #=> InterchangeVal
b.current.functional_group #=> FunctionalGroupVal
b.current.transaction_set #=> TransactionSetVal
b.current.table #=> TableVal
b.current.loop #=> LoopVal
b.current.segment #=> SegmentVal
b.current.position #=> interchange no
# functional group no
# transaction set no
# segment no
Syntax Tree Iteration
o.interchanges
o.functional_groups
o.transaction_sets
o.tables
o.loops
o.segments
Reader Interface
# This operation might only make sense as a way to create a new interchange,
# not so much as a way to concatenate a blob of X12 into the middle of some
# half-generated document. The main concern is if {input} doesn't start with
# an ISA segment, we need to tell the tokenizer about separators.
b.read(input)
# Right now, StreamReader can read ISA and construct a TokenReader, but it
# does/should not need to know about InterchangeConfig etc to create the
# dictionary that TokenReader needs. The dictionary would include all of the
# ISA, ISB, ISE, IEA, TA1 etc SegmentDefs, plus the GS segment's definition.
#
# When Builder gets an ISA SegmentTok, it should construct the correct version
# of the InterchangeVal and ask it for the segment dictionary. Then it should
# copy/update the TokenReader with the interchange version-specific dictionary
#
# When Builder gets a GS SegmentTok, it should construct the correct version of
# FunctionalGroupVal and ask it for the segment dictionary, which it will merge
# with the InterchangeVal's dictionary. The current TokenReader will be updated
# with the merged dictionary.
#
# When Builder closes a FunctionalGroupVal, eg after reading an interchange
# segment, it should once again update TokenReader with the *unmerged* segment
# dictionary, in preperation for the next functional group.
Writer Interface
o.used_chars #=> "ABC...abc...123"
o.write(delimiters, settings)
Writers
X12
XML
Annotated HTML
Annotated Text
Error Handling
b.xxx
o.errors #=> [Error("Invalid segment 'XXX'",
severity,
SegmentVal[XXX](..),
["test.rb:30", ...]),
Error("Invalid segment 'XXX'",
severity,
Failure)]
interchange.errors
functional_group.errors
transaction_set.errors
table.errors
loop.errors
segment.errors
element.errors
interchange.generate_interchange_acknowledgment
functional_group.generate_functional_acknowledgment
functional_group.generate_implementation_acknowledgment