So the question is wich representation Enumerable#to_h should expect -
nested or sequence?
robert
I believe coercion should be as loose less as possible. As a result it
is difficult to imagine that a generic solution is optimal. Only the
actual class knows the optimum. Yet...
One may argue that an Array is a degenerated Hash where the keys are
integer indices. i.e.
["a","b"].to_h() == { 0 => "a", 1 => "b" }
One may argue that the loose less convertion of a Hash to an Array is
an an array of [key, value]. i.e.
{ 0 => "a", 1 => "b"}.to_a() == [[0,"a"],[1,"b"]]
(Ruby does that today)
hum... issue is a.to_h().to_a() is quite different from original a.
Better:
# What you get when converting a Hash into an Array, see Hash##to_a()
class HashAsArray < Array
def to_h()
# Assume self is an array of [key, value], raise exception if not true
# Error checking code skipped, ToDo: it
Hash[*flatten()]
end
end
# What you get when converting an Array into a Hash, see Array##to_h()
class ArrayAsHash < Hash
def to_a()
# Assume keys are integers indices, raise exception if not true
# Error checking code skipped, ToDo: it
super().sort { |(ka,va),(kb,vb)| ka <=> kb }.collect { |(k,v)| v }
# ToDo: There must be a faster solution to do that.
end
end
# Now, have Hash.to_a() return an HashAsArray instead of an Array,
# and, have Array.to_h() return an ArrayAsHash.
class Hash
alias ruby_to_a to_a
def to_a()
HashAsArray.new().replace( ruby_to_a())
end
def to_h()
self
end
end
class Array
def to_h()
ii = 0
aa = []
self.each { |v| aa << (ii += 1); aa << v }
return ArrayAsHash[*aa]
end
end
# As a result, an_array.to_h().to_a() is OK and
# a_hash.to_a().to_h() is ok too.
p a = ["a", "b", "c", "d", "e", "f"]
p h = a.to_h()
p h.class()
p h.kind_of?( Hash)
p h.class() == Hash # not true anymore... but:
case h
when Hash then p "OK"
end
p aa = h.to_a()
p aa.class()
p a.to_h().to_a() == a
p a.to_a().to_h().to_a() == a
p h = { "key_a" => "a", "key_b" => "b" }
p a = h.to_a()
p a.class()
p a.kind_of?( Array)
p a.class() == Array # not true anymore... but:
case a
when Array then p "OK"
end
p hh = a.to_h()
p hh.class()
p h.to_a().to_h() == h
p h.to_h().to_a().to_h() == h
# Most visible change is about these beeing false:
p Array == HashAsArray
p HashAsArray == Array
p Hash == ArrayAsHash
p ArrayAsHash == Hash
# Workaround is so ugly that I don't present it here.
# I believe this only change cannot break much existing code,
# but very unprobable code that would depend on Hash##to_a()
# beeing of class Array precisely. Questionnable
# code that does not respect the OO idea of is_a relationship
# and test class for equality using == instead of
# kind_of? or === (in case statements).
Any drawbacks (beside minor one about .class() == changed) ?
Jean-Hugues