xqsr3 0.38.2 → 0.39.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -6
  3. data/examples/count_word_frequencies.md +12 -12
  4. data/examples/count_word_frequencies.rb +4 -4
  5. data/lib/xqsr3/array_utilities/join_with_or.rb +47 -47
  6. data/lib/xqsr3/array_utilities.rb +2 -2
  7. data/lib/xqsr3/command_line_utilities/map_option_string.rb +60 -60
  8. data/lib/xqsr3/command_line_utilities.rb +2 -2
  9. data/lib/xqsr3/containers/frequency_map.rb +399 -399
  10. data/lib/xqsr3/containers/multi_map.rb +448 -448
  11. data/lib/xqsr3/containers.rb +3 -3
  12. data/lib/xqsr3/conversion/bool_parser.rb +51 -51
  13. data/lib/xqsr3/conversion/integer_parser.rb +87 -87
  14. data/lib/xqsr3/conversion.rb +3 -3
  15. data/lib/xqsr3/diagnostics/exception_utilities.rb +145 -145
  16. data/lib/xqsr3/diagnostics/exceptions/with_cause.rb +90 -90
  17. data/lib/xqsr3/diagnostics/inspect_builder.rb +80 -80
  18. data/lib/xqsr3/diagnostics.rb +3 -3
  19. data/lib/xqsr3/doc_.rb +130 -130
  20. data/lib/xqsr3/extensions/array/join_with_or.rb +9 -9
  21. data/lib/xqsr3/extensions/enumerable/collect_with_index.rb +12 -12
  22. data/lib/xqsr3/extensions/enumerable/detect_map.rb +35 -35
  23. data/lib/xqsr3/extensions/enumerable/unique.rb +29 -28
  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 +28 -28
  33. data/lib/xqsr3/extensions/kernel/integer.rb +20 -20
  34. data/lib/xqsr3/extensions/kernel/raise_with_options.rb +8 -8
  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 -4
  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 -1
  41. data/lib/xqsr3/extensions/string/starts_with.rb +1 -1
  42. data/lib/xqsr3/extensions/string/to_bool.rb +8 -8
  43. data/lib/xqsr3/extensions/string/to_symbol.rb +1 -1
  44. data/lib/xqsr3/extensions/string/truncate.rb +1 -1
  45. data/lib/xqsr3/extensions/test/unit/assert_eql.rb +7 -7
  46. data/lib/xqsr3/extensions/test/unit/assert_false.rb +6 -6
  47. data/lib/xqsr3/extensions/test/unit/assert_not.rb +6 -6
  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 -61
  50. data/lib/xqsr3/extensions/test/unit/assert_subclass_of.rb +7 -7
  51. data/lib/xqsr3/extensions/test/unit/assert_superclass_of.rb +7 -7
  52. data/lib/xqsr3/extensions/test/unit/assert_true.rb +6 -6
  53. data/lib/xqsr3/extensions/test/unit/assert_type_has_instance_methods.rb +36 -36
  54. data/lib/xqsr3/extensions.rb +5 -5
  55. data/lib/xqsr3/hash_utilities/deep_transform.rb +65 -65
  56. data/lib/xqsr3/hash_utilities/key_matching.rb +77 -77
  57. data/lib/xqsr3/hash_utilities.rb +3 -3
  58. data/lib/xqsr3/internal_/test_unit_version_.rb +85 -85
  59. data/lib/xqsr3/io/writelines.rb +119 -119
  60. data/lib/xqsr3/quality/parameter_checking.rb +445 -445
  61. data/lib/xqsr3/quality.rb +2 -2
  62. data/lib/xqsr3/string_utilities/ends_with.rb +59 -59
  63. data/lib/xqsr3/string_utilities/nil_if_empty.rb +28 -28
  64. data/lib/xqsr3/string_utilities/nil_if_whitespace.rb +29 -29
  65. data/lib/xqsr3/string_utilities/quote_if.rb +50 -50
  66. data/lib/xqsr3/string_utilities/starts_with.rb +59 -59
  67. data/lib/xqsr3/string_utilities/to_symbol.rb +75 -75
  68. data/lib/xqsr3/string_utilities/truncate.rb +55 -55
  69. data/lib/xqsr3/string_utilities.rb +8 -8
  70. data/lib/xqsr3/version.rb +12 -12
  71. data/test/performance/frequency_map.rb +12 -12
  72. data/test/scratch/test_assert_raise_with_message.rb +11 -11
  73. data/test/unit/array_utilities/tc_join_with_or.rb +140 -140
  74. data/test/unit/command_line_utilities/tc_map_option_string.rb +18 -18
  75. data/test/unit/containers/tc_frequency_map.rb +591 -591
  76. data/test/unit/containers/tc_multi_map.rb +558 -558
  77. data/test/unit/conversion/tc_integer_parser.rb +72 -72
  78. data/test/unit/conversion/tc_to_bool.rb +25 -25
  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_slice.rb +13 -13
  87. data/test/unit/extensions/integer/tc_to_s_grp.rb +60 -0
  88. data/test/unit/extensions/integer/ts_all.rb +12 -0
  89. data/test/unit/extensions/io/tc_writelines.rb +77 -77
  90. data/test/unit/extensions/kernel/tc_integer.rb +75 -75
  91. data/test/unit/extensions/kernel/tc_raise_with_options.rb +155 -155
  92. data/test/unit/extensions/object/tc_inspect.rb +50 -50
  93. data/test/unit/extensions/string/tc_bool.tb +24 -24
  94. data/test/unit/extensions/string/tc_ends_with.rb +53 -53
  95. data/test/unit/extensions/string/tc_map_option_string.rb +15 -15
  96. data/test/unit/extensions/string/tc_nil_if_empty.rb +8 -8
  97. data/test/unit/extensions/string/tc_nil_if_whitespace.rb +8 -8
  98. data/test/unit/extensions/string/tc_quote_if.rb +18 -18
  99. data/test/unit/extensions/string/tc_starts_with.rb +53 -53
  100. data/test/unit/extensions/string/tc_to_symbol.rb +26 -26
  101. data/test/unit/extensions/string/tc_truncate.rb +18 -18
  102. data/test/unit/extensions/test/unit/tc_assert_raise_with_message.rb +16 -16
  103. data/test/unit/extensions/test/unit/tc_assert_subclass_of.rb +9 -9
  104. data/test/unit/extensions/test/unit/tc_assert_superclass_of.rb +9 -9
  105. data/test/unit/hash_utilities/tc_has_match.rb +70 -70
  106. data/test/unit/hash_utilities/tc_match.rb +83 -83
  107. data/test/unit/io/tc_writelines.rb +106 -106
  108. data/test/unit/quality/tc_parameter_checking.rb +389 -389
  109. data/test/unit/string_utilities/tc_truncate.rb +27 -27
  110. data/test/unit/tc_version.rb +15 -15
  111. metadata +6 -2
