source: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-hash-ext/mrblib/hash.rb@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 9.7 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 o.respond_to?(:to_hash)
31 h = self.new
32 object[0].to_hash.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 # Hash.try_convert(obj) -> hash or nil
66 #
67 # Try to convert <i>obj</i> into a hash, using to_hash method.
68 # Returns converted hash or nil if <i>obj</i> cannot be converted
69 # for any reason.
70 #
71 # Hash.try_convert({1=>2}) # => {1=>2}
72 # Hash.try_convert("1=>2") # => nil
73 #
74 def self.try_convert(obj)
75 if obj.respond_to?(:to_hash)
76 obj.to_hash
77 else
78 nil
79 end
80 end
81
82 ##
83 # call-seq:
84 # hsh.merge!(other_hash) -> hsh
85 # hsh.merge!(other_hash){|key, oldval, newval| block} -> hsh
86 #
87 # Adds the contents of _other_hash_ to _hsh_. If no block is specified,
88 # entries with duplicate keys are overwritten with the values from
89 # _other_hash_, otherwise the value of each duplicate key is determined by
90 # calling the block with the key, its value in _hsh_ and its value in
91 # _other_hash_.
92 #
93 # h1 = { "a" => 100, "b" => 200 }
94 # h2 = { "b" => 254, "c" => 300 }
95 # h1.merge!(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
96 #
97 # h1 = { "a" => 100, "b" => 200 }
98 # h2 = { "b" => 254, "c" => 300 }
99 # h1.merge!(h2) { |key, v1, v2| v1 }
100 # #=> {"a"=>100, "b"=>200, "c"=>300}
101 #
102
103 def merge!(other, &block)
104 raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash)
105 if block
106 other.each_key{|k|
107 self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
108 }
109 else
110 other.each_key{|k| self[k] = other[k]}
111 end
112 self
113 end
114
115 alias update merge!
116
117 ##
118 # call-seq:
119 # hsh.fetch(key [, default] ) -> obj
120 # hsh.fetch(key) {| key | block } -> obj
121 #
122 # Returns a value from the hash for the given key. If the key can't be
123 # found, there are several options: With no other arguments, it will
124 # raise an <code>KeyError</code> exception; if <i>default</i> is
125 # given, then that will be returned; if the optional code block is
126 # specified, then that will be run and its result returned.
127 #
128 # h = { "a" => 100, "b" => 200 }
129 # h.fetch("a") #=> 100
130 # h.fetch("z", "go fish") #=> "go fish"
131 # h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z"
132 #
133 # The following example shows that an exception is raised if the key
134 # is not found and a default value is not supplied.
135 #
136 # h = { "a" => 100, "b" => 200 }
137 # h.fetch("z")
138 #
139 # <em>produces:</em>
140 #
141 # prog.rb:2:in 'fetch': key not found (KeyError)
142 # from prog.rb:2
143 #
144
145 def fetch(key, none=NONE, &block)
146 unless self.key?(key)
147 if block
148 block.call(key)
149 elsif none != NONE
150 none
151 else
152 raise KeyError, "Key not found: #{key}"
153 end
154 else
155 self[key]
156 end
157 end
158
159 ##
160 # call-seq:
161 # hsh.delete_if {| key, value | block } -> hsh
162 # hsh.delete_if -> an_enumerator
163 #
164 # Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
165 # evaluates to <code>true</code>.
166 #
167 # If no block is given, an enumerator is returned instead.
168 #
169 # h = { "a" => 100, "b" => 200, "c" => 300 }
170 # h.delete_if {|key, value| key >= "b" } #=> {"a"=>100}
171 #
172
173 def delete_if(&block)
174 return to_enum :delete_if unless block_given?
175
176 self.each do |k, v|
177 self.delete(k) if block.call(k, v)
178 end
179 self
180 end
181
182 ##
183 # call-seq:
184 # hash.flatten -> an_array
185 # hash.flatten(level) -> an_array
186 #
187 # Returns a new array that is a one-dimensional flattening of this
188 # hash. That is, for every key or value that is an array, extract
189 # its elements into the new array. Unlike Array#flatten, this
190 # method does not flatten recursively by default. The optional
191 # <i>level</i> argument determines the level of recursion to flatten.
192 #
193 # a = {1=> "one", 2 => [2,"two"], 3 => "three"}
194 # a.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
195 # a.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"]
196 #
197
198 def flatten(level=1)
199 self.to_a.flatten(level)
200 end
201
202 ##
203 # call-seq:
204 # hsh.invert -> new_hash
205 #
206 # Returns a new hash created by using <i>hsh</i>'s values as keys, and
207 # the keys as values.
208 #
209 # h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
210 # h.invert #=> {0=>"a", 100=>"m", 200=>"d", 300=>"y"}
211 #
212
213 def invert
214 h = self.class.new
215 self.each {|k, v| h[v] = k }
216 h
217 end
218
219 ##
220 # call-seq:
221 # hsh.keep_if {| key, value | block } -> hsh
222 # hsh.keep_if -> an_enumerator
223 #
224 # Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
225 # evaluates to false.
226 #
227 # If no block is given, an enumerator is returned instead.
228 #
229
230 def keep_if(&block)
231 return to_enum :keep_if unless block_given?
232
233 keys = []
234 self.each do |k, v|
235 unless block.call([k, v])
236 self.delete(k)
237 end
238 end
239 self
240 end
241
242 ##
243 # call-seq:
244 # hsh.key(value) -> key
245 #
246 # Returns the key of an occurrence of a given value. If the value is
247 # not found, returns <code>nil</code>.
248 #
249 # h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
250 # h.key(200) #=> "b"
251 # h.key(300) #=> "c"
252 # h.key(999) #=> nil
253 #
254
255 def key(val)
256 self.each do |k, v|
257 return k if v == val
258 end
259 nil
260 end
261
262 ##
263 # call-seq:
264 # hsh.to_h -> hsh or new_hash
265 #
266 # Returns +self+. If called on a subclass of Hash, converts
267 # the receiver to a Hash object.
268 #
269 def to_h
270 self
271 end
272
273 ##
274 # call-seq:
275 # hash < other -> true or false
276 #
277 # Returns <code>true</code> if <i>hash</i> is subset of
278 # <i>other</i>.
279 #
280 # h1 = {a:1, b:2}
281 # h2 = {a:1, b:2, c:3}
282 # h1 < h2 #=> true
283 # h2 < h1 #=> false
284 # h1 < h1 #=> false
285 #
286 def <(hash)
287 begin
288 hash = hash.to_hash
289 rescue NoMethodError
290 raise TypeError, "can't convert #{hash.class} to Hash"
291 end
292 size < hash.size and all? {|key, val|
293 hash.key?(key) and hash[key] == val
294 }
295 end
296
297 ##
298 # call-seq:
299 # hash <= other -> true or false
300 #
301 # Returns <code>true</code> if <i>hash</i> is subset of
302 # <i>other</i> or equals to <i>other</i>.
303 #
304 # h1 = {a:1, b:2}
305 # h2 = {a:1, b:2, c:3}
306 # h1 <= h2 #=> true
307 # h2 <= h1 #=> false
308 # h1 <= h1 #=> true
309 #
310 def <=(hash)
311 begin
312 hash = hash.to_hash
313 rescue NoMethodError
314 raise TypeError, "can't convert #{hash.class} to Hash"
315 end
316 size <= hash.size and all? {|key, val|
317 hash.key?(key) and hash[key] == val
318 }
319 end
320
321 ##
322 # call-seq:
323 # hash > other -> true or false
324 #
325 # Returns <code>true</code> if <i>other</i> is subset of
326 # <i>hash</i>.
327 #
328 # h1 = {a:1, b:2}
329 # h2 = {a:1, b:2, c:3}
330 # h1 > h2 #=> false
331 # h2 > h1 #=> true
332 # h1 > h1 #=> false
333 #
334 def >(hash)
335 begin
336 hash = hash.to_hash
337 rescue NoMethodError
338 raise TypeError, "can't convert #{hash.class} to Hash"
339 end
340 size > hash.size and hash.all? {|key, val|
341 key?(key) and self[key] == val
342 }
343 end
344
345 ##
346 # call-seq:
347 # hash >= other -> true or false
348 #
349 # Returns <code>true</code> if <i>other</i> is subset of
350 # <i>hash</i> or equals to <i>hash</i>.
351 #
352 # h1 = {a:1, b:2}
353 # h2 = {a:1, b:2, c:3}
354 # h1 >= h2 #=> false
355 # h2 >= h1 #=> true
356 # h1 >= h1 #=> true
357 #
358 def >=(hash)
359 begin
360 hash = hash.to_hash
361 rescue NoMethodError
362 raise TypeError, "can't convert #{hash.class} to Hash"
363 end
364 size >= hash.size and hash.all? {|key, val|
365 key?(key) and self[key] == val
366 }
367 end
368
369 ##
370 # call-seq:
371 # hsh.dig(key,...) -> object
372 #
373 # Extracts the nested value specified by the sequence of <i>key</i>
374 # objects by calling +dig+ at each step, returning +nil+ if any
375 # intermediate step is +nil+.
376 #
377 def dig(idx,*args)
378 n = self[idx]
379 if args.size > 0
380 n&.dig(*args)
381 else
382 n
383 end
384 end
385end
Note: See TracBrowser for help on using the repository browser.