xqsr3 0.38.1.1 → 0.39.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -6
  3. data/examples/count_word_frequencies.md +13 -13
  4. data/examples/count_word_frequencies.rb +5 -5
  5. data/lib/xqsr3/array_utilities/join_with_or.rb +53 -54
  6. data/lib/xqsr3/array_utilities.rb +2 -2
  7. data/lib/xqsr3/command_line_utilities/map_option_string.rb +66 -67
  8. data/lib/xqsr3/command_line_utilities.rb +2 -2
  9. data/lib/xqsr3/containers/frequency_map.rb +405 -404
  10. data/lib/xqsr3/containers/multi_map.rb +454 -453
  11. data/lib/xqsr3/containers.rb +3 -3
  12. data/lib/xqsr3/conversion/bool_parser.rb +56 -57
  13. data/lib/xqsr3/conversion/integer_parser.rb +92 -93
  14. data/lib/xqsr3/conversion.rb +3 -3
  15. data/lib/xqsr3/diagnostics/exception_utilities.rb +152 -151
  16. data/lib/xqsr3/diagnostics/exceptions/with_cause.rb +99 -95
  17. data/lib/xqsr3/diagnostics/inspect_builder.rb +86 -86
  18. data/lib/xqsr3/diagnostics.rb +3 -3
  19. data/lib/xqsr3/doc_.rb +136 -136
  20. data/lib/xqsr3/extensions/array/join_with_or.rb +9 -9
  21. data/lib/xqsr3/extensions/enumerable/collect_with_index.rb +18 -17
  22. data/lib/xqsr3/extensions/enumerable/detect_map.rb +41 -41
  23. data/lib/xqsr3/extensions/enumerable/unique.rb +32 -31
  24. data/lib/xqsr3/extensions/hash/deep_transform.rb +1 -1
  25. data/lib/xqsr3/extensions/hash/except.rb +16 -16
  26. data/lib/xqsr3/extensions/hash/has_match.rb +10 -10
  27. data/lib/xqsr3/extensions/hash/match.rb +10 -10
  28. data/lib/xqsr3/extensions/hash/slice.rb +11 -11
  29. data/lib/xqsr3/extensions/hash.rb +1 -1
  30. data/lib/xqsr3/extensions/integer/to_s_grp.rb +118 -0
  31. data/lib/xqsr3/extensions/integer.rb +3 -0
  32. data/lib/xqsr3/extensions/io/writelines.rb +34 -34
  33. data/lib/xqsr3/extensions/kernel/integer.rb +26 -26
  34. data/lib/xqsr3/extensions/kernel/raise_with_options.rb +15 -14
  35. data/lib/xqsr3/extensions/kernel.rb +1 -0
  36. data/lib/xqsr3/extensions/string/ends_with.rb +1 -1
  37. data/lib/xqsr3/extensions/string/map_option_string.rb +4 -5
  38. data/lib/xqsr3/extensions/string/nil_if_empty.rb +1 -1
  39. data/lib/xqsr3/extensions/string/nil_if_whitespace.rb +1 -1
  40. data/lib/xqsr3/extensions/string/quote_if.rb +1 -2
  41. data/lib/xqsr3/extensions/string/starts_with.rb +1 -1
  42. data/lib/xqsr3/extensions/string/to_bool.rb +8 -9
  43. data/lib/xqsr3/extensions/string/to_symbol.rb +1 -1
  44. data/lib/xqsr3/extensions/string/truncate.rb +1 -2
  45. data/lib/xqsr3/extensions/test/unit/assert_eql.rb +7 -7
  46. data/lib/xqsr3/extensions/test/unit/assert_false.rb +6 -7
  47. data/lib/xqsr3/extensions/test/unit/assert_not.rb +6 -7
  48. data/lib/xqsr3/extensions/test/unit/assert_not_eql.rb +7 -7
  49. data/lib/xqsr3/extensions/test/unit/assert_raise_with_message.rb +61 -62
  50. data/lib/xqsr3/extensions/test/unit/assert_subclass_of.rb +7 -8
  51. data/lib/xqsr3/extensions/test/unit/assert_superclass_of.rb +7 -8
  52. data/lib/xqsr3/extensions/test/unit/assert_true.rb +6 -7
  53. data/lib/xqsr3/extensions/test/unit/assert_type_has_instance_methods.rb +36 -38
  54. data/lib/xqsr3/extensions.rb +5 -5
  55. data/lib/xqsr3/hash_utilities/deep_transform.rb +71 -71
  56. data/lib/xqsr3/hash_utilities/key_matching.rb +82 -82
  57. data/lib/xqsr3/hash_utilities.rb +3 -3
  58. data/lib/xqsr3/internal_/test_unit_version_.rb +130 -88
  59. data/lib/xqsr3/io/writelines.rb +125 -125
  60. data/lib/xqsr3/quality/parameter_checking.rb +452 -453
  61. data/lib/xqsr3/quality.rb +2 -2
  62. data/lib/xqsr3/string_utilities/ends_with.rb +64 -64
  63. data/lib/xqsr3/string_utilities/nil_if_empty.rb +33 -34
  64. data/lib/xqsr3/string_utilities/nil_if_whitespace.rb +35 -35
  65. data/lib/xqsr3/string_utilities/quote_if.rb +55 -56
  66. data/lib/xqsr3/string_utilities/starts_with.rb +64 -64
  67. data/lib/xqsr3/string_utilities/to_symbol.rb +80 -80
  68. data/lib/xqsr3/string_utilities/truncate.rb +60 -61
  69. data/lib/xqsr3/string_utilities.rb +8 -8
  70. data/lib/xqsr3/version.rb +19 -20
  71. data/test/performance/frequency_map.rb +13 -27
  72. data/test/scratch/test_assert_raise_with_message.rb +12 -13
  73. data/test/unit/array_utilities/tc_join_with_or.rb +140 -142
  74. data/test/unit/command_line_utilities/tc_map_option_string.rb +18 -18
  75. data/test/unit/containers/tc_frequency_map.rb +607 -554
  76. data/test/unit/containers/tc_multi_map.rb +573 -522
  77. data/test/unit/conversion/tc_integer_parser.rb +73 -73
  78. data/test/unit/conversion/tc_to_bool.rb +26 -26
  79. data/test/unit/diagnostics/exceptions/tc_with_cause.rb +165 -165
  80. data/test/unit/diagnostics/tc_exception_utilities.rb +156 -156
  81. data/test/unit/extensions/enumerable/tc_collect_with_index.rb +14 -14
  82. data/test/unit/extensions/enumerable/tc_detect_map.rb +20 -20
  83. data/test/unit/extensions/enumerable/tc_unique.rb +34 -34
  84. data/test/unit/extensions/hash/tc_deep_transform.rb +22 -22
  85. data/test/unit/extensions/hash/tc_except.rb +28 -28
  86. data/test/unit/extensions/hash/tc_hash.rb +1 -1
  87. data/test/unit/extensions/hash/tc_slice.rb +14 -14
  88. data/test/unit/extensions/integer/tc_to_s_grp.rb +60 -0
  89. data/test/unit/extensions/integer/ts_all.rb +12 -0
  90. data/test/unit/extensions/io/tc_writelines.rb +77 -77
  91. data/test/unit/extensions/kernel/tc_integer.rb +75 -75
  92. data/test/unit/extensions/kernel/tc_raise_with_options.rb +155 -155
  93. data/test/unit/extensions/object/tc_inspect.rb +51 -51
  94. data/test/unit/extensions/string/tc_bool.tb +24 -24
  95. data/test/unit/extensions/string/tc_ends_with.rb +53 -53
  96. data/test/unit/extensions/string/tc_map_option_string.rb +15 -15
  97. data/test/unit/extensions/string/tc_nil_if_empty.rb +8 -8
  98. data/test/unit/extensions/string/tc_nil_if_whitespace.rb +8 -8
  99. data/test/unit/extensions/string/tc_quote_if.rb +18 -18
  100. data/test/unit/extensions/string/tc_starts_with.rb +53 -53
  101. data/test/unit/extensions/string/tc_to_symbol.rb +26 -26
  102. data/test/unit/extensions/string/tc_truncate.rb +18 -18
  103. data/test/unit/extensions/test/unit/tc_assert_raise_with_message.rb +16 -16
  104. data/test/unit/extensions/test/unit/tc_assert_subclass_of.rb +9 -9
  105. data/test/unit/extensions/test/unit/tc_assert_superclass_of.rb +9 -9
  106. data/test/unit/hash_utilities/tc_has_match.rb +70 -70
  107. data/test/unit/hash_utilities/tc_match.rb +83 -83
  108. data/test/unit/io/tc_writelines.rb +106 -108
  109. data/test/unit/quality/tc_parameter_checking.rb +390 -390
  110. data/test/unit/string_utilities/tc_truncate.rb +28 -28
  111. data/test/unit/tc_version.rb +15 -15
  112. metadata +6 -2
