<p>Hopefully I haven't misunderstood the meaning of "duck typing", but from what I've read, it means that I should write code based on how an object responds to methods rather than what type/class it is.</p>

<p>Here's the code:</p>

<pre><code>def convert_hash(hash)
  if hash.keys.all? { |k| k.is_a?(Integer) }
    return hash
  elsif hash.keys.all? { |k| k.is_a?(Property) }
    new_hash = {}
    hash.each_pair {|k,v| new_hash[k.id] = v}
    return new_hash
  else
    raise "Custom attribute keys should be ID's or Property objects"
  end
end
</code></pre>

<p>What I want is to make sure that I end up with a hash where the keys are an integer representing the ID of an ActiveRecord object. I don't particularly enjoy having to iterate through the hash keys twice with <code>all?</code> to determine if I need to grab the ID's out.</p>

<p>Of course, I'll accept any other suggestions to improve this code as well :)</p>

How you write this method should depend on whether you expect an exception to be thrown during the course of normal program execution.  If you want a readable exception message because an end-user might see it, then throwing one manually makes sense.  Otherwise, I'd just do something like this:
```
```
def convert(hash)
    new_hash = {}
    hash.each_pair { |k,v| new_hash[ k.is_a?(Integer) ? k : k.id ] = v }
    return new_hash
end
```
```
This will accomplish exactly the same thing, and you'll still get an exception if an array key doesn't have an id field.  Even better, this uses a little more duck typing because now anything that has an id field will be acceptable, which is better than explicitly checking for something being a Property.  This makes your code more flexible, especially when unit testing.
We still have an explicit check for integer objects, but this kind of occasional special case is usually acceptable, especially when checking for built-in data types.