Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs out of date for Contract.valid?? #250

Open
aviflax opened this issue Feb 17, 2017 · 7 comments
Open

Docs out of date for Contract.valid?? #250

aviflax opened this issue Feb 17, 2017 · 7 comments

Comments

@aviflax
Copy link

aviflax commented Feb 17, 2017

The docs for Contract.valid read:

  # Used to verify if an argument satisfies a contract.
  #
  # Takes: an argument and a contract.
  #
  # Returns: a tuple: [Boolean, metadata]. The boolean indicates
  # whether the contract was valid or not. If it wasn't, metadata
  # contains some useful information about the failure.

but when I call it, I’m just getting back a boolean — not a tuple.

So:

  1. Perhaps the docstring should be updated?
    1. I’d be happy to submit a PR for this, if desired.
  2. Is there some other way to “manually” validate a value against a contract and, when a value is invalid, obtain the specific reason?
    1. I saw in the code that there’s a callback mechanism for handling failures, but I’m not smart enough to understand how to use that mechanism to actually retrieve the failure data/reason… 😬

Thanks!

@egonSchiele
Copy link
Owner

Hi,
I think the failure_callback could be perfect for your use case. Accessing the data object is easy, it is passed in as an argument to the callback. Check out this example:

require "contracts"
include Contracts

Contract.override_failure_callback do |data|
  p data
end

Contract Num, Num => Num
def add a, b
  a + b
end

add([], [])

This will just print out the data object and you can see all the info that is passed in.

@aviflax
Copy link
Author

aviflax commented Feb 20, 2017

@egonSchiele thank you for the rapid response! I totally see how the callback is great for debugging, logging, and other side effects. But in my case I need the metadata back as a value, within the same context from which I called valid? I apologize if it’s obvious how to do this; I’m still fairly new to Ruby.

@egonSchiele
Copy link
Owner

@aviflax
Could you elaborate on what context you are calling valid? from? And what kind of value you are looking to get back?

@aviflax
Copy link
Author

aviflax commented Feb 20, 2017

Yeah, I could, but… I just realized, that in my specific case, I actually can use the callback mechanism, because in fact all I want to do with the failure metadata is log it… so I just need a side effect. So I think I can get that going.

I guess I was just intuitively uncomfortable, initially, with the callback mechanism, because in general I don’t like callbacks; I like functions with inputs and outputs. If, for example, I needed to actually do something with the failure metadata, like collect multiple errors together and generate a report of some kind… I guess I could rig up a way to do so with callbacks, but it would just seem so much simpler to me to just get back a value from a simple function call.

Would there be any interest in adding another method to Contract, maybe something like valid_or_reason that would return a tuple as described in the docs? Do you think that would be difficult to implement?

Thanks!

@egonSchiele
Copy link
Owner

Sure, that sounds useful @aviflax . I'd say it would be medium difficulty, and would give you a nice tour of this codebase :)

@kliuless
Copy link
Contributor

kliuless commented Mar 15, 2017

@aviflax This may be helpful:

some_contract = Or[ ArrayOf[String], ArrayOf[Integer] ]
unless Contract.valid?(some_value, some_contract)
  # logs "((a collection Array of String) or (a collection Array of Integer))"
  logger.warn Contracts::Formatters::Expected.new( some_contract ).contract.to_s
end

Generating the message is a bit verbose, but you can write your own helper method to make that easier.

EDIT: Sorry, the above was more complex than it needed to be. You can simply do this

logger.warn some_contract.to_s

This only difference is that you won't have the outermost parentheses.

@aviflax
Copy link
Author

aviflax commented Mar 15, 2017

Very helpful — thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants