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 4 years ago
          Updated by dsisnero (Dominic Sisneros) over 4 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 4 years ago
          Updated by Hanmac (Hans Mackowiak) over 4 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 4 years ago
          Updated by nobu (Nobuyoshi Nakada) over 4 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 4 years ago
          Updated by Hanmac (Hans Mackowiak) over 4 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 4 years ago
          Updated by dsisnero (Dominic Sisneros) over 4 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 4 years ago
          Updated by Hanmac (Hans Mackowiak) over 4 years ago
          
          
        
        
      
      @dsisnero
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 4 years ago
          Updated by dsisnero (Dominic Sisneros) over 4 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 4 years ago
          Updated by Hanmac (Hans Mackowiak) over 4 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 4 years ago
          Updated by Dan0042 (Daniel DeLorme) over 4 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.