intridea/hashie — pull request #199 by maxlinc (2014-08-07 02:57:15+00:00)
Title: Coerce only when necessary

This PR probably isn't ready to merge, because:
- I'm not sure it handles `coerce_value` properly or edge cases like collections for `coerce_key`.
- The current code effectively clones an object during coercion. This could be a breaking change for users relying on that behavior.

Still, I wanted to pass along a test case and a possible fix to start a discussion.

I noticed that `coerce_key` always initializes a new object, even if the object already matches the target type. Consider:
```
property :special
coerce_key :special, SpecialHash
```

If `:special` is a Hash, then Hashie should coerce it to a SpecialHash.
If `:special` is a SpecialHash, then Hashie ~~coerces it to a SpecialHash~~ I think Hashie should use it, just as it would if there was no coercion.

I don't mind if Hashie can't coerce a property to a Float, but I want it to tell me "could not coerce :foo from String to Float" rather than rather than telling me to "undefined method `new' for Float:Class" without a property name or line number. That will let me fix the source of the data, which in my case is YAML so I can use [YAML's type casting](http://en.wikipedia.org/wiki/YAML#Casting_data_types) to ensure ambiguous values like "2" are loaded as a Float rather than a String or Fixnum.

Although this PR isn't ready to merge, I do think it might help with some existing issues:
- https://github.com/intridea/hashie/issues/161 - Coercing core types (Boolean, Float, Integer, Symbol): this does't fully solve coercion, but at least makes it possible to use those types for type-checking.
- https://github.com/intridea/hashie/issues/115 - Circular key coercion: Again, this should at least make type checking possible, but I think this could actually solve many circular coercion scenarios.
- Performance - In many cases it's probably negligable, but in some cases not unnecessarily cloning large objects or objects with slow initialization (e.g. compiling regexes) could give a small performance boost.