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,304 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Versions
6
+ module Common
7
+ module ElementTypes
8
+ class ID < SimpleElementDef
9
+ # @return [Schema::CodeList]
10
+ attr_reader :code_list
11
+
12
+ def initialize(id, name, min_length, max_length, code_list = nil, description = nil, parent = nil)
13
+ super(id, name, min_length, max_length, description, parent)
14
+ @code_list = code_list
15
+ end
16
+
17
+ def companion
18
+ IdentifierVal
19
+ end
20
+
21
+ # @return [ID]
22
+ def copy(changes = {})
23
+ ID.new \
24
+ changes.fetch(:id, @id),
25
+ changes.fetch(:name, @name),
26
+ changes.fetch(:min_length, @min_length),
27
+ changes.fetch(:max_length, @max_length),
28
+ changes.fetch(:code_list, @code_list),
29
+ changes.fetch(:description, @description),
30
+ changes.fetch(:parent, @parent)
31
+ end
32
+
33
+ # @return [SimpleElementUse]
34
+ def simple_use(requirement, repeat_count, parent = nil)
35
+ if @code_list.try(:internal?)
36
+ Schema::SimpleElementUse.new(self, requirement, repeat_count, Sets.absolute(@code_list.codes), parent)
37
+ else
38
+ Schema::SimpleElementUse.new(self, requirement, repeat_count, Sets.universal, parent)
39
+ end
40
+ end
41
+
42
+ # @return [ComponentElementUse]
43
+ def component_use(requirement, parent = nil)
44
+ if @code_list.try(:internal?)
45
+ Schema::ComponentElementUse.new(self, requirement, Sets.absolute(@code_list.codes), parent)
46
+ else
47
+ Schema::ComponentElementUse.new(self, requirement, Sets.universal, parent)
48
+ end
49
+ end
50
+ end
51
+
52
+ #
53
+ # @see X222.pdf B.1.1.3.1.3 Identifier
54
+ #
55
+ class IdentifierVal < Values::SimpleElementVal
56
+ def id?
57
+ true
58
+ end
59
+
60
+ def too_long?
61
+ false
62
+ end
63
+
64
+ def too_short?
65
+ false
66
+ end
67
+
68
+ class Invalid < IdentifierVal
69
+ # @return [Object]
70
+ attr_reader :value
71
+
72
+ def initialize(value, usage, position)
73
+ @value = value
74
+ super(usage, position)
75
+ end
76
+
77
+ # @return [Invalid]
78
+ def copy(changes = {})
79
+ self
80
+ end
81
+
82
+ def valid?
83
+ false
84
+ end
85
+
86
+ def empty?
87
+ false
88
+ end
89
+
90
+ # @return [IdentifierVal]
91
+ def map
92
+ self
93
+ end
94
+
95
+ # @return [String]
96
+ # :nocov:
97
+ def inspect
98
+ id = definition.bind do |d|
99
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
100
+ if usage.forbidden?
101
+ ansi.forbidden(s)
102
+ elsif usage.required?
103
+ ansi.required(s)
104
+ else
105
+ ansi.optional(s)
106
+ end
107
+ end
108
+ end
109
+
110
+ ansi.element("ID.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
111
+ end
112
+ # :nocov:
113
+
114
+ # @return [String]
115
+ def to_s
116
+ ""
117
+ end
118
+
119
+ # @return [String]
120
+ def to_x12(truncate = true)
121
+ ""
122
+ end
123
+
124
+ # @return [Boolean]
125
+ def ==(other)
126
+ eql?(other)
127
+ end
128
+ end
129
+
130
+ class Valid < IdentifierVal
131
+ include Comparable
132
+
133
+ # (string any* -> any)
134
+ def_delegators :value, :to_d, :to_s, :to_f, :to_c, :to_r, :to_sym,
135
+ :to_str, :hex, :oct, :ord, :sum, :length, :count, :index, :rindex,
136
+ :lines, :bytes, :chars, :each, :upto, :split, :scan, :unpack, :=~,
137
+ :match, :partition, :rpatition, :encoding, :valid_enocding?,
138
+ :at, :empty?, :blank?
139
+
140
+ # (string any* -> StringVal)
141
+ extend Operators::Wrappers
142
+ wrappers :%, :+, :*, :slice, :take, :drop, :[], :capitalize,
143
+ :center, :ljust, :rjust, :chomp, :delete, :tr, :tr_s,
144
+ :sub, :gsub, :encode, :force_encoding, :squeeze
145
+
146
+ # (string -> StringVal)
147
+ extend Operators::Unary
148
+ unary_operators :chr, :chop, :upcase, :downcase, :strip,
149
+ :lstrip, :rstrip, :dump, :succ, :next, :reverse, :swapcase
150
+
151
+ # (string string -> any)
152
+ extend Operators::Relational
153
+ relational_operators :<=>, :start_with?, :end_with?,
154
+ :include?, :casecmp, :coerce => :to_str
155
+
156
+ def ==(other)
157
+ other = IdentifierVal.value(other, usage, position)
158
+ other.valid? and other.value == value
159
+ end
160
+
161
+ # @return [StringVal]
162
+ def copy(changes = {})
163
+ IdentifierVal.value \
164
+ changes.fetch(:value, value),
165
+ changes.fetch(:usage, usage),
166
+ changes.fetch(:position, position)
167
+ end
168
+
169
+ def coerce(other)
170
+ return IdentifierVal.value(other, usage, position), self
171
+ end
172
+
173
+ # @return [IdentifierVal]
174
+ def map
175
+ IdentifierVal.value(yield(value), usage, position)
176
+ end
177
+
178
+ def valid?
179
+ true
180
+ end
181
+ end
182
+
183
+ class Empty < Valid
184
+ # @return [String]
185
+ def value
186
+ ""
187
+ end
188
+
189
+ # @return [String]
190
+ # :nocov:
191
+ def inspect
192
+ id = definition.bind do |d|
193
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
194
+ if usage.forbidden?
195
+ ansi.forbidden(s)
196
+ elsif usage.required?
197
+ ansi.required(s)
198
+ else
199
+ ansi.optional(s)
200
+ end
201
+ end
202
+ end
203
+
204
+ ansi.element("ID.empty#{id}")
205
+ end
206
+ # :nocov:
207
+
208
+ # @return [String]
209
+ def to_x12(truncate = true)
210
+ ""
211
+ end
212
+ end
213
+
214
+ class NonEmpty < Valid
215
+ # @return [String]
216
+ attr_reader :value
217
+
218
+ def initialize(value, usage, position)
219
+ @value = value
220
+ super(usage, position)
221
+ end
222
+
223
+ def too_long?
224
+ @value.length > definition.max_length
225
+ end
226
+
227
+ def too_short?
228
+ @value.length < definition.min_length
229
+ end
230
+
231
+ # @return [String]
232
+ def to_x12(truncate = true)
233
+ x12 = @value.ljust(definition.min_length, " ")
234
+ truncate ? x12.take(definition.max_length) : x12
235
+ end
236
+
237
+ # @return [String]
238
+ # :nocov:
239
+ def inspect
240
+ id = definition.bind do |d|
241
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
242
+ if usage.forbidden?
243
+ ansi.forbidden(s)
244
+ elsif usage.required?
245
+ ansi.required(s)
246
+ else
247
+ ansi.optional(s)
248
+ end
249
+ end
250
+ end
251
+
252
+ if definition.code_list.try(&:internal?)
253
+ if usage.allowed_values.include?(@value)
254
+ value = "#{@value}: " + ansi.dark(definition.code_list.at(@value))
255
+ elsif definition.code_list.defined_at?(@value)
256
+ value = ansi.red("#{@value}: " + definition.code_list.at(@value))
257
+ else
258
+ value = ansi.red(@value)
259
+ end
260
+ else
261
+ value = @value
262
+ end
263
+
264
+ ansi.element("ID.value#{id}") + "(#{value})"
265
+ end
266
+ # :nocov:
267
+ end
268
+ end
269
+
270
+ class << IdentifierVal
271
+ # @group Constructors
272
+ ###################################################################
273
+
274
+ # @return [IdentifierVal]
275
+ def empty(usage, position)
276
+ self::Empty.new(usage, position)
277
+ end
278
+
279
+ # @return [IdentifierVal]
280
+ def value(object, usage, position)
281
+ if object.is_a?(IdentifierVal)
282
+ object#.copy(:usage => usage, :position => position)
283
+ elsif object.blank?
284
+ self::Empty.new(usage, position)
285
+ else
286
+ self::NonEmpty.new(object.to_s.rstrip, usage, position)
287
+ end
288
+ rescue
289
+ self::Invalid.new(object, usage, position)
290
+ end
291
+
292
+ # @endgroup
293
+ ###################################################################
294
+ end
295
+
296
+ # Prevent direct instantiation of abstract class IdentifierVal
297
+ IdentifierVal.eigenclass.send(:protected, :new)
298
+ IdentifierVal::Empty.eigenclass.send(:public, :new)
299
+ IdentifierVal::Invalid.eigenclass.send(:public, :new)
300
+ IdentifierVal::NonEmpty.eigenclass.send(:public, :new)
301
+ end
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,312 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Versions
6
+ module Common
7
+ module ElementTypes
8
+ class Nn < SimpleElementDef
9
+ # @return [Integer]
10
+ attr_reader :precision
11
+
12
+ def initialize(id, name, min_length, max_length, precision, description = nil, parent = nil)
13
+ super(id, name, min_length, max_length, description, parent)
14
+
15
+ if precision > max_length
16
+ raise Exceptions::InvalidSchemaError,
17
+ "precision cannot be greater than max_length"
18
+ end
19
+
20
+ @precision = precision
21
+ end
22
+
23
+ # @return [Nn]
24
+ def copy(changes = {})
25
+ Nn.new \
26
+ changes.fetch(:id, @id),
27
+ changes.fetch(:name, @name),
28
+ changes.fetch(:min_length, @min_length),
29
+ changes.fetch(:max_length, @max_length),
30
+ changes.fetch(:precision, @precision),
31
+ changes.fetch(:description, @description),
32
+ changes.fetch(:parent, @parent)
33
+ end
34
+
35
+ def companion
36
+ FixnumVal
37
+ end
38
+ end
39
+
40
+ #
41
+ # @see X222.pdf B.1.1.3.1.1 Numeric
42
+ #
43
+ class FixnumVal < Values::SimpleElementVal
44
+ def numeric?
45
+ true
46
+ end
47
+
48
+ def too_long?
49
+ false
50
+ end
51
+
52
+ def too_short?
53
+ false
54
+ end
55
+
56
+ class Invalid < FixnumVal
57
+ # @return [Object]
58
+ attr_reader :value
59
+
60
+ def initialize(value, usage, position)
61
+ @value = value
62
+ super(usage, position)
63
+ end
64
+
65
+ def valid?
66
+ false
67
+ end
68
+
69
+ def empty?
70
+ false
71
+ end
72
+
73
+ # @return [FixnumVal]
74
+ def map
75
+ self
76
+ end
77
+
78
+ # @return [String]
79
+ # :nocov:
80
+ def inspect
81
+ id = definition.bind do |d|
82
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
83
+ if usage.forbidden?
84
+ ansi.forbidden(s)
85
+ elsif usage.required?
86
+ ansi.required(s)
87
+ else
88
+ ansi.optional(s)
89
+ end
90
+ end
91
+ end
92
+
93
+ ansi.element("Nn.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
94
+ end
95
+ # :nocov:
96
+
97
+ # @return [String]
98
+ def to_s
99
+ ""
100
+ end
101
+
102
+ # @return [String]
103
+ def to_x12(truncate = true)
104
+ ""
105
+ end
106
+
107
+ # @return [Boolean]
108
+ def ==(other)
109
+ eql?(other)
110
+ end
111
+
112
+ # @return [Invalid]
113
+ def copy(changes = {})
114
+ self
115
+ end
116
+ end
117
+
118
+ class Valid < FixnumVal
119
+ def valid?
120
+ true
121
+ end
122
+
123
+ # @return [FixnumVal]
124
+ def map
125
+ FixnumVal.value(yield(value), usage, position)
126
+ end
127
+
128
+ # @return [Empty]
129
+ def copy(changes = {})
130
+ FixnumVal.value \
131
+ changes.fetch(:value, value),
132
+ changes.fetch(:usage, usage),
133
+ changes.fetch(:position, position)
134
+ end
135
+
136
+ def coerce(other)
137
+ return FixnumVal.value(other, usage, position), self
138
+ end
139
+
140
+ def ==(other)
141
+ other = FixnumVal.value(other, usage, position)
142
+ other.valid? and other.value == value
143
+ end
144
+ end
145
+
146
+ #
147
+ # Empty numeric value. Shouldn't be directly instantiated -- instead
148
+ # use the {FixnumVal.value} and {FixnumVal.empty} constructors.
149
+ #
150
+ class Empty < Valid
151
+ def value
152
+ nil
153
+ end
154
+
155
+ def empty?
156
+ true
157
+ end
158
+
159
+ # @return [String]
160
+ # :nocov:
161
+ def inspect
162
+ id = definition.bind do |d|
163
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
164
+ if usage.forbidden?
165
+ ansi.forbidden(s)
166
+ elsif usage.required?
167
+ ansi.required(s)
168
+ else
169
+ ansi.optional(s)
170
+ end
171
+ end
172
+ end
173
+
174
+ ansi.element("Nn.empty#{id}")
175
+ end
176
+ # :nocov:
177
+
178
+ # @return [String]
179
+ def to_s
180
+ ""
181
+ end
182
+
183
+ # @return [String]
184
+ def to_x12(truncate = true)
185
+ ""
186
+ end
187
+ end
188
+
189
+ #
190
+ # Non-empty numeric value. Shouldn't be directly instantiated --
191
+ # instead, use the {FixnumVal.value} constructors.
192
+ #
193
+ class NonEmpty < Valid
194
+ # @group Mathematical Operators
195
+ #################################################################
196
+
197
+ extend Operators::Binary
198
+ binary_operators :+, :-, :*, :/, :%, :coerce => :to_d
199
+
200
+ extend Operators::Unary
201
+ unary_operators :abs, :-@, :+@
202
+
203
+ extend Operators::Relational
204
+ relational_operators :<, :>, :<=, :>=, :<=>, :coerce => :to_d
205
+
206
+ # @endgroup
207
+ #################################################################
208
+
209
+ # @return [BigDecimal]
210
+ attr_reader :value
211
+
212
+ def_delegators :value, :to_i, :to_d, :to_f, :to_r, :to_c
213
+
214
+ def initialize(value, usage, position)
215
+ @value = value
216
+ super(usage, position)
217
+ end
218
+
219
+ def empty?
220
+ false
221
+ end
222
+
223
+ def too_long?
224
+ nn = (@value * (10 ** definition.precision)).to_i
225
+
226
+ # The length of a numeric type does not include an optional sign
227
+ definition.max_length < nn.abs.to_s.length
228
+ end
229
+
230
+ # @return [String]
231
+ # :nocov:
232
+ def inspect
233
+ id = definition.bind do |d|
234
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
235
+ if usage.forbidden?
236
+ ansi.forbidden(s)
237
+ elsif usage.required?
238
+ ansi.required(s)
239
+ else
240
+ ansi.optional(s)
241
+ end
242
+ end
243
+ end
244
+
245
+ ansi.element("Nn.value#{id}") + "(#{@value.to_s("F").gsub(/\.0+$/, "")})"
246
+ end
247
+ # :nocov:
248
+
249
+ # @return [String]
250
+ def to_s
251
+ # The number of fractional digits is implied by usage.precision
252
+ @value.to_s("F").gsub(/\.0+$/, "")
253
+ end
254
+
255
+ # @return [String]
256
+ def to_x12(truncate = true)
257
+ nn = (@value * (10 ** definition.precision)).to_i
258
+ sign = (nn < 0) ? "-" : ""
259
+
260
+ # Leading zeros must be suppressed unless necessary to satisfy a
261
+ # minimum length requirement
262
+ if truncate
263
+ sign = sign + nn.abs.to_s.
264
+ take(definition.max_length).
265
+ rjust(definition.min_length, "0")
266
+ else
267
+ sign = sign + nn.abs.to_s.
268
+ rjust(definition.min_length, "0")
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ class << FixnumVal
275
+ # @group Constructors
276
+ ###################################################################
277
+
278
+ # @return [FixnumVal]
279
+ def empty(usage, position)
280
+ self::Empty.new(usage, position)
281
+ end
282
+
283
+ # @return [FixnumVal]
284
+ def value(object, usage, position)
285
+ if object.is_a?(FixnumVal)
286
+ object#.copy(:usage => usage, :position => position)
287
+ elsif object.blank?
288
+ self::Empty.new(usage, position)
289
+ elsif object.is_a?(String)
290
+ # The number of fractional digits is implied by usage.precision
291
+ factor = 10 ** usage.definition.precision
292
+ self::NonEmpty.new(object.to_d / factor, usage, position)
293
+ else
294
+ self::NonEmpty.new(object.to_d, usage, position)
295
+ end
296
+ rescue ArgumentError
297
+ self::Invalid.new(object, usage, position)
298
+ end
299
+
300
+ # @endgroup
301
+ ###################################################################
302
+ end
303
+
304
+ # Prevent direct instantiation of abstract class FixnumVal
305
+ FixnumVal.eigenclass.send(:protected, :new)
306
+ FixnumVal::Empty.eigenclass.send(:public, :new)
307
+ FixnumVal::Invalid.eigenclass.send(:public, :new)
308
+ FixnumVal::NonEmpty.eigenclass.send(:public, :new)
309
+ end
310
+ end
311
+ end
312
+ end