使用关键字参数确定方法的arity

Phr*_*ogz 3 ruby method-dispatch keyword-argument

我正在开发一个Ruby应用程序,我在其中动态调用基于JSON数据的方法.松散:

def items
  # do something
end

def createItem( name:, data:nil )
  # do something that requires a name keyword argument
end

def receive_json(json) # e.g. { "cmd":"createItem", "name":"jim" }
  hash = JSON.parse(json)
  cmd = hash.delete('cmd')
  if respond_to?(cmd)
    params = Hash[ hash.map{ |k,v| [k.to_sym, v } ]
    method(cmd).arity==0 ? send(cmd) : send(cmd,params)
  end
end
Run Code Online (Sandbox Code Playgroud)

如上所示,某些方法不带参数,有些方法带有关键字参数.在Ruby 2.1.0(我正在开发)中arity,上述两种方法都是0.但是,如果我send(cmd,params)总是这样,那么对于不带参数的方法我会收到错误.

如何send在需要时使用正确传递关键字参数,但在没有时省略它们?

Phr*_*ogz 7

使用parameters而不是arity似乎为我的需要工作:

method(cmd).parameters.empty? ? send(cmd) : send(cmd,opts)
Run Code Online (Sandbox Code Playgroud)

更深入地了解parameters返回值的丰富程度:

def foo; end
method(:foo).parameters
#=> [] 

def bar(a,b=nil); end
method(:bar).parameters
#=> [[:req, :a], [:opt, :b]] 

def jim(a:,b:nil); end
method(:jim).parameters
#=> [[:keyreq, :a], [:key, :b]] 
Run Code Online (Sandbox Code Playgroud)

这是一个通用方法,只选择方法支持的那些命名值,以防你的哈希中有额外的键不是方法使用的关键字参数的一部分:

module Kernel
  def dispatch(name,args)
    keyargs = method(name).parameters.map do |type,name|
      [name,args[name]] if args.include?(name)
    end.compact.to_h
    keyargs.empty? ? send(name) : send(name,keyargs)
  end
end

h = {a:1, b:2, c:3}

def no_params
  p :yay
end

def few(a:,b:99)
  p a:a, b:b
end

def extra(a:,b:,c:,z:17)
  p a:a, b:b, c:c, z:z
end

dispatch(:no_params,h) #=> :yay
dispatch(:few,h)       #=> {:a=>1, :b=>2}
dispatch(:extra,h)     #=> {:a=>1, :b=>2, :c=>3, :z=>17}
Run Code Online (Sandbox Code Playgroud)

  • 这个.自从引入带有默认参数的可选参数以来,'arity`一直模糊不清,随着`参数`的引入而变得过时,现在在引入关键字参数后完全无用. (3认同)