@@ -5,13 +5,13 @@
5
5
  # Purpose: multimap container
6
6
  #
7
7
  # Created: 21st March 2007
8
- # Updated: 11th December 2023
8
+ # Updated: 29th March 2024
9
9
  #
10
10
  # Home: http://github.com/synesissoftware/xqsr3
11
11
  #
12
12
  # Author: Matthew Wilson
13
13
  #
14
- # Copyright (c) 2019-2023, Matthew Wilson and Synesis Information Systems
14
+ # Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems
15
15
  # Copyright (c) 2007-2019, Matthew Wilson and Synesis Software
16
16
  # All rights reserved.
17
17
  #
@@ -57,628 +57,628 @@ module Containers
57
57
  # Hash-like class that stores as mapped values in arrays
58
58
  class MultiMap < ::Hash
59
59
 
60
- include Enumerable
60
+ include Enumerable
61
61
 
62
- # Creates an instance from the given arguments
63
- def self.[] *args
62
+ # Creates an instance from the given arguments
63
+ def self.[] *args
64
64
 
65
- return self.new if 0 == args.length
65
+ return self.new if 0 == args.length
66
66
 
67
- if 1 == args.length
67
+ if 1 == args.length
68
68
 
69
- arg = args[0]
69
+ arg = args[0]
70
70
 
71
- case arg
72
- when ::NilClass
71
+ case arg
72
+ when ::NilClass
73
73
 
