Hi all,
请教诸神一个问题
例如:
def f(a = 1, b = 2)
# ...
end
假设我从没见过这个方法的声明,但是我知道这个方法接受两个参数,并且这两个参数都有默认参数(虽然并不知道这两个默认参数分别是什么)。我现在在 call 这个方法的时候,只想为第二个参数指定值,第一个参数则继续使用默认值,我该怎么 call 这个方法才行?(我只知道 SQL 和 Python 是有解决方案的,不知道 Ruby 里怎么搞)
谢谢诸神
def f(args*)
if args.count == 2
f1(args*)
else
f0(args*)
end
end
def f0(a)
end
def f1(a, b)
end
其实这种问题还有另外一个应用场景就是
class A
def f(a, b)
puts "a = #{a}, b = #{b}"
end
end
class B < A
def f(a = 2, b = 3)
super
end
end
class C < A
def f(a = 5, b = 7)
super
end
end
class D < B
def f(a = 8, b = 10)
super
end
end
多个子类都覆盖了父类的一个方法,并且不同实现都有自己的默认值 我现在有一个 A 或 A 子类的对象,要调用这个方法 f,并且指定第二个参数,而第一个参数设为默认值的时候,我即使知道 f 的实现,也完全没有办法指定第一个参数的值啊。
class B < A
alias_method_chain :f, :change
def f(b, a)
f_without_change(a, b)
end
end
你还是要知道 a 的值,否则如何调用原来的 f 方法呢?
办法还是有的,不过很烦。就是先取得这个方法的参数的默认值。调用方法的时候把拿到的默认值再传过去。
可以参考 https://rubygems.org/gems/rdp-arguments 或者以前 merb 里面有个 get_args 的功能 http://stackoverflow.com/questions/622324/getting-argument-names-in-ruby-reflection/625222#625222
这个应该都能取道方法默认值
#24 楼 @iBachue 做法好像是在解析一遍语法,取得默认值。
以前 java 我也干过这个事情,java 的反射没法取到形参的参数名,因为形参的名字本身无意义,形参类型是有意义的,编译成 class 字节码文件后,class 内部不存储方法的形参名。那个时候找到个 hack 的技巧,class 文件在方法内部会放一个局部变量和形参同名,利用 javassist 可以取到那些信息。
具体可以看 http://kenbeit.com/posts/62/javassist%E7%9A%84%E5%AD%A6%E4%B9%A0
可以的哦,前提是 f
是在源文件中定义的,看你的描述应该满足。
假设有方法 f
def f a=1, b=2
# ...
end
那么获取它的默认参数的值可以这么做:
require "method_source"
require "ripper"
class OptParamsBuilder < Ripper::SexpBuilder
def initialize meth
@src = meth.source
super @src
end
def on_def *xs
@method_name ||= xs[0][1]
super
end
def on_params *xs
@opt_params ||= xs[1]
super
end
def opt_params
parse
params = @opt_params.map do |(_, param), value|
param
end
first_line = @src.lines.to_a[0]
eval "#{first_line}\nreturn #{params.join ' , '}\nend"
send @method_name
end
end
p OptParamsBuilder.new(method(:f)).opt_params #=> [1, 2]
P.S. 现在 ruby-china 的 markdown parser 被搞得很奇怪,~~删除~~
前后不加空格的话就不能做删除线,代码中的空行也被自动消灭了 ...