xqsr3 0.8.3

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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +27 -0
  3. data/README.md +26 -0
  4. data/lib/xqsr3/command_line_utilities/map_option_string.rb +137 -0
  5. data/lib/xqsr3/containers/frequency_map.rb +473 -0
  6. data/lib/xqsr3/containers/multi_map.rb +383 -0
  7. data/lib/xqsr3/diagnostics/exception_utilities.rb +216 -0
  8. data/lib/xqsr3/doc_.rb +116 -0
  9. data/lib/xqsr3/extensions/enumerable.rb +4 -0
  10. data/lib/xqsr3/extensions/enumerable/collect_with_index.rb +71 -0
  11. data/lib/xqsr3/extensions/enumerable/unique.rb +102 -0
  12. data/lib/xqsr3/extensions/io.rb +3 -0
  13. data/lib/xqsr3/extensions/io/writelines.rb +66 -0
  14. data/lib/xqsr3/extensions/kernel.rb +3 -0
  15. data/lib/xqsr3/extensions/kernel/raise_with_options.rb +68 -0
  16. data/lib/xqsr3/extensions/string.rb +5 -0
  17. data/lib/xqsr3/extensions/string/ends_with.rb +8 -0
  18. data/lib/xqsr3/extensions/string/map_option_string.rb +8 -0
  19. data/lib/xqsr3/extensions/string/starts_with.rb +8 -0
  20. data/lib/xqsr3/extensions/string/to_symbol.rb +8 -0
  21. data/lib/xqsr3/extensions/test/unit.rb +5 -0
  22. data/lib/xqsr3/extensions/test/unit/assert_eql.rb +18 -0
  23. data/lib/xqsr3/extensions/test/unit/assert_not.rb +18 -0
  24. data/lib/xqsr3/extensions/test/unit/assert_not_eql.rb +18 -0
  25. data/lib/xqsr3/io/writelines.rb +192 -0
  26. data/lib/xqsr3/quality/parameter_checking.rb +343 -0
  27. data/lib/xqsr3/string_utilities/ends_with.rb +134 -0
  28. data/lib/xqsr3/string_utilities/starts_with.rb +127 -0
  29. data/lib/xqsr3/string_utilities/to_symbol.rb +145 -0
  30. data/lib/xqsr3/version.rb +68 -0
  31. data/test/unit/command_line_utilities/tc_map_option_string.rb +39 -0
  32. data/test/unit/command_line_utilities/ts_all.rb +13 -0
  33. data/test/unit/containers/tc_frequency_map.rb +738 -0
  34. data/test/unit/containers/tc_multi_map.rb +640 -0
  35. data/test/unit/containers/ts_all.rb +13 -0
  36. data/test/unit/diagnostics/tc_exception_utilities.rb +221 -0
  37. data/test/unit/diagnostics/ts_all.rb +13 -0
  38. data/test/unit/extensions/enumerable/tc_collect_with_index.rb +36 -0
  39. data/test/unit/extensions/enumerable/tc_unique.rb +47 -0
  40. data/test/unit/extensions/enumerable/ts_all.rb +13 -0
  41. data/test/unit/extensions/io/tc_writelines.rb +110 -0
  42. data/test/unit/extensions/io/ts_all.rb +13 -0
  43. data/test/unit/extensions/kernel/tc_raise_with_options.rb +239 -0
  44. data/test/unit/extensions/kernel/ts_all.rb +13 -0
  45. data/test/unit/extensions/string/tc_ends_with.rb +70 -0
  46. data/test/unit/extensions/string/tc_map_option_string.rb +37 -0
  47. data/test/unit/extensions/string/tc_starts_with.rb +70 -0
  48. data/test/unit/extensions/string/tc_to_symbol.rb +51 -0
  49. data/test/unit/extensions/string/ts_all.rb +13 -0
  50. data/test/unit/extensions/ts_all.rb +13 -0
  51. data/test/unit/io/tc_writelines.rb +200 -0
  52. data/test/unit/io/ts_all.rb +13 -0
  53. data/test/unit/quality/tc_parameter_checking.rb +181 -0
  54. data/test/unit/quality/ts_all.rb +13 -0
  55. data/test/unit/tc_version.rb +37 -0
  56. data/test/unit/ts_all.rb +13 -0
  57. metadata +101 -0