74
- return self.new
75
- when ::Hash
74
+ return self.new
75
+ when ::Hash
76
76
 
77
- mm = self.new
77
+ mm = self.new
78
78
 
79
- arg.each do |k, v|
79
+ arg.each do |k, v|
80
80
 
81
- 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
82
82
 
83
- mm.store k, *v
84
- end
83
+ mm.store k, *v
84
+ end
85
85
 
86
- return mm
87
- when ::Array
86
+ return mm
87
+ when ::Array
88
88
 
89
- # accepted forms:
90
- #
91
- # 1. Empty array
92
- # 2. Array exclusively of arrays
89
+ # accepted forms:
90
+ #
91
+ # 1. Empty array
92
+ # 2. Array exclusively of arrays
93
93
 
94
- # 1. Empty array
94
+ # 1. Empty array
95
95
 
96
- return self.new if arg.empty?
96
+ return self.new if arg.empty?
97
97
 
98
- # 2. Array exclusively of arrays
98
+ # 2. Array exclusively of arrays
99
99
 
100
- if arg.all? { |el| ::Array === el }
100
+ if arg.all? { |el| ::Array === el }
101
101
 
102
- h = Hash.new { |hash, key| hash[key] = [] }
102
+ h = Hash.new { |hash, key| hash[key] = [] }
103
103
 
104
- arg.each do |ar|
104
+ arg.each do |ar|
105
105
 
106
- 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?
107
107
 
108
- key = ar.shift
108
+ key = ar.shift
109
109
 
110
- ar.each { |value| h[key] << value }
111
- end
110
+ ar.each { |value| h[key] << value }
111
+ end
112
112
 
113
- return self.[](h)
114
- end
113
+ return self.[](h)
114
+ end
115
115
 
116
116
 
117
117
 
118
- raise ArgumentError, "array parameter not in an accepted form for subscript initialisation"
119
- else
118
+ raise ArgumentError, "array parameter not in an accepted form for subscript initialisation"
119
+ else
120
120
 
121
- return self.[] arg.to_hash if arg.respond_to? :to_hash
121
+ return self.[] arg.to_hash if arg.respond_to? :to_hash
122
122
 
123
- raise TypeError, "given argument is neither a #{::Hash} nor an #{::Array} and does not respond to the to_hash method"
124
- end
123
+ raise TypeError, "given argument is neither a #{::Hash} nor an #{::Array} and does not respond to the to_hash method"
124
+ end
125
125
 
126
- else
126
+ else
127
127
 
128
- # treat all other argument permutations as having passed in an array
128
+ # treat all other argument permutations as having passed in an array
129
129
 
130
- return self.[] [ *args ]
131
- end
132
- end
130
+ return self.[] [ *args ]
131
+ end
132
+ end
133
133
 
134
- # Initialises an instance
135
- def initialize
134
+ # Initialises an instance
135
+ def initialize
136
136
 
137
- @merge_is_multi = true
137
+ @merge_is_multi = true
138
138
 
139
- @inner = Hash.new
140
- end
139
+ @inner = Hash.new
140
+ end
141
141
 
142
- # Obtains the values, if any, for the given key; returns +nil+ if no
143
- # values are stored
144
- def [] key
142
+ # Obtains the values, if any, for the given key; returns +nil+ if no
143
+ # values are stored
144
+ def [] key
145
145
 
146
- return @inner[key]
147
- end
146
+ return @inner[key]
147
+ end
148
148
 
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
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
160
160
 
161
- values = [] if values.nil?
161
+ values = [] if values.nil?
162
162
 
163
- 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
164
164
 
165
- store key, *values
166
- end
165
+ store key, *values
166
+ end
167
167
 
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
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
176
176
 
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
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
187
187
 
188
- false
189
- end
188
+ false
189
+ end
190
190
 
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
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
194
194
 
195
- @inner.assoc key
196
- end
195
+ @inner.assoc key
196
+ end
197
197
 
198
- # Removes all elements from the instance
199
- def clear
198
+ # Removes all elements from the instance
199
+ def clear
200
200
 
201
- @inner.clear
202
- end
201
+ @inner.clear
202
+ end
203
203
 
204
- # The total number of instances recorded
205
- def count
204
+ # The total number of instances recorded
205
+ def count
206
206
 
