Class: Stupidedi::Reader::StreamReader
- Includes:
- Inspect
- Defined in:
- lib/stupidedi/reader/stream_reader.rb
Overview
The StreamReader is intended to scan the input for a valid ISA segment, after which the TokenReader class can be used to tokenize the remaining input.
Because X12 specifications have no bearing on what happens outside the interchange envelope (from ‘IEA` to `ISA`), out-of-band data like blank lines, human readable text, etc can occur between interchanges. This reader is designed to deal with that problem.
Instance Attribute Summary collapse
-
#input ⇒ Object
readonly
Returns the value of attribute input.
Instance Method Summary collapse
-
#consume_character ⇒ Either<StreamReader>
Skip a single character.
-
#empty? ⇒ Boolean
True if there is no remaining input.
-
#initialize(input) ⇒ StreamReader
constructor
A new instance of StreamReader.
-
#read_character ⇒ Either<Result<Character, StreamReader>>
Read a single character.
-
#read_segment ⇒ Either<Result<SegmentTok TokenReader>>
This method is unaware of subtle differences between interchange versions, so it really only tokenizes 16 elements, plus the element terminator and segment separators.
-
#stream? ⇒ Boolean
True.
Methods included from Inspect
Constructor Details
#initialize(input) ⇒ StreamReader
Returns a new instance of StreamReader.
19 20 21 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 19 def initialize(input) @input = input end |
Instance Attribute Details
#input ⇒ Object (readonly)
Returns the value of attribute input.
17 18 19 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 17 def input @input end |
Instance Method Details
#consume_character ⇒ Either<StreamReader>
Skip a single character
47 48 49 50 51 52 53 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 47 def consume_character unless @input.empty? success(advance(1)) else failure("less than one character available") end end |
#empty? ⇒ Boolean
True if there is no remaining input
29 30 31 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 29 def empty? @input.empty? end |
#read_character ⇒ Either<Result<Character, StreamReader>>
Read a single character
36 37 38 39 40 41 42 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 36 def read_character unless @input.empty? result(@input.at(0), advance(1)) else failure("less than one character available") end end |
#read_segment ⇒ Either<Result<SegmentTok TokenReader>>
This method is unaware of subtle differences between interchange versions, so it really only tokenizes 16 elements, plus the element terminator and segment separators. It does not presume to understand the meaning of the elements, like the repetition separator or the component separator, because these are interchange version-dependent.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 62 def read_segment consume_isa.flatmap do |rest| # The character after "ISA" is defined to be the element separator rest.read_character.flatmap do |char, aR| separators = Separators.new(nil, nil, char, nil) remaining = success(TokenReader.new(aR.input, separators)) elements = [] # Read 15 simple elements into an array. Consume/discard the element # separator that follows each one. 15.times do remaining = remaining.flatmap(&:read_simple_element).flatmap do |e, eR| elements << e # Throw away the following element separator eR.consume_prefix(separators.element) end end # We have to assume the last (16th) element is fixed-length because # it is not terminated by an element separator. The {read_character} # method defined by TokenReader skips past control characters. remaining.flatmap do |w| w.read_character.flatmap do |isa16, cR| elements << SimpleElementTok.build(isa16, w.input, cR.input) # The character after the last element is defined to be the # segment terminator. The {read_character} method here, defined # by StreamReader, does not skip past control character, so the # separator could be a control character. cR.stream.read_character.flatmap do |char, dR| if char == separators.element failure("element separator and segment terminator must be distinct", dR.input) else separators.segment = char token = SegmentTok.build(:ISA, elements, rest.input.position, dR.input.position) result(token, TokenReader.new(dR.input, separators)) end end end end end.or do |reason| # We read "ISA" but failed to tokenize the input that followed. This # was probably a random occurrence of the sequence "ISA", so we'll # skip past it and try again. # # @todo: We should log this as a warning, because we could otherwise # be silently discarding an entire interchange if the ISA segment # was bogus rest.read_segment end end end |
#stream? ⇒ Boolean
Returns true.
24 25 26 |
# File 'lib/stupidedi/reader/stream_reader.rb', line 24 def stream? true end |