source: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/mrblib/hash.rb@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 12.8 KB
Line 
1class Hash
2
3 # ISO does not define Hash#each_pair, so each_pair is defined in gem.
4 alias each_pair each
5
6 ##
7 # call-seq:
8 # Hash[ key, value, ... ] -> new_hash
9 # Hash[ [ [key, value], ... ] ] -> new_hash
10 # Hash[ object ] -> new_hash
11 #
12 # Creates a new hash populated with the given objects.
13 #
14 # Similar to the literal `{ _key_ => _value_, ... }`. In the first
15 # form, keys and values occur in pairs, so there must be an even number of
16 # arguments.
17 #
18 # The second and third form take a single argument which is either an array
19 # of key-value pairs or an object convertible to a hash.
20 #
21 # Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200}
22 # Hash[ [ ["a", 100], ["b", 200] ] ] #=> {"a"=>100, "b"=>200}
23 # Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200}
24 #
25
26 def self.[](*object)
27 length = object.length
28 if length == 1
29 o = object[0]
30 if Hash === o
31 h = self.new
32 o.each { |k, v| h[k] = v }
33 return h
34 elsif o.respond_to?(:to_a)
35 h = self.new
36 o.to_a.each do |i|
37 raise ArgumentError, "wrong element type #{i.class} (expected array)" unless i.respond_to?(:to_a)
38 k, v = nil
39 case i.size
40 when 2
41 k = i[0]
42 v = i[1]
43 when 1
44 k = i[0]
45 else
46 raise ArgumentError, "invalid number of elements (#{i.size} for 1..2)"
47 end
48 h[k] = v
49 end
50 return h
51 end
52 end
53 unless length % 2 == 0
54 raise ArgumentError, 'odd number of arguments for Hash'
55 end
56 h = self.new
57 0.step(length - 2, 2) do |i|
58 h[object[i]] = object[i + 1]
59 end
60 h
61 end
62
63 ##
64 # call-seq:
65 # hsh.merge!(other_hash) -> hsh
66 # hsh.merge!(other_hash){|key, oldval, newval| block} -> hsh
67 #
68 # Adds the contents of _other_hash_ to _hsh_. If no block is specified,
69 # entries with duplicate keys are overwritten with the values from
70 # _other_hash_, otherwise the value of each duplicate key is determined by
71 # calling the block with the key, its value in _hsh_ and its value in
72 # _other_hash_.
73 #
74 # h1 = { "a" => 100, "b" => 200 }
75 # h2 = { "b" => 254, "c" => 300 }
76 # h1.merge!(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
77 #
78 # h1 = { "a" => 100, "b" => 200 }
79 # h2 = { "b" => 254, "c" => 300 }
80 # h1.merge!(h2) { |key, v1, v2| v1 }
81 # #=> {"a"=>100, "b"=>200, "c"=>300}
82 #
83
84 def merge!(other, &block)
85 raise TypeError, "Hash required (#{other.class} given)" unless Hash === other
86 if block
87 other.each_key{|k|
88 self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
89 }
90 else
91 other.each_key{|k| self[k] = other[k]}
92 end
93 self
94 end
95
96 alias update merge!
97
98 ##
99 # call-seq:
100 # hsh.compact! -> hsh
101 #
102 # Removes all nil values from the hash. Returns the hash.
103 # Returns nil if the hash does not contain nil values.
104 #
105 # h = { a: 1, b: false, c: nil }
106 # h.compact! #=> { a: 1, b: false }
107 #
108
109 def compact!
110 keys = self.keys
111 nk = keys.select{|k|
112 self[k] != nil
113 }
114 return nil if (keys.size == nk.size)
115 h = {}
116 nk.each {|k|
117 h[k] = self[k]
118 }
119 h
120 self.replace(h)
121 end
122
123 ##
124 # call-seq:
125 # hsh.compact -> new_hsh
126 #
127 # Returns a new hash with the nil values/key pairs removed
128 #
129 # h = { a: 1, b: false, c: nil }
130 # h.compact #=> { a: 1, b: false }
131 # h #=> { a: 1, b: false, c: nil }
132 #
133 def compact
134 h = {}
135 self.keys.select{|k|
136 self[k] != nil
137 }.each {|k|
138 h[k] = self[k]
139 }
140 h
141 end
142
143 ##
144 # call-seq:
145 # hsh.fetch(key [, default] ) -> obj
146 # hsh.fetch(key) {| key | block } -> obj
147 #
148 # Returns a value from the hash for the given key. If the key can't be
149 # found, there are several options: With no other arguments, it will
150 # raise an <code>KeyError</code> exception; if <i>default</i> is
151 # given, then that will be returned; if the optional code block is
152 # specified, then that will be run and its result returned.
153 #
154 # h = { "a" => 100, "b" => 200 }
155 # h.fetch("a") #=> 100
156 # h.fetch("z", "go fish") #=> "go fish"
157 # h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z"
158 #
159 # The following example shows that an exception is raised if the key
160 # is not found and a default value is not supplied.
161 #
162 # h = { "a" => 100, "b" => 200 }
163 # h.fetch("z")
164 #
165 # <em>produces:</em>
166 #
167 # prog.rb:2:in 'fetch': key not found (KeyError)
168 # from prog.rb:2
169 #
170
171 def fetch(key, none=NONE, &block)
172 unless self.key?(key)
173 if block
174 block.call(key)
175 elsif none != NONE
176 none
177 else
178 raise KeyError, "Key not found: #{key.inspect}"
179 end
180 else
181 self[key]
182 end
183 end
184
185 ##
186 # call-seq:
187 # hsh.delete_if {| key, value | block } -> hsh
188 # hsh.delete_if -> an_enumerator
189 #
190 # Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
191 # evaluates to <code>true</code>.
192 #
193 # If no block is given, an enumerator is returned instead.
194 #
195 # h = { "a" => 100, "b" => 200, "c" => 300 }
196 # h.delete_if {|key, value| key >= "b" } #=> {"a"=>100}
197 #
198
199 def delete_if(&block)
200 return to_enum :delete_if unless block
201
202 self.each do |k, v|
203 self.delete(k) if block.call(k, v)
204 end
205 self
206 end
207
208 ##
209 # call-seq:
210 # hash.flatten -> an_array
211 # hash.flatten(level) -> an_array
212 #
213 # Returns a new array that is a one-dimensional flattening of this
214 # hash. That is, for every key or value that is an array, extract
215 # its elements into the new array. Unlike Array#flatten, this
216 # method does not flatten recursively by default. The optional
217 # <i>level</i> argument determines the level of recursion to flatten.
218 #
219 # a = {1=> "one", 2 => [2,"two"], 3 => "three"}
220 # a.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
221 # a.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"]
222 #
223
224 def flatten(level=1)
225 self.to_a.flatten(level)
226 end
227
228 ##
229 # call-seq:
230 # hsh.invert -> new_hash
231 #
232 # Returns a new hash created by using <i>hsh</i>'s values as keys, and
233 # the keys as values.
234 #
235 # h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
236 # h.invert #=> {0=>"a", 100=>"m", 200=>"d", 300=>"y"}
237 #
238
239 def invert
240 h = self.class.new
241 self.each {|k, v| h[v] = k }
242 h
243 end
244
245 ##
246 # call-seq:
247 # hsh.keep_if {| key, value | block } -> hsh
248 # hsh.keep_if -> an_enumerator
249 #
250 # Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
251 # evaluates to false.
252 #
253 # If no block is given, an enumerator is returned instead.
254 #
255
256 def keep_if(&block)
257 return to_enum :keep_if unless block
258
259 keys = []
260 self.each do |k, v|
261 unless block.call([k, v])
262 self.delete(k)
263 end
264 end
265 self
266 end
267
268 ##
269 # call-seq:
270 # hsh.key(value) -> key
271 #
272 # Returns the key of an occurrence of a given value. If the value is
273 # not found, returns <code>nil</code>.
274 #
275 # h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
276 # h.key(200) #=> "b"
277 # h.key(300) #=> "c"
278 # h.key(999) #=> nil
279 #
280
281 def key(val)
282 self.each do |k, v|
283 return k if v == val
284 end
285 nil
286 end
287
288 ##
289 # call-seq:
290 # hsh.to_h -> hsh or new_hash
291 #
292 # Returns +self+. If called on a subclass of Hash, converts
293 # the receiver to a Hash object.
294 #
295 def to_h
296 self
297 end
298
299 ##
300 # call-seq:
301 # hash < other -> true or false
302 #
303 # Returns <code>true</code> if <i>hash</i> is subset of
304 # <i>other</i>.
305 #
306 # h1 = {a:1, b:2}
307 # h2 = {a:1, b:2, c:3}
308 # h1 < h2 #=> true
309 # h2 < h1 #=> false
310 # h1 < h1 #=> false
311 #
312 def <(hash)
313 raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
314 size < hash.size and all? {|key, val|
315 hash.key?(key) and hash[key] == val
316 }
317 end
318
319 ##
320 # call-seq:
321 # hash <= other -> true or false
322 #
323 # Returns <code>true</code> if <i>hash</i> is subset of
324 # <i>other</i> or equals to <i>other</i>.
325 #
326 # h1 = {a:1, b:2}
327 # h2 = {a:1, b:2, c:3}
328 # h1 <= h2 #=> true
329 # h2 <= h1 #=> false
330 # h1 <= h1 #=> true
331 #
332 def <=(hash)
333 raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
334 size <= hash.size and all? {|key, val|
335 hash.key?(key) and hash[key] == val
336 }
337 end
338
339 ##
340 # call-seq:
341 # hash > other -> true or false
342 #
343 # Returns <code>true</code> if <i>other</i> is subset of
344 # <i>hash</i>.
345 #
346 # h1 = {a:1, b:2}
347 # h2 = {a:1, b:2, c:3}
348 # h1 > h2 #=> false
349 # h2 > h1 #=> true
350 # h1 > h1 #=> false
351 #
352 def >(hash)
353 raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
354 size > hash.size and hash.all? {|key, val|
355 key?(key) and self[key] == val
356 }
357 end
358
359 ##
360 # call-seq:
361 # hash >= other -> true or false
362 #
363 # Returns <code>true</code> if <i>other</i> is subset of
364 # <i>hash</i> or equals to <i>hash</i>.
365 #
366 # h1 = {a:1, b:2}
367 # h2 = {a:1, b:2, c:3}
368 # h1 >= h2 #=> false
369 # h2 >= h1 #=> true
370 # h1 >= h1 #=> true
371 #
372 def >=(hash)
373 raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
374 size >= hash.size and hash.all? {|key, val|
375 key?(key) and self[key] == val
376 }
377 end
378
379 ##
380 # call-seq:
381 # hsh.dig(key,...) -> object
382 #
383 # Extracts the nested value specified by the sequence of <i>key</i>
384 # objects by calling +dig+ at each step, returning +nil+ if any
385 # intermediate step is +nil+.
386 #
387 def dig(idx,*args)
388 n = self[idx]
389 if args.size > 0
390 n&.dig(*args)
391 else
392 n
393 end
394 end
395
396 ##
397 # call-seq:
398 # hsh.transform_keys {|key| block } -> new_hash
399 # hsh.transform_keys -> an_enumerator
400 #
401 # Returns a new hash, with the keys computed from running the block
402 # once for each key in the hash, and the values unchanged.
403 #
404 # If no block is given, an enumerator is returned instead.
405 #
406 def transform_keys(&block)
407 return to_enum :transform_keys unless block
408 hash = {}
409 self.keys.each do |k|
410 new_key = block.call(k)
411 hash[new_key] = self[k]
412 end
413 hash
414 end
415 ##
416 # call-seq:
417 # hsh.transform_keys! {|key| block } -> hsh
418 # hsh.transform_keys! -> an_enumerator
419 #
420 # Invokes the given block once for each key in <i>hsh</i>, replacing it
421 # with the new key returned by the block, and then returns <i>hsh</i>.
422 #
423 # If no block is given, an enumerator is returned instead.
424 #
425 def transform_keys!(&block)
426 return to_enum :transform_keys! unless block
427 self.keys.each do |k|
428 value = self[k]
429 self.__delete(k)
430 k = block.call(k) if block
431 self[k] = value
432 end
433 self
434 end
435 ##
436 # call-seq:
437 # hsh.transform_values {|value| block } -> new_hash
438 # hsh.transform_values -> an_enumerator
439 #
440 # Returns a new hash with the results of running the block once for
441 # every value.
442 # This method does not change the keys.
443 #
444 # If no block is given, an enumerator is returned instead.
445 #
446 def transform_values(&b)
447 return to_enum :transform_values unless block_given?
448 hash = {}
449 self.keys.each do |k|
450 hash[k] = yield(self[k])
451 end
452 hash
453 end
454
455 ##
456 # call-seq:
457 # hsh.transform_values! {|key| block } -> hsh
458 # hsh.transform_values! -> an_enumerator
459 #
460 # Invokes the given block once for each value in the hash, replacing
461 # with the new value returned by the block, and then returns <i>hsh</i>.
462 #
463 # If no block is given, an enumerator is returned instead.
464 #
465 def transform_values!(&b)
466 return to_enum :transform_values! unless block_given?
467 self.keys.each do |k|
468 self[k] = yield(self[k])
469 end
470 self
471 end
472
473 def to_proc
474 ->x{self[x]}
475 end
476
477 ##
478 # call-seq:
479 # hsh.fetch_values(key, ...) -> array
480 # hsh.fetch_values(key, ...) { |key| block } -> array
481 #
482 # Returns an array containing the values associated with the given keys
483 # but also raises <code>KeyError</code> when one of keys can't be found.
484 # Also see <code>Hash#values_at</code> and <code>Hash#fetch</code>.
485 #
486 # h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
487 #
488 # h.fetch_values("cow", "cat") #=> ["bovine", "feline"]
489 # h.fetch_values("cow", "bird") # raises KeyError
490 # h.fetch_values("cow", "bird") { |k| k.upcase } #=> ["bovine", "BIRD"]
491 #
492 def fetch_values(*keys, &block)
493 keys.map do |k|
494 self.fetch(k, &block)
495 end
496 end
497
498 alias filter select
499 alias filter! select!
500end
Note: See TracBrowser for help on using the repository browser.