Feature #17718
open
a method paramaters object that can be pattern matched against
Added by dsisnero (Dominic Sisneros) over 3 years ago.
Updated over 3 years ago.
Description
def get_perdiem(city: nil, state: nil, zip:nil)
case parameters_match # (return an object of the parameters we can pattern match on)
in {zip: zip}
find_perdiem_by_zip(zip)
in {state: s, city: c}
find_perdiem_by_state_and_city(s, c)
in { state: s}
find_perdiem_by_state(s)
else
raise 'need combination of zip, city,state'
end
end
- Tracker changed from Bug to Feature
- Backport deleted (
2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN)
you want **args
def getParam(**args)
case args
in {zip: zip}
p "zip"
in {state: s, city: c}
p "state+city"
in { state: s}
p "state"
else
raise 'need combination of zip, city, state'
end
end
- Description updated (diff)
Hanmac (Hans Mackowiak) wrote in #note-2:
you want **args
I guess that the point is the keywords are checked, that is get_perdiem(nation: "usa")
will raise an ArgumentError
.
I think there was a proposal for a similar concept, "rest keywords including all keywords", but can't find it now.
the ArgumentError can be raised manually when going to raise an Exception anyway
@nobu (Nobuyoshi Nakada) the problem i see there right now if rest keywords should include default param / null.
because the pattern matching above only cares about the existence of the symbol key in case, and doesn't check if the value might be null
what works but is ugly is this:
def getParam(city: nil, state: nil, zip: nil)
case {city: city, state: state, zip: zip}.compact
def get_param(name, city: nil, state:nil, zip: nil, &error)
case parameters_match
in [String, String, String , String, Proc]
puts 'all method types matched against'
in [String, nil, String, nil,nil]
puts 'only city and state matched'
end
end
I don't only want to match on keywords. I want to use an object to make it easy ruby methods like multimethods
@dsisnero (Dominic Sisneros)
this is even more problematic because ruby doesn't know which parameter should be at which position there
it may not know which param you want at which in your in comparison, especially if you mix key args with non key args
You can still use args for this
def get_param(name, **args, &error)
case args
in {city: String, state: String, zip: String}
puts 'all method types matched against'
in {city: String, state: String}
puts 'only city and state matched'
end
end
the parameters method returns the name in order. I know ruby doesn't do it yet, this is a feature request to add a
method like the parameters argument that could be pattern matched against.
there could be a way, like method(__method__).parameters
can return the parameters of the current method,
it is still more unclean than just use **args
nobu (Nobuyoshi Nakada) wrote in #note-3:
I think there was a proposal for a similar concept, "rest keywords including all keywords", but can't find it now.
I believe you're talking about #15049. In #16253 there was also brief talk of making argument forwarding work like that so we could use Hash[...]
, but unfortunately that option was not retained.
But in this particular case I think it wouldn't work anyway; let's say you use get_perdiem(state: 'CA')
then I would expect parameters_match
to return all parameters including their default values like {city: nil, state: 'CA', zip:nil}
. And that would match in {zip: zip}
unlike what the OP intends. Or use parameters_match.compact
like Hanmac suggests.
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0