我正在开发一个Ruby应用程序,我在其中动态调用基于JSON数据的方法。松散:
from django.db.models import Q
user = request.user
conditions = Q(creator=user) | Q(friend=user)
relevant_friends_list = FriendShip.objects.filter(conditions)
如上所示,有些方法不带参数,有些方法带有关键字参数。在Ruby 2.1.0(我正在开发的地方)下,上述两种方法的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
都是arity
。但是,如果我总是0
,那么对于不带参数的方法我会收到错误。
如何在需要时使用send(cmd,params)
正确传递关键字参数,但在没有时省略它们?
答案 0 :(得分:7)
使用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}
答案 1 :(得分:0)
首先,当params
值为:cmd
时,我认为"items"
应该为空,在这种情况下,Jesse Sielaff的答案是正确的。但既然你似乎声称它不是,我认为这是你的设计缺陷。不要试图以这种方式发送,而应该让这些方法只是吞噬参数:
def items(name:nil, data:nil)
...
end