source: EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-hash-ext/mrblib/hash.rb@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby
File size: 8.9 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 = Hash.new
32 object[0].to_hash.each { |k, v| h[k] = v }
33 return h
34 elsif o.respond_to?(:to_a)
35 h = Hash.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 = Hash.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, "can't convert argument into Hash" unless other.respond_to?(:to_hash)
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.fetch(key [, default] ) -> obj
101 # hsh.fetch(key) {| key | block } -> obj
102 #
103 # Returns a value from the hash for the given key. If the key can't be
104 # found, there are several options: With no other arguments, it will
105 # raise an <code>KeyError</code> exception; if <i>default</i> is
106 # given, then that will be returned; if the optional code block is
107 # specified, then that will be run and its result returned.
108 #
109 # h = { "a" => 100, "b" => 200 }
110 # h.fetch("a") #=> 100
111 # h.fetch("z", "go fish") #=> "go fish"
112 # h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z"
113 #
114 # The following example shows that an exception is raised if the key
115 # is not found and a default value is not supplied.
116 #
117 # h = { "a" => 100, "b" => 200 }
118 # h.fetch("z")
119 #
120 # <em>produces:</em>
121 #
122 # prog.rb:2:in 'fetch': key not found (KeyError)
123 # from prog.rb:2
124 #
125
126 def fetch(key, none=NONE, &block)
127 unless self.key?(key)
128 if block
129 block.call(key)
130 elsif none != NONE
131 none
132 else
133 raise KeyError, "Key not found: #{key}"
134 end
135 else
136 self[key]
137 end
138 end
139
140 ##
141 # call-seq:
142 # hsh.delete_if {| key, value | block } -> hsh
143 # hsh.delete_if -> an_enumerator
144 #
145 # Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
146 # evaluates to <code>true</code>.
147 #
148 # If no block is given, an enumerator is returned instead.
149 #
150 # h = { "a" => 100, "b" => 200, "c" => 300 }
151 # h.delete_if {|key, value| key >= "b" } #=> {"a"=>100}
152 #
153
154 def delete_if(&block)
155 return to_enum :delete_if unless block_given?
156
157 self.each do |k, v|
158 self.delete(k) if block.call(k, v)
159 end
160 self
161 end
162
163 ##
164 # call-seq:
165 # hash.flatten -> an_array
166 # hash.flatten(level) -> an_array
167 #
168 # Returns a new array that is a one-dimensional flattening of this
169 # hash. That is, for every key or value that is an array, extract
170 # its elements into the new array. Unlike Array#flatten, this
171 # method does not flatten recursively by default. The optional
172 # <i>level</i> argument determines the level of recursion to flatten.
173 #
174 # a = {1=> "one", 2 => [2,"two"], 3 => "three"}
175 # a.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
176 # a.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"]
177 #
178
179 def flatten(level=1)
180 self.to_a.flatten(level)
181 end
182
183 ##
184 # call-seq:
185 # hsh.invert -> new_hash
186 #
187 # Returns a new hash created by using <i>hsh</i>'s values as keys, and
188 # the keys as values.
189 #
190 # h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
191 # h.invert #=> {0=>"a", 100=>"m", 200=>"d", 300=>"y"}
192 #
193
194 def invert
195 h = Hash.new
196 self.each {|k, v| h[v] = k }
197 h
198 end
199
200 ##
201 # call-seq:
202 # hsh.keep_if {| key, value | block } -> hsh
203 # hsh.keep_if -> an_enumerator
204 #
205 # Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
206 # evaluates to false.
207 #
208 # If no block is given, an enumerator is returned instead.
209 #
210
211 def keep_if(&block)
212 return to_enum :keep_if unless block_given?
213
214 keys = []
215 self.each do |k, v|
216 unless block.call([k, v])
217 self.delete(k)
218 end
219 end
220 self
221 end
222
223 ##
224 # call-seq:
225 # hsh.key(value) -> key
226 #
227 # Returns the key of an occurrence of a given value. If the value is
228 # not found, returns <code>nil</code>.
229 #
230 # h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
231 # h.key(200) #=> "b"
232 # h.key(300) #=> "c"
233 # h.key(999) #=> nil
234 #
235
236 def key(val)
237 self.each do |k, v|
238 return k if v == val
239 end
240 nil
241 end
242
243 ##
244 # call-seq:
245 # hsh.to_h -> hsh or new_hash
246 #
247 # Returns +self+. If called on a subclass of Hash, converts
248 # the receiver to a Hash object.
249 #
250 def to_h
251 self
252 end
253
254 ##
255 # call-seq:
256 # hash < other -> true or false
257 #
258 # Returns <code>true</code> if <i>hash</i> is subset of
259 # <i>other</i>.
260 #
261 # h1 = {a:1, b:2}
262 # h2 = {a:1, b:2, c:3}
263 # h1 < h2 #=> true
264 # h2 < h1 #=> false
265 # h1 < h1 #=> false
266 #
267 def <(hash)
268 begin
269 hash = hash.to_hash
270 rescue NoMethodError
271 raise TypeError, "can't convert #{hash.class} to Hash"
272 end
273 size < hash.size and all? {|key, val|
274 hash.key?(key) and hash[key] == val
275 }
276 end
277
278 ##
279 # call-seq:
280 # hash <= other -> true or false
281 #
282 # Returns <code>true</code> if <i>hash</i> is subset of
283 # <i>other</i> or equals to <i>other</i>.
284 #
285 # h1 = {a:1, b:2}
286 # h2 = {a:1, b:2, c:3}
287 # h1 <= h2 #=> true
288 # h2 <= h1 #=> false
289 # h1 <= h1 #=> true
290 #
291 def <=(hash)
292 begin
293 hash = hash.to_hash
294 rescue NoMethodError
295 raise TypeError, "can't convert #{hash.class} to Hash"
296 end
297 size <= hash.size and all? {|key, val|
298 hash.key?(key) and hash[key] == val
299 }
300 end
301
302 ##
303 # call-seq:
304 # hash > other -> true or false
305 #
306 # Returns <code>true</code> if <i>other</i> is subset of
307 # <i>hash</i>.
308 #
309 # h1 = {a:1, b:2}
310 # h2 = {a:1, b:2, c:3}
311 # h1 > h2 #=> false
312 # h2 > h1 #=> true
313 # h1 > h1 #=> false
314 #
315 def >(hash)
316 begin
317 hash = hash.to_hash
318 rescue NoMethodError
319 raise TypeError, "can't convert #{hash.class} to Hash"
320 end
321 size > hash.size and hash.all? {|key, val|
322 key?(key) and self[key] == val
323 }
324 end
325
326 ##
327 # call-seq:
328 # hash >= other -> true or false
329 #
330 # Returns <code>true</code> if <i>other</i> is subset of
331 # <i>hash</i> or equals to <i>hash</i>.
332 #
333 # h1 = {a:1, b:2}
334 # h2 = {a:1, b:2, c:3}
335 # h1 >= h2 #=> false
336 # h2 >= h1 #=> true
337 # h1 >= h1 #=> true
338 #
339 def >=(hash)
340 begin
341 hash = hash.to_hash
342 rescue NoMethodError
343 raise TypeError, "can't convert #{hash.class} to Hash"
344 end
345 size >= hash.size and hash.all? {|key, val|
346 key?(key) and self[key] == val
347 }
348 end
349end
Note: See TracBrowser for help on using the repository browser.