207
- @inner.each_value.map { |ar| ar.size}.inject(0, :+)
208
- end
207
+ @inner.each_value.map { |ar| ar.size}.inject(0, :+)
208
+ end
209
209
 
210
- # Deletes all values mapped with the given +key+
211
- #
212
- # * *Parameters:*
213
- # - +key+ The key to delete
214
- 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
215
215
 
216
- @inner.delete key
217
- end
216
+ @inner.delete key
217
+ end
218
218
 
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
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
227
227
 
228
- raise ArgumentError, "may only supply 0 or 1 defaults" if defaults.size > 1
229
- 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?
230
230
 
231
- @inner.each do |key, values|
231
+ @inner.each do |key, values|
232
232
 
233
- if values.empty? && !defaults.empty?
233
+ if values.empty? && !defaults.empty?
234
234
 
235
- yield key, defaults[0]
235
+ yield key, defaults[0]
236
236
 
237
- next
238
- end
237
+ next
238
+ end
239
239
 
240
- values.each { |value| yield key, value }
241
- end
242
- end
240
+ values.each { |value| yield key, value }
241
+ end
242
+ end
243
243
 
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
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
247
247
 
248
- return @inner.each_key unless block_given?
248
+ return @inner.each_key unless block_given?
249
249
 
250
- @inner.each_key { |key| yield key }
251
- end
250
+ @inner.each_key { |key| yield key }
251
+ end
252
252
 
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
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
256
256
 
257
- return @inner.each unless block_given?
257
+ return @inner.each unless block_given?
258
258
 
259
- @inner.each { |key, value| yield key, value }
260
- end
259
+ @inner.each { |key, value| yield key, value }
260
+ end
261
261
 
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
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
266
266
 
267
- return @inner.each_with_index unless block_given?
267
+ return @inner.each_with_index unless block_given?
268
268
 
269
- @inner.each_with_index { |kv, index| yield kv, index }
270
- end
269
+ @inner.each_with_index { |kv, index| yield kv, index }
270
+ end
271
271
 
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
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
275
275
 
276
- return @inner.each_value unless block_given?
276
+ return @inner.each_value unless block_given?
277
277
 
278
- @inner.each do |key, values|
278
+ @inner.each do |key, values|
279
279
 
280
- values.each { |value| yield value }
281
- end
282
- end
280
+ values.each { |value| yield value }
281
+ end
282
+ end
283
283
 
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
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
290
290
 
291
- raise ArgumentError, 'block is required' unless block_given?
291
+ raise ArgumentError, 'block is required' unless block_given?
292
292
 
293
- index = 0
294
- self.each do |key, value|
293
+ index = 0
294
+ self.each do |key, value|
295
295
 
296
- yield key, value, index
296
+ yield key, value, index
297
297
 
298
- index += 1
299
- end
300
- end
298
+ index += 1
299
+ end
300
+ end
301
301
 
302
- # Returns +true+ if instance contains no elements; +false+ otherwise
303
- def empty?
302
+ # Returns +true+ if instance contains no elements; +false+ otherwise
303
+ def empty?
304
304
 
305
- @inner.empty?
306
- end
305
+ @inner.empty?
306
+ end
307
307
 
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
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
311
311
 
312
- case rhs
313
- when self.class
314
- return self == rhs
315
- else
316
- return false
317
- end
318
- end
312
+ case rhs
313
+ when self.class
314
+ return self == rhs
315
+ else
316
+ return false
317
+ end
318
+ end
319
319
 
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
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
326
326
 
327
- unless default_parameter_defaulted_
327
+ unless default_parameter_defaulted_
328
328
 
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
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
336
336
 
337
- unless @inner.has_key? key
337
+ unless @inner.has_key? key
338
338
 
339
- return default unless default_parameter_defaulted_
339
+ return default unless default_parameter_defaulted_
340
340
 
341
- if block_given?
341
+ if block_given?
342
342
 
343
- r = nil
343
+ r = nil
344
344
 
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
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
353
353
 
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
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
359
359
 
360
- r = r.to_ary
361
- end
360
+ r = r.to_ary
361
+ end
362
362
 
363
- return r
364
- end
363
+ return r
364
+ end
365
365
 