@@ -1,16 +1,17 @@
1
1
 
2
2
  # ######################################################################## #
3
- # File: lib/xqsr3/containers/multi_map.rb
3
+ # File: lib/xqsr3/containers/multi_map.rb
4
4
  #
5
- # Purpose: multimap container
5
+ # Purpose: multimap container
6
6
  #
7
- # Created: 21st March 2007
8
- # Updated: 15th April 2019
7
+ # Created: 21st March 2007
8
+ # Updated: 29th March 2024
9
9
  #
10
- # Home: http://github.com/synesissoftware/xqsr3
10
+ # Home: http://github.com/synesissoftware/xqsr3
11
11
  #
12
- # Author: Matthew Wilson
12
+ # Author: Matthew Wilson
13
13
  #
14
+ # Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems
14
15
  # Copyright (c) 2007-2019, Matthew Wilson and Synesis Software
15
16
  # All rights reserved.
16
17
  #
@@ -25,7 +26,7 @@
25
26
  # notice, this list of conditions and the following disclaimer in the
26
27
  # documentation and/or other materials provided with the distribution.
27
28
  #
28
- # * Neither the names of the copyright holder nor the names of its
29
+ # * Neither the names of the copyright holders nor the names of its
29
30
  # contributors may be used to endorse or promote products derived from
30
31
  # this software without specific prior written permission.
31
32
  #
@@ -56,628 +57,628 @@ module Containers
56
57
  # Hash-like class that stores as mapped values in arrays
57
58
  class MultiMap < ::Hash
58
59
 
59
- include Enumerable
60
+ include Enumerable
60
61
 
