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.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +319 -0
  3. data/LICENSE +26 -0
  4. data/README.md +308 -0
  5. data/Rakefile +33 -0
  6. data/bin/tediparse +102 -0
  7. data/doc/Defining.md +97 -0
  8. data/doc/Generating-Grammars.md +241 -0
  9. data/doc/Generating.md +332 -0
  10. data/doc/Navigating.md +670 -0
  11. data/doc/Parsing.md +133 -0
  12. data/doc/README.md +51 -0
  13. data/doc/Serializing.md +100 -0
  14. data/doc/Tokenizing.md +136 -0
  15. data/doc/Validating.md +140 -0
  16. data/lib/ruby/array.rb +226 -0
  17. data/lib/ruby/blank.rb +52 -0
  18. data/lib/ruby/exception.rb +14 -0
  19. data/lib/ruby/hash.rb +14 -0
  20. data/lib/ruby/module.rb +60 -0
  21. data/lib/ruby/object.rb +56 -0
  22. data/lib/ruby/string.rb +89 -0
  23. data/lib/ruby/to_d.rb +82 -0
  24. data/lib/ruby/to_date.rb +26 -0
  25. data/lib/ruby/to_time.rb +21 -0
  26. data/lib/ruby/try.rb +46 -0
  27. data/lib/stupidedi/builder.rb +6 -0
  28. data/lib/stupidedi/color.rb +94 -0
  29. data/lib/stupidedi/config/code_list_config.rb +45 -0
  30. data/lib/stupidedi/config/functional_group_config.rb +72 -0
  31. data/lib/stupidedi/config/interchange_config.rb +86 -0
  32. data/lib/stupidedi/config/transaction_set_config.rb +73 -0
  33. data/lib/stupidedi/config.rb +100 -0
  34. data/lib/stupidedi/either.rb +286 -0
  35. data/lib/stupidedi/exceptions/invalid_element_error.rb +7 -0
  36. data/lib/stupidedi/exceptions/invalid_schema_error.rb +7 -0
  37. data/lib/stupidedi/exceptions/missing_grammar_error.rb +50 -0
  38. data/lib/stupidedi/exceptions/output_error.rb +7 -0
  39. data/lib/stupidedi/exceptions/parse_error.rb +7 -0
  40. data/lib/stupidedi/exceptions/stupidedi_error.rb +7 -0
  41. data/lib/stupidedi/exceptions/tokenize_error.rb +7 -0
  42. data/lib/stupidedi/exceptions/zipper_error.rb +7 -0
  43. data/lib/stupidedi/exceptions.rb +13 -0
  44. data/lib/stupidedi/inspect.rb +26 -0
  45. data/lib/stupidedi/interchanges/element_types/separator_val.rb +79 -0
  46. data/lib/stupidedi/interchanges/element_types/special_val.rb +48 -0
  47. data/lib/stupidedi/interchanges/element_types.rb +11 -0
  48. data/lib/stupidedi/interchanges.rb +21 -0
  49. data/lib/stupidedi/parser/builder_dsl.rb +292 -0
  50. data/lib/stupidedi/parser/constraint_table.rb +566 -0
  51. data/lib/stupidedi/parser/generation.rb +147 -0
  52. data/lib/stupidedi/parser/identifier_stack.rb +248 -0
  53. data/lib/stupidedi/parser/instruction.rb +112 -0
  54. data/lib/stupidedi/parser/instruction_table.rb +222 -0
  55. data/lib/stupidedi/parser/navigation.rb +786 -0
  56. data/lib/stupidedi/parser/state_machine.rb +62 -0
  57. data/lib/stupidedi/parser/states/abstract_state.rb +385 -0
  58. data/lib/stupidedi/parser/states/failure_state.rb +69 -0
  59. data/lib/stupidedi/parser/states/functional_group_state.rb +101 -0
  60. data/lib/stupidedi/parser/states/initial_state.rb +62 -0
  61. data/lib/stupidedi/parser/states/interchange_state.rb +96 -0
  62. data/lib/stupidedi/parser/states/loop_state.rb +74 -0
  63. data/lib/stupidedi/parser/states/table_state.rb +90 -0
  64. data/lib/stupidedi/parser/states/transaction_set_state.rb +120 -0
  65. data/lib/stupidedi/parser/states/transmission_state.rb +59 -0
  66. data/lib/stupidedi/parser/tokenization.rb +195 -0
  67. data/lib/stupidedi/parser.rb +32 -0
  68. data/lib/stupidedi/reader/input/abstract_input.rb +137 -0
  69. data/lib/stupidedi/reader/input/delegated_input.rb +112 -0
  70. data/lib/stupidedi/reader/input/file_input.rb +157 -0
  71. data/lib/stupidedi/reader/input.rb +31 -0
  72. data/lib/stupidedi/reader/position.rb +78 -0
  73. data/lib/stupidedi/reader/result.rb +172 -0
  74. data/lib/stupidedi/reader/segment_dict.rb +176 -0
  75. data/lib/stupidedi/reader/separators.rb +90 -0
  76. data/lib/stupidedi/reader/stream_reader.rb +173 -0
  77. data/lib/stupidedi/reader/token_reader.rb +465 -0
  78. data/lib/stupidedi/reader/tokens/component_element_tok.rb +71 -0
  79. data/lib/stupidedi/reader/tokens/composite_element_tok.rb +85 -0
  80. data/lib/stupidedi/reader/tokens/repeated_element_tok.rb +74 -0
  81. data/lib/stupidedi/reader/tokens/segment_tok.rb +74 -0
  82. data/lib/stupidedi/reader/tokens/simple_element_tok.rb +76 -0
  83. data/lib/stupidedi/reader.rb +121 -0
  84. data/lib/stupidedi/schema/abstract_def.rb +76 -0
  85. data/lib/stupidedi/schema/abstract_element_def.rb +35 -0
  86. data/lib/stupidedi/schema/abstract_element_use.rb +47 -0
  87. data/lib/stupidedi/schema/abstract_use.rb +79 -0
  88. data/lib/stupidedi/schema/code_list.rb +99 -0
  89. data/lib/stupidedi/schema/component_element_use.rb +76 -0
  90. data/lib/stupidedi/schema/composite_element_def.rb +103 -0
  91. data/lib/stupidedi/schema/composite_element_use.rb +78 -0
  92. data/lib/stupidedi/schema/element_req.rb +57 -0
  93. data/lib/stupidedi/schema/functional_group_def.rb +124 -0
  94. data/lib/stupidedi/schema/generation/definition_generator.rb +139 -0
  95. data/lib/stupidedi/schema/generation/element_generator.rb +221 -0
  96. data/lib/stupidedi/schema/generation/flat_file_reader.rb +551 -0
  97. data/lib/stupidedi/schema/generation/functional_group_generator.rb +64 -0
  98. data/lib/stupidedi/schema/generation/interchange_generator.rb +145 -0
  99. data/lib/stupidedi/schema/generation/master_loader_generator.rb +121 -0
  100. data/lib/stupidedi/schema/generation/models.rb +85 -0
  101. data/lib/stupidedi/schema/generation/module_loader_generator.rb +64 -0
  102. data/lib/stupidedi/schema/generation/registration_generator.rb +230 -0
  103. data/lib/stupidedi/schema/generation/runner.rb +161 -0
  104. data/lib/stupidedi/schema/generation/segment_generator.rb +130 -0
  105. data/lib/stupidedi/schema/generation/support.rb +78 -0
  106. data/lib/stupidedi/schema/generation/support_modules_generator.rb +126 -0
  107. data/lib/stupidedi/schema/generation/version_modules.rb +35 -0
  108. data/lib/stupidedi/schema/generation.rb +94 -0
  109. data/lib/stupidedi/schema/interchange_def.rb +103 -0
  110. data/lib/stupidedi/schema/loop_def.rb +156 -0
  111. data/lib/stupidedi/schema/repeat_count.rb +86 -0
  112. data/lib/stupidedi/schema/segment_def.rb +122 -0
  113. data/lib/stupidedi/schema/segment_req.rb +46 -0
  114. data/lib/stupidedi/schema/segment_use.rb +99 -0
  115. data/lib/stupidedi/schema/simple_element_def.rb +51 -0
  116. data/lib/stupidedi/schema/simple_element_use.rb +83 -0
  117. data/lib/stupidedi/schema/syntax_note.rb +52 -0
  118. data/lib/stupidedi/schema/table_def.rb +178 -0
  119. data/lib/stupidedi/schema/transaction_set_def.rb +125 -0
  120. data/lib/stupidedi/schema.rb +30 -0
  121. data/lib/stupidedi/sets.rb +42 -0
  122. data/lib/stupidedi/transaction_sets/builder/dsl.rb +192 -0
  123. data/lib/stupidedi/transaction_sets/builder.rb +188 -0
  124. data/lib/stupidedi/transaction_sets/common/implementations/element_reqs.rb +37 -0
  125. data/lib/stupidedi/transaction_sets/common/implementations/segment_reqs.rb +31 -0
  126. data/lib/stupidedi/transaction_sets/common/implementations.rb +11 -0
  127. data/lib/stupidedi/transaction_sets/common.rb +8 -0
  128. data/lib/stupidedi/transaction_sets/validation/ambiguity.rb +395 -0
  129. data/lib/stupidedi/transaction_sets/validation/implementation.rb +12 -0
  130. data/lib/stupidedi/transaction_sets/validation.rb +9 -0
  131. data/lib/stupidedi/transaction_sets.rb +25 -0
  132. data/lib/stupidedi/values/abstract_element_val.rb +19 -0
  133. data/lib/stupidedi/values/abstract_val.rb +133 -0
  134. data/lib/stupidedi/values/composite_element_val.rb +102 -0
  135. data/lib/stupidedi/values/functional_group_val.rb +105 -0
  136. data/lib/stupidedi/values/interchange_val.rb +102 -0
  137. data/lib/stupidedi/values/invalid_envelope_val.rb +61 -0
  138. data/lib/stupidedi/values/invalid_segment_val.rb +89 -0
  139. data/lib/stupidedi/values/loop_val.rb +73 -0
  140. data/lib/stupidedi/values/repeated_element_val.rb +113 -0
  141. data/lib/stupidedi/values/segment_val.rb +105 -0
  142. data/lib/stupidedi/values/segment_val_group.rb +20 -0
  143. data/lib/stupidedi/values/simple_element_val.rb +80 -0
  144. data/lib/stupidedi/values/table_val.rb +69 -0
  145. data/lib/stupidedi/values/transaction_set_val.rb +69 -0
  146. data/lib/stupidedi/values/transmission_val.rb +56 -0
  147. data/lib/stupidedi/values.rb +22 -0
  148. data/lib/stupidedi/version.rb +4 -0
  149. data/lib/stupidedi/versions/common/element_reqs.rb +13 -0
  150. data/lib/stupidedi/versions/common/element_types/an.rb +386 -0
  151. data/lib/stupidedi/versions/common/element_types/dt.rb +572 -0
  152. data/lib/stupidedi/versions/common/element_types/id.rb +304 -0
  153. data/lib/stupidedi/versions/common/element_types/nn.rb +312 -0
  154. data/lib/stupidedi/versions/common/element_types/operators.rb +128 -0
  155. data/lib/stupidedi/versions/common/element_types/r.rb +342 -0
  156. data/lib/stupidedi/versions/common/element_types/simple_element.rb +73 -0
  157. data/lib/stupidedi/versions/common/element_types/tm.rb +347 -0
  158. data/lib/stupidedi/versions/common/element_types.rb +29 -0
  159. data/lib/stupidedi/versions/common/segment_reqs.rb +15 -0
  160. data/lib/stupidedi/versions/common/syntax_notes.rb +172 -0
  161. data/lib/stupidedi/versions/common.rb +11 -0
  162. data/lib/stupidedi/versions.rb +25 -0
  163. data/lib/stupidedi/writer/claredi.rb +178 -0
  164. data/lib/stupidedi/writer/default.rb +119 -0
  165. data/lib/stupidedi/writer.rb +7 -0
  166. data/lib/stupidedi/zipper/abstract_cursor.rb +351 -0
  167. data/lib/stupidedi/zipper/dangling_cursor.rb +103 -0
  168. data/lib/stupidedi/zipper/edited_cursor.rb +157 -0
  169. data/lib/stupidedi/zipper/memoized_cursor.rb +133 -0
  170. data/lib/stupidedi/zipper/path.rb +132 -0
  171. data/lib/stupidedi/zipper/root_cursor.rb +120 -0
  172. data/lib/stupidedi/zipper/stack_cursor.rb +107 -0
  173. data/lib/stupidedi/zipper.rb +45 -0
  174. data/lib/stupidedi.rb +69 -0
  175. data/lib/tediparse.rb +1 -0
  176. metadata +249 -0
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Schema
6
+ class SimpleElementUse < AbstractElementUse
7
+ # @return [SimpleElementDef]
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 [AbstractSet]
19
+ attr_reader :allowed_values
20
+
21
+ # @return [SegmentDef]
22
+ attr_reader :parent
23
+
24
+ def initialize(definition, requirement, repeat_count, allowed_values, parent)
25
+ @definition, @requirement, @repeat_count, @allowed_values, @parent =
26
+ definition, requirement, repeat_count, allowed_values, parent
27
+
28
+ # Delay re-parenting until the entire definition tree has a root
29
+ # to prevent unnecessarily copying objects
30
+ unless parent.nil?
31
+ @definition = @definition.copy(:parent => self)
32
+ end
33
+ end
34
+
35
+ # @return [SimpleElementUse]
36
+ def copy(changes = {})
37
+ SimpleElementUse.new \
38
+ changes.fetch(:definition, @definition),
39
+ changes.fetch(:requirement, @requirement),
40
+ changes.fetch(:repeat_count, @repeat_count),
41
+ changes.fetch(:allowed_values, @allowed_values),
42
+ changes.fetch(:parent, @parent)
43
+ end
44
+
45
+ # @return [String]
46
+ def descriptor
47
+ idx = parent.element_uses.index{|u| u.eql?(self) } + 1
48
+ "element #{parent.id}#{"%02d" % idx} #{definition.name}".strip
49
+ end
50
+
51
+ def repeatable?
52
+ @repeat_count.try{|r| r.include?(2) }
53
+ end
54
+
55
+ # @return true
56
+ def simple?
57
+ true
58
+ end
59
+
60
+ # @return false
61
+ def component?
62
+ false
63
+ end
64
+
65
+ # @return [void]
66
+ def pretty_print(q)
67
+ q.text("SimpleElementUse")
68
+ q.group(2, "(", ")") do
69
+ q.breakable ""
70
+ q.pp @definition
71
+ q.text ","
72
+
73
+ q.breakable
74
+ q.pp @requirement
75
+ q.text ","
76
+
77
+ q.breakable
78
+ q.pp @repeat_count
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Schema
6
+ #
7
+ # The 5010 X12 "condition code"s include
8
+ # P - Paired or Multiple (if one then all)
9
+ # R - Required (at least one)
10
+ # E - Exclusion (no more than one)
11
+ # C - Conditional (if first then all)
12
+ # L - List Conditional (if first than at least one more)
13
+ #
14
+ # @see X222.pdf B.1.1.3.5 Syntax Notes
15
+ # @see X222.pdf B.1.1.3.9 Condition Designator
16
+ #
17
+ class SyntaxNote
18
+ # @return [Array<Integer>]
19
+ attr_reader :indexes
20
+
21
+ def initialize(indexes)
22
+ @indexes = indexes
23
+ end
24
+
25
+ # Returns the AbstractElementVals from the given segment or composite
26
+ # element that must be present, given the presence of other elements
27
+ #
28
+ # @return [Array<Zipper::AbstractCursor<Values::AbstractElementVal>>]
29
+ abstract :required, :args => %w(zipper)
30
+
31
+ # Returns the AbstractElementVals from the given segment or composite
32
+ # element that must not be present, given the presence of other elements
33
+ #
34
+ # @return [Array<Zipper::AbstractCursor<Values::AbstractElementVal>>]
35
+ abstract :forbidden, :args => %w(zipper)
36
+
37
+ # @return [String]
38
+ abstract :reason, :args => %w(zipper)
39
+
40
+ def satisfied?(zipper)
41
+ forbidden(zipper).all?{|c| c.node.blank? } and
42
+ required(zipper).all?{|c| c.node.present? }
43
+ end
44
+
45
+ private
46
+
47
+ def children(zipper)
48
+ indexes.map{|n| zipper.child(n - 1) }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Schema
6
+ class TableDef < AbstractDef
7
+ # @return [String]
8
+ attr_reader :id
9
+
10
+ # @return [Array<SegmentUse, LoopDef>]
11
+ attr_reader :children
12
+
13
+ # @return [TransactionSetDef]
14
+ attr_reader :parent
15
+
16
+ # @return [Integer]
17
+ attr_reader :position
18
+
19
+ def initialize(id, position, children, parent)
20
+ @id, @position, @children, @parent =
21
+ id, position, children, 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
+ @children = @children.map{|x| x.copy(:parent => self) }
27
+ end
28
+ end
29
+
30
+ # @return [TableDef]
31
+ def copy(changes = {})
32
+ TableDef.new \
33
+ changes.fetch(:id, @id),
34
+ changes.fetch(:position, @position),
35
+ changes.fetch(:children, @children),
36
+ changes.fetch(:parent, @parent)
37
+ end
38
+
39
+ # Returns segments before the first LoopDef.
40
+ # @deprecated Use {#children} instead. This method does not include
41
+ # segments that appear between child loops in interleaved structures.
42
+ # @return [Array<SegmentUse>]
43
+ def header_segment_uses
44
+ @children.take_while{|x| x.is_a?(SegmentUse) }
45
+ end
46
+
47
+ # Returns all LoopDef children.
48
+ # @deprecated Use {#children} instead and filter with `select{|x| x.is_a?(LoopDef)}`.
49
+ # @return [Array<LoopDef>]
50
+ def loop_defs
51
+ @children.select{|x| x.is_a?(LoopDef) }
52
+ end
53
+
54
+ # Returns segments after the last LoopDef.
55
+ # @deprecated Use {#children} instead. This method does not include
56
+ # segments that appear between child loops in interleaved structures.
57
+ # @return [Array<SegmentUse>]
58
+ def trailer_segment_uses
59
+ last_loop_idx = @children.rindex{|x| x.is_a?(LoopDef) }
60
+ return [] if last_loop_idx.nil?
61
+ @children.drop(last_loop_idx + 1).select{|x| x.is_a?(SegmentUse) }
62
+ end
63
+
64
+ # @return [String]
65
+ def descriptor
66
+ "table #{id}"
67
+ end
68
+
69
+ def repeatable?
70
+ header_segment_uses.empty? and
71
+ loop_defs.present? and
72
+ loop_defs.head.repeatable?
73
+ end
74
+
75
+ def repeat_count
76
+ if repeatable?
77
+ RepeatCount.unbounded
78
+ else
79
+ RepeatCount.bounded(1)
80
+ end
81
+ end
82
+
83
+ def required?
84
+ entry_segment_uses.any?(&:required?)
85
+ end
86
+
87
+ # @return [Array<SegmentUse>]
88
+ def entry_segment_uses
89
+ uses = @children.map do |child|
90
+ if child.is_a?(SegmentUse)
91
+ child
92
+ else
93
+ child.entry_segment_use
94
+ end
95
+ end
96
+
97
+ # Up to and including the first required segment
98
+ suffix = uses.drop_while(&:optional?)
99
+
100
+ if suffix.present?
101
+ # Some segment(s) is required, so table can't start without it
102
+ position = suffix.map(&:position).min
103
+ uses.take_while{|u| u.position <= position }
104
+ else
105
+ # Nothing is required, table can begin at any of these
106
+ uses
107
+ end
108
+ end
109
+
110
+ # @return [Values::TableVal]
111
+ def empty
112
+ Values::TableVal.new(self, [])
113
+ end
114
+
115
+ def table?
116
+ true
117
+ end
118
+
119
+ # @return [AbstractSet<CodeList>]
120
+ def code_lists
121
+ @children.map(&:code_lists).inject(&:|)
122
+ end
123
+
124
+ # @return [void]
125
+ def pretty_print(q)
126
+ q.text("TableDef[#{@id}]")
127
+ q.group(2, "(", ")") do
128
+ q.breakable ""
129
+ @children.each do |e|
130
+ unless q.current_group.first?
131
+ q.text ","
132
+ q.breakable
133
+ end
134
+ q.pp e
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ class << TableDef
141
+ # @group Constructors
142
+ #########################################################################
143
+
144
+ # @return [TableDef]
145
+ def header(id, *children)
146
+ unless id.is_a?(String)
147
+ raise Exceptions::InvalidSchemaError,
148
+ "first argument to TableDef.header must be a String but got #{id.inspect}"
149
+ end
150
+
151
+ new(id, 1, children, nil)
152
+ end
153
+
154
+ # @return [TableDef]
155
+ def detail(id, *children)
156
+ unless id.is_a?(String)
157
+ raise Exceptions::InvalidSchemaError,
158
+ "first argument to TableDef.detail must be a String but got #{id.inspect}"
159
+ end
160
+
161
+ new(id, 2, children, nil)
162
+ end
163
+
164
+ # @return [TableDef]
165
+ def summary(id, *children)
166
+ unless id.is_a?(String)
167
+ raise Exceptions::InvalidSchemaError,
168
+ "first argument to TableDef.summary must be a String but got #{id.inspect}"
169
+ end
170
+
171
+ new(id, 3, children, nil)
172
+ end
173
+
174
+ # @endgroup
175
+ #########################################################################
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Schema
6
+ class TransactionSetDef < AbstractDef
7
+ include Inspect
8
+
9
+ # @return [String]
10
+ attr_reader :id
11
+
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ # @return [String]
16
+ attr_reader :functional_group
17
+
18
+ # @return [Array<TableDef>]
19
+ attr_reader :table_defs
20
+
21
+ def initialize(functional_group, id, name, table_defs)
22
+ @functional_group, @id, @name, @table_defs =
23
+ functional_group, id, name, table_defs
24
+
25
+ @table_defs = table_defs.map{|x| x.copy(:parent => self) }
26
+ end
27
+
28
+ def copy(changes = {})
29
+ TransactionSetDef.new \
30
+ changes.fetch(:functional_group, @functional_group),
31
+ changes.fetch(:id, @id),
32
+ changes.fetch(:name, @name),
33
+ changes.fetch(:table_defs, @table_defs)
34
+ end
35
+
36
+ # @return [String]
37
+ def descriptor
38
+ "transaction set #{functional_group}#{id} #{name}"
39
+ end
40
+
41
+ # @return [Values::TransactionSetVal]
42
+ def empty
43
+ Values::TransactionSetVal.new(self, [])
44
+ end
45
+
46
+ # @return [SegmentUse]
47
+ def entry_segment_use
48
+ @table_defs.head.header_segment_uses.head
49
+ end
50
+
51
+ # @return [SegmentUse]
52
+ def first_segment_use
53
+ @table_defs.head.header_segment_uses.head
54
+ end
55
+
56
+ # @return [SegmentUse]
57
+ def last_segment_use
58
+ @table_defs.last.trailer_segment_uses.last
59
+ end
60
+
61
+ # @return [Array<TableDef>]
62
+ def children
63
+ @table_defs
64
+ end
65
+
66
+ def transaction?
67
+ true
68
+ end
69
+
70
+ # @return [AbstractSet<CodeList>]
71
+ def code_lists
72
+ @table_defs.map(&:code_lists).inject(&:|)
73
+ end
74
+
75
+ # @return [void]
76
+ def pretty_print(q)
77
+ q.text("TransactionSetDef[#{@functional_group}#{@id}]")
78
+ q.group(2, "(", ")") do
79
+ q.breakable ""
80
+ @table_defs.each do |e|
81
+ unless q.current_group.first?
82
+ q.text ","
83
+ q.breakable
84
+ end
85
+ q.pp e
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ class << TransactionSetDef
92
+ # @return [TransactionSetDef]
93
+ def build(functional_group, id, name, *table_defs)
94
+ table_defs.each.with_index do |t, k|
95
+ unless t.table?
96
+ if t.respond_to?(:pretty_inspect)
97
+ raise Exceptions::InvalidSchemaError,
98
+ "argument #{k+4} is not a TableDef: #{t.pretty_inspect}"
99
+ else
100
+ raise Exceptions::InvalidSchemaError,
101
+ "argument #{k+4} is not a TableDef: #{t.inspect}"
102
+ end
103
+ end
104
+
105
+ # next unless t.repeatable?
106
+
107
+ # [t.header_segment_uses, t.loop_defs, t.trailer_segment_uses].each do |s|
108
+ # opt, req = s.split_until(&:optional?)
109
+ # prefix = opt.concat(req.take(1))
110
+
111
+ # if x = prefix.find(&:repeatable?)
112
+ # raise Exceptions::InvalidSchemaError,
113
+ # %Q("#{x.id}" is an entry point into "#{t.id}", and both are marked
114
+ # repeatable).join
115
+ # end
116
+
117
+ # break if req.present?
118
+ # end
119
+ end
120
+
121
+ new(functional_group, id, name, table_defs)
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Schema
4
+ autoload :AbstractElementUse, "stupidedi/schema/abstract_element_use"
5
+ autoload :AbstractUse, "stupidedi/schema/abstract_use"
6
+ autoload :ComponentElementUse, "stupidedi/schema/component_element_use"
7
+ autoload :CompositeElementUse, "stupidedi/schema/composite_element_use"
8
+ autoload :SegmentUse, "stupidedi/schema/segment_use"
9
+ autoload :SimpleElementUse, "stupidedi/schema/simple_element_use"
10
+
11
+ autoload :AbstractDef, "stupidedi/schema/abstract_def"
12
+ autoload :AbstractElementDef, "stupidedi/schema/abstract_element_def"
13
+ autoload :CompositeElementDef, "stupidedi/schema/composite_element_def"
14
+ autoload :FunctionalGroupDef, "stupidedi/schema/functional_group_def"
15
+ autoload :InterchangeDef, "stupidedi/schema/interchange_def"
16
+ autoload :LoopDef, "stupidedi/schema/loop_def"
17
+ autoload :SegmentDef, "stupidedi/schema/segment_def"
18
+ autoload :SimpleElementDef, "stupidedi/schema/simple_element_def"
19
+ autoload :TableDef, "stupidedi/schema/table_def"
20
+ autoload :TransactionSetDef, "stupidedi/schema/transaction_set_def"
21
+
22
+ autoload :ElementReq, "stupidedi/schema/element_req"
23
+ autoload :SegmentReq, "stupidedi/schema/segment_req"
24
+ autoload :RepeatCount, "stupidedi/schema/repeat_count"
25
+ autoload :SyntaxNote, "stupidedi/schema/syntax_note"
26
+ autoload :CodeList, "stupidedi/schema/code_list"
27
+
28
+ autoload :Generation, "stupidedi/schema/generation"
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ require "cantor"
3
+
4
+ module Stupidedi
5
+ using Refinements
6
+
7
+ module Sets
8
+ end
9
+
10
+ class << Sets
11
+ # @group Constructors
12
+ ###########################################################################
13
+
14
+ # @return [Cantor::AbstractSet]
15
+ def build(object)
16
+ Cantor.build(object)
17
+ end
18
+
19
+ # @return [Cantor::AbstractSet]
20
+ def complement(other)
21
+ Cantor.complement(other)
22
+ end
23
+
24
+ # @return [Cantor::UniversalSet]
25
+ def universal
26
+ Cantor.universal
27
+ end
28
+
29
+ # @return [Cantor::NullSet]
30
+ def empty
31
+ Cantor.empty
32
+ end
33
+
34
+ # @return [Cantor::AbsoluteSet]
35
+ def absolute(other, universe = other)
36
+ Cantor.absolute(other, universe)
37
+ end
38
+
39
+ # @endgroup
40
+ ###########################################################################
41
+ end
42
+ end
@@ -0,0 +1,192 @@
1
+ module Stupidedi
2
+ module TransactionSets
3
+ module Builder
4
+ class Dsl
5
+
6
+ ##
7
+ # Build a definition for a given document using DSL-style.
8
+ # DSL style is a bit easier to use than manually building a syntax tree.
9
+ def self.build(shortcode, code, name, &block)
10
+ body = DocumentBodyDSL.new(&block).tables
11
+ Builder.build(shortcode, code, name, *body)
12
+ end
13
+
14
+ private
15
+
16
+ ##
17
+ # Syntax for DSLs in which you can define elements.
18
+ module ElementSyntax
19
+
20
+ ##
21
+ # Define an element within this block
22
+ def element(*args)
23
+ add_element(Builder::Element(*args))
24
+ end
25
+
26
+ ##
27
+ # Define a composite element within this block, using a sub-block for the sub-elements
28
+ def composite(*args, &block)
29
+ subelements = SegmentBodyDSL.new(&block).elements
30
+ add_element(Builder::Element(*(args + subelements)))
31
+ end
32
+
33
+ end
34
+
35
+ ##
36
+ # Syntax for DSLs in which you can define segments.
37
+ module SegmentSyntax
38
+
39
+ def segment(pos, type, name, requirement, repeat, &block)
40
+ elements = SegmentBodyDSL.new(&block).elements
41
+ segment = Builder::Segment(
42
+ pos,
43
+ type,
44
+ name,
45
+ requirement,
46
+ repeat,
47
+ *elements
48
+ )
49
+
50
+ add_segment(segment)
51
+ end
52
+
53
+ end
54
+
55
+ ##
56
+ # Syntax for DSLs in which you can define loops.
57
+ module LoopSyntax
58
+
59
+ ##
60
+ # Define a loop within this block.
61
+ # The underscore is there because "loop" is a ruby keyword.
62
+ def loop_(name, repeat, &block)
63
+ body = LoopBodyDSL.new(&block).elements
64
+ add_loop(Schema::LoopDef.build(name, repeat, *body))
65
+ end
66
+
67
+ end
68
+
69
+ ##
70
+ # Syntax for DSLs in which you can define tables.
71
+ module TableSyntax
72
+
73
+ ##
74
+ # Define a header table within this block.
75
+ def table_header(name, &block)
76
+ add_table(Schema::TableDef.header(name, *get_table_contents(&block)))
77
+ end
78
+
79
+ ##
80
+ # Define a detail table within this block
81
+ def table_detail(name, &block)
82
+ add_table(Schema::TableDef.detail(name, *get_table_contents(&block)))
83
+ end
84
+
85
+ ##
86
+ # Helper method to get the body of a table.
87
+ def get_table_contents(&block)
88
+ TableBodyDSL.new(&block).elements
89
+ end
90
+
91
+ end
92
+
93
+ ##
94
+ # Syntax for DSLs in which you can define values lists.
95
+ module ValuesSyntax
96
+
97
+ def values(*args)
98
+ Builder::Values(*args)
99
+ end
100
+
101
+ end
102
+
103
+ ##
104
+ # A DSL for the body of a loop, which allows defining loops and segments
105
+ class LoopBodyDSL
106
+
107
+ include LoopSyntax
108
+ include SegmentSyntax
109
+
110
+ def initialize(&block)
111
+ @elements = []
112
+ instance_eval(&block)
113
+ end
114
+
115
+ attr_accessor :elements
116
+
117
+ def add_loop(loop_)
118
+ elements << loop_
119
+ end
120
+
121
+ def add_segment(segment)
122
+ elements << segment
123
+ end
124
+
125
+ end
126
+
127
+ ##
128
+ # A DSL for the body of a segment, which allows defining elements and using
129
+ # values lists.
130
+ class SegmentBodyDSL
131
+
132
+ include ElementSyntax
133
+ include ValuesSyntax
134
+
135
+ def initialize(&block)
136
+ @elements = []
137
+ instance_eval(&block)
138
+ end
139
+
140
+ def add_element(e)
141
+ @elements << e
142
+ end
143
+
144
+ attr_accessor :elements
145
+ end
146
+
147
+ ##
148
+ # A DSL for the body of a table, which allows defining segments and loops.
149
+ class TableBodyDSL
150
+
151
+ include LoopSyntax
152
+ include SegmentSyntax
153
+
154
+ def initialize(&block)
155
+ @elements = []
156
+ instance_eval(&block)
157
+ end
158
+
159
+ def add_loop(l)
160
+ @elements << l
161
+ end
162
+
163
+ def add_segment(segment)
164
+ @elements << segment
165
+ end
166
+
167
+ attr_accessor :elements
168
+ end
169
+
170
+ ##
171
+ # A DSL for the body of a document, which allows defining tables.
172
+ class DocumentBodyDSL
173
+
174
+ include TableSyntax
175
+
176
+ def initialize(&block)
177
+ @tables = []
178
+ instance_eval(&block)
179
+ end
180
+
181
+ attr_accessor :tables
182
+
183
+ def add_table(table)
184
+ tables << table
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+ end
191
+ end
192
+ end