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,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
|