61
- # Creates an instance from the given arguments
62
- def self.[] *args
62
+ # Creates an instance from the given arguments
63
+ def self.[] *args
63
64
 
64
- return self.new if 0 == args.length
65
+ return self.new if 0 == args.length
65
66
 
66
- if 1 == args.length
67
+ if 1 == args.length
67
68
 
68
- arg = args[0]
69
+ arg = args[0]
69
70
 
70
- case arg
71
- when ::NilClass
71
+ case arg
72
+ when ::NilClass
72
73
 
73
- return self.new
74
- when ::Hash
74
+ return self.new
75
+ when ::Hash
75
76
 
76
- mm = self.new
77
+ mm = self.new
77
78
 
78
- arg.each do |k, v|
79
+ arg.each do |k, v|
79
80
 
80
- raise ArgumentError, "mapped elements in hashes must be arrays, #{v.class} given" unless v.kind_of? ::Array
81
+ raise ArgumentError, "mapped elements in hashes must be arrays, #{v.class} given" unless v.kind_of? ::Array
81
82
 
82
- mm.store k, *v
83
- end
83
+ mm.store k, *v
84
+ end
84
85
 
85
- return mm
86
- when ::Array
86
+ return mm
87
+ when ::Array
87
88
 
88
- # accepted forms:
89
- #
90
- # 1. Empty array
91
- # 2. Array exclusively of arrays
89
+ # accepted forms:
90
+ #
91
+ # 1. Empty array
92
+ # 2. Array exclusively of arrays
92
93
 
93
- # 1. Empty array
94
+ # 1. Empty array
94
95
 
95
- return self.new if arg.empty?
96
+ return self.new if arg.empty?
96
97
 
97
- # 2. Array exclusively of arrays
98
+ # 2. Array exclusively of arrays
98
99
 
99
- if arg.all? { |el| ::Array === el }
100
+ if arg.all? { |el| ::Array === el }
100
101
 
101
- h = Hash.new { |hash, key| hash[key] = [] }
102
+ h = Hash.new { |hash, key| hash[key] = [] }
102
103
 
103
- arg.each do |ar|
104
+ arg.each do |ar|
104
105
 
105
- raise ArgumentError, "cannot pass an empty array in array of arrays initialiser" if ar.empty?
106
+ raise ArgumentError, "cannot pass an empty array in array of arrays initialiser" if ar.empty?
106
107
 
107
- key = ar.shift
108
+ key = ar.shift
108
109
 
109
- ar.each { |value| h[key] << value }
110
- end
110
+ ar.each { |value| h[key] << value }
111
+ end
111
112
 
112
- return self.[](h)
113
- end
113
+ return self.[](h)
114
+ end
114
115
 
115
116
 
116
117
 
117
- raise ArgumentError, "array parameter not in an accepted form for subscript initialisation"
118
- else
118
+ raise ArgumentError, "array parameter not in an accepted form for subscript initialisation"
119
+ else
119
120
 
120
- return self.[] arg.to_hash if arg.respond_to? :to_hash
121
+ return self.[] arg.to_hash if arg.respond_to? :to_hash
121
122
 
122
- raise TypeError, "given argument is neither a #{::Hash} nor an #{::Array} and does not respond to the to_hash method"
123
- end
123
+ raise TypeError, "given argument is neither a #{::Hash} nor an #{::Array} and does not respond to the to_hash method"
124
+ end
124
125
 
125
- else
126
+ else
126
127
 
127
- # treat all other argument permutations as having passed in an array
128
+ # treat all other argument permutations as having passed in an array
128
129
 
129
- return self.[] [ *args ]
130
- end
131
- end
130
+ return self.[] [ *args ]
131
+ end
132
+ end
132
133
 
133
- # Initialises an instance
134
- def initialize
134
+ # Initialises an instance
135
+ def initialize
135
136
 
136
- @merge_is_multi = true
137
+ @merge_is_multi = true
137
138
 
138
- @inner = Hash.new
139
- end
139
+ @inner = Hash.new
140
+ end
140
141
 
141
- # Obtains the values, if any, for the given key; returns +nil+ if no
142
- # values are stored
143
- def [] key
142
+ # Obtains the values, if any, for the given key; returns +nil+ if no
143
+ # values are stored
144
+ def [] key
144
145
 
145
- return @inner[key]
146
- end
146
+ return @inner[key]
147
+ end
147
148
 
148
- # Adds/assigns a new key+values pair. Equivalent to
149
- #
150
- # store(key, *values)
151
- #
152
- # * *Parameters:*
153
- # - +key+ The element key
154
- # - +values+ (Array) The values to be associated with the key
155
- #
156
- # * *Exceptions:*
157
- # - +::TypeError+ if +values+ is not an array
158
- def []= key, values
149
+ # Adds/assigns a new key+values pair. Equivalent to
150
+ #
151
+ # store(key, *values)
152
+ #
153
+ # * *Parameters:*
154
+ # - +key+ The element key
155
+ # - +values+ (Array) The values to be associated with the key
156
+ #
157
+ # * *Exceptions:*
158
+ # - +::TypeError+ if +values+ is not an array
159
+ def []= key, values
159
160
 
160
- values = [] if values.nil?
161
+ values = [] if values.nil?
161
162
 
162
- raise TypeError, "values must be an array, but #{values.class} given" unless values.kind_of? ::Array
163
+ raise TypeError, "values must be an array, but #{values.class} given" unless values.kind_of? ::Array
163
164
 