@@ -0,0 +1,383 @@
1
+
2
+ # ######################################################################## #
3
+ # File: lib/xqsr3/containers/multi_map.rb
4
+ #
5
+ # Purpose: multimap container
6
+ #
7
+ # Created: 21st March 2007
8
+ # Updated: 10th June 2016
9
+ #
10
+ # Home: http://github.com/synesissoftware/xqsr3
11
+ #
12
+ # Author: Matthew Wilson
13
+ #
14
+ # Copyright (c) 2007-2016, Matthew Wilson and Synesis Software
15
+ # All rights reserved.
16
+ #
17
+ # Redistribution and use in source and binary forms, with or without
18
+ # modification, are permitted provided that the following conditions are
19
+ # met:
20
+ #
21
+ # * Redistributions of source code must retain the above copyright
22
+ # notice, this list of conditions and the following disclaimer.
23
+ #
24
+ # * Redistributions in binary form must reproduce the above copyright
25
+ # notice, this list of conditions and the following disclaimer in the
26
+ # documentation and/or other materials provided with the distribution.
27
+ #
28
+ # * Neither the names of the copyright holder nor the names of its
29
+ # contributors may be used to endorse or promote products derived from
30
+ # this software without specific prior written permission.
31
+ #
32
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
33
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
34
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
36
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
38
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
39
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+ #
44
+ # ######################################################################## #
45
+
46
+
47
+ =begin
48
+ =end
49
+
50
+ module Xqsr3
51
+ module Containers
52
+
53
+ class MultiMap < ::Hash
54
+
55
+ include Enumerable
56
+
57
+ def self.[] *args
58
+
59
+ return self.new if 0 == args.length
60
+
61
+ if 1 == args.length
62
+
63
+ arg = args[0]
64
+
65
+ case arg
66
+ when ::NilClass
67
+
68
+ return self.new
69
+ when ::Hash
70
+
71
+ fm = self.new
72
+
73
+ arg.each do |k, v|
74
+
75
+ raise ArgumentError, "mapped elements in hashes must be arrays, #{v.class} given" unless v.kind_of? ::Array
76
+
77
+ fm.store k, *v
78
+ end
79
+
80
+ return fm
81
+ when ::Array
82
+
83
+ # accepted forms:
84
+ #
85
+ # 1. Empty array
86
+ # 2. Array exclusively of arrays
87
+
88
+ # 1. Empty array
89
+
90
+ return self.new if arg.empty?
91
+
92
+ # 2. Array exclusively of arrays
93
+
94
+ if arg.all? { |el| ::Array === el }
95
+
96
+ h = Hash.new { |hash, key| hash[key] = [] }
97
+
98
+ arg.each do |ar|
99
+
100
+ raise ArgumentError, "cannot pass an empty array in array of arrays initialiser" if ar.empty?
101
+
102
+ key = ar.shift
103
+
104
+ ar.each { |value| h[key] << value }
105
+ end
106
+
107
+ return self.[](h)
108
+ end
109
+
110
+
111
+
112
+ raise ArgumentError, "array parameter not in an accepted form for subscript initialisation"
113
+ else
114
+
115
+ return self.[] arg.to_hash if arg.respond_to? :to_hash
116
+
117
+ raise TypeError, "given argument is neither a #{::Hash} nor an #{::Array} and does not respond to the to_hash method"
118
+ end
119
+
120
+ else
121
+
122
+ # treat all other argument permutations as having passed in an array
123
+
124
+ return self.[] [ *args ]
125
+ end
126
+ end
127
+
128
+ def initialize
129
+
130
+ @inner = Hash.new
131
+ end
132
+
133
+ def [] key
134
+
135
+ return @inner[key]
136
+ end
137
+
138
+ def []= key, values
139
+
140
+ values = [] if values.nil?
141
+
142
+ raise TypeError, "values must be an array, but #{values.class} given" unless values.kind_of? ::Array
143
+
144
+ store key, *values
145
+ end
146
+
147
+ def == rhs
148
+
149
+ case rhs
150
+ when ::NilClass
151
+ return false
152
+ when ::Hash
153
+ return rhs.size == @inner.size && rhs == @inner
154
+ when self.class
155
+ return rhs.size == self.size && rhs == @inner
156
+ else
157
+ raise TypeError, "can compare #{self.class} only to instances of #{self.class} and #{::Hash}, but #{rhs.class} given"
158
+ end
159
+
160
+ false
161
+ end
162
+
163
+ def assoc key
164
+
165
+ @inner.assoc key
166
+ end
167
+
168
+ def clear
169
+
170
+ @inner.clear
171
+ end
172
+
173
+ def count
174
+
175
+ @inner.each_value.map { |ar| ar.size}.inject(0, :+)
176
+ end
177
+
178
+ def delete key
179
+
180
+ @inner.delete key
181
+ end
182
+
183
+ def each *defaults
184
+
185
+ raise ArgumentError, "may only supply 0 or 1 defaults" if defaults.size > 1
186
+
187
+ @inner.each do |key, values|
188
+
189
+ if values.empty? && !defaults.empty?
190
+
191
+ yield key, defaults[0]
192
+
193
+ next
194
+ end
195
+
196
+ values.each { |value| yield key, value }
197
+ end
198
+ end
199
+
200
+ def each_key
201
+
202
+ @inner.each_key { |key| yield key }
203
+ end
204
+
205
+ def each_value
206
+
207
+ @inner.each do |key, values|
208
+
209
+ values.each { |value| yield value }
210
+ end
211
+ end
212
+
213
+ def each_with_index
214
+
215
+ index = 0
216
+ self.each do |key, value|
217
+
218
+ yield key, value, index
219
+
220
+ index += 1
221
+ end
222
+ end
223
+
224
+ def empty?
225
+
226
+ @inner.empty?
227
+ end
228
+
229
+ def eql? rhs
230
+
231
+ case rhs
232
+ when self.class
233
+ return self == rhs
234
+ else
235
+ return false
236
+ end
237
+ end
238
+
239
+ def fetch key, default = nil, &block
240
+
241
+ case default
242
+ when ::NilClass, ::Array
243
+ ;
244
+ else
245
+ raise TypeError, "default parameter ('#{default}') must be of type #{::Array}, but was of type #{default.class}"
246
+ end
247
+
248
+ unless @inner.has_key? key
249
+
250
+ return default unless default.nil?
251
+
252
+ if block_given?
253
+
254
+ r = nil
255
+
256
+ case block.arity
257
+ when 0
258
+ r = yield
259
+ when 1
260
+ r = yield key
261
+ else
262
+ raise ArgumentError, "given block must take a single parameter - #{block.arity} given"
263
+ end
264
+
265
+ case r
266
+ when ::Array
267
+ ;
268
+ else
269
+ raise ArgumentError, "given block must return a value of type #{::Array} or one convertible implicitly to such" unless r.respond_to? :to_ary
270
+
271
+ r = r.to_ary
272
+ end
273
+
274
+ return r
275
+ end
276
+
277
+ raise KeyError, "given key '#{key}' (#{key.class}) does not exist"
278
+ end
279
+
280
+ @inner.fetch key
281
+ end
282
+
283
+ def flatten
284
+
285
+ r = []
286
+
287
+ @inner.each do |key, values|
288
+
289
+ if values.empty?
290
+
291
+ r << key << []
292
+ else
293
+
294
+ values.each do |value|
295
+
296
+ r << key << value
297
+ end
298
+ end
299
+ end
300
+
301
+ r
302
+ end
303
+
304
+ def has_key? key
305
+
306
+ @inner.has_key? key
307
+ end
308
+
309
+ def has_value? value
310
+
311
+ @inner.has_value? value
312
+ end
313
+
314
+ def key value
315
+
316
+ @inner.key value
317
+ end
318
+
319
+ def merge fm
320
+
321
+ raise TypeError, "parameter must be an instance of type #{self.class}" unless fm.instance_of? self.class
322
+
323
+ fm_new = self.class.new
324
+
325
+ fm_new.merge! self
326
+ fm_new.merge! fm
327
+
328
+ fm_new
329
+ end
330
+
331
+ def merge! fm
332
+
333
+ fm.each do |k, v|
334
+
335
+ self.push k, v
336
+ end
337
+
338
+ self
339
+ end
340
+
341
+ def push key, *values
342
+
343
+ @inner[key] = [] unless @inner.has_key? key
344
+
345
+ @inner[key].push(*values)
346
+ end
347
+
348
+ def shift
349
+
350
+ @inner.shift
351
+ end
352
+
353
+ def size
354
+
355
+ @inner.size
356
+ end
357
+
358
+ def store key, *values
359
+
360
+ @inner[key] = values
361
+ end
362
+
363
+ def to_a
364
+
365
+ self.flatten
366
+ end
367
+
368
+ def to_h
369
+
370
+ @inner.dup
371
+ end
372
+
373
+ def values
374
+
375
+ @inner.values
376
+ end
377
+ end # class MultiMap
378
+
379
+ end # module Containers
380
+ end # module Xqsr3
381
+
382
+ # ############################## end of file ############################# #
383
+
@@ -0,0 +1,216 @@
1
+
2
+ # ######################################################################## #
3
+ # File: lib/xqsr3/diagnostics/exception_utilities.rb
4
+ #
5
+ # Purpose: Definition of the ExceptionUtilities module
6
+ #
7
+ # Created: 12th February 2015
8
+ # Updated: 10th June 2016
9
+ #
10
+ # Home: http://github.com/synesissoftware/xqsr3
11
+ #
12
+ # Author: Matthew Wilson
13
+ #
14
+ # Copyright (c) 2015-2016, Matthew Wilson and Synesis Software
15
+ # All rights reserved.
16
+ #
17
+ # Redistribution and use in source and binary forms, with or without
18
+ # modification, are permitted provided that the following conditions are
19
+ # met:
20
+ #
21
+ # * Redistributions of source code must retain the above copyright notice,
22
+ # this list of conditions and the following disclaimer.
23
+ #
24
+ # * Redistributions in binary form must reproduce the above copyright
25
+ # notice, this list of conditions and the following disclaimer in the
26
+ # documentation and/or other materials provided with the distribution.
27
+ #
28
+ # * Neither the names of the copyright holder nor the names of its
29
+ # contributors may be used to endorse or promote products derived from
30
+ # this software without specific prior written permission.
31
+ #
32
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
33
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
34
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
36
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
38
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
39
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+ #
44
+ # ######################################################################## #
45
+
46
+
47
+ =begin
48
+ =end
49
+
50
+ module Xqsr3
51
+ module Diagnostics
52
+
53
+ module ExceptionUtilities
54
+
55
+ # Raises an instance of a named exception that takes options in its
56
+ # constructor, as in:
57
+ #
58
+ # class ArgumentErrorWithOptions < ArgumentError
59
+ #
60
+ # def initialize(message = nil, **options)
61
+ #
62
+ # . . .
63
+ # end
64
+ #
65
+ # attr_reader :options
66
+ # end
67
+ #
68
+ # begin
69
+ #
70
+ # raise_with_options ArgumentErrorWithOptions, "message-1", opt1: :val1, opt2: 'val2'
71
+ # rescue => x
72
+ #
73
+ # $stderr.puts x.options # => {:opt1=>:val1, :opt2=>"val2"}
74
+ # end
75
+ #
76
+ # It can also be used with full compatibility with <tt>Kernel#raise</tt>, as in:
77
+ #
78
+ # begin
79
+ #
80
+ # raise_with_options ArgumentError, "message-2"
81
+ # rescue => x
82
+ #
83
+ # $stderr.puts x.class # => ArgumenError
84
+ # $stderr.puts x.message # => "message-2"
85
+ # end
86
+ #
87
+ # and:
88
+ #
89
+ # begin
90
+ #
91
+ # raise_with_options "message-3"
92
+ # rescue => x
93
+ #
94
+ # $stderr.puts x.class # => RuntimeError
95
+ # $stderr.puts x.message # => "message-3"
96
+ # end
97
+ #
98
+ # === Parameters
99
+ #
100
+ # * +args+:: 0 or more arguments
101
+ # * +options+:: An options hash
102
+ #
103
+ # === Parameter Interpretation
104
+ #
105
+ # If the first argument is a class, it is assumed to be the exception
106
+ # type that will be raised; if not, RuntimeError is raised as is normal
107
+ # with Kernel#raise. The remaining arguments are passed - via the
108
+ # <tt>*</tt> operator - to the class's constructor.
109
+ #
110
+ # All options passed to this method are respread - by the
111
+ # <tt>**</tt> operator - and passed to the underlying
112
+ # <tt>Kernel#raise</tt> call.
113
+ #
114
+ # === Exceptions
115
+ #
116
+ # - An instance of <tt>arg[0]</tt> if <tt>args[0].is_a?(::Class)</tt>; or
117
+ # - An instance of +RuntimeError+
118
+ def self.raise_with_options *args, **options
119
+
120
+ # special handling in case called indirectly
121
+
122
+ called_indirectly = options[:called_indirectly_06d353cb_5a6c_47ca_8dbe_ff76359c7e96]
123
+
124
+ case called_indirectly
125
+ when nil, false
126
+
127
+ called_indirectly = 0
128
+ when true
129
+
130
+ called_indirectly = 1
131
+ when ::Integer
132
+
133
+ ;
134
+ else
135
+
136
+ abort "indirect-call option (#{called_indirectly}) has invalid type (#{called_indirectly.class})"
137
+ end
138
+
139
+ options.delete :called_indirectly_06d353cb_5a6c_47ca_8dbe_ff76359c7e96 if called_indirectly
140
+
141
+
142
+ # Use cases:
143
+ #
144
+ # 1. No options
145
+ # 2. Non-class and options
146
+ # 3. Class and options
147
+ # 3.a Class and options
148
+ # 3.b Class and options and message
149
+ # 3.c Class and options and message and call-stack
150
+
151
+ class_given = args.size > 0 && args[0].is_a?(::Class)
152
+
153
+ if class_given && !options.empty?
154
+
155
+ exception_class_or_instance_or_message_string = args.shift
156
+
157
+ # 3. Class and options
158
+
159
+ # 3.a Class and options
160
+ # 3.b Class and options and message
161
+ # 3.c Class and options and message and call-stack
162
+
163
+
164
+ xargs = []
165
+
166
+ xargs << args.shift unless args.empty?
167
+
168
+ x = exception_class_or_instance_or_message_string.new *xargs, **options
169
+
170
+ rargs = []
171
+ rargs << x
172
+ rargs += [ nil, args.shift ] unless args.empty?
173
+
174
+ # now need to trim backtrace
175
+
176
+ begin
177
+
178
+ Kernel.raise *rargs
179
+ rescue => x
180
+
181
+ bt = x.backtrace
182
+ (0..called_indirectly).each { bt.shift }
183
+ Kernel.raise x, x.message, bt
184
+ end
185
+ end
186
+
187
+ unless options.empty?
188
+
189
+ # 2. Non-class and options
190
+
191
+ warn "cannot utilise options in raise_with_options when first argument is non-class"
192
+ else
193
+
194
+ # 1. No options
195
+ end
196
+
197
+
198
+ # now need to trim backtrace
199
+
200
+ begin
201
+
202
+ Kernel.raise *args
203
+ rescue => x
204
+
205
+ bt = x.backtrace
206
+ (0..called_indirectly).each { bt.shift }
207
+ Kernel.raise x, x.message, bt
208
+ end
209
+ end
210
+ end # module ExceptionUtilities
211
+
212
+ end # module Diagnostics
213
+ end # module Xqsr3
214
+
215
+ # ############################## end of file ############################# #
216
+