Use validate
helper to check interconnection between several options.
The helper takes name (unique for a current scope) and a block. Validation fails when a block returns falsey value.
class CatsAPI < Evil::Client
option :token, optional: true
option :user, optional: true
option :password, optional: true
# All requests should be made with either token or user/password
# This is required by any request
validate(:valid_credentials) { token ^ password }
validate(:password_given) { user ^ !password }
scope :cats do
option :version, proc(&:to_i)
# Check that operation of cats scope include token after API v1
# This doesn't affect other subscopes of CatsAPI root scope
validate(:token_based) { token || version.zero? }
end
# ...
end
CatsAPI.new password: "foo" # raises Evil::Client::ValidationError
The error message is translated using i18n gem. You should provide translations for a corresponding scope:
# config/locales/evil-client.en.yml
---
en:
evil:
client:
errors:
cats_api:
valid_credentials: "Provide either a token or a password"
password_given: "User and password should accompany one another"
cats:
token_based: "The token is required for operations with cats in API v1+"
The root scope for error messages is {locale}.evil.client.errors.{class_name}
as shown above.
Remember, that you can initialize client with some valid options, and then reload that options in a nested subscope/operation. All validations defined from the root of the client will be used for any set of options. See the example:
client = CatsAPI.new token: "foo"
# valid
cats = client.cats(version: 0)
# valid
cats.fetch id: 3
# valid
cats.fetch id: 3, token: nil
# fails due to 'valid_credentials' is broken
cats.fetch id: 3, token: nil, user: "andy", password: "qux"
# valid
cats.fetch id: 3, token: nil, user: "andy", password: "qux", version: 1
# fails due to 'cats.token_based' is broken