164
- store key, *values
165
- end
165
+ store key, *values
166
+ end
166
167
 
167
- # Compares the instance for equality against +rhs+
168
- #
169
- # * *Parameters:*
170
- # - +rhs+ (+nil+, +::Hash+, +MultiMap+) The instance to compare against
171
- #
172
- # * *Exceptions:*
173
- # - +::TypeError+ if +rhs+ is not of the required type(s)
174
- def == rhs
168
+ # Compares the instance for equality against +rhs+
169
+ #
170
+ # * *Parameters:*
171
+ # - +rhs+ (+nil+, +::Hash+, +MultiMap+) The instance to compare against
172
+ #
173
+ # * *Exceptions:*
174
+ # - +::TypeError+ if +rhs+ is not of the required type(s)
175
+ def == rhs
175
176
 
176
- case rhs
177
- when ::NilClass
178
- return false
179
- when ::Hash
180
- return rhs.size == @inner.size && rhs == @inner
181
- when self.class
182
- return rhs.size == self.size && rhs == @inner
183
- else
184
- raise TypeError, "can compare #{self.class} only to instances of #{self.class} and #{::Hash}, but #{rhs.class} given"
185
- end
177
+ case rhs
178
+ when ::NilClass
179
+ return false
180
+ when ::Hash
181
+ return rhs.size == @inner.size && rhs == @inner
182
+ when self.class
183
+ return rhs.size == self.size && rhs == @inner
184
+ else
185
+ raise TypeError, "can compare #{self.class} only to instances of #{self.class} and #{::Hash}, but #{rhs.class} given"
186
+ end
186
187
 
187
- false
188
- end
188
+ false
189
+ end
189
190
 
190
- # Searches the instance comparing each element with +key+, returning the
191
- # mapped values array if found, or +nil+ if not
192
- def assoc key
191
+ # Searches the instance comparing each element with +key+, returning the
192
+ # mapped values array if found, or +nil+ if not
193
+ def assoc key
193
194
 
194
- @inner.assoc key
195
- end
195
+ @inner.assoc key
196
+ end
196
197
 
197
- # Removes all elements from the instance
198
- def clear
198
+ # Removes all elements from the instance
199
+ def clear
199
200
 
200
- @inner.clear
201
- end
201
+ @inner.clear
202
+ end
202
203
 
203
- # The total number of instances recorded
204
- def count
204
+ # The total number of instances recorded
205
+ def count
205
206
 
206
- @inner.each_value.map { |ar| ar.size}.inject(0, :+)
207
- end
207
+ @inner.each_value.map { |ar| ar.size}.inject(0, :+)
208
+ end
208
209
 
209
- # Deletes all values mapped with the given +key+
210
- #
211
- # * *Parameters:*
212
- # - +key+ The key to delete
213
- def delete key
210
+ # Deletes all values mapped with the given +key+
211
+ #
212
+ # * *Parameters:*
213
+ # - +key+ The key to delete
214
+ def delete key
214
215
 
215
- @inner.delete key
216
- end
216
+ @inner.delete key
217
+ end
217
218
 
218
- # Calls _block_ once for each key-value pair, passing the key and each
219
- # of its values in turn. If the values for a given key are empty and
220
- # +defaults+ is not empty, the block is invoked for that key (with
221
- # +defaults[0]+) once
222
- #
223
- # * *Exceptions:*
224
- # - +ArgumentError+ if more than 1 +defaults+ is provided, or no block is given
225
- def each *defaults
219
+ # Calls _block_ once for each key-value pair, passing the key and each
220
+ # of its values in turn. If the values for a given key are empty and
221
+ # +defaults+ is not empty, the block is invoked for that key (with
222
+ # +defaults[0]+) once
223
+ #
224
+ # * *Exceptions:*
225
+ # - +ArgumentError+ if more than 1 +defaults+ is provided, or no block is given
226
+ def each *defaults
226
227
 
227
- raise ArgumentError, "may only supply 0 or 1 defaults" if defaults.size > 1
228
- raise ArgumentError, 'block is required' unless block_given?
228
+ raise ArgumentError, "may only supply 0 or 1 defaults" if defaults.size > 1
229
+ raise ArgumentError, 'block is required' unless block_given?
229
230
 
230
- @inner.each do |key, values|
231
+ @inner.each do |key, values|
231
232
 
232
- if values.empty? && !defaults.empty?
233
+ if values.empty? && !defaults.empty?
233
234
 
234
- yield key, defaults[0]
235
+ yield key, defaults[0]
235
236
 
236
- next
237
- end
237
+ next
238
+ end
238
239
 
239
- values.each { |value| yield key, value }
240
- end
241
- end
240
+ values.each { |value| yield key, value }
241
+ end
242
+ end
242
243
 
243
- # Calls _block_ once for each key in the instance, passing the key. If no
244
- # block is provided, an enumerator is returned
245
- def each_key
244
+ # Calls _block_ once for each key in the instance, passing the key. If no
245
+ # block is provided, an enumerator is returned
246
+ def each_key
246
247
 
247
- return @inner.each_key unless block_given?
248
+ return @inner.each_key unless block_given?
248
249
 
249
- @inner.each_key { |key| yield key }
250
- end
250
+ @inner.each_key { |key| yield key }
251
+ end
251
252
 
