Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-hash-ext / mrblib / hash.rb
1 class 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 end