solnic / coercible

Powerful, flexible and configurable coercion library. And nothing more.
MIT License
137 stars 16 forks source link

Raise an exception if the coercion not supported #4

Closed handiwiguna closed 11 years ago

handiwiguna commented 11 years ago
coercer[String].to_integer('a')
Coercible::UnsupportedCoercion: Coercible::Coercer::String#to_integer doesn't know how to coerce "a"
felipeelias commented 11 years ago

That's very useful imo. But I'm not sure if in all cases you'd want this behaviour.

solnic commented 11 years ago

@handiwiguna thank you!

@felipeelias it was actually planned to make coercible work in such a strict wait. client libraries (like virtus) can catch those exceptions and silently return input value that couldn't be coerced

mbj commented 11 years ago

@solnic I dislike catching exceptions to steer control flow, cant we have two differend methods? One that raises exceptions and one that doesnt? This would also fit very well in my planned refactoring.

solnic commented 11 years ago

@mbj I'm not sure. I need to think about this. I want to keep coercible as simple as possible.

felipeelias commented 11 years ago

@mbj I think it depends on the purpose of the gem. If you want to coerce a string into a date for example and it fails for some reason, it's much better (imo) to throw an exception than failing silently.

mbj commented 11 years ago

@felipeelias This is the reason I'd like to see two separate entry points. One that does return the input, and one that raises an exception. For both I see valid use cases.

EDIT: * on failure ;)

solnic commented 11 years ago

@mbj yeah my initial idea was to make coercible to work in strict and non-strict mode. Maybe let's think how to approach this w/o complicating coercible code too much :smile:

mbj commented 11 years ago

@solnic There is also a refactoring I was planning. I think this refactoring would allow such an interface easily.

solnic commented 11 years ago

@mbj that's cool. So what's your idea?

On niedz., mar 31, 2013 at 9:36 AM, Markus Schirp notifications@github.com="mailto:notifications@github.com"> wrote:

@solnic There is also a refactoring I was planning. I think this refactoring would allow such an interface easily.

— Reply to this email directly or view it on GitHub.

mbj commented 11 years ago

@solnic

Primary interface (with exceptions) on failure:

coercer.from(String).to(Integer).call(value)

Secondary interface (returns input on failure)

coercer.from(String).to(Integer).try_convert(value)

# To check for failure
coercion = coercer.from(String).to(Integer)
value = coercion.try_convert("asdsa") # => "asda"
coercion.coerced?(value) # => false

The "coercion" objects returned by coercer.from(Source).to(Target) could be tracked per virtus attribute. Overhead of the new API would be the same as current. (One method call to reach coercion logic).

EDIT: s/path/coercion/

mbj commented 11 years ago

@solnic, @dkubb We could also provide a ducktrap compatible API that returns a result object:

coercion = coercer.from(String).to(Integer)

result = coercion.run('foo')
result.successful? # false

result = coercion.run('100')
result.successful? # true
result.output # 100

The use of explicit inversable coercion "path" objects allows different calling semantics quite easily without adding bloat.

mbj commented 11 years ago

Last addition (Sorry for rushing out with so many comments)

The "coercion" objects would support #inverse.

coercion = coercer.from(String).to(Integer)

value = "100"

coercion.inverse.call(coercion.call(value)).eql?("100") # => true

This is not only nice for ducktrap, form objects and friends. It also eases testing as transitive properties of the coercible domain could and IMHO should be exploited for correctness!

solnic commented 11 years ago

This would be a nice abstraction but I'm worried about a massive overhead it would add.

mbj commented 11 years ago

@solnic Yeah the "Returning a Result object" adds a serious amount of overhead.

The other ideas not. If you reuse the "coercion" objects. They do not have mutable state, so are perfect candidates for living inside Virtus attributes. Instead of having a "coercion_method" you just have a "coercer" where you can use #call on.

solnic commented 11 years ago

Oh yes I was referring to return objects — Sent from Mailbox for iPhone

On Sun, Mar 31, 2013 at 3:38 PM, Markus Schirp notifications@github.com wrote:

@solnic Yeah the "Returning a Result object" adds a serious amount of overhead.

The other ideas not. If you reuse the "coercion" objects. They do not have mutable state, so are perfect candidates for living inside Virtus attributes. Instead of having a "coercion_method" you just have a "coercer" where you can use #call on.

Reply to this email directly or view it on GitHub: https://github.com/solnic/coercible/pull/4#issuecomment-15691385

mbj commented 11 years ago

I think this returning objects API is fast enough for parsing forms. It should be up to the user to decide which one he uses. I'll not implement the "Result Objects" in my first refactoring.