252
- # Calls _block_ once for each key-values pair, passing the key and its
253
- # values array. If no block is provided, an enumerator is returned
254
- def each_unflattened
253
+ # Calls _block_ once for each key-values pair, passing the key and its
254
+ # values array. If no block is provided, an enumerator is returned
255
+ def each_unflattened
255
256
 
256
- return @inner.each unless block_given?
257
+ return @inner.each unless block_given?
257
258
 
258
- @inner.each { |key, value| yield key, value }
259
- end
259
+ @inner.each { |key, value| yield key, value }
260
+ end
260
261
 
261
- # Calls _block_ once for each key-values pair, passing the key and its
262
- # values array and a key index. If no block is provided, an enumerator
263
- # is returned
264
- def each_unflattened_with_index
262
+ # Calls _block_ once for each key-values pair, passing the key and its
263
+ # values array and a key index. If no block is provided, an enumerator
264
+ # is returned
265
+ def each_unflattened_with_index
265
266
 
266
- return @inner.each_with_index unless block_given?
267
+ return @inner.each_with_index unless block_given?
267
268
 
268
- @inner.each_with_index { |kv, index| yield kv, index }
269
- end
269
+ @inner.each_with_index { |kv, index| yield kv, index }
270
+ end
270
271
 
271
- # Calls _block_ once for each value in the instance, passing the value.
272
- # If no block is provided, an enumerator is returned
273
- def each_value
272
+ # Calls _block_ once for each value in the instance, passing the value.
273
+ # If no block is provided, an enumerator is returned
274
+ def each_value
274
275
 
275
- return @inner.each_value unless block_given?
276
+ return @inner.each_value unless block_given?
276
277
 
277
- @inner.each do |key, values|
278
+ @inner.each do |key, values|
278
279
 
279
- values.each { |value| yield value }
280
- end
281
- end
280
+ values.each { |value| yield value }
281
+ end
282
+ end
282
283
 
283
- # Calls _block_ once for each key-values, passing the key and each of its
284
- # values and a value index
285
- #
286
- # * *Exceptions:*
287
- # - +ArgumentError+ if no block is given
288
- def each_with_index
284
+ # Calls _block_ once for each key-values, passing the key and each of its
285
+ # values and a value index
286
+ #
287
+ # * *Exceptions:*
288
+ # - +ArgumentError+ if no block is given
289
+ def each_with_index
289
290
 
290
- raise ArgumentError, 'block is required' unless block_given?
291
+ raise ArgumentError, 'block is required' unless block_given?
291
292
 
292
- index = 0
293
- self.each do |key, value|
293
+ index = 0
294
+ self.each do |key, value|
294
295
 
295
- yield key, value, index
296
+ yield key, value, index
296
297
 
297
- index += 1
298
- end
299
- end
298
+ index += 1
299
+ end
300
+ end
300
301
 
301
- # Returns +true+ if instance contains no elements; +false+ otherwise
302
- def empty?
302
+ # Returns +true+ if instance contains no elements; +false+ otherwise
303
+ def empty?
303
304
 
304
- @inner.empty?
305
- end
305
+ @inner.empty?
306
+ end
306
307
 
307
- # Returns +true+ if +rhs+ is an instance of +MultiMap+ and contains
308
- # the same elements and their counts; +false+ otherwise
309
- def eql? rhs
308
+ # Returns +true+ if +rhs+ is an instance of +MultiMap+ and contains
309
+ # the same elements and their counts; +false+ otherwise
310
+ def eql? rhs
310
311
 
311
- case rhs
312
- when self.class
313
- return self == rhs
314
- else
315
- return false
316
- end
317
- end
312
+ case rhs
313
+ when self.class
314
+ return self == rhs
315
+ else
316
+ return false
317
+ end
318
+ end
318
319
 
319
- # Returns the values associated with the given key
320
- #
321
- # * *Parameters:*
322
- # - +key+ The key
323
- # - +default+ The default value
324
- def fetch key, default = (default_parameter_defaulted_ = true; nil), &block
320
+ # Returns the values associated with the given key
321
+ #
322
+ # * *Parameters:*
323
+ # - +key+ The key
324
+ # - +default+ The default value
325
+ def fetch key, default = (default_parameter_defaulted_ = true; nil), &block
325
326
 
326
- unless default_parameter_defaulted_
327
+ unless default_parameter_defaulted_
327
328
 
328
- case default
329
- when ::NilClass, ::Array
330
- ;
331
- else
332
- raise TypeError, "default parameter ('#{default}') must be of type #{::Array}, but was of type #{default.class}"
333
- end
334
- end
329
+ case default
330
+ when ::NilClass, ::Array
331
+ ;
332
+ else
333
+ raise TypeError, "default parameter ('#{default}') must be of type #{::Array}, but was of type #{default.class}"
334
+ end
335
+ end
335
336
 
336
- unless @inner.has_key? key
337
+ unless @inner.has_key? key
337
338
 
338
- return default unless default_parameter_defaulted_
339
+ return default unless default_parameter_defaulted_
339
340
 
340
- if block_given?
341
+ if block_given?
341
342
 
342
- r = nil
343
+ r = nil
343
344
 
