【问题标题】:Determine arity of method with keyword arguments用关键字参数确定方法的数量
【发布时间】:2015-10-24 11:23:59
【问题描述】:

我正在开发一个 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

如上所示,有些方法不带参数,有些方法带关键字参数。在 Ruby 2.1.0(我正在开发的地方)下,上述两种方法的arity0。但是,如果我总是send(cmd,params),我会收到不带参数的方法的错误。

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

【问题讨论】:

    标签: ruby keyword-argument method-dispatch


    【解决方案1】:

    使用parameters 而不是arity 似乎可以满足我的需求:

    method(cmd).parameters.empty? ? send(cmd) : send(cmd,opts)
    

    更深入地了解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]] 
    

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

    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}
    

    【讨论】:

    • 这个。 arity 自从引入带有默认参数的可选参数以来就一直默默无闻,随着 parameters 的引入变得过时,现在在引入关键字参数后完全没用。
    【解决方案2】:

    起初,我认为当:cmd 的值为"items" 时,params 应该为空,在这种情况下,Jesse Sielaff 的答案是正确的。但既然你似乎声称它不是,我认为这是你的设计缺陷。与其尝试以这种方式调度,不如让这些方法只是吞噬参数:

    def items(name:nil, data:nil)
      ...
    end
    

    【讨论】:

    • 目前计划了超过 20 种不同的方法,具有不同的参数。我不想删除所有未使用参数的超集。相反,我想在适当的时候传递参数,而不是在方法不需要它们时传递它们。使用parameters,我现在可以将命令集减少到匹配的那些。
    猜你喜欢
    • 2011-01-28
    • 1970-01-01
    • 2013-08-09
    • 2014-09-07
    • 1970-01-01
    • 2021-07-27
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多