366
- raise KeyError, "given key '#{key}' (#{key.class}) does not exist"
367
- end
366
+ raise KeyError, "given key '#{key}' (#{key.class}) does not exist"
367
+ end
368
368
 
369
- @inner.fetch key
370
- end
369
+ @inner.fetch key
370
+ end
371
371
 
372
- # Returns the equivalent flattened form of the instance
373
- def flatten
372
+ # Returns the equivalent flattened form of the instance
373
+ def flatten
374
374
 
375
- r = []
375
+ r = []
376
376
 
377
- @inner.each do |key, values|
377
+ @inner.each do |key, values|
378
378
 
379
- if values.empty?
379
+ if values.empty?
380
380
 
381
- r << key << []
382
- else
381
+ r << key << []
382
+ else
383
383
 
384
- values.each do |value|
384
+ values.each do |value|
385
385
 
386
- r << key << value
387
- end
388
- end
389
- end
386
+ r << key << value
387
+ end
388
+ end
389
+ end
390
390
 
391
- r
392
- end
391
+ r
392
+ end
393
393
 
394
- # Returns +true+ if an element with the given +key+ is in the map; +false+
395
- # otherwise
396
- 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
397
397
 
398
- @inner.has_key? key
399
- end
398
+ @inner.has_key? key
399
+ end
400
400
 
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
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
406
406
 
407
- @inner.each do |k, vals|
407
+ @inner.each do |k, vals|
408
408
 
409
- return true if vals.include? value
410
- end
409
+ return true if vals.include? value
410
+ end
411
411
 
412
- false
413
- end
412
+ false
413
+ end
414
414
 
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
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
423
423
 
424
- 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
425
425
 
426
- @inner.has_value? values
427
- end
426
+ @inner.has_value? values
427
+ end
428
428
 
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
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
439
439
 
440
- case values.size
441
- when 0
440
+ case values.size
441
+ when 0
442
442
 
443
- return nil
444
- when 1
443
+ return nil
444
+ when 1
445
445
 
446
- i = nil
446
+ i = nil
447
447
 
448
- @inner.each do |k, vals|
448
+ @inner.each do |k, vals|
449
449
 
450
- return k if vals == values
450
+ return k if vals == values
451
451
 
452
- if i.nil?
452
+ if i.nil?
453
453
 
454
- i = k if vals.include? values[0]
455
- end
456
- end
454
+ i = k if vals.include? values[0]
455
+ end
456
+ end
457
457
 
458
- return i
459
- else
458
+ return i
459
+ else
460
460
 
461
- @inner.each do |key, vals|
461
+ @inner.each do |key, vals|
462
462
 
463
- return key if vals == values
464
- end
463
+ return key if vals == values
464
+ end
465
465
 
466
- return nil
467
- end
468
- end
466
+ return nil
467
+ end
468
+ end
469
469
 
470
- # The number of elements in the map
471
- def length
470
+ # The number of elements in the map
471
+ def length
472
472
 
473
- @inner.size
474
- end
473
+ @inner.size
474
+ end
475
475
 
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
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
488
488
 
489
- mm = self.class.new
489
+ mm = self.class.new
490
490
 
491
- mm.merge! self
492
- mm.merge! other
491
+ mm.merge! self
492
+ mm.merge! other
493
493
 
494
- mm
495
- end
494
+ mm
495
+ end
496
496
 
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
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
508
508
 
509
- case other
510
- when self.class
509
+ case other
510
+ when self.class
511
511
 
512
- ;
513
- when ::Hash
512
+ ;
513
+ when ::Hash
514
514
 
515
- ;
516
- else
517
-
518
- raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
519
- end
515
+ ;
516
+ else
517
+
518
+ raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
519
+ end
520
520
 
521
- other.each do |k, v|
521
+ other.each do |k, v|
522
522
 
523
- self.push k, v
524
- end
523
+ self.push k, v
524
+ end
525
525
 
526
- self
527
- end
526
+ self
527
+ end
528
528
 
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
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
541
541
 
542
- mm = self.class.new
542
+ mm = self.class.new
543
543
 
544
- mm.strict_merge! self
545
- mm.strict_merge! other
544
+ mm.strict_merge! self
545
+ mm.strict_merge! other
546
546
 
