gorillib 0.0.8 → 0.1.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.
- data/CHANGELOG.textile +6 -0
- data/README.textile +34 -11
- data/VERSION +1 -1
- data/gorillib.gemspec +63 -5
- data/lib/gorillib/enumerable/sum.rb +2 -2
- data/lib/gorillib/hash/compact.rb +2 -29
- data/lib/gorillib/hash/deep_compact.rb +2 -12
- data/lib/gorillib/hash/deep_dup.rb +4 -0
- data/lib/gorillib/hash/deep_merge.rb +2 -14
- data/lib/gorillib/hash/indifferent_access.rb +207 -0
- data/lib/gorillib/hash/keys.rb +2 -40
- data/lib/gorillib/hash/reverse_merge.rb +2 -24
- data/lib/gorillib/hash/slice.rb +2 -51
- data/lib/gorillib/hash/tree_merge.rb +4 -0
- data/lib/gorillib/hashlike.rb +824 -0
- data/lib/gorillib/hashlike/compact.rb +60 -0
- data/lib/gorillib/hashlike/deep_compact.rb +18 -0
- data/lib/gorillib/hashlike/deep_dup.rb +15 -0
- data/lib/gorillib/hashlike/deep_merge.rb +20 -0
- data/lib/gorillib/hashlike/hashlike_via_accessors.rb +169 -0
- data/lib/gorillib/hashlike/keys.rb +59 -0
- data/lib/gorillib/hashlike/reverse_merge.rb +31 -0
- data/lib/gorillib/hashlike/slice.rb +67 -0
- data/lib/gorillib/hashlike/tree_merge.rb +76 -0
- data/lib/gorillib/metaprogramming/mattr_accessor.rb +1 -1
- data/lib/gorillib/receiver.rb +315 -0
- data/lib/gorillib/receiver/active_model_shim.rb +19 -0
- data/lib/gorillib/receiver/acts_as_hash.rb +191 -0
- data/lib/gorillib/receiver/acts_as_loadable.rb +42 -0
- data/lib/gorillib/receiver/tree_diff.rb +74 -0
- data/lib/gorillib/receiver/validations.rb +30 -0
- data/lib/gorillib/struct/acts_as_hash.rb +108 -0
- data/lib/gorillib/struct/hashlike_iteration.rb +0 -0
- data/notes/fancy_hashes_and_receivers.textile +120 -0
- data/notes/hash_rdocs.textile +97 -0
- data/spec/hash/deep_merge_spec.rb +0 -2
- data/spec/hash/indifferent_access_spec.rb +391 -0
- data/spec/hash/slice_spec.rb +35 -12
- data/spec/hashlike/behave_same_as_hash_spec.rb +105 -0
- data/spec/hashlike/hashlike_behavior_spec.rb +824 -0
- data/spec/hashlike/hashlike_via_accessors_fuzzing_spec.rb +37 -0
- data/spec/hashlike/hashlike_via_accessors_spec.rb +262 -0
- data/spec/hashlike_spec.rb +302 -0
- data/spec/metaprogramming/aliasing_spec.rb +3 -0
- data/spec/metaprogramming/cattr_accessor_spec.rb +2 -0
- data/spec/metaprogramming/class_attribute_spec.rb +2 -0
- data/spec/metaprogramming/delegation_spec.rb +2 -0
- data/spec/metaprogramming/mattr_accessor_spec.rb +2 -0
- data/spec/metaprogramming/singleton_class_spec.rb +3 -0
- data/spec/receiver/acts_as_hash_spec.rb +286 -0
- data/spec/receiver_spec.rb +478 -0
- data/spec/spec_helper.rb +11 -6
- data/spec/string/truncate_spec.rb +1 -0
- data/spec/struct/acts_as_hash_fuzz_spec.rb +67 -0
- data/spec/struct/acts_as_hash_spec.rb +426 -0
- data/spec/support/hashlike_fuzzing_helper.rb +127 -0
- data/spec/support/hashlike_helper.rb +75 -0
- data/spec/support/hashlike_struct_helper.rb +37 -0
- data/spec/support/hashlike_via_delegation.rb +30 -0
- data/spec/support/matchers/be_array_eql.rb +12 -0
- data/spec/support/matchers/be_hash_eql.rb +14 -0
- data/spec/support/matchers/enumerate_method.rb +10 -0
- data/spec/support/matchers/evaluate_to_true.rb +5 -0
- metadata +62 -4
data/lib/gorillib/hash/keys.rb
CHANGED
@@ -1,42 +1,4 @@
|
|
1
|
+
require 'gorillib/hashlike/keys'
|
1
2
|
class Hash
|
2
|
-
|
3
|
-
def stringify_keys
|
4
|
-
dup.stringify_keys!
|
5
|
-
end unless method_defined?(:stringify_keys)
|
6
|
-
|
7
|
-
# Destructively convert all keys to strings.
|
8
|
-
def stringify_keys!
|
9
|
-
keys.each do |key|
|
10
|
-
self[key.to_s] = delete(key)
|
11
|
-
end
|
12
|
-
self
|
13
|
-
end unless method_defined?(:stringify_keys!)
|
14
|
-
|
15
|
-
# Return a new hash with all keys converted to symbols, as long as
|
16
|
-
# they respond to +to_sym+.
|
17
|
-
def symbolize_keys
|
18
|
-
dup.symbolize_keys!
|
19
|
-
end unless method_defined?(:symbolize_keys)
|
20
|
-
|
21
|
-
# Destructively convert all keys to symbols, as long as they respond
|
22
|
-
# to +to_sym+.
|
23
|
-
def symbolize_keys!
|
24
|
-
keys.each do |key|
|
25
|
-
self[(key.to_sym rescue key) || key] = delete(key)
|
26
|
-
end
|
27
|
-
self
|
28
|
-
end unless method_defined?(:symbolize_keys!)
|
29
|
-
|
30
|
-
# Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
|
31
|
-
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
|
32
|
-
# as keys, this will fail.
|
33
|
-
#
|
34
|
-
# ==== Examples
|
35
|
-
# { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
|
36
|
-
# { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
|
37
|
-
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
38
|
-
def assert_valid_keys(*valid_keys)
|
39
|
-
unknown_keys = keys - [valid_keys].flatten
|
40
|
-
raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
|
41
|
-
end unless method_defined?(:assert_valid_keys)
|
3
|
+
include Gorillib::Hashlike::Keys
|
42
4
|
end
|
@@ -1,26 +1,4 @@
|
|
1
|
+
require 'gorillib/hashlike/reverse_merge'
|
1
2
|
class Hash
|
2
|
-
|
3
|
-
# in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
|
4
|
-
#
|
5
|
-
# def setup(options = {})
|
6
|
-
# options.reverse_merge! :size => 25, :velocity => 10
|
7
|
-
# end
|
8
|
-
#
|
9
|
-
# Using <tt>merge</tt>, the above example would look as follows:
|
10
|
-
#
|
11
|
-
# def setup(options = {})
|
12
|
-
# { :size => 25, :velocity => 10 }.merge(options)
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
|
16
|
-
# have the respective key.
|
17
|
-
def reverse_merge(other_hash)
|
18
|
-
other_hash.merge(self)
|
19
|
-
end unless method_defined?(:reverse_merge)
|
20
|
-
|
21
|
-
# Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
|
22
|
-
# Modifies the receiver in place.
|
23
|
-
def reverse_merge!(other_hash)
|
24
|
-
merge!( other_hash ){|k,o,n| o }
|
25
|
-
end unless method_defined?(:reverse_merge!)
|
3
|
+
include Gorillib::Hashlike::ReverseMerge
|
26
4
|
end
|
data/lib/gorillib/hash/slice.rb
CHANGED
@@ -1,53 +1,4 @@
|
|
1
|
+
require 'gorillib/hashlike/slice'
|
1
2
|
class Hash
|
2
|
-
|
3
|
-
# limiting an options hash to valid keys before passing to a method:
|
4
|
-
#
|
5
|
-
# def search(criteria = {})
|
6
|
-
# assert_valid_keys(:mass, :velocity, :time)
|
7
|
-
# end
|
8
|
-
#
|
9
|
-
# search(options.slice(:mass, :velocity, :time))
|
10
|
-
#
|
11
|
-
# If you have an array of keys you want to limit to, you should splat them:
|
12
|
-
#
|
13
|
-
# valid_keys = [:mass, :velocity, :time]
|
14
|
-
# search(options.slice(*valid_keys))
|
15
|
-
def slice(*keys)
|
16
|
-
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
17
|
-
hash = self.class.new
|
18
|
-
keys.each { |k| hash[k] = self[k] if has_key?(k) }
|
19
|
-
hash
|
20
|
-
end unless method_defined?(:slice)
|
21
|
-
|
22
|
-
# Replaces the hash with only the given keys.
|
23
|
-
# Returns a hash containing the removed key/value pairs
|
24
|
-
# @example
|
25
|
-
# hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
|
26
|
-
# hsh.slice!(:a, :b)
|
27
|
-
# # => {:c => 3, :d =>4}
|
28
|
-
# hsh
|
29
|
-
# # => {:a => 1, :b => 2}
|
30
|
-
def slice!(*keys)
|
31
|
-
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
32
|
-
omit = slice(*self.keys - keys)
|
33
|
-
hash = slice(*keys)
|
34
|
-
replace(hash)
|
35
|
-
omit
|
36
|
-
end unless method_defined?(:slice!)
|
37
|
-
|
38
|
-
# Removes the given keys from the hash
|
39
|
-
# Returns a hash containing the removed key/value pairs
|
40
|
-
#
|
41
|
-
# @example
|
42
|
-
# hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
|
43
|
-
# hsh.extract!(:a, :b)
|
44
|
-
# # => {:a => 1, :b => 2}
|
45
|
-
# hsh
|
46
|
-
# # => {:c => 3, :d =>4}
|
47
|
-
def extract!(*keys)
|
48
|
-
result = {}
|
49
|
-
keys.each {|key| result[key] = delete(key) }
|
50
|
-
result
|
51
|
-
end unless method_defined?(:extract!)
|
3
|
+
include Gorillib::Hashlike::Slice
|
52
4
|
end
|
53
|
-
|
@@ -0,0 +1,824 @@
|
|
1
|
+
if (RUBY_VERSION < '1.9') && (not defined?(KeyError))
|
2
|
+
class KeyError < IndexError ; end
|
3
|
+
end
|
4
|
+
|
5
|
+
module Gorillib
|
6
|
+
#
|
7
|
+
# Your class must provide #[], #[]=, #delete, and #keys --
|
8
|
+
#
|
9
|
+
# * hsh[key] Element Reference -- Retrieves the value stored for +key+.
|
10
|
+
# * hsh[key] = val Element Assignment -- Associates +val+ with +key+.
|
11
|
+
# * hsh.delete(key) Deletes & returns the value whose key is equal to +key+.
|
12
|
+
# * hsh.keys Returns a new array populated with the keys.
|
13
|
+
#
|
14
|
+
# (see Hashlike::HashlikeViaAccessors for example)
|
15
|
+
#
|
16
|
+
# Given the above, hashlike will provide the rest, defining the methods
|
17
|
+
#
|
18
|
+
# :each_pair, :each, :each_key, :each_value, :values_at, :values_of, :values,
|
19
|
+
# :size, :length, :has_key?, :include?, :key?, :member?, :has_value?, :value?,
|
20
|
+
# :fetch, :key, :assoc, :rassoc, :empty?, :merge, :update, :merge!, :reject!,
|
21
|
+
# :select!, :delete_if, :keep_if, :reject, :clear, :store, :to_hash, :invert,
|
22
|
+
# :flatten
|
23
|
+
#
|
24
|
+
# and these methods added by Enumerable:
|
25
|
+
#
|
26
|
+
# :each_cons, :each_entry, :each_slice, :each_with_index, :each_with_object,
|
27
|
+
# :entries, :to_a, :map, :collect, :collect_concat, :group_by, :flat_map,
|
28
|
+
# :inject, :reduce, :chunk, :reverse_each, :slice_before, :drop, :drop_while,
|
29
|
+
# :take, :take_while, :detect, :find, :find_all, :select, :find_index, :grep,
|
30
|
+
# :all?, :any?, :none?, :one?, :first, :count, :zip, :max, :max_by, :min,
|
31
|
+
# :min_by, :minmax, :minmax_by, :sort, :sort_by, :cycle, :partition,
|
32
|
+
#
|
33
|
+
# It does not define these methods that do exist on hash:
|
34
|
+
#
|
35
|
+
# :default, :default=, :default_proc, :default_proc=,
|
36
|
+
# :compare_by_identity, :compare_by_identity?,
|
37
|
+
# :replace, :rehash, :shift
|
38
|
+
#
|
39
|
+
# === Chinese wall
|
40
|
+
#
|
41
|
+
# With a few exceptions, all methods are defined only in terms of
|
42
|
+
#
|
43
|
+
# #[], #[]=, #delete, #keys, #each_pair and #has_key?
|
44
|
+
#
|
45
|
+
# (exceptions: merge family depend on #update; the reject/select/xx_if family
|
46
|
+
# depend on each other; #invert & #flatten call #to_hash; #rassoc calls #key)
|
47
|
+
#
|
48
|
+
# === custom iterators
|
49
|
+
#
|
50
|
+
# Hashlike typically defines the following fundamental iterators by including
|
51
|
+
# Gorillib::Hashlike::EnumerateFromKeys:
|
52
|
+
#
|
53
|
+
# :each_pair, :each, :values, :values_at, :length
|
54
|
+
#
|
55
|
+
# However, if the #each_pair method already exists on the class (as it does
|
56
|
+
# for Struct), those methods will *not* be defined. The class is held
|
57
|
+
# responsible for the implementation of all five. (Of these, #each_pair
|
58
|
+
# is the only method called from elsewhere in Hashlike, while #each is the
|
59
|
+
# only method called from Enumerable).
|
60
|
+
#
|
61
|
+
# === #convert_key (Indifferent Access)
|
62
|
+
#
|
63
|
+
# If you define #convert_key the #values_at, #has_key?, #fetch, and #assoc
|
64
|
+
# methods will use it to sanitize keys coming in from the outside. It's
|
65
|
+
# assumed that you will do the same with #[], #[]= and #delete. (see
|
66
|
+
# Gorillib::HashWithIndifferentAccess for an example).
|
67
|
+
#
|
68
|
+
module Hashlike
|
69
|
+
|
70
|
+
#
|
71
|
+
# Provides a natural default iteration behavior by iterating over #keys.
|
72
|
+
# Since most classes will want this behaviour, it is included by default
|
73
|
+
# *unless* the class has already defined an #each method.
|
74
|
+
#
|
75
|
+
# Classes that wish to define their own iteration behavior (Struct for
|
76
|
+
# example, or a database facade) must define all of the methods within this
|
77
|
+
# module.
|
78
|
+
#
|
79
|
+
module EnumerateFromKeys
|
80
|
+
|
81
|
+
#
|
82
|
+
# Calls +block+ once for each key in +hsh+, passing the key/value pair as
|
83
|
+
# parameters.
|
84
|
+
#
|
85
|
+
# If no block is given, an enumerator is returned instead.
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
# hsh = { :a => 100, :b => 200 }
|
89
|
+
# hsh.each_pair{|key, value| puts "#{key} is #{value}" }
|
90
|
+
# # produces:
|
91
|
+
# a is 100
|
92
|
+
# b is 200
|
93
|
+
#
|
94
|
+
# @example with block arity:
|
95
|
+
# hsh = {[:a,:b] => 3, [:c, :d] => 4, :e => 5}
|
96
|
+
# seen_args = []
|
97
|
+
# hsh.each_pair{|arg1, arg2, arg3| seen_args << [arg1, arg2, arg3] }
|
98
|
+
# # => [[[:a, :b], 3, nil], [[:c, :d], 4, nil], [:e, 5, nil]]
|
99
|
+
#
|
100
|
+
# seen_args = []
|
101
|
+
# hsh.each_pair{|(arg1, arg2), arg3| seen_args << [arg1, arg2, arg3] }
|
102
|
+
# # => [[:a, :b, 3], [:c, :d, 4], [:e, nil, 5]]
|
103
|
+
#
|
104
|
+
# @overload hsh.each_pair{|key, val| block } -> hsh
|
105
|
+
# Calls block once for each key in +hsh+
|
106
|
+
# @yield [key, val] in order, each key and its associated value
|
107
|
+
# @return [Hashlike]
|
108
|
+
#
|
109
|
+
# @overload hsh.each_pair -> an_enumerator
|
110
|
+
# with no block, returns a raw enumerator
|
111
|
+
# @return [Enumerator]
|
112
|
+
#
|
113
|
+
def each_pair
|
114
|
+
return enum_for(:each_pair) unless block_given?
|
115
|
+
keys.each do |key|
|
116
|
+
yield([key, self[key]])
|
117
|
+
end
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Calls +block+ once for each key in +hsh+, passing the key/value pair as
|
123
|
+
# parameters.
|
124
|
+
#
|
125
|
+
# If no block is given, an enumerator is returned instead.
|
126
|
+
#
|
127
|
+
# @example
|
128
|
+
# hsh = { :a => 100, :b => 200 }
|
129
|
+
# hsh.each{|key, value| puts "#{key} is #{value}" }
|
130
|
+
# # produces:
|
131
|
+
# a is 100
|
132
|
+
# b is 200
|
133
|
+
#
|
134
|
+
# @example with block arity:
|
135
|
+
# hsh = {[:a,:b] => 3, [:c, :d] => 4, :e => 5}
|
136
|
+
# seen_args = []
|
137
|
+
# hsh.each{|arg1, arg2, arg3| seen_args << [arg1, arg2, arg3] }
|
138
|
+
# # => [[[:a, :b], 3, nil], [[:c, :d], 4, nil], [:e, 5, nil]]
|
139
|
+
#
|
140
|
+
# seen_args = []
|
141
|
+
# hsh.each{|(arg1, arg2), arg3| seen_args << [arg1, arg2, arg3] }
|
142
|
+
# # => [[:a, :b, 3], [:c, :d, 4], [:e, nil, 5]]
|
143
|
+
#
|
144
|
+
# @overload hsh.each{|key, val| block } -> hsh
|
145
|
+
# Calls block once for each key in +hsh+
|
146
|
+
# @yield [key, val] in order, each key and its associated value
|
147
|
+
# @return [Hashlike]
|
148
|
+
#
|
149
|
+
# @overload hsh.each -> an_enumerator
|
150
|
+
# with no block, returns a raw enumerator
|
151
|
+
# @return [Enumerator]
|
152
|
+
#
|
153
|
+
def each(&block)
|
154
|
+
return enum_for(:each) unless block_given?
|
155
|
+
each_pair(&block)
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Returns the number of key/value pairs in the hashlike.
|
160
|
+
#
|
161
|
+
# @example
|
162
|
+
# hsh = { :d => 100, :a => 200, :v => 300, :e => 400 }
|
163
|
+
# hsh.length # => 4
|
164
|
+
# hsh.delete(:a) # => 200
|
165
|
+
# hsh.length # => 3
|
166
|
+
#
|
167
|
+
# @return [Fixnum] number of key-value pairs
|
168
|
+
#
|
169
|
+
def length
|
170
|
+
keys.length
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# A new array populated with the values from +hsh+.
|
175
|
+
#
|
176
|
+
# @see Hashlike#keys.
|
177
|
+
#
|
178
|
+
# @example
|
179
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
180
|
+
# hsh.values # => [100, 200, 300]
|
181
|
+
#
|
182
|
+
# @return [Array] the values, in order by their key.
|
183
|
+
#
|
184
|
+
def values
|
185
|
+
[].tap{|arr| each_pair{|key, val| arr << val } }
|
186
|
+
end
|
187
|
+
|
188
|
+
#
|
189
|
+
# Array containing the values associated with the given keys.
|
190
|
+
#
|
191
|
+
# @see Hashlike#select.
|
192
|
+
#
|
193
|
+
# @example
|
194
|
+
# hsh = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
|
195
|
+
# hsh.values_at("cow", "cat") # => ["bovine", "feline"]
|
196
|
+
#
|
197
|
+
# @example
|
198
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
199
|
+
# hsh.values_at(:c, :a, :c, :z, :a)
|
200
|
+
# # => [300, 100, 300, nil, 100]
|
201
|
+
#
|
202
|
+
# @param *allowed_keys [Object] the keys to retrieve.
|
203
|
+
# @return [Array] the values, in order according to allowed_keys.
|
204
|
+
#
|
205
|
+
def values_at(*allowed_keys)
|
206
|
+
allowed_keys.map do |key|
|
207
|
+
key = convert_key(key) if respond_to?(:convert_key)
|
208
|
+
self[key] if has_key?(key)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# alias for #[]=
|
214
|
+
def store(key, val)
|
215
|
+
self[key] = val
|
216
|
+
end
|
217
|
+
|
218
|
+
# Hashlike#each_key
|
219
|
+
#
|
220
|
+
# Calls +block+ once for each key in +hsh+, passing the key as a parameter.
|
221
|
+
#
|
222
|
+
# If no block is given, an enumerator is returned instead.
|
223
|
+
#
|
224
|
+
# @example
|
225
|
+
# hsh = { :a => 100, :b => 200 }
|
226
|
+
# hsh.each_key{|key| puts key }
|
227
|
+
# # produces:
|
228
|
+
# a
|
229
|
+
# b
|
230
|
+
#
|
231
|
+
# @example with block arity:
|
232
|
+
# hsh = {[:a,:b] => 3, [:c, :d] => 4, :e => 5}
|
233
|
+
# seen_args = []
|
234
|
+
# hsh.each_key{|arg1, arg2, arg3| seen_args << [arg1, arg2, arg3] }
|
235
|
+
# # => [[:a, :b, nil], [:c, :d, nil], [:e, nil, nil]]
|
236
|
+
#
|
237
|
+
# seen_args = []
|
238
|
+
# hsh.each_key{|(arg1, arg2), arg3| seen_args << [arg1, arg2, arg3] }
|
239
|
+
# # => [[:a, nil, :b], [:c, nil, :d], [:e, nil, nil]]
|
240
|
+
#
|
241
|
+
# @overload hsh.each_key{|key| block } -> hsh
|
242
|
+
# Calls +block+ once for each key in +hsh+
|
243
|
+
# @yield [key] in order, each key
|
244
|
+
# @return [Hashlike]
|
245
|
+
#
|
246
|
+
# @overload hsh.each_key -> an_enumerator
|
247
|
+
# with no block, returns a raw enumerator
|
248
|
+
# @return [Enumerator]
|
249
|
+
#
|
250
|
+
def each_key
|
251
|
+
return enum_for(:each_key) unless block_given?
|
252
|
+
each_pair{|k,v| yield k }
|
253
|
+
self
|
254
|
+
end
|
255
|
+
|
256
|
+
#
|
257
|
+
# Calls +block+ once for each key in +hsh+, passing the value as a parameter.
|
258
|
+
#
|
259
|
+
# If no block is given, an enumerator is returned instead.
|
260
|
+
#
|
261
|
+
# @example
|
262
|
+
# hsh = { :a => 100, :b => 200 }
|
263
|
+
# hsh.each_value{|value| puts value }
|
264
|
+
# # produces:
|
265
|
+
# 100
|
266
|
+
# 200
|
267
|
+
#
|
268
|
+
# @example with block arity:
|
269
|
+
# hsh = {:a => [300,333], :b => [400,444], :e => 500})
|
270
|
+
# seen_args = []
|
271
|
+
# hsh.each_value{|arg1, arg2, arg3| seen_args << [arg1, arg2, arg3] }
|
272
|
+
# # => [[300, 333, nil], [400, 444, nil], [500, nil, nil]]
|
273
|
+
#
|
274
|
+
# seen_args = []
|
275
|
+
# hsh.each_value{|(arg1, arg2), arg3| seen_args << [arg1, arg2, arg3] }
|
276
|
+
# # => [[300, nil, 333], [400, nil, 444], [500, nil, nil]]
|
277
|
+
#
|
278
|
+
# @overload hsh.each_value{|val| block } -> hsh
|
279
|
+
# Calls +block+ once for each value in +hsh+
|
280
|
+
# @yield [val] in order by its key, each value
|
281
|
+
# @return [Hashlike]
|
282
|
+
#
|
283
|
+
# @overload hsh.each_value -> an_enumerator
|
284
|
+
# with no block, returns a raw enumerator
|
285
|
+
# @return [Enumerator]
|
286
|
+
#
|
287
|
+
def each_value
|
288
|
+
return enum_for(:each_value) unless block_given?
|
289
|
+
each_pair{|k,v| yield v }
|
290
|
+
self
|
291
|
+
end
|
292
|
+
|
293
|
+
#
|
294
|
+
# Array containing the values associated with the given keys.
|
295
|
+
#
|
296
|
+
# @see Hashlike#select.
|
297
|
+
#
|
298
|
+
# @example
|
299
|
+
# hsh = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
|
300
|
+
# hsh.values_of("cow", "cat") # => ["bovine", "feline"]
|
301
|
+
#
|
302
|
+
# @example
|
303
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
304
|
+
# hsh.values_of(:c, :a, :c, :z, :a)
|
305
|
+
# # => [300, 100, 300, nil, 100]
|
306
|
+
#
|
307
|
+
# @param *allowed_keys [Object] the keys to retrieve.
|
308
|
+
# @return [Array] the values, in order according to allowed_keys.
|
309
|
+
#
|
310
|
+
def values_of(*allowed_keys)
|
311
|
+
allowed_keys.map do |key|
|
312
|
+
key = convert_key(key) if respond_to?(:convert_key)
|
313
|
+
self[key] if has_key?(key)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
#
|
318
|
+
# Returns true if the given key is present in +hsh+.
|
319
|
+
#
|
320
|
+
# @example
|
321
|
+
# hsh = { :a => 100, :b => 200 }
|
322
|
+
# hsh.has_key?(:a) # => true
|
323
|
+
# hsh.has_key?(:z) # => false
|
324
|
+
#
|
325
|
+
# @param key [Object] the key to check for.
|
326
|
+
# @return [true, false] true if the key is present, false otherwise
|
327
|
+
#
|
328
|
+
def has_key?(key)
|
329
|
+
key = convert_key(key) if respond_to?(:convert_key)
|
330
|
+
keys.include?(key)
|
331
|
+
end
|
332
|
+
|
333
|
+
#
|
334
|
+
# Returns true if the given value is present for some key in +hsh+.
|
335
|
+
#
|
336
|
+
# @example
|
337
|
+
# hsh = { :a => 100, :b => 200 }
|
338
|
+
# hsh.has_value?(100) # => true
|
339
|
+
# hsh.has_value?(999) # => false
|
340
|
+
#
|
341
|
+
# @param target [Object] the value to query
|
342
|
+
# @return [true, false] true if the value is present, false otherwise
|
343
|
+
#
|
344
|
+
def has_value?(target)
|
345
|
+
# don't refactor this to any? -- Struct's #any is weird
|
346
|
+
each_pair{|key, val| return true if (val == target) }
|
347
|
+
false
|
348
|
+
end
|
349
|
+
|
350
|
+
#
|
351
|
+
# Returns a value from the hashlike for the given key. If the key can't be
|
352
|
+
# found, there are several options:
|
353
|
+
# * With no other arguments, it will raise a +KeyError+ exception;
|
354
|
+
# * if default is given, then that will be returned;
|
355
|
+
# * if the optional code block is specified, then that will be run and its result returned.
|
356
|
+
#
|
357
|
+
# @example
|
358
|
+
# hsh = { :a => 100, :b => 200 }
|
359
|
+
# hsh.fetch(:a) # => 100
|
360
|
+
# hsh.fetch(:z, "go fish") # => "go fish"
|
361
|
+
# hsh.fetch(:z){|el| "go fish, #{el}"} # => "go fish, z"
|
362
|
+
#
|
363
|
+
# @example An exception is raised if the key is not found and a default value is not supplied.
|
364
|
+
# hsh = { :a => 100, :b => 200 }
|
365
|
+
# hsh.fetch(:z)
|
366
|
+
# # produces:
|
367
|
+
# prog.rb:2:in `fetch': key not found (KeyError) from prog.rb:2
|
368
|
+
#
|
369
|
+
# hsh.fetch(:z, 3)
|
370
|
+
# # => 3
|
371
|
+
#
|
372
|
+
# hsh.fetch(:z){|key| key.to_s * 5 }
|
373
|
+
# # => "zzzzz"
|
374
|
+
#
|
375
|
+
# @param key [Object] the key to query
|
376
|
+
# @param default [Object] the value to use if the key is missing
|
377
|
+
# @raise [KeyError] raised if missing, and neither +default+ nor +block+ is supplied
|
378
|
+
# @yield [key] if missing, block called with the key requested
|
379
|
+
# @return [Object] the value; if missing, the default; if missing, the
|
380
|
+
# block's return value
|
381
|
+
#
|
382
|
+
def fetch(key, default=nil, &block)
|
383
|
+
key = convert_key(key) if respond_to?(:convert_key)
|
384
|
+
warn "#{caller[0]}: warning: block supersedes default value argument" if default && block_given?
|
385
|
+
if has_key?(key) then self[key]
|
386
|
+
elsif block_given? then yield(key)
|
387
|
+
elsif default then default
|
388
|
+
else raise KeyError, "key not found: #{key.inspect}"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
#
|
393
|
+
# Searches the hash for an entry whose value == +val+, returning the
|
394
|
+
# corresponding key. If not found, returns +nil+.
|
395
|
+
#
|
396
|
+
# You are guaranteed that the first matching key in #keys will be the one
|
397
|
+
# returned.
|
398
|
+
#
|
399
|
+
# @example
|
400
|
+
# hsh = { :a => 100, :b => 200 }
|
401
|
+
# hsh.key(200) # => :b
|
402
|
+
# hsh.key(999) # => nil
|
403
|
+
#
|
404
|
+
# @param val [Object] the value to look up
|
405
|
+
# @return [Object, nil] the key for the given val, or nil if missing
|
406
|
+
#
|
407
|
+
def key(val)
|
408
|
+
keys.find{|key| self[key] == val }
|
409
|
+
end
|
410
|
+
|
411
|
+
#
|
412
|
+
# Searches through the hashlike comparing obj with the key using ==.
|
413
|
+
# Returns the key-value pair (two elements array) or nil if no match is
|
414
|
+
# found.
|
415
|
+
#
|
416
|
+
# @see Array#assoc.
|
417
|
+
#
|
418
|
+
# @example
|
419
|
+
# hsh = { "colors" => ["red", "blue", "green"],
|
420
|
+
# "letters" => [:a, :b, :c ]}
|
421
|
+
# hsh.assoc("letters") # => ["letters", [:a, :b, :c]]
|
422
|
+
# hsh.assoc("foo") # => nil
|
423
|
+
#
|
424
|
+
# @return [Array, nil] the key-value pair (two elements array) or nil if no
|
425
|
+
# match is found.
|
426
|
+
#
|
427
|
+
def assoc(key)
|
428
|
+
key = convert_key(key) if respond_to?(:convert_key)
|
429
|
+
return unless has_key?(key)
|
430
|
+
[key, self[key]]
|
431
|
+
end
|
432
|
+
|
433
|
+
#
|
434
|
+
# Searches through the hashlike comparing obj with the value using ==.
|
435
|
+
# Returns the first key-value pair (two-element array) that matches, or nil
|
436
|
+
# if no match is found.
|
437
|
+
#
|
438
|
+
# @see Array#rassoc.
|
439
|
+
#
|
440
|
+
# @example
|
441
|
+
# hsh = { 1 => "one", 2 => "two", 3 => "three", "ii" => "two"}
|
442
|
+
# hsh.rassoc("two") # => [2, "two"]
|
443
|
+
# hsh.rassoc("four") # => nil
|
444
|
+
#
|
445
|
+
# @return [Array, nil] The first key-value pair (two-element array) that
|
446
|
+
# matches, or nil if no match is found
|
447
|
+
#
|
448
|
+
def rassoc(val)
|
449
|
+
key = key(val) or return
|
450
|
+
[key, self[key]]
|
451
|
+
end
|
452
|
+
|
453
|
+
#
|
454
|
+
# Returns true if the hashlike contains no key-value pairs, false otherwise.
|
455
|
+
#
|
456
|
+
# @example
|
457
|
+
# {}.empty? # => true
|
458
|
+
#
|
459
|
+
# @return [true, false] true if +hsh+ contains no key-value pairs, false otherwise
|
460
|
+
#
|
461
|
+
def empty?
|
462
|
+
keys.empty?
|
463
|
+
end
|
464
|
+
|
465
|
+
#
|
466
|
+
# Adds the contents of +other_hash+ to +hsh+. If no block is
|
467
|
+
# specified, entries with duplicate keys are overwritten with the values from
|
468
|
+
# +other_hash+, otherwise the value of each duplicate key is determined by
|
469
|
+
# calling the block with the key, its value in +hsh+ and its value in
|
470
|
+
# +other_hash+.
|
471
|
+
#
|
472
|
+
# @example
|
473
|
+
# h1 = { :a => 100, :b => 200 }
|
474
|
+
# h2 = { :b => 254, :c => 300 }
|
475
|
+
# h1.merge!(h2)
|
476
|
+
# # => { :a => 100, :b => 254, :c => 300 }
|
477
|
+
#
|
478
|
+
# h1 = { :a => 100, :b => 200 }
|
479
|
+
# h2 = { :b => 254, :c => 300 }
|
480
|
+
# h1.merge!(h2){|key, v1, v2| v1 }
|
481
|
+
# # => { :a => 100, :b => 200, :c => 300 }
|
482
|
+
#
|
483
|
+
# @overload hsh.update(other_hash) -> hsh
|
484
|
+
# Adds the contents of +other_hash+ to +hsh+. Entries with duplicate keys are
|
485
|
+
# overwritten with the values from +other_hash+
|
486
|
+
# @param other_hash [Hash, Hashlike] the hash to merge (it wins)
|
487
|
+
# @return [Hashlike] this hashlike, updated
|
488
|
+
#
|
489
|
+
# @overload hsh.update(other_hash){|key, oldval, newval| block} -> hsh
|
490
|
+
# Adds the contents of +other_hash+ to +hsh+. The value of each duplicate key
|
491
|
+
# is determined by calling the block with the key, its value in +hsh+ and its
|
492
|
+
# value in +other_hash+.
|
493
|
+
# @param other_hash [Hash, Hashlike] the hash to merge (it wins)
|
494
|
+
# @yield [Object, Object, Object] called if key exists in each +hsh+
|
495
|
+
# @return [Hashlike] this hashlike, updated
|
496
|
+
#
|
497
|
+
def update(other_hash)
|
498
|
+
raise TypeError, "can't convert #{other_hash.nil? ? 'nil' : other_hash.class} into Hash" unless other_hash.respond_to?(:each_pair)
|
499
|
+
other_hash.each_pair do |key, val|
|
500
|
+
if block_given? && has_key?(key)
|
501
|
+
val = yield(key, val, self[key])
|
502
|
+
end
|
503
|
+
self[key] = val
|
504
|
+
end
|
505
|
+
self
|
506
|
+
end
|
507
|
+
|
508
|
+
#
|
509
|
+
# Returns a new hashlike containing the contents of +other_hash+ and the
|
510
|
+
# contents of +hsh+. If no block is specified, the value for entries with
|
511
|
+
# duplicate keys will be that of +other_hash+. Otherwise the value for each
|
512
|
+
# duplicate key is determined by calling the block with the key, its value in
|
513
|
+
# +hsh+ and its value in +other_hash+.
|
514
|
+
#
|
515
|
+
# @example
|
516
|
+
# h1 = { :a => 100, :b => 200 }
|
517
|
+
# h2 = { :b => 254, :c => 300 }
|
518
|
+
# h1.merge(h2)
|
519
|
+
# # => { :a=>100, :b=>254, :c=>300 }
|
520
|
+
# h1.merge(h2){|key, oldval, newval| newval - oldval}
|
521
|
+
# # => { :a => 100, :b => 54, :c => 300 }
|
522
|
+
# h1
|
523
|
+
# # => { :a => 100, :b => 200 }
|
524
|
+
#
|
525
|
+
# @overload hsh.merge(other_hash) -> hsh
|
526
|
+
# Adds the contents of +other_hash+ to +hsh+. Entries with duplicate keys are
|
527
|
+
# overwritten with the values from +other_hash+
|
528
|
+
# @param other_hash [Hash, Hashlike] the hash to merge (it wins)
|
529
|
+
# @return [Hashlike] a new merged hashlike
|
530
|
+
#
|
531
|
+
# @overload hsh.merge(other_hash){|key, oldval, newval| block} -> hsh
|
532
|
+
# Adds the contents of +other_hash+ to +hsh+. The value of each duplicate key
|
533
|
+
# is determined by calling the block with the key, its value in +hsh+ and its
|
534
|
+
# value in +other_hash+.
|
535
|
+
# @param other_hash [Hash, Hashlike] the hash to merge (it wins)
|
536
|
+
# @yield [Object, Object, Object] called if key exists in each +hsh+
|
537
|
+
# @return [Hashlike] a new merged hashlike
|
538
|
+
#
|
539
|
+
def merge(*args, &block)
|
540
|
+
self.dup.update(*args, &block)
|
541
|
+
end
|
542
|
+
|
543
|
+
#
|
544
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy
|
545
|
+
# (equivalent to Hashlike#delete_if), but returns nil if no changes were made.
|
546
|
+
#
|
547
|
+
# @example
|
548
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
549
|
+
# hsh.delete_if{|key, val| key.to_s >= "b" } # => { :a => 100 }
|
550
|
+
#
|
551
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
552
|
+
# hsh.delete_if{|key, val| key.to_s >= "z" } # nil
|
553
|
+
#
|
554
|
+
# @overload hsh.reject!{|key, val| block } -> hsh or nil
|
555
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
|
556
|
+
# @return [Hashlike, nil]
|
557
|
+
#
|
558
|
+
# @overload hsh.reject! -> an_enumerator
|
559
|
+
# with no block, returns a raw enumerator
|
560
|
+
# @return [Enumerator]
|
561
|
+
#
|
562
|
+
def reject!(&block)
|
563
|
+
return enum_for(:reject!) unless block_given?
|
564
|
+
changed = false
|
565
|
+
each_pair do |key, val|
|
566
|
+
if yield(*[key, val].take(block.arity))
|
567
|
+
changed = true
|
568
|
+
delete(key)
|
569
|
+
end
|
570
|
+
end
|
571
|
+
changed ? self : nil
|
572
|
+
end
|
573
|
+
|
574
|
+
#
|
575
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy
|
576
|
+
# (equivalent to Hashlike#keep_if), but returns nil if no changes were made.
|
577
|
+
#
|
578
|
+
# @example
|
579
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
580
|
+
# hsh.select!{|key, val| key.to_s >= "b" } # => { :b => 200, :c => 300 }
|
581
|
+
#
|
582
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
583
|
+
# hsh.select!{|key, val| key.to_s >= "a" } # => { :a => 100, :b => 200, :c => 300 }
|
584
|
+
#
|
585
|
+
# @overload hsh.select!{|key, val| block } -> hsh or nil
|
586
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy.
|
587
|
+
# @return [Hashlike]
|
588
|
+
#
|
589
|
+
# @overload hsh.select! -> an_enumerator
|
590
|
+
# with no block, returns a raw enumerator
|
591
|
+
# @return [Enumerator]
|
592
|
+
#
|
593
|
+
def select!(&block)
|
594
|
+
return enum_for(:select!) unless block_given?
|
595
|
+
changed = false
|
596
|
+
each_pair do |key, val|
|
597
|
+
if not yield(*[key, val].take(block.arity))
|
598
|
+
changed = true
|
599
|
+
delete(key)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
changed ? self : nil
|
603
|
+
end
|
604
|
+
|
605
|
+
#
|
606
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
|
607
|
+
#
|
608
|
+
# If no block is given, an enumerator is returned instead.
|
609
|
+
#
|
610
|
+
# @example
|
611
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
612
|
+
# hsh.delete_if{|key, val| key.to_s >= "b" } # => { :a => 100 }
|
613
|
+
#
|
614
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
615
|
+
# hsh.delete_if{|key, val| key.to_s >= "z" } # => { :a => 100, :b => 200, :c => 300 }
|
616
|
+
#
|
617
|
+
# @overload hsh.delete_if{|key, val| block } -> hsh
|
618
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
|
619
|
+
# @return [Hashlike]
|
620
|
+
#
|
621
|
+
# @overload hsh.delete_if -> an_enumerator
|
622
|
+
# with no block, returns a raw enumerator
|
623
|
+
# @return [Enumerator]
|
624
|
+
#
|
625
|
+
def delete_if(&block)
|
626
|
+
return enum_for(:delete_if) unless block_given?
|
627
|
+
reject!(&block)
|
628
|
+
self
|
629
|
+
end
|
630
|
+
|
631
|
+
#
|
632
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy.
|
633
|
+
#
|
634
|
+
# If no block is given, an enumerator is returned instead.
|
635
|
+
#
|
636
|
+
# @example
|
637
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
638
|
+
# hsh.keep_if{|key, val| key.to_s >= "b" } # => { :b => 200, :c => 300 }
|
639
|
+
#
|
640
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
641
|
+
# hsh.keep_if{|key, val| key.to_s >= "a" } # => { :a => 100, :b => 200, :c => 300 }
|
642
|
+
#
|
643
|
+
# @overload hsh.keep_if{|key, val| block } -> hsh
|
644
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy.
|
645
|
+
# @return [Hashlike]
|
646
|
+
#
|
647
|
+
# @overload hsh.keep_if -> an_enumerator
|
648
|
+
# with no block, returns a raw enumerator
|
649
|
+
# @return [Enumerator]
|
650
|
+
#
|
651
|
+
def keep_if(&block)
|
652
|
+
return enum_for(:keep_if) unless block_given?
|
653
|
+
select!(&block)
|
654
|
+
self
|
655
|
+
end
|
656
|
+
|
657
|
+
#
|
658
|
+
# Overrides the implementation in Enumerable, which iterates on keys, not
|
659
|
+
# key/value pairs
|
660
|
+
#
|
661
|
+
module OverrideEnumerable
|
662
|
+
#
|
663
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates to
|
664
|
+
# true (similar to Hashlike#delete_if), but works on (and returns) a copy of
|
665
|
+
# the +hsh+. Equivalent to <tt>hsh.dup.delete_if</tt>.
|
666
|
+
#
|
667
|
+
# @example
|
668
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
669
|
+
# hsh.reject{|key, val| key.to_s >= "b" } # => { :a => 100 }
|
670
|
+
# hsh # => { :a => 100, :b => 200, :c => 300 }
|
671
|
+
#
|
672
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
673
|
+
# hsh.reject{|key, val| key.to_s >= "z" } # => { :a => 100, :b => 200, :c => 300 }
|
674
|
+
# hsh # => { :a => 100, :b => 200, :c => 300 }
|
675
|
+
#
|
676
|
+
# @overload hsh.reject{|key, val| block } -> new_hashlike
|
677
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
|
678
|
+
# @return [Hashlike]
|
679
|
+
#
|
680
|
+
# @overload hsh.reject -> an_enumerator
|
681
|
+
# with no block, returns a raw enumerator
|
682
|
+
# @return [Enumerator]
|
683
|
+
#
|
684
|
+
# Overrides the implementation in Enumerable, which does the keys wrong.
|
685
|
+
#
|
686
|
+
def reject(&block)
|
687
|
+
return enum_for(:reject) unless block_given?
|
688
|
+
self.dup.delete_if(&block)
|
689
|
+
end
|
690
|
+
|
691
|
+
#
|
692
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates to
|
693
|
+
# false (similar to Hashlike#keep_if), but works on (and returns) a copy of
|
694
|
+
# the +hsh+. Equivalent to <tt>hsh.dup.keep_if</tt>.
|
695
|
+
#
|
696
|
+
# @example
|
697
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
698
|
+
# hsh.select{|key, val| key.to_s >= "b" } # => { :b => 200, :c => 300 }
|
699
|
+
# hsh # => { :a => 100, :b => 200, :c => 300 }
|
700
|
+
#
|
701
|
+
# hsh = { :a => 100, :b => 200, :c => 300 }
|
702
|
+
# hsh.select{|key, val| key.to_s >= "z" } # => { }
|
703
|
+
# hsh # => { :a => 100, :b => 200, :c => 300 }
|
704
|
+
#
|
705
|
+
# @overload hsh.select{|key, val| block } -> new_hashlike
|
706
|
+
# Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
|
707
|
+
# @return [Hashlike]
|
708
|
+
#
|
709
|
+
# @overload hsh.select -> an_enumerator
|
710
|
+
# with no block, returns a raw enumerator
|
711
|
+
# @return [Enumerator]
|
712
|
+
#
|
713
|
+
# Overrides the implementation in Enumerable, which does the keys wrong.
|
714
|
+
#
|
715
|
+
def select(&block)
|
716
|
+
return enum_for(:select) unless block_given?
|
717
|
+
self.dup.keep_if(&block)
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
#
|
722
|
+
# Removes all key-value pairs from +hsh+.
|
723
|
+
#
|
724
|
+
# @example
|
725
|
+
# hsh = { :a => 100, :b => 200 } # => { :a => 100, :b => 200 }
|
726
|
+
# hsh.clear # => {}
|
727
|
+
#
|
728
|
+
# @return [Hashlike] this hashlike, emptied
|
729
|
+
#
|
730
|
+
def clear
|
731
|
+
each_pair{|k,v| delete(k) }
|
732
|
+
end
|
733
|
+
|
734
|
+
#
|
735
|
+
# Returns a hash with each key set to its associated value.
|
736
|
+
#
|
737
|
+
# @example
|
738
|
+
# my_hshlike = MyHashlike.new
|
739
|
+
# my_hshlike[:a] = 100; my_hshlike[:b] = 200
|
740
|
+
# my_hshlike.to_hash # => { :a => 100, :b => 200 }
|
741
|
+
#
|
742
|
+
# @return [Hash] a new Hash instance, with each key set to its associated value.
|
743
|
+
#
|
744
|
+
def to_hash
|
745
|
+
{}.tap{|hsh| each_pair{|key, val| hsh[key] = val } }
|
746
|
+
end
|
747
|
+
|
748
|
+
#
|
749
|
+
# Returns a new hash created by using +hsh+'s values as keys, and the keys as
|
750
|
+
# values. If +hsh+ has duplicate values, the result will contain only one of
|
751
|
+
# them as a key -- which one is not predictable.
|
752
|
+
#
|
753
|
+
# @example
|
754
|
+
# hsh = { :n => 100, :m => 100, :y => 300, :d => 200, :a => 0 }
|
755
|
+
# hsh.invert # => { 0 => :a, 100 => :m, 200 => :d, 300 => :y }
|
756
|
+
#
|
757
|
+
# @return [Hash] a new hash, with values for keys and vice-versa
|
758
|
+
#
|
759
|
+
def invert
|
760
|
+
to_hash.invert
|
761
|
+
end
|
762
|
+
|
763
|
+
#
|
764
|
+
# Returns a new array that is a one-dimensional flattening of this
|
765
|
+
# hashlike. That is, for every key or value that is an array, extract its
|
766
|
+
# elements into the new array. Unlike Array#flatten, this method does not
|
767
|
+
# flatten recursively by default; pass +nil+ explicitly to flatten
|
768
|
+
# recursively. The optional level argument determines the level of
|
769
|
+
# recursion to flatten.
|
770
|
+
#
|
771
|
+
# @example
|
772
|
+
# hsh = {1=> "one", 2 => [2,"two"], 3 => "three"}
|
773
|
+
# hsh.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
|
774
|
+
# hsh.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"]
|
775
|
+
#
|
776
|
+
# @example with deep nesting
|
777
|
+
# hsh = { [1, 2, [3, 4]] => [1, [2, 3, [4, 5, 6]]] }
|
778
|
+
# hsh.flatten
|
779
|
+
# # => [[1, 2, [3, 4]], [1, [2, 3, [4, 5, 6]]]]
|
780
|
+
# hsh.flatten(0)
|
781
|
+
# # => [[[1, 2, [3, 4]], [1, [2, 3, [4, 5, 6]]]]]
|
782
|
+
# hsh.flatten(1)
|
783
|
+
# # => [[1, 2, [3, 4]], [1, [2, 3, [4, 5, 6]]]]
|
784
|
+
# hsh.flatten(2)
|
785
|
+
# # => [1, 2, [3, 4], 1, [2, 3, [4, 5, 6]]]
|
786
|
+
# hsh.flatten(3)
|
787
|
+
# # => [1, 2, 3, 4, 1, 2, 3, [4, 5, 6]]
|
788
|
+
# hsh.flatten(4)
|
789
|
+
# # => [1, 2, 3, 4, 1, 2, 3, 4, 5, 6]
|
790
|
+
# hsh.flatten.flatten
|
791
|
+
# # => [1, 2, 3, 4, 1, 2, 3, 4, 5, 6]
|
792
|
+
#
|
793
|
+
# @example nil level means complete flattening
|
794
|
+
# hsh.flatten(nil)
|
795
|
+
# # => [1, 2, 3, 4, 1, 2, 3, 4, 5, 6]
|
796
|
+
#
|
797
|
+
# @param level [Integer] the level of recursion to flatten, 0 by default.
|
798
|
+
# @return [Array] the flattened key-value array.
|
799
|
+
#
|
800
|
+
def flatten(*args)
|
801
|
+
to_hash.flatten(*args)
|
802
|
+
end
|
803
|
+
|
804
|
+
def self.included(base)
|
805
|
+
base.class_eval do
|
806
|
+
base.send(:include, EnumerateFromKeys) unless base.method_defined?(:each_pair)
|
807
|
+
unless base.include?(Enumerable)
|
808
|
+
base.send(:include, Enumerable)
|
809
|
+
base.send(:include, OverrideEnumerable)
|
810
|
+
end
|
811
|
+
|
812
|
+
# included here so they win out over Enumerable
|
813
|
+
alias_method :include?, :has_key?
|
814
|
+
alias_method :key?, :has_key?
|
815
|
+
alias_method :member?, :has_key?
|
816
|
+
alias_method :value?, :has_value?
|
817
|
+
alias_method :merge!, :update
|
818
|
+
alias_method :size, :length
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|