Ruby中method_missing+send处理混合参数(含命名参数)报错问题
解决Ruby代理模式中转发含命名参数方法的问题
问题场景
实现代理模式时,调用包含普通参数与命名参数的方法时报错,原代码及错误信息如下:
原代码
class ExecuteProxy def initialize(controller_object) @controller_object = controller_object end def method_missing(method, *args) args.empty? ? @controller_object.send(method) : @controller_object.send(method, *args) return end end class MyClass def no_arghuments puts "no_arghuments" end def one_argument(arg1) puts "one_argument #{arg1}" end def one_argument_and_named(arg1, count:1) puts "one_argument #{arg1} and count #{count}" end end obj = MyClass.new proxy = ExecuteProxy.new(obj) proxy.no_arghuments proxy.one_argument("test") proxy.one_argument_and_named("test2") proxy.one_argument_and_named("test2", count:2)
错误输出
no_arghuments one_argument test one_argument test2 and count 1 test1.rb:20:in `one_argument_and_named': wrong number of arguments (given 2, expected 1) (ArgumentError) from test1.rb:8:in `method_missing' from test1.rb:31:in `<main>'
问题原因
原method_missing方法仅捕获了普通参数*args,未处理Ruby的命名参数。调用带命名参数的方法时,命名参数会被当作普通参数传入args,导致目标方法接收到的参数数量不符,触发参数错误。
解决方案
修改method_missing方法,添加**kw参数捕获所有命名参数,调用send时同时传递普通参数和命名参数即可解决问题。
可行代码
class ExecuteProxy def initialize(controller_object) @controller_object = controller_object end def method_missing(method, *args, **kw) @controller_object.send(method, *args, **kw) return end end class MyClass def no_arghuments puts "no_arghuments" end def one_argument(arg1) puts "one_argument #{arg1}" end def one_argument_and_named(arg1, count:1) puts "one_argument #{arg1} and count #{count}" end def only_named(count:, str:"") puts "only_named count #{count}, str: #{str}" end def manyarguments_and_named_args(arg1, arg2, arg3 = "def", count:1, some_other:"d") puts "manyarguments_and_named_args #{arg1}, #{arg2}, #{arg3} and count #{count}, some_other #{some_other}" end end obj = MyClass.new proxy = ExecuteProxy.new(obj) proxy.no_arghuments proxy.one_argument("test") proxy.one_argument_and_named("test2") proxy.one_argument_and_named("test2", count:2) proxy.only_named(count:3) proxy.only_named(count:3,str:"string") proxy.manyarguments_and_named_args("a1","a2") proxy.manyarguments_and_named_args("a1","a2", "s3") proxy.manyarguments_and_named_args("a1","a2", count:4) proxy.manyarguments_and_named_args("a1","a2", count:4, some_other:nil)
(注:修正了原可行代码中遗漏的语法闭合符,确保代码可正常运行)
执行输出
no_arghuments one_argument test one_argument test2 and count 1 one_argument test2 and count 2 only_named count 3, str: only_named count 3, str: string manyarguments_and_named_args a1, a2, def and count 1, some_other d manyarguments_and_named_args a1, a2, s3 and count 1, some_other d manyarguments_and_named_args a1, a2, def and count 4, some_other d manyarguments_and_named_args a1, a2, def and count 4, some_other
内容的提问来源于stack exchange,提问作者Roman Gelembjuk
相关产品推荐
相关产品推荐

