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
data/lib/ruby/array.rb ADDED
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Array do
5
+ def blank?
6
+ empty?
7
+ end
8
+
9
+ def present?
10
+ not empty?
11
+ end
12
+
13
+ # Return the first item. Raises an `IndexError` if the Array is `empty?`.
14
+ #
15
+ # @example
16
+ # [1, 2, 3].head #=> 1
17
+ #
18
+ def head
19
+ raise IndexError, "head of empty array" if empty?
20
+ x, = self
21
+ x
22
+ end
23
+
24
+ # True if `#at` is defined for the given `n`
25
+ #
26
+ # @example
27
+ # [1, 2, 3].defined_at?(0) #=> true
28
+ # [].defined_at?(0) #=> false
29
+ #
30
+ def defined_at?(n)
31
+ n < length and -n <= length
32
+ end
33
+
34
+ # @group Selection
35
+ #############################################################################
36
+
37
+ # Selects all elements except the first.
38
+ #
39
+ # @example
40
+ # [1, 2, 3].tail #=> [2, 3]
41
+ # [1].tail #=> []
42
+ # [].tail #=> []
43
+ #
44
+ # @return [Array]
45
+ def tail
46
+ _, *xs = self
47
+ xs
48
+ end
49
+
50
+ # Selects all elements except the last `n` ones.
51
+ #
52
+ # @example
53
+ # [1, 2, 3].init #=> [1, 2]
54
+ # [1, 2, 3].init(2) #=> [1]
55
+ # [].tail #=> []
56
+ #
57
+ # @return [Array]
58
+ def init(n = 1)
59
+ raise ArgumentError, "n cannot be negative" if n < 0
60
+ slice(0..-(n + 1)) or []
61
+ end
62
+
63
+ # Select all elements except the first `n` ones.
64
+ #
65
+ # @example
66
+ # [1, 2, 3].drop(1) #=> [2, 3]
67
+ # [1, 3, 3].drop(2) #=> [3]
68
+ # [].drop(10) #=> []
69
+ #
70
+ # @return [Array]
71
+ def drop(n)
72
+ raise ArgumentError, "n cannot be negative" if n < 0
73
+ slice(n..-1) or []
74
+ end
75
+
76
+ # Select the first `n` elements.
77
+ #
78
+ # @example
79
+ # [1, 2, 3].take(2) #=> [1, 2]
80
+ # [1, 2, 3].take(0) #=> []
81
+ #
82
+ # @return [Array]
83
+ def take(n)
84
+ raise ArgumentError, "n cannot be negative" if n < 0
85
+ slice(0, n) or []
86
+ end
87
+
88
+ # Split the array in two at the given position.
89
+ #
90
+ # @example
91
+ # [1, 2, 3].split_at(2) #=> [[1,2], [3]]
92
+ # [1, 2, 3].split_at(0) #=> [[], [1,2,3]]
93
+ #
94
+ # @return [(Array, Array)]
95
+ def split_at(n)
96
+ n = length + n if n < 0
97
+ return take(n), drop(n)
98
+ end
99
+
100
+ # @endgroup
101
+ #############################################################################
102
+
103
+ # @group Filtering
104
+ #############################################################################
105
+
106
+ # Drops the longest prefix of elements that satisfy the predicate.
107
+ #
108
+ # @return [Array]
109
+ def drop_while(&block)
110
+ # This is in tail call form
111
+ if not empty? and yield(head)
112
+ tail.drop_while(&block)
113
+ else
114
+ self
115
+ end
116
+ end
117
+
118
+ # Drops the longest prefix of elements that do not satisfy the predicate.
119
+ #
120
+ # @return [Array]
121
+ def drop_until(&block)
122
+ # This is in tail call form
123
+ unless empty? or yield(head)
124
+ tail.drop_until(&block)
125
+ else
126
+ self
127
+ end
128
+ end
129
+
130
+ # Takes the longest prefix of elements that satisfy the predicate.
131
+ #
132
+ # @return [Array]
133
+ def take_while(accumulator = [], &block)
134
+ # This is in tail call form
135
+ if not empty? and yield(head)
136
+ tail.take_while(head.snoc(accumulator), &block)
137
+ else
138
+ accumulator
139
+ end
140
+ end
141
+
142
+ # Takes the longest prefix of elements that do not satisfy the predicate.
143
+ #
144
+ # @return [Array]
145
+ def take_until(accumulator = [], &block)
146
+ # This is in tail call form
147
+ unless empty? or yield(head)
148
+ tail.take_until(head.snoc(accumulator), &block)
149
+ else
150
+ accumulator
151
+ end
152
+ end
153
+
154
+ # Splits the array into prefix/suffix pair according to the predicate.
155
+ #
156
+ # @return [(Array, Array)]
157
+ def split_until(&block)
158
+ prefix = take_while(&block)
159
+ suffix = drop(prefix.length)
160
+ return prefix, suffix
161
+ end
162
+
163
+ # Splits the array into prefix/suffix pair according to the predicate.
164
+ #
165
+ # @return [(Array, Array)]
166
+ def split_when(&block)
167
+ prefix = take_until(&block)
168
+ suffix = drop(prefix.length)
169
+ return prefix, suffix
170
+ end
171
+
172
+ # Returns a list of sublists, where each sublist contains only equal
173
+ # elements. Equality is determined by a two-argument block parameter.
174
+ # The concatenation of the result is equal to the original argument.
175
+ #
176
+ # @example
177
+ # "abba".split(//).group_seq(&:==) #=> [["y"], ["a"], ["b", "b"], ["a"]]
178
+ #
179
+ # @return [[Array]]
180
+ def runs(&block)
181
+ unless empty?
182
+ as, bs = tail.split_until{|x| block.call(head, x) }
183
+ head.cons(as).cons(bs.runs(&block))
184
+ else
185
+ []
186
+ end
187
+ end
188
+
189
+ # @endgroup
190
+ #############################################################################
191
+
192
+ # Accumulate elements using the `+` method, optionally
193
+ # transforming them first using a block
194
+ #
195
+ # @example
196
+ # ["a", "b", "cd"].sum #=> "abcd"
197
+ # ["a", "b", "cd"].sum(&:length) #=> 4
198
+ #
199
+ def sum(&block)
200
+ if block_given?
201
+ tail.inject(yield(head)){|sum,e| sum + yield(e) }
202
+ else
203
+ tail.inject(head){|sum,e| sum + e }
204
+ end
205
+ end
206
+
207
+ # Count the number of elements that satisfy the predicate
208
+ #
209
+ # @example
210
+ # ["abc", "de", "fg", "hi"].count{|s| s.length == 2 } #=> 3
211
+ # ["a", "b", "a", "c", "a"].count("a") #=> 3
212
+ # [1, 3, 5, 9, 0].count #=> 5
213
+ #
214
+ # @return [Integer]
215
+ def count(*args)
216
+ if block_given?
217
+ inject(0){|n, e| yield(e) ? n + 1 : n }
218
+ elsif args.empty?
219
+ size
220
+ else
221
+ inject(0){|n, e| e == args.first ? n + 1 : n }
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
data/lib/ruby/blank.rb ADDED
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine String do
5
+ # True if the string is `empty?` or contains all whitespace
6
+ #
7
+ # @example
8
+ # "abc".blank? #=> false
9
+ # " ".blank? #=> true
10
+ # "".blank? #=> true
11
+ #
12
+ def blank?
13
+ self !~ /\S/
14
+ end
15
+
16
+ def present?
17
+ self =~ /\S/
18
+ end
19
+ end
20
+
21
+ refine NilClass do
22
+ # Always `true`. Note this overrides {Object#blank?} which returns false.
23
+ #
24
+ # @example
25
+ # nil.blank? #=> true
26
+ #
27
+ def blank?
28
+ true
29
+ end
30
+
31
+ def present?
32
+ false
33
+ end
34
+ end
35
+
36
+ refine Object do
37
+ # Always `false`. Note that {NilClass#blank?} is overridden to return `true`
38
+ #
39
+ # @example
40
+ # false.blank? #=> false
41
+ # 100.blank? #=> false
42
+ #
43
+ def blank?
44
+ false
45
+ end
46
+
47
+ def present?
48
+ true
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Exception do
5
+ def print(name: nil, io: $stderr)
6
+ ansi = Stupidedi::Color.ansi
7
+ io.puts "warning: #{ansi.red("#{self.class} #{message}")}"
8
+ io.puts " module: #{name}" unless name.nil?
9
+ io.puts backtrace.map{|x| " " + x}.join("\n")
10
+ io.puts
11
+ end
12
+ end
13
+ end
14
+ end
data/lib/ruby/hash.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Hash do
5
+ def defined_at?(x)
6
+ include?(x)
7
+ end
8
+
9
+ def at(x)
10
+ self[x]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Module do
5
+ # Creates an abstract method
6
+ #
7
+ # @example
8
+ # class Collection
9
+ # abstract :size
10
+ # abstract :add, :args => %w(item)
11
+ # end
12
+ #
13
+ # @return [void]
14
+ def abstract(name, *params)
15
+ if params.last.is_a?(Hash)
16
+ # abstract :method, :args => %w(a b c)
17
+ params = params.last[:args]
18
+ end
19
+
20
+ file, line, = Stupidedi.caller
21
+
22
+ if params.empty?
23
+ class_eval(<<-RUBY, file, line.to_i - 1)
24
+ def #{name}(*args)
25
+ raise NoMethodError,
26
+ "method \#{self.class.name}.#{name} is abstract"
27
+ end
28
+ RUBY
29
+ else
30
+ class_eval(<<-RUBY, file, line.to_i - 1)
31
+ def #{name}(*args)
32
+ raise NoMethodError,
33
+ "method \#{self.class.name}.#{name}(#{params.join(", ")}) is abstract"
34
+ end
35
+ RUBY
36
+ end
37
+ end
38
+
39
+ def def_delegators(target, *methods)
40
+ file, line, = Stupidedi.caller
41
+
42
+ for m in methods
43
+ if m.to_s =~ /=$/
44
+ class_eval(<<-RUBY, file, line.to_i - 1)
45
+ def #{m}(value)
46
+ #{target}.#{m}(value)
47
+ end
48
+ RUBY
49
+ else
50
+ class_eval(<<-RUBY, file, line.to_i - 1)
51
+ def #{m}(*args, &block)
52
+ #{target}.#{m}(*args, &block)
53
+ end
54
+ RUBY
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Object do
5
+ # @group List Constructors
6
+ #############################################################################
7
+
8
+ # Prepend the item to the front of a new list
9
+ #
10
+ # @example
11
+ # 1.cons #=> [1]
12
+ # 1.cons(2.cons) #=> [1, 2]
13
+ # 1.cons([0, 0, 0]) #=> [1, 0, 0, 0]
14
+ #
15
+ # @return [Array]
16
+ def cons(array = [])
17
+ [self] + array
18
+ end
19
+
20
+ # Append the item to rear of a new list
21
+ #
22
+ # @example
23
+ # 1.snoc #=> [1]
24
+ # 1.snoc(2.snoc) #=> [2, 1]
25
+ # 1.snoc([0, 0, 0]) #=> [0, 0, 0, 1]
26
+ #
27
+ # @return [Array]
28
+ def snoc(array = [])
29
+ array + [self]
30
+ end
31
+
32
+ # @group Combinators
33
+ #############################################################################
34
+
35
+ # Yields `self` to a block argument
36
+ #
37
+ # @example
38
+ # nil.bind{|a| a.nil? } #=> true
39
+ # 100.bind{|a| a.nil? } #=> false
40
+ #
41
+ def bind
42
+ yield self
43
+ end
44
+
45
+ # @endgroup
46
+ #############################################################################
47
+
48
+ # Return the "eigenclass" where singleton methods reside
49
+ #
50
+ # @return [Class]
51
+ def eigenclass
52
+ class << self; self; end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine String do
5
+ # Return the one-character string at the given index
6
+ #
7
+ # @example
8
+ # "abc".at(0) #=> "a"
9
+ # "abc".at(2) #=> "c"
10
+ #
11
+ # @param [Integer] n zero-based index of the character to read
12
+ #
13
+ # @return [String]
14
+ def at(n)
15
+ raise ArgumentError, "n must be positive" if n < 0
16
+ self[n, 1] unless n >= length
17
+ end
18
+
19
+ # Return the string with `n` characters removed from the front
20
+ #
21
+ # @example
22
+ # "abc".drop(0) #=> "abc"
23
+ # "abc".drop(2) #=> "c"
24
+ #
25
+ # @param [Integer] n number of characters to drop (`n > 0`)
26
+ #
27
+ # @return [String]
28
+ def drop(n)
29
+ raise ArgumentError, "n must be positive" if n < 0
30
+ (length >= n) ? self[n..-1] : ""
31
+ end
32
+
33
+ # Return the first `n` characters from the front
34
+ #
35
+ # @example
36
+ # "abc".take(0) #=> ""
37
+ # "abc".take(2) #=> "ab"
38
+ #
39
+ # @param [Integer] n number of characters to select (`n > 0`)
40
+ #
41
+ # @return [String]
42
+ def take(n)
43
+ raise ArgumentError, "n must be positive" if n < 0
44
+ self[0, n]
45
+ end
46
+
47
+ # Split the string in two at the given position
48
+ #
49
+ # @example
50
+ # "abc".split_at(0) #=> ["", "abc"]
51
+ # "abc".split_at(2) #=> ["ab", "c"]
52
+ #
53
+ # @param [Integer] n number of characters at which to split (`n > 0`)
54
+ #
55
+ # @return [Array(String, String)]
56
+ def split_at(n)
57
+ [take(n), drop(n)]
58
+ end
59
+
60
+ # True if the string is long enough such that {#at} is defined for the
61
+ # given `n`
62
+ #
63
+ # @example
64
+ # "abc".defined_at?(0) #=> true
65
+ # "abc".defined_at?(3) #=> false
66
+ def defined_at?(n)
67
+ n < length
68
+ end
69
+
70
+ # To make String compatible with the {Stupidedi::Reader::Input} interface,
71
+ # we have to define `#position`... shameful!
72
+ def position
73
+ nil
74
+ end
75
+
76
+ # Join multi-line string into a single line, removing leading whitespace
77
+ # from the beginning of each line
78
+ #
79
+ # @example
80
+ # "this is a
81
+ # multiline string".join #=> "this is a multiline string"
82
+ #
83
+ # @return [String]
84
+ def join
85
+ gsub(/\n[ \t]+/, " ")
86
+ end
87
+ end
88
+ end
89
+ end
data/lib/ruby/to_d.rb ADDED
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ require "bigdecimal"
3
+ require "rational"
4
+
5
+ module Stupidedi
6
+ module Refinements
7
+ refine BigDecimal do
8
+ # @return [BigDecimal] self
9
+ def to_d
10
+ self
11
+ end
12
+ end
13
+
14
+ BIGDECIMAL = /\A[+-]? (?# optional leading sign )
15
+ (?:
16
+ (?:\d+\.?\d*) | (?# whole with optional decimal or ..)
17
+ (?:\d*?\.?\d+) ) (?# optional whole with decimal )
18
+ (?:E[+-]?\d+)? (?# optional exponent )
19
+ \Z/ix
20
+
21
+ refine String do
22
+ # Converts the string to a BigDecimal after validating the format. If the
23
+ # string does not match the pattern for a valid number, an `ArgumentError`
24
+ # is raised.
25
+ #
26
+ # @example
27
+ # "1.0".to_d #=> BigDecimal("1.0")
28
+ #
29
+ # @return [BigDecimal]
30
+ def to_d
31
+ if BIGDECIMAL =~ self
32
+ BigDecimal(to_s)
33
+ else
34
+ raise ArgumentError, "#{inspect} is not a valid number"
35
+ end
36
+ end
37
+ end
38
+
39
+ refine Integer do
40
+ # Converts the integer to a BigDecimal
41
+ #
42
+ # @example
43
+ # 10.to_d #=> BigDecimal("10")
44
+ #
45
+ # @return [BigDecimal]
46
+ def to_d
47
+ BigDecimal(to_s)
48
+ end
49
+ end
50
+
51
+ refine Rational do
52
+ # Converts the rational to a BigDecimal
53
+ #
54
+ # @example
55
+ # Rational(3, 4).to_d #=> BigDecimal("3") / BigDecimal("4")
56
+ #
57
+ # @return [BigDecimal]
58
+ def to_d
59
+ numerator.to_d / denominator.to_d
60
+ end
61
+ end
62
+
63
+ refine Float do
64
+ # Raises a `TypeError` exception. The reason this method is defined at
65
+ # all is to produce a more meaningful error than `NoSuchMethod`.
66
+ #
67
+ # @return [void]
68
+ def to_d
69
+ # The problem is there isn't a way to know the correct precision,
70
+ # since there are (many) values that cannot be represented exactly
71
+ # using Floats. For instance, we can't assume which value is correct
72
+ #
73
+ # "%0.10f" % 1.8 #=> "1.8000000000"
74
+ # "%0.20f" % 1.8 #=> "1.80000000000000004441"
75
+ #
76
+ # The programmer should convert the Float to a String using whatever
77
+ # precision he chooses, and call #to_d on the String.
78
+ raise TypeError, "cannot convert Float to BigDecimal"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Time do
5
+ def to_date
6
+ Date.civil(year, month, day)
7
+ end
8
+ end
9
+
10
+ refine String do
11
+ def to_date
12
+ Date.parse(self)
13
+ end
14
+ end
15
+
16
+ refine Date do
17
+ def to_date
18
+ self
19
+ end
20
+ end
21
+
22
+ class << Date
23
+ public :parse
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Time do
5
+ # @return [Time]
6
+ def to_time
7
+ self
8
+ end
9
+ end
10
+
11
+ class << Time
12
+ public :parse
13
+ end
14
+
15
+ refine String do
16
+ def to_time
17
+ Time.parse(self)
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/ruby/try.rb ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Refinements
4
+ refine Object do
5
+ # @group Combinators
6
+ #############################################################################
7
+
8
+ # Sends the arguments to `self` or yields `self` (when `self` is non-`nil`).
9
+ # This is overridden by {NilClass#try}, which always returns `nil`.
10
+ #
11
+ # @example
12
+ # "non-nil".try(&:length) #=> 7
13
+ # nil.try(&:length) #=> nil
14
+ #
15
+ # "non-nil".try(:slice, 0, 3) #=> "non"
16
+ # nil.try(:slice, 0, 3) #=> nil
17
+ #
18
+ def try(*args, &block)
19
+ if args.empty?
20
+ yield self
21
+ else
22
+ __send__(*args, &block)
23
+ end
24
+ end
25
+ end
26
+
27
+ refine NilClass do
28
+ # @group Combinators
29
+ #############################################################################
30
+
31
+ # Returns `nil` (when `self` is `nil`). This overrides {Object#try}
32
+ #
33
+ # @example
34
+ # "non-nil".try(&:length) #=> 7
35
+ # nil.try(&:length) #=> nil
36
+ #
37
+ # "non-nil".try(:slice, 0, 3) #=> "non"
38
+ # nil.try(:slice, 0, 3) #=> nil
39
+ #
40
+ # @return nil
41
+ def try(*args)
42
+ self
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,6 @@
1
+ module Stupidedi
2
+ warn "DEPRECATION WARNING: Stupidedi::Builder is depecated, use Stupidedi::Parser instead"
3
+
4
+ # @deprecated Use Stupidedi::Parser instead
5
+ Builder = Parser
6
+ end