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,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Schema
|
|
6
|
+
#
|
|
7
|
+
# @see X222 B.1.1.3.3 Composite Data Structure
|
|
8
|
+
#
|
|
9
|
+
class CompositeElementDef < AbstractElementDef
|
|
10
|
+
# @return [Array<ComponentElementUse>]
|
|
11
|
+
attr_reader :component_uses
|
|
12
|
+
|
|
13
|
+
# @return [Array<SyntaxNote>]
|
|
14
|
+
attr_reader :syntax_notes
|
|
15
|
+
|
|
16
|
+
# @return [CompositeElementUse]
|
|
17
|
+
attr_reader :parent
|
|
18
|
+
|
|
19
|
+
def initialize(id, name, description, component_uses, syntax_notes, parent)
|
|
20
|
+
@id, @name, @description, @component_uses, @syntax_notes, @parent =
|
|
21
|
+
id, name, description, component_uses, syntax_notes, parent
|
|
22
|
+
|
|
23
|
+
# Delay re-parenting until the entire definition tree has a root
|
|
24
|
+
# to prevent unnecessarily copying objects
|
|
25
|
+
unless parent.nil?
|
|
26
|
+
@component_uses = @component_uses.map{|x| x.copy(:parent => self) }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [CompositeElementDef]
|
|
31
|
+
def copy(changes = {})
|
|
32
|
+
CompositeElementDef.new \
|
|
33
|
+
changes.fetch(:id, @id),
|
|
34
|
+
changes.fetch(:name, @name),
|
|
35
|
+
changes.fetch(:description, @description),
|
|
36
|
+
changes.fetch(:component_uses, @component_uses),
|
|
37
|
+
changes.fetch(:syntax_notes, @syntax_notes),
|
|
38
|
+
changes.fetch(:parent, @parent)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return false
|
|
42
|
+
def simple?
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return true
|
|
47
|
+
def composite?
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [CompositeElementUse]
|
|
52
|
+
def simple_use(requirement, repeat_count, parent = nil)
|
|
53
|
+
CompositeElementUse.new(self, requirement, repeat_count, parent)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @return [CompositeElementVal]
|
|
57
|
+
def value(component_vals, usage, position)
|
|
58
|
+
Values::CompositeElementVal.new(component_vals, usage)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [CompositeElementVal]
|
|
62
|
+
def empty(usage, position)
|
|
63
|
+
Values::CompositeElementVal.new([], usage)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [AbstractSet<CodeList>]
|
|
67
|
+
def code_lists
|
|
68
|
+
@component_uses.map(&:code_lists).inject(&:|)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @return [void]
|
|
72
|
+
def pretty_print(q)
|
|
73
|
+
q.text("CompositeElementDef[#{@id}]")
|
|
74
|
+
q.group(2, "(", ")") do
|
|
75
|
+
q.breakable ""
|
|
76
|
+
@component_uses.each do |e|
|
|
77
|
+
unless q.current_group.first?
|
|
78
|
+
q.text ","
|
|
79
|
+
q.breakable
|
|
80
|
+
end
|
|
81
|
+
q.pp e
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class << CompositeElementDef
|
|
88
|
+
# @group Constructors
|
|
89
|
+
#########################################################################
|
|
90
|
+
|
|
91
|
+
# @return [CompositeElementDef]
|
|
92
|
+
def build(id, name, description, *args)
|
|
93
|
+
component_uses = args.take_while{|x| x.is_a?(AbstractElementUse) }
|
|
94
|
+
syntax_notes = args.drop(component_uses.length)
|
|
95
|
+
|
|
96
|
+
new(id, name, description, component_uses, syntax_notes, nil)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @endgroup
|
|
100
|
+
#########################################################################
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Schema
|
|
6
|
+
class CompositeElementUse < AbstractElementUse
|
|
7
|
+
# @return [CompositeElementDef]
|
|
8
|
+
attr_reader :definition
|
|
9
|
+
|
|
10
|
+
def_delegators :definition, :id, :name, :description
|
|
11
|
+
|
|
12
|
+
# @return [ElementReq]
|
|
13
|
+
attr_reader :requirement
|
|
14
|
+
|
|
15
|
+
# @return [RepeatCount]
|
|
16
|
+
attr_reader :repeat_count
|
|
17
|
+
|
|
18
|
+
# @return [SegmentDef]
|
|
19
|
+
attr_reader :parent
|
|
20
|
+
|
|
21
|
+
def initialize(definition, requirement, repeat_count, parent)
|
|
22
|
+
@definition, @requirement, @repeat_count, @parent =
|
|
23
|
+
definition, requirement, repeat_count, parent
|
|
24
|
+
|
|
25
|
+
# Delay re-parenting until the entire definition tree has a root
|
|
26
|
+
# to prevent unnecessarily copying objects
|
|
27
|
+
unless parent.nil?
|
|
28
|
+
@definition = @definition.copy(:parent => self)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [CompositeElementUse]
|
|
33
|
+
def copy(changes = {})
|
|
34
|
+
CompositeElementUse.new \
|
|
35
|
+
changes.fetch(:definition, @definition),
|
|
36
|
+
changes.fetch(:requirement, @requirement),
|
|
37
|
+
changes.fetch(:repeat_count, @repeat_count),
|
|
38
|
+
changes.fetch(:parent, @parent)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def descriptor
|
|
42
|
+
n = parent.element_uses.index{|u| u.eql?(self) } + 1
|
|
43
|
+
"element #{parent.id}#{"%02d" % n} #{definition.name}".strip
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def repeatable?
|
|
47
|
+
@repeat_count.try{|r| r.include?(2) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return false
|
|
51
|
+
def simple?
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @return false
|
|
56
|
+
def component?
|
|
57
|
+
false
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [void]
|
|
61
|
+
def pretty_print(q)
|
|
62
|
+
q.text("CompositeElementUse")
|
|
63
|
+
q.group(2, "(", ")") do
|
|
64
|
+
q.breakable ""
|
|
65
|
+
q.pp @definition
|
|
66
|
+
q.text ","
|
|
67
|
+
|
|
68
|
+
q.breakable
|
|
69
|
+
q.pp @requirement
|
|
70
|
+
q.text ","
|
|
71
|
+
|
|
72
|
+
q.breakable
|
|
73
|
+
q.pp @repeat_count
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Schema
|
|
6
|
+
#
|
|
7
|
+
# The 5010 X12 "condition designator"s include
|
|
8
|
+
# M - Mandatory
|
|
9
|
+
# O - Optional
|
|
10
|
+
# X - Relational
|
|
11
|
+
#
|
|
12
|
+
# Where "Relational" indicates this element is subject to relational
|
|
13
|
+
# conditions between two or more elements (encoded as a SyntaxNote)
|
|
14
|
+
#
|
|
15
|
+
# @see X222 B.1.1.3.9 Condition Designator
|
|
16
|
+
#
|
|
17
|
+
# The "Implementation Usage" from the 5010 HIPAA implementation guides
|
|
18
|
+
# have three descriptors:
|
|
19
|
+
# REQUIRED
|
|
20
|
+
# NOT USED
|
|
21
|
+
# SITUATIONAL
|
|
22
|
+
#
|
|
23
|
+
# @see X222.pdf 2.2.1 Industry Usage
|
|
24
|
+
#
|
|
25
|
+
class ElementReq
|
|
26
|
+
def initialize(required, forbidden, to_s)
|
|
27
|
+
@required, @forbidden, @to_s =
|
|
28
|
+
required, forbidden, to_s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# True if the element's presence is unconditionally required
|
|
32
|
+
def required?
|
|
33
|
+
@required
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# True if the element's presence is unconditionally forbidden
|
|
37
|
+
def forbidden?
|
|
38
|
+
@forbidden
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# True if the element's presence is required conditionally
|
|
42
|
+
def optional?
|
|
43
|
+
not (@required or @forbidden)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [void]
|
|
47
|
+
def pretty_print(q)
|
|
48
|
+
q.text @to_s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [String]
|
|
52
|
+
def inspect
|
|
53
|
+
@to_s
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Schema
|
|
6
|
+
#
|
|
7
|
+
# X12 standards are released three times yearly. The version codes sent in
|
|
8
|
+
# the `GS08` and `ST03` elements encode the version (eg 004, 005), the
|
|
9
|
+
# release (eg 0040, 0050), the subrelease (00501, 00602) and the level
|
|
10
|
+
# (eg 005010)
|
|
11
|
+
#
|
|
12
|
+
# The release schedules look like this:
|
|
13
|
+
#
|
|
14
|
+
# Approved by Available Ballot Results Available for
|
|
15
|
+
# Version Subcommitees for Ballot Approved Distribution
|
|
16
|
+
# ---------------------------------------------------------------------
|
|
17
|
+
# 005010 Feb 03 Jun 03 Oct 03 Jan 04
|
|
18
|
+
# 005011 Jun 03 Oct 04 Feb 04 Mar 04
|
|
19
|
+
# 005012 Oct 03 Feb 04 Jun 04 Jul 04
|
|
20
|
+
#
|
|
21
|
+
# 005020 Feb 04 Jun 04 Oct 04 Jan 05
|
|
22
|
+
# 005021 Jun 04 Oct 04 Feb 05 Mar 05
|
|
23
|
+
# 005022 Oct 04 Feb 05 Jun 05 Jul 05
|
|
24
|
+
#
|
|
25
|
+
# @see http://www.disa.org/x12org/subcommittees/dev/pdf/X12RELEASESCHED.pdf
|
|
26
|
+
#
|
|
27
|
+
# @see X222.pdf B.1.1.3.13 Functional Group
|
|
28
|
+
# @see X222.pdf B.1.1.4.2 Functional Groups
|
|
29
|
+
#
|
|
30
|
+
class FunctionalGroupDef < AbstractDef
|
|
31
|
+
include Inspect
|
|
32
|
+
|
|
33
|
+
# @return [String]
|
|
34
|
+
attr_reader :id
|
|
35
|
+
|
|
36
|
+
# @return [Array<SegmentUses>]
|
|
37
|
+
attr_reader :header_segment_uses
|
|
38
|
+
|
|
39
|
+
# @return [Array<SegmentUses>]
|
|
40
|
+
attr_reader :trailer_segment_uses
|
|
41
|
+
|
|
42
|
+
# @return [Hash, Module]
|
|
43
|
+
abstract :segment_dict
|
|
44
|
+
|
|
45
|
+
def initialize(id, header_segment_uses, trailer_segment_uses)
|
|
46
|
+
@id, @header_segment_uses, @trailer_segment_uses =
|
|
47
|
+
id, header_segment_uses, trailer_segment_uses
|
|
48
|
+
|
|
49
|
+
@header_segment_uses = header_segment_uses.map{|x| x.copy(:parent => self) }
|
|
50
|
+
@trailer_segment_uses = trailer_segment_uses.map{|x| x.copy(:parent => self) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [FunctionalGroupDef]
|
|
54
|
+
def copy(changes = {})
|
|
55
|
+
FunctionalGroupDef.new \
|
|
56
|
+
changes.fetch(:id, @id),
|
|
57
|
+
changes.fetch(:header_segment_uses, @header_segment_uses),
|
|
58
|
+
changes.fetch(:trailer_segment_uses, @trailer_segment_uses)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [String]
|
|
62
|
+
def descriptor
|
|
63
|
+
"transaction set #{id}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def required?
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [SegmentUse]
|
|
71
|
+
def entry_segment_use
|
|
72
|
+
@header_segment_uses.head
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [Array<SegmentUse>]
|
|
76
|
+
def children
|
|
77
|
+
@header_segment_uses + @trailer_segment_uses
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Values::FunctionalGroupVal]
|
|
81
|
+
def empty
|
|
82
|
+
Values::FunctionalGroupVal.new(self, [], [])
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def functional_group?
|
|
86
|
+
true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @return [AbstractSet<CodeList>
|
|
90
|
+
def code_lists
|
|
91
|
+
children.map(&:code_lists).inject(&:|)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [void]
|
|
95
|
+
def pretty_print(q)
|
|
96
|
+
q.text("FunctionalGroupDef")
|
|
97
|
+
q.group(2, "(", ")") do
|
|
98
|
+
q.breakable ""
|
|
99
|
+
@header_segment_uses.each do |e|
|
|
100
|
+
unless q.current_group.first?
|
|
101
|
+
q.text ","
|
|
102
|
+
q.breakable
|
|
103
|
+
end
|
|
104
|
+
q.pp e
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
unless q.current_group.first?
|
|
108
|
+
q.text ","
|
|
109
|
+
q.breakable
|
|
110
|
+
end
|
|
111
|
+
q.text "... (TRANSACTION SETS) ..."
|
|
112
|
+
|
|
113
|
+
@trailer_segment_uses.each do |e|
|
|
114
|
+
unless q.current_group.first?
|
|
115
|
+
q.text ","
|
|
116
|
+
q.breakable
|
|
117
|
+
end
|
|
118
|
+
q.pp e
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stupidedi
|
|
4
|
+
module Schema
|
|
5
|
+
module Generation
|
|
6
|
+
# Generates one transaction-set standard file (e.g. SM204.rb). Walks the
|
|
7
|
+
# transaction set's table definitions and recursively emits loops and
|
|
8
|
+
# segment uses. This is the heart of the grammar.
|
|
9
|
+
class DefinitionGenerator
|
|
10
|
+
include Support
|
|
11
|
+
|
|
12
|
+
AREA_METHODS = {
|
|
13
|
+
"heading" => "header",
|
|
14
|
+
"detail" => "detail",
|
|
15
|
+
"summary" => "summary"
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
def initialize(transaction_set, namespace: "Edi")
|
|
19
|
+
@transaction_set = transaction_set
|
|
20
|
+
@namespace = namespace
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def generate
|
|
24
|
+
validate_release!
|
|
25
|
+
build_ruby_content
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def constant_name
|
|
29
|
+
func_group = transaction_set.func_group
|
|
30
|
+
code = transaction_set.code
|
|
31
|
+
# If func_group is nil/empty, prefix with 'TS' to create a valid Ruby constant
|
|
32
|
+
func_group = "TS" if func_group.nil? || func_group.empty?
|
|
33
|
+
"#{func_group}#{code}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def output_path
|
|
37
|
+
"#{namespace_path}/#{underscore(version_module)}/standards/#{constant_name}.rb"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
attr_reader :transaction_set
|
|
43
|
+
|
|
44
|
+
def release_code
|
|
45
|
+
transaction_set.release.code
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def build_ruby_content
|
|
49
|
+
lines = []
|
|
50
|
+
lines << 'require "tediparse"'
|
|
51
|
+
lines << "if !defined?(#{namespace}::#{version_module}::Standards::#{constant_name})"
|
|
52
|
+
lines << " module #{namespace}"
|
|
53
|
+
lines << " module #{version_module}"
|
|
54
|
+
lines << " module Standards"
|
|
55
|
+
lines << " b = Stupidedi::TransactionSets::Builder"
|
|
56
|
+
lines << " d = Stupidedi::Schema"
|
|
57
|
+
lines << " r = #{namespace}::#{version_module}::SegmentReqs"
|
|
58
|
+
lines << " s = #{namespace}::#{version_module}::SegmentDefs"
|
|
59
|
+
lines << build_transaction_set_definition
|
|
60
|
+
lines << " end"
|
|
61
|
+
lines << " end"
|
|
62
|
+
lines << " end"
|
|
63
|
+
lines << "end"
|
|
64
|
+
lines.join("\n") + "\n"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_transaction_set_definition
|
|
68
|
+
tables = transaction_set.table_definitions.to_a
|
|
69
|
+
table_defs = tables.each_with_index.map do |table, index|
|
|
70
|
+
generate_table_def(table, is_last: index == tables.length - 1)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
header = %[ #{constant_name} = b.build("#{transaction_set.func_group}", "#{transaction_set.code}", "#{transaction_set.name}",]
|
|
74
|
+
footer = " )"
|
|
75
|
+
|
|
76
|
+
[header, *table_defs, footer].join("\n")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def generate_table_def(table, is_last:)
|
|
80
|
+
area_method = AREA_METHODS.fetch(table.area)
|
|
81
|
+
children = table.ordered_children
|
|
82
|
+
|
|
83
|
+
child_lines = children.each_with_index.map do |child, index|
|
|
84
|
+
child_is_last = index == children.length - 1
|
|
85
|
+
generate_child(child, indent_level: 6, is_last: child_is_last)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
trailing_comma = is_last ? "" : ","
|
|
89
|
+
header = %[#{indent(5)}d::TableDef.#{area_method}("#{table.name}",]
|
|
90
|
+
footer = "#{indent(5)})#{trailing_comma}"
|
|
91
|
+
|
|
92
|
+
[header, *child_lines, footer].join("\n")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def generate_child(child, indent_level:, is_last:)
|
|
96
|
+
if child.segment_use?
|
|
97
|
+
generate_segment_use(child, indent_level: indent_level, is_last: is_last)
|
|
98
|
+
else
|
|
99
|
+
generate_loop_def(child, indent_level: indent_level, is_last: is_last)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def generate_loop_def(loop, indent_level:, is_last:)
|
|
104
|
+
children = loop.ordered_children
|
|
105
|
+
repeat_count = format_repeat_count(loop.max_reps)
|
|
106
|
+
|
|
107
|
+
child_lines = children.each_with_index.map do |child, index|
|
|
108
|
+
child_is_last = index == children.length - 1
|
|
109
|
+
generate_child(child, indent_level: indent_level + 1, is_last: child_is_last)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
trailing_comma = is_last ? "" : ","
|
|
113
|
+
header = %[#{indent(indent_level)}d::LoopDef.build("#{loop.identifier}", #{repeat_count},]
|
|
114
|
+
footer = "#{indent(indent_level)})#{trailing_comma}"
|
|
115
|
+
|
|
116
|
+
[header, *child_lines, footer].join("\n")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def generate_segment_use(segment_use, indent_level:, is_last:)
|
|
120
|
+
segment_code = segment_use.segment.code
|
|
121
|
+
position = (segment_use.x12_sequence || segment_use.position).to_i
|
|
122
|
+
requirement = format_requirement(segment_use.requirement)
|
|
123
|
+
repeat_count = format_repeat_count(segment_use.max_reps)
|
|
124
|
+
|
|
125
|
+
trailing_comma = is_last ? "" : ","
|
|
126
|
+
"#{indent(indent_level)}s::#{segment_code}.use(#{position}, #{requirement}, #{repeat_count})#{trailing_comma}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def format_repeat_count(max_reps)
|
|
130
|
+
if max_reps.nil?
|
|
131
|
+
"d::RepeatCount.unbounded"
|
|
132
|
+
else
|
|
133
|
+
"d::RepeatCount.bounded(#{max_reps})"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|