1##
2# Hash
3#
4# ISO 15.2.13
5class Hash
6  ##
7  #  Equality---Two hashes are equal if they each contain the same number
8  #  of keys and if each key-value pair is equal to (according to
9  #  <code>Object#==</code>) the corresponding elements in the other
10  #  hash.
11  #
12  # ISO 15.2.13.4.1
13  def ==(hash)
14    return true if self.equal?(hash)
15    unless Hash === hash
16      return false
17    end
18    return false if self.size != hash.size
19    self.each do |k,v|
20      return false unless hash.key?(k)
21      return false unless self[k] == hash[k]
22    end
23    return true
24  end
25
26  ##
27  # Returns <code>true</code> if <i>hash</i> and <i>other</i> are
28  # both hashes with the same content compared by eql?.
29  #
30  # ISO 15.2.13.4.32 (x)
31  def eql?(hash)
32    return true if self.equal?(hash)
33    unless Hash === hash
34      return false
35    end
36    return false if self.size != hash.size
37    self.each do |k,v|
38      return false unless hash.key?(k)
39      return false unless self[k].eql?(hash[k])
40    end
41    return true
42  end
43
44  ##
45  # Delete the element with the key +key+.
46  # Return the value of the element if +key+
47  # was found. Return nil if nothing was
48  # found. If a block is given, call the
49  # block with the value of the element.
50  #
51  # ISO 15.2.13.4.8
52  def delete(key, &block)
53    if block && !self.has_key?(key)
54      return block.call(key)
55    end
56    self.__delete(key)
57  end
58
59  ##
60  # Calls the given block for each element of +self+
61  # and pass the key and value of each element.
62  #
63  # call-seq:
64  #   hsh.each      {| key, value | block } -> hsh
65  #   hsh.each_pair {| key, value | block } -> hsh
66  #   hsh.each                              -> an_enumerator
67  #   hsh.each_pair                         -> an_enumerator
68  #
69  #
70  # If no block is given, an enumerator is returned instead.
71  #
72  #     h = { "a" => 100, "b" => 200 }
73  #     h.each {|key, value| puts "#{key} is #{value}" }
74  #
75  # <em>produces:</em>
76  #
77  # a is 100
78  # b is 200
79  #
80  # ISO 15.2.13.4.9
81  def each(&block)
82    return to_enum :each unless block
83
84    keys = self.keys
85    vals = self.values
86    len = self.size
87    i = 0
88    while i < len
89      block.call [keys[i], vals[i]]
90      i += 1
91    end
92    self
93  end
94
95  ##
96  # Calls the given block for each element of +self+
97  # and pass the key of each element.
98  #
99  # call-seq:
100  #   hsh.each_key {| key | block } -> hsh
101  #   hsh.each_key                  -> an_enumerator
102  #
103  # If no block is given, an enumerator is returned instead.
104  #
105  #   h = { "a" => 100, "b" => 200 }
106  #   h.each_key {|key| puts key }
107  #
108  # <em>produces:</em>
109  #
110  #  a
111  #  b
112  #
113  # ISO 15.2.13.4.10
114  def each_key(&block)
115    return to_enum :each_key unless block
116
117    self.keys.each{|k| block.call(k)}
118    self
119  end
120
121  ##
122  # Calls the given block for each element of +self+
123  # and pass the value of each element.
124  #
125  # call-seq:
126  #   hsh.each_value {| value | block } -> hsh
127  #   hsh.each_value                    -> an_enumerator
128  #
129  # If no block is given, an enumerator is returned instead.
130  #
131  #  h = { "a" => 100, "b" => 200 }
132  #  h.each_value {|value| puts value }
133  #
134  # <em>produces:</em>
135  #
136  #  100
137  #  200
138  #
139  # ISO 15.2.13.4.11
140  def each_value(&block)
141    return to_enum :each_value unless block
142
143    self.values.each{|v| block.call(v)}
144    self
145  end
146
147  ##
148  # Replaces the contents of <i>hsh</i> with the contents of other hash
149  #
150  # ISO 15.2.13.4.23
151  def replace(hash)
152    raise TypeError, "Hash required (#{hash.class} given)" unless Hash === hash
153    self.clear
154    hash.each_key{|k|
155      self[k] = hash[k]
156    }
157    if hash.default_proc
158      self.default_proc = hash.default_proc
159    else
160      self.default = hash.default
161    end
162    self
163  end
164  # ISO 15.2.13.4.17
165  alias initialize_copy replace
166
167  ##
168  # Return a hash which contains the content of
169  # +self+ and +other+. If a block is given
170  # it will be called for each element with
171  # a duplicate key. The value of the block
172  # will be the final value of this element.
173  #
174  # ISO 15.2.13.4.22
175  def merge(other, &block)
176    raise TypeError, "Hash required (#{other.class} given)" unless Hash === other
177    h = self.dup
178    if block
179      other.each_key{|k|
180        h[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
181      }
182    else
183      other.each_key{|k| h[k] = other[k]}
184    end
185    h
186  end
187
188  # internal method for Hash inspection
189  def _inspect(recur_list)
190    return "{}" if self.size == 0
191    return "{...}" if recur_list[self.object_id]
192    recur_list[self.object_id] = true
193    ary=[]
194    keys=self.keys
195    vals=self.values
196    size=keys.size
197    i=0
198    while i<size
199      ary<<(keys[i]._inspect(recur_list) + "=>" + vals[i]._inspect(recur_list))
200      i+=1
201    end
202    "{"+ary.join(", ")+"}"
203  end
204  ##
205  # Return the contents of this hash as a string.
206 #
207  # ISO 15.2.13.4.30 (x)
208  def inspect
209    self._inspect({})
210  end
211  # ISO 15.2.13.4.31 (x)
212  alias to_s inspect
213
214  ##
215  #  call-seq:
216  #     hsh.reject! {| key, value | block }  -> hsh or nil
217  #     hsh.reject!                          -> an_enumerator
218  #
219  #  Equivalent to <code>Hash#delete_if</code>, but returns
220  #  <code>nil</code> if no changes were made.
221  #
222  #  1.8/1.9 Hash#reject! returns Hash; ISO says nothing.
223  #
224  def reject!(&block)
225    return to_enum :reject! unless block
226
227    keys = []
228    self.each{|k,v|
229      if block.call([k, v])
230        keys.push(k)
231      end
232    }
233    return nil if keys.size == 0
234    keys.each{|k|
235      self.delete(k)
236    }
237    self
238  end
239
240  ##
241  #  call-seq:
242  #     hsh.reject {|key, value| block}   -> a_hash
243  #     hsh.reject                        -> an_enumerator
244  #
245  #  Returns a new hash consisting of entries for which the block returns false.
246  #
247  #  If no block is given, an enumerator is returned instead.
248  #
249  #     h = { "a" => 100, "b" => 200, "c" => 300 }
250  #     h.reject {|k,v| k < "b"}  #=> {"b" => 200, "c" => 300}
251  #     h.reject {|k,v| v > 100}  #=> {"a" => 100}
252  #
253  #  1.8/1.9 Hash#reject returns Hash; ISO says nothing.
254  #
255  def reject(&block)
256    return to_enum :reject unless block
257
258    h = {}
259    self.each{|k,v|
260      unless block.call([k, v])
261        h[k] = v
262      end
263    }
264    h
265  end
266
267  ##
268  #  call-seq:
269  #     hsh.select! {| key, value | block }  -> hsh or nil
270  #     hsh.select!                          -> an_enumerator
271  #
272  #  Equivalent to <code>Hash#keep_if</code>, but returns
273  #  <code>nil</code> if no changes were made.
274  #
275  #  1.9 Hash#select! returns Hash; ISO says nothing.
276  #
277  def select!(&block)
278    return to_enum :select! unless block
279
280    keys = []
281    self.each{|k,v|
282      unless block.call([k, v])
283        keys.push(k)
284      end
285    }
286    return nil if keys.size == 0
287    keys.each{|k|
288      self.delete(k)
289    }
290    self
291  end
292
293  ##
294  #  call-seq:
295  #     hsh.select {|key, value| block}   -> a_hash
296  #     hsh.select                        -> an_enumerator
297  #
298  #  Returns a new hash consisting of entries for which the block returns true.
299  #
300  #  If no block is given, an enumerator is returned instead.
301  #
302  #     h = { "a" => 100, "b" => 200, "c" => 300 }
303  #     h.select {|k,v| k > "a"}  #=> {"b" => 200, "c" => 300}
304  #     h.select {|k,v| v < 200}  #=> {"a" => 100}
305  #
306  #  1.9 Hash#select returns Hash; ISO says nothing
307  #
308  def select(&block)
309    return to_enum :select unless block
310
311    h = {}
312    self.each{|k,v|
313      if block.call([k, v])
314        h[k] = v
315      end
316    }
317    h
318  end
319end
320
321##
322# Hash is enumerable
323#
324# ISO 15.2.13.3
325class Hash
326  include Enumerable
327end
328