xqsr3 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
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
+