344
- case block.arity
345
- when 0
346
- r = yield
347
- when 1
348
- r = yield key
349
- else
350
- raise ArgumentError, "given block must take a single parameter - #{block.arity} given"
351
- end
345
+ case block.arity
346
+ when 0
347
+ r = yield
348
+ when 1
349
+ r = yield key
350
+ else
351
+ raise ArgumentError, "given block must take a single parameter - #{block.arity} given"
352
+ end
352
353
 
353
- case r
354
- when ::Array
355
- ;
356
- else
357
- raise ArgumentError, "given block must return a value of type #{::Array} or one convertible implicitly to such" unless r.respond_to? :to_ary
354
+ case r
355
+ when ::Array
356
+ ;
357
+ else
358
+ raise ArgumentError, "given block must return a value of type #{::Array} or one convertible implicitly to such" unless r.respond_to? :to_ary
358
359
 
359
- r = r.to_ary
360
- end
360
+ r = r.to_ary
361
+ end
361
362
 
362
- return r
363
- end
363
+ return r
364
+ end
364
365
 
365
- raise KeyError, "given key '#{key}' (#{key.class}) does not exist"
366
- end
366
+ raise KeyError, "given key '#{key}' (#{key.class}) does not exist"
367
+ end
367
368
 
368
- @inner.fetch key
369
- end
369
+ @inner.fetch key
370
+ end
370
371
 
371
- # Returns the equivalent flattened form of the instance
372
- def flatten
372
+ # Returns the equivalent flattened form of the instance
373
+ def flatten
373
374
 
374
- r = []
375
+ r = []
375
376
 
376
- @inner.each do |key, values|
377
+ @inner.each do |key, values|
377
378
 
378
- if values.empty?
379
+ if values.empty?
379
380
 
380
- r << key << []
381
- else
381
+ r << key << []
382
+ else
382
383
 
383
- values.each do |value|
384
+ values.each do |value|
384
385
 
385
- r << key << value
386
- end
387
- end
388
- end
386
+ r << key << value
387
+ end
388
+ end
389
+ end
389
390
 
390
- r
391
- end
391
+ r
392
+ end
392
393
 
393
- # Returns +true+ if an element with the given +key+ is in the map; +false+
394
- # otherwise
395
- def has_key? key
394
+ # Returns +true+ if an element with the given +key+ is in the map; +false+
395
+ # otherwise
396
+ def has_key? key
396
397
 
397
- @inner.has_key? key
398
- end
398
+ @inner.has_key? key
399
+ end
399
400
 
400
- # Returns +true+ if any key has the given +value+; +false+ otherwise
401
- #
402
- # * *Parameters:*
403
- # - +value+ The value for which to search
404
- def has_value? value
401
+ # Returns +true+ if any key has the given +value+; +false+ otherwise
402
+ #
403
+ # * *Parameters:*
404
+ # - +value+ The value for which to search
405
+ def has_value? value
405
406
 
406
- @inner.each do |k, vals|
407
+ @inner.each do |k, vals|
407
408
 
408
- return true if vals.include? value
409
- end
409
+ return true if vals.include? value
410
+ end
410
411
 
411
- false
412
- end
412
+ false
413
+ end
413
414
 
414
- # Returns +true+ if any key has the given +values+; +false+ otherwise
415
- #
416
- # * *Parameters:*
417
- # - +values+ (Array) The values for which to search
418
- #
419
- # * *Exceptions:*
420
- # - +::TypeError+ if +value+ is not an Array
421
- def has_values? values
415
+ # Returns +true+ if any key has the given +values+; +false+ otherwise
416
+ #
417
+ # * *Parameters:*
418
+ # - +values+ (Array) The values for which to search
419
+ #
420
+ # * *Exceptions:*
421
+ # - +::TypeError+ if +value+ is not an Array
422
+ def has_values? values
422
423
 
423
- raise TypeError, "'values' parameter must be of type #{::Array}" unless Array === values
424
+ raise TypeError, "'values' parameter must be of type #{::Array}" unless Array === values
424
425
 
425
- @inner.has_value? values
426
- end
426
+ @inner.has_value? values
427
+ end
427
428
 
428
- # Returns the key for the given value(s)
429
- #
430
- # * *Parameters:*
431
- # - +values+ (Array) The value(s) for which to search
432
- #
433
- # If a single value is specified, the entries in the instance are
434
- # searched first for an exact match to all (1) value(s); if that fails,
435
- # then the first key with a values containing the given value is
436
- # returned
437
- def key *values
429
+ # Returns the key for the given value(s)
430
+ #
431
+ # * *Parameters:*
432
+ # - +values+ (Array) The value(s) for which to search
433
+ #
434
+ # If a single value is specified, the entries in the instance are
435
+ # searched first for an exact match to all (1) value(s); if that fails,
436
+ # then the first key with a values containing the given value is
437
+ # returned
438
+ def key *values
438
439
 
439
- case values.size
440
- when 0
440
+ case values.size
441
+ when 0
441
442
 
442
- return nil
443
- when 1
443
+ return nil
444
+ when 1
444
445
 
445
- i = nil
446
+ i = nil
446
447
 
447
- @inner.each do |k, vals|
448
+ @inner.each do |k, vals|
448
449
 
449
- return k if vals == values
450
+ return k if vals == values
450
451
 
451
- if i.nil?
452
+ if i.nil?
452
453
 
453
- i = k if vals.include? values[0]
454
- end
455
- end
454
+ i = k if vals.include? values[0]
455
+ end
456
+ end
456
457
 
