xqsr3 0.32.2 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/xqsr3/all_extensions.rb +6 -0
- data/lib/xqsr3/array_utilities.rb +10 -0
- data/lib/xqsr3/array_utilities/join_with_or.rb +7 -14
- data/lib/xqsr3/command_line_utilities.rb +10 -0
- data/lib/xqsr3/command_line_utilities/map_option_string.rb +21 -8
- data/lib/xqsr3/containers.rb +11 -0
- data/lib/xqsr3/containers/frequency_map.rb +19 -2
- data/lib/xqsr3/containers/multi_map.rb +316 -27
- data/lib/xqsr3/conversion.rb +11 -0
- data/lib/xqsr3/conversion/bool_parser.rb +11 -14
- data/lib/xqsr3/conversion/integer_parser.rb +10 -16
- data/lib/xqsr3/diagnostics.rb +11 -0
- data/lib/xqsr3/diagnostics/exception_utilities.rb +2 -2
- data/lib/xqsr3/diagnostics/exceptions/with_cause.rb +15 -7
- data/lib/xqsr3/diagnostics/inspect_builder.rb +16 -16
- data/lib/xqsr3/doc_.rb +138 -9
- data/lib/xqsr3/extensions.rb +13 -0
- data/lib/xqsr3/extensions/array.rb +3 -0
- data/lib/xqsr3/extensions/array/join_with_or.rb +6 -0
- data/lib/xqsr3/extensions/enumerable/collect_with_index.rb +5 -4
- data/lib/xqsr3/extensions/enumerable/detect_map.rb +6 -7
- data/lib/xqsr3/extensions/hash.rb +5 -0
- data/lib/xqsr3/extensions/hash/has_match.rb +7 -0
- data/lib/xqsr3/extensions/hash/match.rb +7 -0
- data/lib/xqsr3/extensions/hash/slice.rb +22 -0
- data/lib/xqsr3/extensions/io/writelines.rb +38 -6
- data/lib/xqsr3/extensions/kernel/integer.rb +6 -13
- data/lib/xqsr3/extensions/string/to_bool.rb +4 -0
- data/lib/xqsr3/extensions/test/unit/assert_eql.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_false.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_not.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_not_eql.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_raise_with_message.rb +25 -4
- data/lib/xqsr3/extensions/test/unit/assert_subclass_of.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_superclass_of.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_true.rb +1 -0
- data/lib/xqsr3/extensions/test/unit/assert_type_has_instance_methods.rb +3 -12
- data/lib/xqsr3/hash_utilities.rb +11 -0
- data/lib/xqsr3/hash_utilities/deep_transform.rb +2 -2
- data/lib/xqsr3/hash_utilities/key_matching.rb +6 -4
- data/lib/xqsr3/internal_/test_unit_version_.rb +30 -4
- data/lib/xqsr3/io/writelines.rb +55 -19
- data/lib/xqsr3/quality.rb +8 -1
- data/lib/xqsr3/quality/parameter_checking.rb +52 -78
- data/lib/xqsr3/string_utilities.rb +16 -0
- data/lib/xqsr3/string_utilities/ends_with.rb +16 -7
- data/lib/xqsr3/string_utilities/nil_if_empty.rb +8 -4
- data/lib/xqsr3/string_utilities/nil_if_whitespace.rb +9 -4
- data/lib/xqsr3/string_utilities/quote_if.rb +12 -14
- data/lib/xqsr3/string_utilities/starts_with.rb +23 -5
- data/lib/xqsr3/string_utilities/to_symbol.rb +24 -5
- data/lib/xqsr3/string_utilities/truncate.rb +20 -4
- data/lib/xqsr3/version.rb +3 -2
- data/test/unit/containers/tc_multi_map.rb +174 -16
- data/test/unit/extensions/hash/tc_hash.rb +6 -0
- data/test/unit/extensions/hash/tc_slice.rb +31 -0
- data/test/unit/extensions/io/tc_writelines.rb +36 -0
- metadata +16 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4e3f5e422b5b6d6f88ee0c0eb620f38ce468ef54e1cf9d55ab41f24e909c897b
|
4
|
+
data.tar.gz: 80f3675582a96f52a108687c4a77911691972dd0a2167138ffa0c9992c13e3ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41b2ac34f613f74b684223073ff61c3350b8433bda18520bb0af25db2464a22ed1be8fe53859eaf37f60d366d7053d8cab77d653b45b33a57ebd1a619b6186c6
|
7
|
+
data.tar.gz: 28d271b3501677420540ec6a55b1bf69bedf398dc422362ff7ca5e50e1d827d4f4fccc45c73eece170949bab755a47472d78f207a0b7c992cb942b13d368be76
|
@@ -56,6 +56,7 @@ require 'xqsr3/quality/parameter_checking'
|
|
56
56
|
module Xqsr3
|
57
57
|
module ArrayUtilities
|
58
58
|
|
59
|
+
# +include+-able module that provides sequence-joining functionality
|
59
60
|
module JoinWithOr
|
60
61
|
|
61
62
|
extend self
|
@@ -65,22 +66,14 @@ module JoinWithOr
|
|
65
66
|
# === Signature
|
66
67
|
#
|
67
68
|
# * *Parameters:*
|
68
|
-
#
|
69
|
-
#
|
70
|
-
# - +ar+:: [Array] The array whose contents are to be joined
|
71
|
-
#
|
72
|
-
# * *Options parameters*:
|
73
|
-
# - +options+:: [Hash] Options that control the behaviour of the
|
74
|
-
# method
|
69
|
+
# - +ar+ (Array) The array whose contents are to be joined
|
70
|
+
# - +options+ (Hash) Options that control the behaviour of the method
|
75
71
|
#
|
76
72
|
# * *Options:*
|
77
|
-
#
|
78
|
-
# - +:
|
79
|
-
# - +:
|
80
|
-
#
|
81
|
-
# - +:quote_char+ [String] The quote character. Default is empty
|
82
|
-
# string
|
83
|
-
# - +:separator+ [String] The separator character. Default is +','+
|
73
|
+
# - +:or+ (String) A string that is used instead of 'or'
|
74
|
+
# - +:oxford_comma+ (boolean) Determines whether an Oxford comma will be used. Default is +true+
|
75
|
+
# - +:quote_char+ (String) The quote character. Default is empty string ''
|
76
|
+
# - +:separator+ (String) The separator character. Default is ','
|
84
77
|
def join_with_or ar, **options
|
85
78
|
|
86
79
|
::Xqsr3::Quality::ParameterChecking.check_parameter ar, 'ar', type: ::Array, allow_nil: true
|
@@ -6,13 +6,13 @@
|
|
6
6
|
# ::Xqsr3::CommandLineUtilities::MapOptionString module
|
7
7
|
#
|
8
8
|
# Created: 15th April 2016
|
9
|
-
# Updated:
|
9
|
+
# Updated: 15th April 2019
|
10
10
|
#
|
11
11
|
# Home: http://github.com/synesissoftware/xqsr3
|
12
12
|
#
|
13
13
|
# Author: Matthew Wilson
|
14
14
|
#
|
15
|
-
# Copyright (c) 2016-
|
15
|
+
# Copyright (c) 2016-2019, Matthew Wilson and Synesis Software
|
16
16
|
# All rights reserved.
|
17
17
|
#
|
18
18
|
# Redistribution and use in source and binary forms, with or without
|
@@ -56,21 +56,21 @@ require 'xqsr3/string_utilities/to_symbol'
|
|
56
56
|
module Xqsr3
|
57
57
|
module CommandLineUtilities
|
58
58
|
|
59
|
-
#
|
59
|
+
# +include+-able module providing facilities for mapping strings to options
|
60
60
|
#
|
61
61
|
# === Components of interest
|
62
|
-
# * ::Xqsr3::CommandLineUtilities::MapOptionString.
|
62
|
+
# * ::Xqsr3::CommandLineUtilities::MapOptionString.map_option_string_from_string
|
63
|
+
# * ::Xqsr3::CommandLineUtilities::MapOptionString#map_option_string
|
63
64
|
module MapOptionString
|
64
65
|
|
65
|
-
# :nodoc:
|
66
|
-
def self.included includer
|
66
|
+
def self.included includer # :nodoc:
|
67
67
|
|
68
68
|
raise TypeError, "module #{self} cannot be included into #{includer} because it does not respond to to_str" unless includer.method_defined? :to_str
|
69
69
|
end
|
70
70
|
|
71
71
|
private
|
72
|
-
#
|
73
|
-
module MapOptionString_Helper_ # :nodoc:
|
72
|
+
# @!visibility private
|
73
|
+
module MapOptionString_Helper_ # :nodoc: all
|
74
74
|
|
75
75
|
def self.map_option_string_with_options_ s, option_strings, options
|
76
76
|
|
@@ -117,6 +117,13 @@ module MapOptionString
|
|
117
117
|
|
118
118
|
# Attempts to translate the value of a given string according
|
119
119
|
# to a collection of options strings
|
120
|
+
#
|
121
|
+
# === Signature
|
122
|
+
#
|
123
|
+
# * *Parameters:*
|
124
|
+
# - +s+ (::String) The string to be mapped
|
125
|
+
# - +option_strings+ ([::String]) An array of strings against which the mapping will be performed
|
126
|
+
# - +options+ (Hash) Options that control the behaviour of the method
|
120
127
|
def self.map_option_string_from_string s, option_strings, options = {}
|
121
128
|
|
122
129
|
MapOptionString_Helper_.map_option_string_with_options_ s, option_strings, options
|
@@ -124,6 +131,11 @@ module MapOptionString
|
|
124
131
|
|
125
132
|
# Attempts to translate the (string) value of the receiver according
|
126
133
|
# to a collection of options strings
|
134
|
+
#
|
135
|
+
# === Signature
|
136
|
+
#
|
137
|
+
# * *Parameters:*
|
138
|
+
# - +option_strings+ ([::String]) An array of strings against which the mapping will be performed
|
127
139
|
def map_option_string option_strings, options = {}
|
128
140
|
|
129
141
|
s = self.kind_of?(::String) ? self : self.to_str
|
@@ -137,3 +149,4 @@ end # module Xqsr3
|
|
137
149
|
|
138
150
|
# ############################## end of file ############################# #
|
139
151
|
|
152
|
+
|
@@ -5,7 +5,7 @@
|
|
5
5
|
# Purpose: FrequencyMap container
|
6
6
|
#
|
7
7
|
# Created: 28th January 2005
|
8
|
-
# Updated:
|
8
|
+
# Updated: 15th April 2019
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
@@ -77,6 +77,7 @@ class FrequencyMap
|
|
77
77
|
# fm[:z] # => 0
|
78
78
|
ByElement = Class.new do
|
79
79
|
|
80
|
+
# Create an instance of Xqsr3::FrequencyMap from an array
|
80
81
|
def self.[] *args
|
81
82
|
|
82
83
|
fm = FrequencyMap.new
|
@@ -163,7 +164,7 @@ class FrequencyMap
|
|
163
164
|
# Pushes an element into the map, assigning it an initial count of 1
|
164
165
|
#
|
165
166
|
# * *Parameters:*
|
166
|
-
# - +key
|
167
|
+
# - +key+ The element to insert
|
167
168
|
def << key
|
168
169
|
|
169
170
|
push key, 1
|
@@ -180,12 +181,16 @@ class FrequencyMap
|
|
180
181
|
|
181
182
|
case rhs
|
182
183
|
when ::NilClass
|
184
|
+
|
183
185
|
return false
|
184
186
|
when ::Hash
|
187
|
+
|
185
188
|
return rhs.size == @elements.size && rhs == @elements
|
186
189
|
when self.class
|
190
|
+
|
187
191
|
return rhs.count == self.count && rhs == @elements
|
188
192
|
else
|
193
|
+
|
189
194
|
raise TypeError, "can compare #{self.class} only to instances of #{self.class} and #{::Hash}, but #{rhs.class} given"
|
190
195
|
end
|
191
196
|
|
@@ -407,6 +412,12 @@ class FrequencyMap
|
|
407
412
|
|
408
413
|
# Returns +true+ if an element with a count of the given +value+ is in the
|
409
414
|
# map; +false+ otherwise
|
415
|
+
#
|
416
|
+
# * *Parameters:*
|
417
|
+
# - +value+ (Integer) The value of the count for which to search
|
418
|
+
#
|
419
|
+
# * *Exceptions:*
|
420
|
+
# - +::TypeError+ if +value+ is not an Integer
|
410
421
|
def has_value? value
|
411
422
|
|
412
423
|
case value
|
@@ -437,6 +448,8 @@ class FrequencyMap
|
|
437
448
|
#
|
438
449
|
# @elements.keep_if
|
439
450
|
# end
|
451
|
+
=begin
|
452
|
+
=end
|
440
453
|
|
441
454
|
# Returns the element that has the given count, or +nil+ if none found
|
442
455
|
#
|
@@ -540,6 +553,8 @@ class FrequencyMap
|
|
540
553
|
self
|
541
554
|
end
|
542
555
|
|
556
|
+
# Removes a key-value pair from the instance and return as a two-item
|
557
|
+
# array
|
543
558
|
def shift
|
544
559
|
|
545
560
|
r = @elements.shift
|
@@ -589,11 +604,13 @@ class FrequencyMap
|
|
589
604
|
@elements.to_hash
|
590
605
|
end
|
591
606
|
|
607
|
+
# A string-form of the instance
|
592
608
|
def to_s
|
593
609
|
|
594
610
|
@elements.to_s
|
595
611
|
end
|
596
612
|
|
613
|
+
# An array of all frequencies (without element keys) in the instance
|
597
614
|
def values
|
598
615
|
|
599
616
|
@elements.values
|
@@ -5,7 +5,7 @@
|
|
5
5
|
# Purpose: multimap container
|
6
6
|
#
|
7
7
|
# Created: 21st March 2007
|
8
|
-
# Updated:
|
8
|
+
# Updated: 15th April 2019
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
@@ -53,10 +53,12 @@
|
|
53
53
|
module Xqsr3
|
54
54
|
module Containers
|
55
55
|
|
56
|
+
# Hash-like class that stores as mapped values in arrays
|
56
57
|
class MultiMap < ::Hash
|
57
58
|
|
58
59
|
include Enumerable
|
59
60
|
|
61
|
+
# Creates an instance from the given arguments
|
60
62
|
def self.[] *args
|
61
63
|
|
62
64
|
return self.new if 0 == args.length
|
@@ -71,16 +73,16 @@ class MultiMap < ::Hash
|
|
71
73
|
return self.new
|
72
74
|
when ::Hash
|
73
75
|
|
74
|
-
|
76
|
+
mm = self.new
|
75
77
|
|
76
78
|
arg.each do |k, v|
|
77
79
|
|
78
80
|
raise ArgumentError, "mapped elements in hashes must be arrays, #{v.class} given" unless v.kind_of? ::Array
|
79
81
|
|
80
|
-
|
82
|
+
mm.store k, *v
|
81
83
|
end
|
82
84
|
|
83
|
-
return
|
85
|
+
return mm
|
84
86
|
when ::Array
|
85
87
|
|
86
88
|
# accepted forms:
|
@@ -128,16 +130,31 @@ class MultiMap < ::Hash
|
|
128
130
|
end
|
129
131
|
end
|
130
132
|
|
133
|
+
# Initialises an instance
|
131
134
|
def initialize
|
132
135
|
|
136
|
+
@merge_is_multi = true
|
137
|
+
|
133
138
|
@inner = Hash.new
|
134
139
|
end
|
135
140
|
|
141
|
+
# Obtains the values, if any, for the given key; returns +nil+ if no
|
142
|
+
# values are stored
|
136
143
|
def [] key
|
137
144
|
|
138
145
|
return @inner[key]
|
139
146
|
end
|
140
147
|
|
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
|
141
158
|
def []= key, values
|
142
159
|
|
143
160
|
values = [] if values.nil?
|
@@ -147,6 +164,13 @@ class MultiMap < ::Hash
|
|
147
164
|
store key, *values
|
148
165
|
end
|
149
166
|
|
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)
|
150
174
|
def == rhs
|
151
175
|
|
152
176
|
case rhs
|
@@ -163,29 +187,45 @@ class MultiMap < ::Hash
|
|
163
187
|
false
|
164
188
|
end
|
165
189
|
|
190
|
+
# Searches the instance comparing each element with +key+, returning the
|
191
|
+
# mapped values array if found, or +nil+ if not
|
166
192
|
def assoc key
|
167
193
|
|
168
194
|
@inner.assoc key
|
169
195
|
end
|
170
196
|
|
197
|
+
# Removes all elements from the instance
|
171
198
|
def clear
|
172
199
|
|
173
200
|
@inner.clear
|
174
201
|
end
|
175
202
|
|
203
|
+
# The total number of instances recorded
|
176
204
|
def count
|
177
205
|
|
178
206
|
@inner.each_value.map { |ar| ar.size}.inject(0, :+)
|
179
207
|
end
|
180
208
|
|
209
|
+
# Deletes all values mapped with the given +key+
|
210
|
+
#
|
211
|
+
# * *Parameters:*
|
212
|
+
# - +key+ The key to delete
|
181
213
|
def delete key
|
182
214
|
|
183
215
|
@inner.delete key
|
184
216
|
end
|
185
217
|
|
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
|
186
225
|
def each *defaults
|
187
226
|
|
188
227
|
raise ArgumentError, "may only supply 0 or 1 defaults" if defaults.size > 1
|
228
|
+
raise ArgumentError, 'block is required' unless block_given?
|
189
229
|
|
190
230
|
@inner.each do |key, values|
|
191
231
|
|
@@ -200,6 +240,8 @@ class MultiMap < ::Hash
|
|
200
240
|
end
|
201
241
|
end
|
202
242
|
|
243
|
+
# Calls _block_ once for each key in the instance, passing the key. If no
|
244
|
+
# block is provided, an enumerator is returned
|
203
245
|
def each_key
|
204
246
|
|
205
247
|
return @inner.each_key unless block_given?
|
@@ -207,26 +249,46 @@ class MultiMap < ::Hash
|
|
207
249
|
@inner.each_key { |key| yield key }
|
208
250
|
end
|
209
251
|
|
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
|
210
254
|
def each_unflattened
|
211
255
|
|
256
|
+
return @inner.each unless block_given?
|
257
|
+
|
212
258
|
@inner.each { |key, value| yield key, value }
|
213
259
|
end
|
214
260
|
|
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
|
215
264
|
def each_unflattened_with_index
|
216
265
|
|
266
|
+
return @inner.each_with_index unless block_given?
|
267
|
+
|
217
268
|
@inner.each_with_index { |kv, index| yield kv, index }
|
218
269
|
end
|
219
270
|
|
271
|
+
# Calls _block_ once for each value in the instance, passing the value.
|
272
|
+
# If no block is provided, an enumerator is returned
|
220
273
|
def each_value
|
221
274
|
|
275
|
+
return @inner.each_value unless block_given?
|
276
|
+
|
222
277
|
@inner.each do |key, values|
|
223
278
|
|
224
279
|
values.each { |value| yield value }
|
225
280
|
end
|
226
281
|
end
|
227
282
|
|
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
|
228
288
|
def each_with_index
|
229
289
|
|
290
|
+
raise ArgumentError, 'block is required' unless block_given?
|
291
|
+
|
230
292
|
index = 0
|
231
293
|
self.each do |key, value|
|
232
294
|
|
@@ -236,11 +298,14 @@ class MultiMap < ::Hash
|
|
236
298
|
end
|
237
299
|
end
|
238
300
|
|
301
|
+
# Returns +true+ if instance contains no elements; +false+ otherwise
|
239
302
|
def empty?
|
240
303
|
|
241
304
|
@inner.empty?
|
242
305
|
end
|
243
306
|
|
307
|
+
# Returns +true+ if +rhs+ is an instance of +MultiMap+ and contains
|
308
|
+
# the same elements and their counts; +false+ otherwise
|
244
309
|
def eql? rhs
|
245
310
|
|
246
311
|
case rhs
|
@@ -251,18 +316,26 @@ class MultiMap < ::Hash
|
|
251
316
|
end
|
252
317
|
end
|
253
318
|
|
254
|
-
|
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
|
255
325
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
326
|
+
unless default_parameter_defaulted_
|
327
|
+
|
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
|
261
334
|
end
|
262
335
|
|
263
336
|
unless @inner.has_key? key
|
264
337
|
|
265
|
-
return default unless
|
338
|
+
return default unless default_parameter_defaulted_
|
266
339
|
|
267
340
|
if block_given?
|
268
341
|
|
@@ -295,6 +368,7 @@ class MultiMap < ::Hash
|
|
295
368
|
@inner.fetch key
|
296
369
|
end
|
297
370
|
|
371
|
+
# Returns the equivalent flattened form of the instance
|
298
372
|
def flatten
|
299
373
|
|
300
374
|
r = []
|
@@ -316,36 +390,134 @@ class MultiMap < ::Hash
|
|
316
390
|
r
|
317
391
|
end
|
318
392
|
|
393
|
+
# Returns +true+ if an element with the given +key+ is in the map; +false+
|
394
|
+
# otherwise
|
319
395
|
def has_key? key
|
320
396
|
|
321
397
|
@inner.has_key? key
|
322
398
|
end
|
323
399
|
|
400
|
+
# Returns +true+ if any key has the given +value+; +false+ otherwise
|
401
|
+
#
|
402
|
+
# * *Parameters:*
|
403
|
+
# - +value+ The value for which to search
|
324
404
|
def has_value? value
|
325
405
|
|
326
|
-
@inner.
|
406
|
+
@inner.each do |k, vals|
|
407
|
+
|
408
|
+
return true if vals.include? value
|
409
|
+
end
|
410
|
+
|
411
|
+
false
|
327
412
|
end
|
328
413
|
|
329
|
-
|
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
|
330
422
|
|
331
|
-
|
423
|
+
raise TypeError, "'values' parameter must be of type #{::Array}" unless Array === values
|
424
|
+
|
425
|
+
@inner.has_value? values
|
332
426
|
end
|
333
427
|
|
334
|
-
|
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
|
438
|
+
|
439
|
+
case values.size
|
440
|
+
when 0
|
441
|
+
|
442
|
+
return nil
|
443
|
+
when 1
|
335
444
|
|
336
|
-
|
445
|
+
i = nil
|
337
446
|
|
338
|
-
|
447
|
+
@inner.each do |k, vals|
|
339
448
|
|
340
|
-
|
341
|
-
fm_new.merge! fm
|
449
|
+
return k if vals == values
|
342
450
|
|
343
|
-
|
451
|
+
if i.nil?
|
452
|
+
|
453
|
+
i = k if vals.include? values[0]
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
return i
|
458
|
+
else
|
459
|
+
|
460
|
+
@inner.each do |key, vals|
|
461
|
+
|
462
|
+
return key if vals == values
|
463
|
+
end
|
464
|
+
|
465
|
+
return nil
|
466
|
+
end
|
344
467
|
end
|
345
468
|
|
346
|
-
|
469
|
+
# The number of elements in the map
|
470
|
+
def length
|
347
471
|
|
348
|
-
|
472
|
+
@inner.size
|
473
|
+
end
|
474
|
+
|
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
|
487
|
+
|
488
|
+
mm = self.class.new
|
489
|
+
|
490
|
+
mm.merge! self
|
491
|
+
mm.merge! other
|
492
|
+
|
493
|
+
mm
|
494
|
+
end
|
495
|
+
|
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
|
507
|
+
|
508
|
+
case other
|
509
|
+
when self.class
|
510
|
+
|
511
|
+
;
|
512
|
+
when ::Hash
|
513
|
+
|
514
|
+
;
|
515
|
+
else
|
516
|
+
|
517
|
+
raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
|
518
|
+
end
|
519
|
+
|
520
|
+
other.each do |k, v|
|
349
521
|
|
350
522
|
self.push k, v
|
351
523
|
end
|
@@ -353,6 +525,96 @@ class MultiMap < ::Hash
|
|
353
525
|
self
|
354
526
|
end
|
355
527
|
|
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
|
540
|
+
|
541
|
+
mm = self.class.new
|
542
|
+
|
543
|
+
mm.strict_merge! self
|
544
|
+
mm.strict_merge! other
|
545
|
+
|
546
|
+
mm
|
547
|
+
end
|
548
|
+
|
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
|
560
|
+
|
561
|
+
case other
|
562
|
+
when self.class
|
563
|
+
|
564
|
+
other.each_unflattened do |k, vals|
|
565
|
+
|
566
|
+
self.store k, *vals
|
567
|
+
end
|
568
|
+
when ::Hash
|
569
|
+
|
570
|
+
other.each do |k, v|
|
571
|
+
|
572
|
+
self.store k, v
|
573
|
+
end
|
574
|
+
else
|
575
|
+
|
576
|
+
raise TypeError, "parameter must be an instance of #{self.class} or #{Hash}"
|
577
|
+
end
|
578
|
+
|
579
|
+
self
|
580
|
+
end
|
581
|
+
|
582
|
+
# See #merge
|
583
|
+
def merge other
|
584
|
+
|
585
|
+
if @merge_is_multi
|
586
|
+
|
587
|
+
multi_merge other
|
588
|
+
else
|
589
|
+
|
590
|
+
strict_merge other
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
# See #merge!
|
595
|
+
def merge! other
|
596
|
+
|
597
|
+
if @merge_is_multi
|
598
|
+
|
599
|
+
multi_merge! other
|
600
|
+
else
|
601
|
+
|
602
|
+
strict_merge! other
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
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+
|
356
618
|
def push key, *values
|
357
619
|
|
358
620
|
@inner[key] = [] unless @inner.has_key? key
|
@@ -360,33 +622,60 @@ class MultiMap < ::Hash
|
|
360
622
|
@inner[key].push(*values)
|
361
623
|
end
|
362
624
|
|
625
|
+
# Removes a key-value pair from the instance and return as a two-item
|
626
|
+
# array
|
363
627
|
def shift
|
364
628
|
|
365
629
|
@inner.shift
|
366
630
|
end
|
367
631
|
|
368
|
-
|
369
|
-
|
370
|
-
@inner.size
|
371
|
-
end
|
632
|
+
alias size length
|
372
633
|
|
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
|
373
637
|
def store key, *values
|
374
638
|
|
375
639
|
@inner[key] = values
|
376
640
|
end
|
377
641
|
|
642
|
+
# Converts instance to an array of +[key,value]+ pairs
|
378
643
|
def to_a
|
379
644
|
|
380
645
|
self.flatten
|
381
646
|
end
|
382
647
|
|
648
|
+
# Obtains reference to internal hash instance (which must *not* be modified)
|
383
649
|
def to_h
|
384
650
|
|
385
|
-
@inner.
|
651
|
+
@inner.to_h
|
386
652
|
end
|
387
653
|
|
654
|
+
# Obtains equivalent hash to instance
|
655
|
+
def to_hash
|
656
|
+
|
657
|
+
@elements.to_hash
|
658
|
+
end
|
659
|
+
|
660
|
+
# A string-form of the instance
|
661
|
+
def to_s
|
662
|
+
|
663
|
+
@inner.to_s
|
664
|
+
end
|
665
|
+
|
666
|
+
# An array of all values in the instance
|
388
667
|
def values
|
389
668
|
|
669
|
+
r = []
|
670
|
+
|
671
|
+
@inner.values.each { |vals| r += vals }
|
672
|
+
|
673
|
+
r
|
674
|
+
end
|
675
|
+
|
676
|
+
# An array of all sets of values in the instance
|
677
|
+
def values_unflattened
|
678
|
+
|
390
679
|
@inner.values
|
391
680
|
end
|
392
681
|
end # class MultiMap
|