Feature #17718
opena method paramaters object that can be pattern matched against
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
Updated by dsisnero (Dominic Sisneros) over 3 years ago
- Tracker changed from Bug to Feature
- Backport deleted (
2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN)
Updated by Hanmac (Hans Mackowiak) over 3 years ago
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
Updated by nobu (Nobuyoshi Nakada) over 3 years ago
- 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.
Updated by Hanmac (Hans Mackowiak) over 3 years ago
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
Updated by dsisnero (Dominic Sisneros) over 3 years ago
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
Updated by Hanmac (Hans Mackowiak) over 3 years ago
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
Updated by dsisnero (Dominic Sisneros) over 3 years ago
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.
Updated by Hanmac (Hans Mackowiak) over 3 years ago
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
Updated by Dan0042 (Daniel DeLorme) over 3 years ago
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.