457
- return i
458
- else
458
+ return i
459
+ else
459
460
 
460
- @inner.each do |key, vals|
461
+ @inner.each do |key, vals|
461
462
 
462
- return key if vals == values
463
- end
463
+ return key if vals == values
464
+ end
464
465
 
465
- return nil
466
- end
467
- end
466
+ return nil
467
+ end
468
+ end
468
469
 
469
- # The number of elements in the map
470
- def length
470
+ # The number of elements in the map
471
+ def length
471
472
 
472
- @inner.size
473
- end
473
+ @inner.size
474
+ end
474
475
 
475
- # Returns a new instance containing a merging of the current instance and
476
- # the +other+ instance
477
- #
478
- # NOTE: where any key is found in both merging instances the values
479
- # resulting will be a concatenation of the sets of values
480
- #
481
- # * *Parameters:*
482
- # - +other+ (MultiMap, Hash) The instance from which to merge
483
- #
484
- # * *Exceptions:*
485
- # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
486
- def multi_merge other
476
+ # Returns a new instance containing a merging of the current instance and
477
+ # the +other+ instance
478
+ #
479
+ # NOTE: where any key is found in both merging instances the values
480
+ # resulting will be a concatenation of the sets of values
481
+ #
482
+ # * *Parameters:*
483
+ # - +other+ (MultiMap, Hash) The instance from which to merge
484
+ #
485
+ # * *Exceptions:*
486
+ # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
487
+ def multi_merge other
487
488
 
488
- mm = self.class.new
489
+ mm = self.class.new
489
490
 
490
- mm.merge! self
491
- mm.merge! other
491
+ mm.merge! self
492
+ mm.merge! other
492
493
 
493
- mm
494
- end
494
+ mm
495
+ end
495
496
 
496
- # Merges the contents of +other+ into the current instance
497
- #
498
- # NOTE: where any key is found in both merging instances the values
499
- # resulting will be a concatenation of the sets of values
500
- #
501
- # * *Parameters:*
502
- # - +other+ (MultiMap, Hash) The instance from which to merge
503
- #
504
- # * *Exceptions:*
505
- # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
506
- def multi_merge! other
497
+ # Merges the contents of +other+ into the current instance
498
+ #
499
+ # NOTE: where any key is found in both merging instances the values
500
+ # resulting will be a concatenation of the sets of values
501
+ #
502
+ # * *Parameters:*
503
+ # - +other+ (MultiMap, Hash) The instance from which to merge
504
+ #
505
+ # * *Exceptions:*
506
+ # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
507
+ def multi_merge! other
507
508
 
508
- case other
509
- when self.class
509
+ case other
510
+ when self.class
510
511
 
511
- ;
512
- when ::Hash
512
+ ;
513
+ when ::Hash
513
514
 
514
- ;
515
- else
516
-
517
- raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
518
- end
515
+ ;
516
+ else
517
+
518
+ raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
519
+ end
519
520
 
520
- other.each do |k, v|
521
+ other.each do |k, v|
521
522
 
522
- self.push k, v
523
- end
523
+ self.push k, v
524
+ end
524
525
 
525
- self
526
- end
526
+ self
527
+ end
527
528
 
528
- # Returns a new instance containing a merging of the current instance and
529
- # the +other+ instance
530
- #
531
- # NOTE: where any key is found in both merging instances the values from
532
- # +other+ will be used
533
- #
534
- # * *Parameters:*
535
- # - +other+ (MultiMap, Hash) The instance from which to merge
536
- #
537
- # * *Exceptions:*
538
- # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
539
- def strict_merge other
529
+ # Returns a new instance containing a merging of the current instance and
530
+ # the +other+ instance
531
+ #
532
+ # NOTE: where any key is found in both merging instances the values from
533
+ # +other+ will be used
534
+ #
535
+ # * *Parameters:*
536
+ # - +other+ (MultiMap, Hash) The instance from which to merge
537
+ #
538
+ # * *Exceptions:*
539
+ # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
540
+ def strict_merge other
540
541
 
541
- mm = self.class.new
542
+ mm = self.class.new
542
543
 
543
- mm.strict_merge! self
544
- mm.strict_merge! other
544
+ mm.strict_merge! self
545
+ mm.strict_merge! other
545
546
 
546
- mm
547
- end
547
+ mm
548
+ end
548
549
 
549
- # Merges the contents of +other+ into the current instance
550
- #
551
- # NOTE: where any key is found in both merging instances the values from
552
- # +other+ will be used
553
- #
554
- # * *Parameters:*
555
- # - +other+ (MultiMap, Hash) The instance from which to merge
556
- #
557
- # * *Exceptions:*
558
- # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
559
- def strict_merge! other
550
+ # Merges the contents of +other+ into the current instance
551
+ #
552
+ # NOTE: where any key is found in both merging instances the values from
553
+ # +other+ will be used
554
+ #
555
+ # * *Parameters:*
556
+ # - +other+ (MultiMap, Hash) The instance from which to merge
557
+ #
558
+ # * *Exceptions:*
559
+ # - +TypeError+ Raised if +other+ is not a MultiMap or a Hash
560
+ def strict_merge! other
560
561
 
561
- case other
562
- when self.class
562
+ case other
563
+ when self.class
563
564
 
564
- other.each_unflattened do |k, vals|
565
+ other.each_unflattened do |k, vals|
565
566
 
