Last active
January 24, 2018 12:54
-
-
Save bryanp/938d2982c8eb2dafcb5189afbad9b558 to your computer and use it in GitHub Desktop.
Detect Optional Keyword Arguments in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NOT_PASSED = Object.new | |
def foo(bar: NOT_PASSED) | |
if bar.equal?(NOT_PASSED) | |
... | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# For context, this is a validator. Here's what I was trying to make work initially: | |
module Validations | |
class Acceptance | |
NOT_PASSED = Object.new | |
def self.valid?(value, accepts: NOT_PASSED) | |
if accepts.equal?(NOT_PASSED) | |
OtherValidator.valid?(value) | |
else | |
value == accepts | |
end | |
end | |
end | |
end | |
Acceptance.valid?(true) | |
# => true | |
Acceptance.valid?(nil) | |
# => false | |
Acceptance.valid?("no", accepts: "yes") | |
# => false | |
# BUT, you could do this instead (sort of resembling what @piisalie was suggesting on twitter): | |
module Validations | |
class Acceptance | |
def self.valid?(value, accepts: OtherValidator) | |
if accepts.respond_to?(:valid?) | |
accepts.valid?(value) | |
else | |
value == accepts | |
end | |
end | |
end | |
end |
Alright, your update is closer to what I was thinking but I would probably go one step further using a generic validator like:
class GenericValidator
def self.acceptable(value)
new(value)
end
def self.valid?(value)
true
end
def initialize(value)
@value = value
end
def valid?(value)
@value == value
end
end
module Validations
class Acceptance
def self.valid?(value, accepts: GenericValidator)
accepts.valid?(value) && !!value
end
end
end
Validations::Acceptance.valid?("no", accepts: GenericValidator.acceptable("yes"))
# => false
Validations::Acceptance.valid?("yes", accepts: GenericValidator.acceptable("yes"))
# => true
Validations::Acceptance.valid?(nil)
# => false
Validations::Acceptance.valid?(false)
# => false
The idea being, we should always pass a Validator as the accepts
option, and that validator knows how to tell if it is actually valid through the generic valid?
interface. In this way the Acceptance class doesn't have to have any knowledge about what validators exist and what to do with them.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I like your solution I think because I'm biased against
nil
. That said, I would probably use a symbol:not_passed
instead of a constant.Another solution I have often seen people use is like:
Edit: I think I misunderstood your question on Twitter. Rethinking my answer... ;-)