lib/stupidedi/parser/states/transaction_set_state.rb
# frozen_string_literal: true
module Stupidedi
using Refinements
module Parser
class TransactionSetState < AbstractState
# @return [Reader::Separators]
attr_reader :separators
# @return [Reader::SegmentDict]
attr_reader :segment_dict
# @return [InstructionTable]
attr_reader :instructions
# @return [Zipper::AbstractCursor]
attr_reader :zipper
# @return [Array<AbstractState>]
attr_reader :children
def initialize(separators, segment_dict, instructions, zipper, children)
@separators, @segment_dict, @instructions, @zipper, @children =
separators, segment_dict, instructions, zipper, children
end
# @return [TransactionSetState]
def copy(changes = {})
TransactionSetState.new \
changes.fetch(:separators, @separators),
changes.fetch(:segment_dict, @segment_dict),
changes.fetch(:instructions, @instructions),
changes.fetch(:zipper, @zipper),
changes.fetch(:children, @children)
end
end
class << TransactionSetState
# @group Constructors
#########################################################################
# @return [TransactionSetState]
def push(zipper, parent, segment_tok, segment_use, config)
# GS01: Functional Identifier Code
gs01 = parent.gs01
# ST01: Transaction Set Identifier Code
st01 = segment_tok.element_toks.at(0).try(:value)
# ST03: Implementation Convention Reference
#
# The implementation convention reference (ST03) is used by the
# translation routines of the interchange partners to select the
# appropriate implementation convention to match the transaction set
# definition. When used, this implementation convention reference takes
# precedence over the implementation reference specified in the GS08
st03 = segment_tok.element_toks.at(2).try(:value)
# Fall back to GS08 if ST03 isn't available
if st03.blank? or st03.is_a?(Symbol)
# GS08: Version / Release / Industry Identifier Code
st03 = parent.gs08
end
# Fall back to GS08 if ST03 isn't recognized
# unless config.transaction_set.defined_at?(st03, gs01, st01)
# if config.transaction_set.defined_at?(parent.gs08, gs01, st01)
# st03 = parent.gs08
# end
# end
unless config.transaction_set.defined_at?(st03, gs01, st01)
context = "#{st03.inspect} #{gs01.inspect} #{st01.inspect}"
return FailureState.push(
zipper,
parent,
segment_tok,
"unknown transaction set #{context}")
end
envelope_def = config.transaction_set.at(st03, gs01, st01)
envelope_val = envelope_def.empty
segment_use = envelope_def.entry_segment_use
zipper = zipper.append_child \
TransactionSetState.new(
parent.separators,
parent.segment_dict,
parent.instructions.push(instructions(envelope_def)),
parent.zipper.append(envelope_val).dangle.last,
[])
TableState.push(zipper, zipper.node, segment_tok, segment_use, config)
end
# @endgroup
#########################################################################
private
# @return [Array<Instruction>]
def instructions(transaction_set_def)
@__instructions ||= Hash.new
@__instructions[transaction_set_def] ||= begin
# When first segment is repeatable, then `successors` should include
# an {Instruction} for it; but when it's non-repeatable, there should
# be no successor instruction for that segment.
if transaction_set_def.table_defs.head.repeatable?
tsequence(transaction_set_def.table_defs)
else
tsequence(transaction_set_def.table_defs.tail)
end
end
end
end
end
end