566
- self.store k, *vals
567
- end
568
- when ::Hash
567
+ self.store k, *vals
568
+ end
569
+ when ::Hash
569
570
 
570
- other.each do |k, v|
571
+ other.each do |k, v|
571
572
 
572
- self.store k, v
573
- end
574
- else
573
+ self.store k, v
574
+ end
575
+ else
575
576
 
576
- raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
577
- end
577
+ raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
578
+ end
578
579
 
579
- self
580
- end
580
+ self
581
+ end
581
582
 
582
- # See #merge
583
- def merge other
583
+ # See #merge
584
+ def merge other
584
585
 
585
- if @merge_is_multi
586
+ if @merge_is_multi
586
587
 
587
- multi_merge other
588
- else
588
+ multi_merge other
589
+ else
589
590
 
590
- strict_merge other
591
- end
592
- end
591
+ strict_merge other
592
+ end
593
+ end
593
594
 
594
- # See #merge!
595
- def merge! other
595
+ # See #merge!
596
+ def merge! other
596
597
 
597
- if @merge_is_multi
598
+ if @merge_is_multi
598
599
 
599
- multi_merge! other
600
- else
600
+ multi_merge! other
601
+ else
601
602
 
602
- strict_merge! other
603
- end
604
- end
603
+ strict_merge! other
604
+ end
605
+ end
605
606
 
606
- # Pushes the given +key+ and +values+. If the +key+ is already in the
607
- # map then the +values+ will be concatenated with those already present
608
- #
609
- # === Signature
610
- #
611
- # * *Parameters:*
612
- # - +key+ The element key
613
- # - +values+ (*Array) The value(s) to be pushed
614
- #
615
- # === Exceptions
616
- # - +::RangeError+ raised if the value of +count+ results in a negative count for the given element
617
- # - +::TypeError+ if +count+ is not an +::Integer+
618
- def push key, *values
607
+ # Pushes the given +key+ and +values+. If the +key+ is already in the
608
+ # map then the +values+ will be concatenated with those already present
609
+ #
610
+ # === Signature
611
+ #
612
+ # * *Parameters:*
613
+ # - +key+ The element key
614
+ # - +values+ (*Array) The value(s) to be pushed
615
+ #
616
+ # === Exceptions
617
+ # - +::RangeError+ raised if the value of +count+ results in a negative count for the given element
618
+ # - +::TypeError+ if +count+ is not an +::Integer+
619
+ def push key, *values
619
620
 
620
- @inner[key] = [] unless @inner.has_key? key
621
+ @inner[key] = [] unless @inner.has_key? key
621
622
 
622
- @inner[key].push(*values)
623
- end
623
+ @inner[key].push(*values)
624
+ end
624
625
 
625
- # Removes a key-value pair from the instance and return as a two-item
626
- # array
627
- def shift
626
+ # Removes a key-value pair from the instance and return as a two-item
627
+ # array
628
+ def shift
628
629
 
629
- @inner.shift
630
- end
630
+ @inner.shift
631
+ end
631
632
 
632
- alias size length
633
+ alias size length
633
634
 
634
- # Causes an element with the given +key+ and +values+ to be stored. If an
635
- # element with the given +key+ already exists, its values will b
636
- # replaced
637
- def store key, *values
635
+ # Causes an element with the given +key+ and +values+ to be stored. If an
636
+ # element with the given +key+ already exists, its values will b
637
+ # replaced
638
+ def store key, *values
638
639
 
639
- @inner[key] = values
640
- end
640
+ @inner[key] = values
641
+ end
641
642
 
642
- # Converts instance to an array of +[key,value]+ pairs
643
- def to_a
643
+ # Converts instance to an array of +[key,value]+ pairs
644
+ def to_a
644
645
 
645
- self.flatten
646
- end
646
+ self.flatten
647
+ end
647
648
 
648
- # Obtains reference to internal hash instance (which must *not* be modified)
649
- def to_h
649
+ # Obtains reference to internal hash instance (which must *not* be modified)
650
+ def to_h
650
651
 
651
- @inner.to_h
652
- end
652
+ @inner.to_h
653
+ end
653
654
 
654
- # Obtains equivalent hash to instance
655
- def to_hash
655
+ # Obtains equivalent hash to instance
656
+ def to_hash
656
657
 
657
- @elements.to_hash
658
- end
658
+ @elements.to_hash
659
+ end
659
660
 
660
- # A string-form of the instance
661
- def to_s
661
+ # A string-form of the instance
662
+ def to_s
662
663
 
663
- @inner.to_s
664
- end
664
+ @inner.to_s
665
+ end
665
666
 
666
- # An array of all values in the instance
667
- def values
667
+ # An array of all values in the instance
668
+ def values
668
669
 
669
- r = []
670
+ r = []
670
671
 
671
- @inner.values.each { |vals| r += vals }
672
+ @inner.values.each { |vals| r += vals }
672
673
 
673
- r
674
- end
674
+ r
675
+ end
675
676
 
676
- # An array of all sets of values in the instance
677
- def values_unflattened
677
+ # An array of all sets of values in the instance
678
+ def values_unflattened
678
679
 
679
- @inner.values
680
- end
680
+ @inner.values
681
+ end
681
682
  end # class MultiMap
682
683
 
683
684
  end # module Containers