What's an efficient, rubyesque way of testing if a collection supports string indexing?
Long version:
I'd like for a class of mine to normalize certain values. To achieve this, an instance takes a collection of values as its 'values' attribute. I'd like values=
to accept both lists (integer indexed collections, including the built-in Array) and associative arrays (object indexed collections, such as Hash). If passed a list, it turns the list into an associative array by inverting keys & values. This means the method needs to distinguish lists from associative arrays. It should also work on any indexed collection, not just descendants of Array and Hash, so any sort of type sniffing the collection type is considered ugly and wrong. Type sniffing the index type, however...
Currently, I'm using exceptions to tell the difference, but I prefer to use exceptions for, well, exceptional circumstances rather than a general control structure. It's just a personal preference, one I'm not too attached to. If exceptions are the ruby way to solve this problem, please let me know.
def values=(values)
begin
values['']
@values = values.dup
rescue TypeError
@values = Hash[ values.zip((0..values.length-1).to_a) ]
end
@values.each_value { |v| @values[v] = v}
end
Note: a complete solution would take the transitive closure of values
, but for now I can assume the keys & values of values
are from different domains.
The point of all this is to enable code like:
toggle.values = [:off, :on]
toggle.normalise(:off) == 0
toggle.normalise(1) == 1
bool.values = {:off => 0, :false => 0, :no => 0,
:on => 1, :true => 1, :yes => 1}
bool.normalise(:yes) == 1
bool.normalise(0) == 0
PS. This is for a personal project, so elegance and the Ruby way are paramount. I'm looking for interesting approaches, especially if they illustrate an interesting concept (such as "exceptions can be used as behavioral tests").