tediparse 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +319 -0
- data/LICENSE +26 -0
- data/README.md +308 -0
- data/Rakefile +33 -0
- data/bin/tediparse +102 -0
- data/doc/Defining.md +97 -0
- data/doc/Generating-Grammars.md +241 -0
- data/doc/Generating.md +332 -0
- data/doc/Navigating.md +670 -0
- data/doc/Parsing.md +133 -0
- data/doc/README.md +51 -0
- data/doc/Serializing.md +100 -0
- data/doc/Tokenizing.md +136 -0
- data/doc/Validating.md +140 -0
- data/lib/ruby/array.rb +226 -0
- data/lib/ruby/blank.rb +52 -0
- data/lib/ruby/exception.rb +14 -0
- data/lib/ruby/hash.rb +14 -0
- data/lib/ruby/module.rb +60 -0
- data/lib/ruby/object.rb +56 -0
- data/lib/ruby/string.rb +89 -0
- data/lib/ruby/to_d.rb +82 -0
- data/lib/ruby/to_date.rb +26 -0
- data/lib/ruby/to_time.rb +21 -0
- data/lib/ruby/try.rb +46 -0
- data/lib/stupidedi/builder.rb +6 -0
- data/lib/stupidedi/color.rb +94 -0
- data/lib/stupidedi/config/code_list_config.rb +45 -0
- data/lib/stupidedi/config/functional_group_config.rb +72 -0
- data/lib/stupidedi/config/interchange_config.rb +86 -0
- data/lib/stupidedi/config/transaction_set_config.rb +73 -0
- data/lib/stupidedi/config.rb +100 -0
- data/lib/stupidedi/either.rb +286 -0
- data/lib/stupidedi/exceptions/invalid_element_error.rb +7 -0
- data/lib/stupidedi/exceptions/invalid_schema_error.rb +7 -0
- data/lib/stupidedi/exceptions/missing_grammar_error.rb +50 -0
- data/lib/stupidedi/exceptions/output_error.rb +7 -0
- data/lib/stupidedi/exceptions/parse_error.rb +7 -0
- data/lib/stupidedi/exceptions/stupidedi_error.rb +7 -0
- data/lib/stupidedi/exceptions/tokenize_error.rb +7 -0
- data/lib/stupidedi/exceptions/zipper_error.rb +7 -0
- data/lib/stupidedi/exceptions.rb +13 -0
- data/lib/stupidedi/inspect.rb +26 -0
- data/lib/stupidedi/interchanges/element_types/separator_val.rb +79 -0
- data/lib/stupidedi/interchanges/element_types/special_val.rb +48 -0
- data/lib/stupidedi/interchanges/element_types.rb +11 -0
- data/lib/stupidedi/interchanges.rb +21 -0
- data/lib/stupidedi/parser/builder_dsl.rb +292 -0
- data/lib/stupidedi/parser/constraint_table.rb +566 -0
- data/lib/stupidedi/parser/generation.rb +147 -0
- data/lib/stupidedi/parser/identifier_stack.rb +248 -0
- data/lib/stupidedi/parser/instruction.rb +112 -0
- data/lib/stupidedi/parser/instruction_table.rb +222 -0
- data/lib/stupidedi/parser/navigation.rb +786 -0
- data/lib/stupidedi/parser/state_machine.rb +62 -0
- data/lib/stupidedi/parser/states/abstract_state.rb +385 -0
- data/lib/stupidedi/parser/states/failure_state.rb +69 -0
- data/lib/stupidedi/parser/states/functional_group_state.rb +101 -0
- data/lib/stupidedi/parser/states/initial_state.rb +62 -0
- data/lib/stupidedi/parser/states/interchange_state.rb +96 -0
- data/lib/stupidedi/parser/states/loop_state.rb +74 -0
- data/lib/stupidedi/parser/states/table_state.rb +90 -0
- data/lib/stupidedi/parser/states/transaction_set_state.rb +120 -0
- data/lib/stupidedi/parser/states/transmission_state.rb +59 -0
- data/lib/stupidedi/parser/tokenization.rb +195 -0
- data/lib/stupidedi/parser.rb +32 -0
- data/lib/stupidedi/reader/input/abstract_input.rb +137 -0
- data/lib/stupidedi/reader/input/delegated_input.rb +112 -0
- data/lib/stupidedi/reader/input/file_input.rb +157 -0
- data/lib/stupidedi/reader/input.rb +31 -0
- data/lib/stupidedi/reader/position.rb +78 -0
- data/lib/stupidedi/reader/result.rb +172 -0
- data/lib/stupidedi/reader/segment_dict.rb +176 -0
- data/lib/stupidedi/reader/separators.rb +90 -0
- data/lib/stupidedi/reader/stream_reader.rb +173 -0
- data/lib/stupidedi/reader/token_reader.rb +465 -0
- data/lib/stupidedi/reader/tokens/component_element_tok.rb +71 -0
- data/lib/stupidedi/reader/tokens/composite_element_tok.rb +85 -0
- data/lib/stupidedi/reader/tokens/repeated_element_tok.rb +74 -0
- data/lib/stupidedi/reader/tokens/segment_tok.rb +74 -0
- data/lib/stupidedi/reader/tokens/simple_element_tok.rb +76 -0
- data/lib/stupidedi/reader.rb +121 -0
- data/lib/stupidedi/schema/abstract_def.rb +76 -0
- data/lib/stupidedi/schema/abstract_element_def.rb +35 -0
- data/lib/stupidedi/schema/abstract_element_use.rb +47 -0
- data/lib/stupidedi/schema/abstract_use.rb +79 -0
- data/lib/stupidedi/schema/code_list.rb +99 -0
- data/lib/stupidedi/schema/component_element_use.rb +76 -0
- data/lib/stupidedi/schema/composite_element_def.rb +103 -0
- data/lib/stupidedi/schema/composite_element_use.rb +78 -0
- data/lib/stupidedi/schema/element_req.rb +57 -0
- data/lib/stupidedi/schema/functional_group_def.rb +124 -0
- data/lib/stupidedi/schema/generation/definition_generator.rb +139 -0
- data/lib/stupidedi/schema/generation/element_generator.rb +221 -0
- data/lib/stupidedi/schema/generation/flat_file_reader.rb +551 -0
- data/lib/stupidedi/schema/generation/functional_group_generator.rb +64 -0
- data/lib/stupidedi/schema/generation/interchange_generator.rb +145 -0
- data/lib/stupidedi/schema/generation/master_loader_generator.rb +121 -0
- data/lib/stupidedi/schema/generation/models.rb +85 -0
- data/lib/stupidedi/schema/generation/module_loader_generator.rb +64 -0
- data/lib/stupidedi/schema/generation/registration_generator.rb +230 -0
- data/lib/stupidedi/schema/generation/runner.rb +161 -0
- data/lib/stupidedi/schema/generation/segment_generator.rb +130 -0
- data/lib/stupidedi/schema/generation/support.rb +78 -0
- data/lib/stupidedi/schema/generation/support_modules_generator.rb +126 -0
- data/lib/stupidedi/schema/generation/version_modules.rb +35 -0
- data/lib/stupidedi/schema/generation.rb +94 -0
- data/lib/stupidedi/schema/interchange_def.rb +103 -0
- data/lib/stupidedi/schema/loop_def.rb +156 -0
- data/lib/stupidedi/schema/repeat_count.rb +86 -0
- data/lib/stupidedi/schema/segment_def.rb +122 -0
- data/lib/stupidedi/schema/segment_req.rb +46 -0
- data/lib/stupidedi/schema/segment_use.rb +99 -0
- data/lib/stupidedi/schema/simple_element_def.rb +51 -0
- data/lib/stupidedi/schema/simple_element_use.rb +83 -0
- data/lib/stupidedi/schema/syntax_note.rb +52 -0
- data/lib/stupidedi/schema/table_def.rb +178 -0
- data/lib/stupidedi/schema/transaction_set_def.rb +125 -0
- data/lib/stupidedi/schema.rb +30 -0
- data/lib/stupidedi/sets.rb +42 -0
- data/lib/stupidedi/transaction_sets/builder/dsl.rb +192 -0
- data/lib/stupidedi/transaction_sets/builder.rb +188 -0
- data/lib/stupidedi/transaction_sets/common/implementations/element_reqs.rb +37 -0
- data/lib/stupidedi/transaction_sets/common/implementations/segment_reqs.rb +31 -0
- data/lib/stupidedi/transaction_sets/common/implementations.rb +11 -0
- data/lib/stupidedi/transaction_sets/common.rb +8 -0
- data/lib/stupidedi/transaction_sets/validation/ambiguity.rb +395 -0
- data/lib/stupidedi/transaction_sets/validation/implementation.rb +12 -0
- data/lib/stupidedi/transaction_sets/validation.rb +9 -0
- data/lib/stupidedi/transaction_sets.rb +25 -0
- data/lib/stupidedi/values/abstract_element_val.rb +19 -0
- data/lib/stupidedi/values/abstract_val.rb +133 -0
- data/lib/stupidedi/values/composite_element_val.rb +102 -0
- data/lib/stupidedi/values/functional_group_val.rb +105 -0
- data/lib/stupidedi/values/interchange_val.rb +102 -0
- data/lib/stupidedi/values/invalid_envelope_val.rb +61 -0
- data/lib/stupidedi/values/invalid_segment_val.rb +89 -0
- data/lib/stupidedi/values/loop_val.rb +73 -0
- data/lib/stupidedi/values/repeated_element_val.rb +113 -0
- data/lib/stupidedi/values/segment_val.rb +105 -0
- data/lib/stupidedi/values/segment_val_group.rb +20 -0
- data/lib/stupidedi/values/simple_element_val.rb +80 -0
- data/lib/stupidedi/values/table_val.rb +69 -0
- data/lib/stupidedi/values/transaction_set_val.rb +69 -0
- data/lib/stupidedi/values/transmission_val.rb +56 -0
- data/lib/stupidedi/values.rb +22 -0
- data/lib/stupidedi/version.rb +4 -0
- data/lib/stupidedi/versions/common/element_reqs.rb +13 -0
- data/lib/stupidedi/versions/common/element_types/an.rb +386 -0
- data/lib/stupidedi/versions/common/element_types/dt.rb +572 -0
- data/lib/stupidedi/versions/common/element_types/id.rb +304 -0
- data/lib/stupidedi/versions/common/element_types/nn.rb +312 -0
- data/lib/stupidedi/versions/common/element_types/operators.rb +128 -0
- data/lib/stupidedi/versions/common/element_types/r.rb +342 -0
- data/lib/stupidedi/versions/common/element_types/simple_element.rb +73 -0
- data/lib/stupidedi/versions/common/element_types/tm.rb +347 -0
- data/lib/stupidedi/versions/common/element_types.rb +29 -0
- data/lib/stupidedi/versions/common/segment_reqs.rb +15 -0
- data/lib/stupidedi/versions/common/syntax_notes.rb +172 -0
- data/lib/stupidedi/versions/common.rb +11 -0
- data/lib/stupidedi/versions.rb +25 -0
- data/lib/stupidedi/writer/claredi.rb +178 -0
- data/lib/stupidedi/writer/default.rb +119 -0
- data/lib/stupidedi/writer.rb +7 -0
- data/lib/stupidedi/zipper/abstract_cursor.rb +351 -0
- data/lib/stupidedi/zipper/dangling_cursor.rb +103 -0
- data/lib/stupidedi/zipper/edited_cursor.rb +157 -0
- data/lib/stupidedi/zipper/memoized_cursor.rb +133 -0
- data/lib/stupidedi/zipper/path.rb +132 -0
- data/lib/stupidedi/zipper/root_cursor.rb +120 -0
- data/lib/stupidedi/zipper/stack_cursor.rb +107 -0
- data/lib/stupidedi/zipper.rb +45 -0
- data/lib/stupidedi.rb +69 -0
- data/lib/tediparse.rb +1 -0
- metadata +249 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stupidedi
|
|
4
|
+
module Schema
|
|
5
|
+
module Generation
|
|
6
|
+
# Generates element_defs.rb for a release: every simple and composite
|
|
7
|
+
# element definition. ID elements with code lists emit a CodeList; control
|
|
8
|
+
# /separator elements (e.g. I15, I65) that carry no x12_type are emitted
|
|
9
|
+
# with the Separator type so #separator? is true.
|
|
10
|
+
class ElementGenerator
|
|
11
|
+
include Support
|
|
12
|
+
|
|
13
|
+
TYPE_MAPPING = {
|
|
14
|
+
"AN" => :AN,
|
|
15
|
+
"ID" => :ID,
|
|
16
|
+
"DT" => :DT,
|
|
17
|
+
"TM" => :TM,
|
|
18
|
+
"R" => :R,
|
|
19
|
+
"N0" => :Nn,
|
|
20
|
+
"N1" => :Nn,
|
|
21
|
+
"N2" => :Nn,
|
|
22
|
+
"N4" => :Nn,
|
|
23
|
+
"N6" => :Nn,
|
|
24
|
+
"N" => :Nn,
|
|
25
|
+
"B" => :AN # Binary as AN
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def initialize(release, namespace: "Edi")
|
|
29
|
+
@release = release
|
|
30
|
+
@namespace = namespace
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def generate
|
|
34
|
+
validate_release!
|
|
35
|
+
build_ruby_content
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def output_path
|
|
39
|
+
"#{namespace_path}/#{underscore(version_module)}/element_defs.rb"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
attr_reader :release
|
|
45
|
+
|
|
46
|
+
def release_code
|
|
47
|
+
release.code
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_ruby_content
|
|
51
|
+
lines = []
|
|
52
|
+
lines << 'require "tediparse"'
|
|
53
|
+
lines << "module #{namespace}"
|
|
54
|
+
lines << " module #{version_module}"
|
|
55
|
+
lines << " module ElementDefs"
|
|
56
|
+
lines << " t = #{namespace}::#{version_module}::ElementTypes"
|
|
57
|
+
lines << " r = #{namespace}::#{version_module}::ElementReqs"
|
|
58
|
+
lines << " s = Stupidedi::Schema"
|
|
59
|
+
lines << ""
|
|
60
|
+
lines << build_simple_element_definitions
|
|
61
|
+
lines << ""
|
|
62
|
+
lines << "#{indent(3)}# Composite Elements"
|
|
63
|
+
lines << build_composite_element_definitions
|
|
64
|
+
lines << " end"
|
|
65
|
+
lines << " end"
|
|
66
|
+
lines << "end"
|
|
67
|
+
lines.join("\n") + "\n"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def build_simple_element_definitions
|
|
71
|
+
elements = release.elements.reject(&:is_composite).reject { |e| blank_type?(e) }
|
|
72
|
+
|
|
73
|
+
sorted_elements = sort_elements(elements)
|
|
74
|
+
simple_defs = sorted_elements.map { |element| generate_element_def(element) }
|
|
75
|
+
|
|
76
|
+
# Add special control/separator elements (e.g. I15, I65, I69) that have
|
|
77
|
+
# no x12_type but are referenced by segments in this release.
|
|
78
|
+
control_defs = control_elements.map { |element| generate_control_element_def(element) }
|
|
79
|
+
|
|
80
|
+
(simple_defs + control_defs).join("\n")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def build_composite_element_definitions
|
|
84
|
+
composites = release.elements.select(&:is_composite)
|
|
85
|
+
|
|
86
|
+
sorted_composites = sort_elements(composites)
|
|
87
|
+
sorted_composites.map { |composite| generate_composite_def(composite) }.join("\n")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Simple elements with no x12_type that are referenced by some segment's
|
|
91
|
+
# element use (the ISA control/separator elements).
|
|
92
|
+
def control_elements
|
|
93
|
+
referenced_codes = release.segments
|
|
94
|
+
.flat_map(&:element_uses)
|
|
95
|
+
.map(&:element)
|
|
96
|
+
.select { |el| !el.is_composite && blank_type?(el) }
|
|
97
|
+
.map(&:code)
|
|
98
|
+
.uniq
|
|
99
|
+
|
|
100
|
+
release.elements.select do |el|
|
|
101
|
+
!el.is_composite && blank_type?(el) && referenced_codes.include?(el.code)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def blank_type?(element)
|
|
106
|
+
element.x12_type.nil? || element.x12_type.empty?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def sort_elements(elements)
|
|
110
|
+
# Sort numeric codes numerically, then alphanumeric codes alphabetically
|
|
111
|
+
elements.sort_by do |element|
|
|
112
|
+
code = element.code
|
|
113
|
+
if code.match?(/^\d+$/)
|
|
114
|
+
[0, code.to_i, ""]
|
|
115
|
+
else
|
|
116
|
+
[1, 0, code]
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def generate_element_def(element)
|
|
122
|
+
stupidedi_type = stupidedi_type_for(element)
|
|
123
|
+
|
|
124
|
+
if element.x12_type == "ID" && element.element_codes.any?
|
|
125
|
+
generate_id_element(element, stupidedi_type)
|
|
126
|
+
elsif stupidedi_type == :Nn
|
|
127
|
+
generate_numeric_element(element, stupidedi_type)
|
|
128
|
+
else
|
|
129
|
+
generate_simple_element(element, stupidedi_type)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# The X12 Nn type carries 0-9 implied decimals, so any "N<digits>" is a
|
|
134
|
+
# valid numeric type even when not enumerated in TYPE_MAPPING (e.g. N3,
|
|
135
|
+
# N5, N7, N8, N9). The engine's Nn accepts arbitrary precision, so map
|
|
136
|
+
# them all to :Nn rather than raising.
|
|
137
|
+
def stupidedi_type_for(element)
|
|
138
|
+
type = element.x12_type
|
|
139
|
+
return TYPE_MAPPING[type] if TYPE_MAPPING.key?(type)
|
|
140
|
+
return :Nn if type.to_s =~ /\AN\d+\z/
|
|
141
|
+
|
|
142
|
+
raise ArgumentError, "Unknown x12_type: #{type} for element #{element.code}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def generate_composite_def(composite)
|
|
146
|
+
component_uses = composite.component_uses.sort_by(&:position)
|
|
147
|
+
|
|
148
|
+
lines = []
|
|
149
|
+
lines << "#{indent(3)}#{composite.code} ||= s::CompositeElementDef.build(:#{composite.code},"
|
|
150
|
+
lines << "#{indent(4)}#{escape_string(composite.name)},"
|
|
151
|
+
lines << "#{indent(4)}#{escape_string(composite.description || '')},"
|
|
152
|
+
|
|
153
|
+
component_uses.each_with_index do |component_use, index|
|
|
154
|
+
is_last = index == component_uses.length - 1
|
|
155
|
+
lines << generate_component_use(component_use, is_last: is_last)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
lines << "#{indent(3)})"
|
|
159
|
+
lines.join("\n")
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def generate_component_use(component_use, is_last:)
|
|
163
|
+
element = component_use.element
|
|
164
|
+
requirement = format_requirement(component_use.requirement)
|
|
165
|
+
trailing_comma = is_last ? "" : ","
|
|
166
|
+
|
|
167
|
+
"#{indent(4)}E#{element.code}.component_use(#{requirement})#{trailing_comma}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def generate_simple_element(element, stupidedi_type)
|
|
171
|
+
max_length = element.max_length || element.min_length
|
|
172
|
+
"#{indent(3)}E#{element.code} ||= t::#{stupidedi_type}.new(:E#{element.code}, #{escape_string(element.name)}, #{element.min_length}, #{max_length})"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Separator elements (I15, I65) have no x12_type - use Tediparse's
|
|
176
|
+
# Separator type so that #separator? returns true and the writer excludes
|
|
177
|
+
# them from data character checks.
|
|
178
|
+
def generate_control_element_def(element)
|
|
179
|
+
max_length = element.max_length || element.min_length
|
|
180
|
+
"#{indent(3)}E#{element.code} ||= Stupidedi::Interchanges::ElementTypes::Separator.new(:E#{element.code}, #{escape_string(element.name)}, #{element.min_length}, #{max_length})"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def generate_numeric_element(element, stupidedi_type)
|
|
184
|
+
max_length = element.max_length || element.min_length
|
|
185
|
+
digits = extract_decimal_places(element)
|
|
186
|
+
"#{indent(3)}E#{element.code} ||= t::#{stupidedi_type}.new(:E#{element.code}, #{escape_string(element.name)}, #{element.min_length}, #{max_length}, #{digits})"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def generate_id_element(element, stupidedi_type)
|
|
190
|
+
codes = element.element_codes.sort_by { |c| [c.paragraph, c.code] }
|
|
191
|
+
|
|
192
|
+
return generate_simple_element(element, stupidedi_type) if codes.empty?
|
|
193
|
+
|
|
194
|
+
max_length = element.max_length || element.min_length
|
|
195
|
+
lines = []
|
|
196
|
+
lines << "#{indent(3)}E#{element.code} ||= t::#{stupidedi_type}.new(:E#{element.code}, #{escape_string(element.name)}, #{element.min_length}, #{max_length},"
|
|
197
|
+
lines << "#{indent(4)}s::CodeList.build("
|
|
198
|
+
|
|
199
|
+
code_lines = codes.map do |code|
|
|
200
|
+
"#{indent(5)}#{escape_string(code.code)} => #{escape_string(code.name)}"
|
|
201
|
+
end
|
|
202
|
+
lines << code_lines.join(",\n") + "))"
|
|
203
|
+
|
|
204
|
+
lines.join("\n")
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def extract_decimal_places(element)
|
|
208
|
+
case element.x12_type
|
|
209
|
+
when "N0", "N" then 0
|
|
210
|
+
when "N1" then 1
|
|
211
|
+
when "N2" then 2
|
|
212
|
+
when "N4" then 4
|
|
213
|
+
when "N6" then 6
|
|
214
|
+
else
|
|
215
|
+
element.digits || 0
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|