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,128 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Versions
6
+ module Common
7
+ module ElementTypes
8
+ module Operators
9
+ module Unary
10
+ def unary_operators(*ops)
11
+ file, line, = Stupidedi.caller
12
+
13
+ ops.each do |op|
14
+ class_eval(<<-RUBY, file, line.to_i - 1)
15
+ def #{op}(&block)
16
+ copy(:value => value.#{op}(&block))
17
+ end
18
+ RUBY
19
+ end
20
+ end
21
+ end
22
+
23
+ module Binary
24
+ def binary_operators(*ops)
25
+ file, line, = Stupidedi.caller
26
+
27
+ if ops.last.is_a?(Hash)
28
+ options = ops.pop
29
+
30
+ case options[:coerce]
31
+ when String, Symbol
32
+ coerce = options[:coerce]
33
+ else
34
+ raise ArgumentError,
35
+ "must pass :coerce => :method"
36
+ end
37
+ else
38
+ raise ArgumentError,
39
+ "must pass :coerce => :method"
40
+ end
41
+
42
+ # Note that we can't test respond_to?(coerce) because coerce is
43
+ # often a refinement method, like #to_d, #to_time, etc. Currently
44
+ # respond_to? returns false on refinment methods, so we just call
45
+ # the method and assume a NoMethodError is due to coerce (hopefully
46
+ # not some other missing method)
47
+ ops.each do |op|
48
+ class_eval(<<-RUBY, file, line.to_i - 1)
49
+ def #{op}(other, &block)
50
+ begin
51
+ copy(:value => value.#{op}(other.#{coerce}, &block))
52
+ rescue NoMethodError
53
+ begin
54
+ me, he = other.coerce(self)
55
+ copy(:value => me.#{op}(he, &block).#{coerce})
56
+ rescue NoMethodError
57
+ raise TypeError,
58
+ "cannot coerce \#{other.class} to \#{self.class}"
59
+ end
60
+ end
61
+ end
62
+ RUBY
63
+ end
64
+ end
65
+ end
66
+
67
+ module Relational
68
+ def relational_operators(*ops)
69
+ file, line, = Stupidedi.caller
70
+
71
+ if ops.last.is_a?(Hash)
72
+ options = ops.pop
73
+
74
+ case options[:coerce]
75
+ when String, Symbol
76
+ coerce = options[:coerce]
77
+ else
78
+ raise ArgumentError,
79
+ "must pass :coerce => :method"
80
+ end
81
+ else
82
+ raise ArgumentError,
83
+ "must pass :coerce => :method"
84
+ end
85
+
86
+ # Note that we can't test respond_to?(coerce) because coerce is
87
+ # often a refinement method, like #to_d, #to_time, etc. Currently
88
+ # respond_to? returns false on refinment methods, so we just call
89
+ # the method and assume a NoMethodError is due to coerce (hopefully
90
+ # not some other missing method)
91
+ ops.each do |op|
92
+ class_eval(<<-RUBY, file, line.to_i - 1)
93
+ def #{op}(other, &block)
94
+ begin
95
+ value.#{op}(other.#{coerce}, &block)
96
+ rescue NoMethodError
97
+ begin
98
+ me, he = other.coerce(self)
99
+ me.#{op}(he, &block)
100
+ rescue NoMethodError
101
+ raise TypeError,
102
+ "cannot coerce \#{other.class} to \#{self.class}"
103
+ end
104
+ end
105
+ end
106
+ RUBY
107
+ end
108
+ end
109
+ end
110
+
111
+ module Wrappers
112
+ def wrappers(*ops)
113
+ file, line, = Stupidedi.caller
114
+
115
+ ops.each do |op|
116
+ class_eval(<<-RUBY, file, line.to_i - 1)
117
+ def #{op}(*args, &block)
118
+ copy(:value => value.#{op}(*args, &block))
119
+ end
120
+ RUBY
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,342 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Versions
6
+ module Common
7
+ module ElementTypes
8
+ class R < SimpleElementDef
9
+ # @return [Integer]
10
+ attr_reader :max_precision
11
+
12
+ def initialize(id, name, min_length, max_length, max_precision = nil, description = nil, parent = nil)
13
+ super(id, name, min_length, max_length, description, parent)
14
+
15
+ if max_precision.try(:>, max_length)
16
+ raise Exceptions::InvalidSchemaError,
17
+ "max_precision cannot be greater than max_length"
18
+ end
19
+
20
+ @max_precision = max_precision
21
+ end
22
+
23
+ # @return [R]
24
+ def copy(changes = {})
25
+ R.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(:max_precision, @max_precision),
31
+ changes.fetch(:description, @description),
32
+ changes.fetch(:parent, @parent)
33
+ end
34
+
35
+ def companion
36
+ FloatVal
37
+ end
38
+ end
39
+
40
+ #
41
+ # @see X222.pdf B.1.1.3.1.2 Decimal
42
+ #
43
+ class FloatVal < 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 < FloatVal
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 [FloatVal]
74
+ def map
75
+ self
76
+ end
77
+
78
+ # @return [String]
79
+ # :nocov:
80
+ def inspect
81
+ id = definition.try 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(" R.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 < FloatVal
119
+ def valid?
120
+ true
121
+ end
122
+
123
+ def coerce(other)
124
+ return FloatVal.value(other, usage, position), self
125
+ end
126
+
127
+ # @return [Empty]
128
+ def copy(changes = {})
129
+ FloatVal.value \
130
+ changes.fetch(:value, value),
131
+ changes.fetch(:usage, usage),
132
+ changes.fetch(:position, position)
133
+ end
134
+
135
+ # @return [FloatVal]
136
+ def map
137
+ FloatVal.value(yield(value), usage, position)
138
+ end
139
+
140
+ # @return [Boolean]
141
+ def ==(other)
142
+ other = FloatVal.value(other, usage, position)
143
+ other.valid? and other.value == value
144
+ end
145
+ end
146
+
147
+ class Empty < Valid
148
+ def value
149
+ nil
150
+ end
151
+
152
+ def empty?
153
+ true
154
+ end
155
+
156
+ # @return [String]
157
+ # :nocov:
158
+ def inspect
159
+ id = definition.try do |d|
160
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
161
+ if usage.forbidden?
162
+ ansi.forbidden(s)
163
+ elsif usage.required?
164
+ ansi.required(s)
165
+ else
166
+ ansi.optional(s)
167
+ end
168
+ end
169
+ end
170
+
171
+ ansi.element(" R.empty#{id}")
172
+ end
173
+ # :nocov:
174
+
175
+ # @return [String]
176
+ def to_s
177
+ ""
178
+ end
179
+
180
+ # @return [String]
181
+ def to_x12(truncate = true)
182
+ ""
183
+ end
184
+ end
185
+
186
+ class NonEmpty < Valid
187
+ # @group Mathematical Operators
188
+ #################################################################
189
+
190
+ extend Operators::Binary
191
+ binary_operators :+, :-, :*, :/, :%, :coerce => :to_d
192
+
193
+ extend Operators::Unary
194
+ unary_operators :abs, :-@, :+@
195
+
196
+ extend Operators::Relational
197
+ relational_operators :<, :>, :<=, :>=, :<=>, :coerce => :to_d
198
+
199
+ # @endgroup
200
+ #################################################################
201
+
202
+ # @return [BigDecimal]
203
+ attr_reader :value
204
+
205
+ def_delegators :value, :to_i, :to_d, :to_f, :to_r, :to_c
206
+
207
+ def initialize(value, usage, position)
208
+ @value = value
209
+ super(usage, position)
210
+ end
211
+
212
+ def empty?
213
+ false
214
+ end
215
+
216
+ # @return [String]
217
+ # :nocov:
218
+ def inspect
219
+ id = definition.try do |d|
220
+ "[#{"% 5s" % d.id}: #{d.name}]".bind do |s|
221
+ if usage.forbidden?
222
+ ansi.forbidden(s)
223
+ elsif usage.required?
224
+ ansi.required(s)
225
+ else
226
+ ansi.optional(s)
227
+ end
228
+ end
229
+ end
230
+
231
+ ansi.element(" R.value#{id}") + "(#{to_s})"
232
+ end
233
+ # :nocov:
234
+
235
+ # @return [String]
236
+ def to_s
237
+ if definition.max_precision.present?
238
+ @value.round(definition.max_precision).to_s("F")
239
+ else
240
+ @value.to_s("F")
241
+ end
242
+ end
243
+
244
+ # While the ASC X12 standard supports the usage of exponential
245
+ # notation, the HIPAA guides prohibit it. In the interest of
246
+ # simplicity, this method will not output exponential notation,
247
+ # as there is currently no configuration attribute to indicate
248
+ # if this is allowed or not -- if this is required in the future,
249
+ # the best place for it to fit would be in SimpleElementUse
250
+ #
251
+ # @return [String]
252
+ def to_x12(truncate = true)
253
+ remaining =
254
+ if @value.to_i.zero?
255
+ definition.max_length
256
+ else
257
+ definition.max_length - @value.to_i.abs.to_s.length
258
+ end
259
+
260
+ # The integer part consumes all the space, so there is no room
261
+ # for a fractional amount
262
+ if remaining <= 0 and truncate
263
+ int = @value.to_i
264
+ sign = (int < 0) ? "-" : ""
265
+ return sign + int.abs.to_s.take(definition.max_length)
266
+ end
267
+
268
+ # Don't exceed the definition's max_precision
269
+ precision =
270
+ if definition.max_precision.present?
271
+ (definition.max_precision < remaining) ?
272
+ definition.max_precision : remaining
273
+ else
274
+ remaining
275
+ end
276
+
277
+ rounded = @value.round(precision)
278
+ sign = (rounded < 0) ? "-" : ""
279
+
280
+ # Leading zeros preceeding the decimal point and trailing zeros
281
+ # following the decimal point must be supressed unless necessary
282
+ # to satisfy a minimum length requirement or to indicate
283
+ # precision, respectively.
284
+ if rounded.zero?
285
+ "0" * definition.min_length
286
+ else
287
+ base = rounded.abs
288
+ base = base.is_a?(BigDecimal) ? base : BigDecimal(base)
289
+ sign + base.to_s("F").
290
+ gsub(/^0+/, ""). # leading zeros
291
+ gsub(/0+$/, ""). # trailing zeros
292
+ gsub(/\.$/, ""). # trailing decimal point
293
+ rjust(definition.min_length, "0")
294
+ end
295
+ end
296
+
297
+ def too_long?
298
+ # We can truncate the fractional portion as much as needed, so
299
+ # the only concern we have about length is regarding the digits
300
+ # to the left of the decimal place.
301
+
302
+ # The length of a decimal type does not include an optional sign
303
+ definition.max_length < @value.to_i.abs.to_s.length
304
+ end
305
+ end
306
+ end
307
+
308
+ class << FloatVal
309
+ # @group Constructors
310
+ ###################################################################
311
+
312
+ # @return [FloatVal]
313
+ def empty(usage, position)
314
+ self::Empty.new(usage, position)
315
+ end
316
+
317
+ # @return [FloatVal]
318
+ def value(object, usage, position)
319
+ if object.is_a?(FloatVal)
320
+ object#.copy(:usage => usage, :position => position)
321
+ elsif object.blank?
322
+ self::Empty.new(usage, position)
323
+ else
324
+ self::NonEmpty.new(object.to_d, usage, position)
325
+ end
326
+ rescue ArgumentError
327
+ self::Invalid.new(object, usage, position)
328
+ end
329
+
330
+ # @endgroup
331
+ ###################################################################
332
+ end
333
+
334
+ # Prevent direct instantiation of abstract class FloatVal
335
+ FloatVal.eigenclass.send(:protected, :new)
336
+ FloatVal::Empty.eigenclass.send(:public, :new)
337
+ FloatVal::Invalid.eigenclass.send(:public, :new)
338
+ FloatVal::NonEmpty.eigenclass.send(:public, :new)
339
+ end
340
+ end
341
+ end
342
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Versions
6
+ module Common
7
+ module ElementTypes
8
+ class SimpleElementDef < Schema::SimpleElementDef
9
+ # @return [Symbol]
10
+ attr_reader :id
11
+
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ # @return [String]
16
+ attr_reader :description
17
+
18
+ # @return [Integer]
19
+ attr_reader :min_length
20
+
21
+ # @return [Integer]
22
+ attr_reader :max_length
23
+
24
+ # @return [Schema::SegmentDef, Schema::CompositeElementDef]
25
+ attr_reader :parent
26
+
27
+ # @return [Class<Values::SimpleElementVal>]
28
+ abstract :companion
29
+
30
+ def initialize(id, name, min_length, max_length, description = nil, parent = nil)
31
+ @id, @name, @min_length, @max_length, @description, @parent =
32
+ id, name, min_length, max_length, description, parent
33
+
34
+ if min_length < 1
35
+ raise Exceptions::InvalidSchemaError,
36
+ "min_length must be positive"
37
+ end
38
+
39
+ if min_length > max_length
40
+ raise Exceptions::InvalidSchemaError,
41
+ "min_length cannot be greater than max_length"
42
+ end
43
+ end
44
+
45
+ # @return [SimpleElementDef]
46
+ def copy(changes = {})
47
+ self.class.new \
48
+ changes.fetch(:id, @id),
49
+ changes.fetch(:name, @name),
50
+ changes.fetch(:min_length, @min_length),
51
+ changes.fetch(:max_length, @max_length),
52
+ changes.fetch(:description, @description),
53
+ changes.fetch(:parent, @parent)
54
+ end
55
+
56
+ # Constructs a SimpleElementVal from the given `value`
57
+ #
58
+ # @return [Values::SimpleElementVal]
59
+ def value(object, usage, position)
60
+ companion.value(object, usage, position)
61
+ end
62
+
63
+ # Constructs an empty SimpleElementVal
64
+ #
65
+ # @return [Values::SimpleElementVal]
66
+ def empty(usage, position)
67
+ companion.empty(usage, position)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end