547
- mm
548
- end
547
+ mm
548
+ end
549
549
 
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
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
561
561
 
562
- case other
563
- when self.class
562
+ case other
563
+ when self.class
564
564
 
565
- other.each_unflattened do |k, vals|
565
+ other.each_unflattened do |k, vals|
566
566
 
567
- self.store k, *vals
568
- end
569
- when ::Hash
567
+ self.store k, *vals
568
+ end
569
+ when ::Hash
570
570
 
571
- other.each do |k, v|
571
+ other.each do |k, v|
572
572
 
573
- self.store k, v
574
- end
575
- else
573
+ self.store k, v
574
+ end
575
+ else
576
576
 
577
- raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
578
- end
577
+ raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
578
+ end
579
579
 
580
- self
581
- end
580
+ self
581
+ end
582
582
 
583
- # See #merge
584
- def merge other
583
+ # See #merge
584
+ def merge other
585
585
 
586
- if @merge_is_multi
586
+ if @merge_is_multi
587
587
 
588
- multi_merge other
589
- else
588
+ multi_merge other
589
+ else
590
590
 
591
- strict_merge other
592
- end
593
- end
591
+ strict_merge other
592
+ end
593
+ end
594
594
 
595
- # See #merge!
596
- def merge! other
595
+ # See #merge!
596
+ def merge! other
597
597
 
598
- if @merge_is_multi
598
+ if @merge_is_multi
599
599
 
600
- multi_merge! other
601
- else
600
+ multi_merge! other
601
+ else
602
602
 
603
- strict_merge! other
604
- end
605
- end
603
+ strict_merge! other
604
+ end
605
+ end
606
606
 
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
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
620
620
 
621
- @inner[key] = [] unless @inner.has_key? key
621
+ @inner[key] = [] unless @inner.has_key? key
622
622
 
623
- @inner[key].push(*values)
624
- end
623
+ @inner[key].push(*values)
624
+ end
625
625
 
626
- # Removes a key-value pair from the instance and return as a two-item
627
- # array
628
- def shift
626
+ # Removes a key-value pair from the instance and return as a two-item
627
+ # array
628
+ def shift
629
629
 
630
- @inner.shift
631
- end
630
+ @inner.shift
631
+ end
632
632
 
633
- alias size length
633
+ alias size length
634
634
 
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
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
639
639
 
640
- @inner[key] = values
641
- end
640
+ @inner[key] = values
641
+ end
642
642
 
643
- # Converts instance to an array of +[key,value]+ pairs
644
- def to_a
643
+ # Converts instance to an array of +[key,value]+ pairs
644
+ def to_a
645
645
 
646
- self.flatten
647
- end
646
+ self.flatten
647
+ end
648
648
 
649
- # Obtains reference to internal hash instance (which must *not* be modified)
650
- def to_h
649
+ # Obtains reference to internal hash instance (which must *not* be modified)
650
+ def to_h
651
651
 
652
- @inner.to_h
653
- end
652
+ @inner.to_h
653
+ end
654
654
 
655
- # Obtains equivalent hash to instance
656
- def to_hash
655
+ # Obtains equivalent hash to instance
656
+ def to_hash
657
657
 
658
- @elements.to_hash
659
- end
658
+ @elements.to_hash
659
+ end
660
660
 
661
- # A string-form of the instance
662
- def to_s
661
+ # A string-form of the instance
662
+ def to_s
663
663
 
664
- @inner.to_s
665
- end
664
+ @inner.to_s
665
+ end
666
666
 
667
- # An array of all values in the instance
668
- def values
667
+ # An array of all values in the instance
668
+ def values
669
669
 
670
- r = []
670
+ r = []
671
671
 
672
- @inner.values.each { |vals| r += vals }
672
+ @inner.values.each { |vals| r += vals }
673
673
 
674
- r
675
- end
674
+ r
675
+ end
676
676
 
677
- # An array of all sets of values in the instance
678
- def values_unflattened
677
+ # An array of all sets of values in the instance
678
+ def values_unflattened
679
679
 
680
- @inner.values
681
- end
680
+ @inner.values
681
+ end
682
682
  end # class MultiMap
683
683
 
684
684
  end # module Containers