def values
  @store.values.flatten
 end
 def each
  @store.each {|k,v| v.each {|y| yield k,y}}
 end
 alias each_pair each
 def each_key
  self.keys.each {|k| yield k}
 end
 def each_value
  self.values.each {|v| yield v}
 end
 def has_key? k
  self.keys.include? k
 end
 def has_value? v
  self.values.include? v
 end
 def length
  self.values.size
 end
 alias size length
 def delete k
  val = @store[k]
  @store.delete k
  val
 end
 def delete k,v
  @store[k] -= [v] if @store[k]
  v
 end
 # Остальные методы опущены...
end
# He будет работать... для повторяющихся ключей
# актуально только последнее значение.
h = {1=>1, 2=>4, 3=>9, 4=>16, 2=>0}
# А так будет...
h = HashDup.new(1,1, 2,4, 3,9, 4,16, 2,0)
k = h.keys   # [4, 1, 2, 2, 3]
v = h.values # [16, 1, 4, 0, 9]
n = h.size   # 5
h.each {|k,v| puts '#{k} => #{v}'}
# Печатается:
# 4 => 16
# 1 => 1
# 2 => 4
# 2 => 0
# 3 => 9
Но если не пользоваться литеральными хэшами, то задача решаема. В листинге 8.1 реализован класс, содержащий атрибут @store, который является обычным хэшем; каждое значение этого хэша представляет собой массив. Доступ к хэшу организован так, что при необходимости добавить ключ, который уже существует, мы на самом деле добавляем новое значение в массив, ассоциированный с этим ключом.
Что должен возвращать метод size? Очевидно, «истинное» число пар ключ-значение, включая и дубликаты. Аналогично метод keys возвращает массив, который может содержать дубликаты. Итераторы ведут себя естественно; как и в случае обычного хэша, порядок обхода непредсказуем.
Помимо стандартного метода delete мы реализовали метод delete_pair. Первый удаляет все значения, ассоциированные с данным ключом, второй — только конкретную пару ключ-значение. (Отметим, что было бы затруднительно реализовать единственный метод вида delete(k, v=nil), так как nil — допустимое значение в любом хэше.)
Для краткости мы не стали реализовывать весь класс целиком и, честно говоря, для некоторых методов, например invert, пришлось бы принимать небанальные решения по поводу желательного поведения. Интересующийся читатель может восполнить пробелы.
8.3. Перечисляемые структуры в общем
Что делает набор перечисляемым? Вообще-то сам тот факт, что это набор. Модуль Enumerable требует, чтобы был определен стандартный итератор each. Последовательность обхода не имеет значения, так как даже неупорядоченные наборы, например хэш, могут обладать итераторами.
Кроме того, если предполагается пользоваться методами min, max и sort, то для набора должен быть определен метод сравнения (<=>). Все это достаточно очевидно.
Итак, 
