Project

General

Profile

Actions

Feature #17718

open

a method paramaters object that can be pattern matched against

Added by dsisnero (Dominic Sisneros) about 3 years ago. Updated almost 3 years ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:102829]

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
Actions #1

Updated by dsisnero (Dominic Sisneros) about 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) about 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) about 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) about 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) about 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) about 3 years ago

@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

Updated by dsisnero (Dominic Sisneros) about 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) about 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) almost 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.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0