gpt4 book ai didi

ruby - 如何传递方法发送的所有参数

转载 作者:太空宇宙 更新时间:2023-11-03 17:42:39 24 4
gpt4 key购买 nike

问题

在一个方法中,如何将作为发送方法的一部分提供的所有参数传递给另一个发送方法?所有参数都应该按照没有像 *args 这样的占位符/包罗万象的方式来命名,但它们可以是关键字参数和非关键字参数的混合。此外,内部方法 send 不是 super

例子(伪代码)

def some_method(a_parameter, a_named_parameter:)
...do something...
some_other_method([send with original parameters])
...do something else...
end

相关问题

Is there a way to access method arguments in Ruby? 7 年前就有人问过。

丑陋的骇客

根据我的发现,可以对关键字参数执行类似这样的操作:

def some_method(a_named_parameter:, another_named_parameter:)
...do something...

params = method(__method__)
.parameters
.map { |p| [p[1], binding.local_variable_get(p[1])] }
.to_h

some_other_method(**params)
...do something else...
end

对于非关键字参数:

def some_method(a_named_parameter, another_named_parameter)
...do something...

params = method(__method__)
.parameters
.map { |p| binding.local_variable_get(p[1]) }

some_other_method(*params)
...do something else...
end

根据 method(__method__).parameters 返回的信息,我们还可以制定出一种对两者都适用的解决方案,但即使考虑到可以将所有这些提取到一个 helper ,太复杂了。

最佳答案

这是一个非常有趣的问题,所以首先感谢您提出这个问题。

鉴于 Binding 是一个对象,与其他任何对象一样,我们可以构建一个类来提供此类功能,并利用原始方法中的绑定(bind)将所有参数委托(delegate)给下一个方法,例如所以:

class ArgsBuilder 
attr_reader
def initialize(b)
@standard_args, @kwargs = [],{}
@binding = b
build!
end
def delegate(m)
@binding.receiver.send(m,*@standard_args,**@kwargs,&@block)
end
private
def build!
set_block(&@binding.eval('Proc.new')) if @binding.eval('block_given?')
@binding.eval('method(__method__)')
.parameters.each do |type,name|
next if type == :block
val = @binding.local_variable_get(name)
if type =~ /key/
@kwargs.merge!(type == :keyrest ? val : {name => val})
else
type == :rest ? @standard_args.concat(val) : @standard_args << val
end
end
end
def set_block(&block)
@block = block
end
end

用法:

class B 

def some_method(a,b,c, *d, e:, f:, g: nil, **h)
ArgsBuilder.new(binding).delegate(:some_other_method)
end

def some_other_method(a,b,c, *d, e:, f:, g: , **h)
yield __method__ if block_given?
"I received: #{[a,b,c,d,e,f,g,h].inspect}"
end
end

B.new.some_method(1,2,3,4,5,6, e: 7, f: 8, p: 9, n: 10) do |m|
puts "called from #{m}"
end
# called from some_other_method
#=> "I received: [1, 2, 3, [4, 5, 6], 7, 8, nil, {:p=>9, :n=>10}]"
# a b c ----d---- e f g -------h-------

看起来很简单,可以成为一个帮助程序并处理跨方法传递的命名和匿名 block 。

长话短说

这显然需要与 super 工作方式类似的委托(delegate)方法中的匹配或至少可接受的 like 签名。然而,我们可以更进一步并为参数类型创建类 [:req,:opt,:rest,:keyreq,:key,:keyrest,:block] 将它们放入收集然后询问被委托(delegate)的方法以确定要传递的正确参数;但是我不确定这种类型的示例是否适合 SO 帖子。

附加说明:因为 build!initialize 中被调用,局部变量绑定(bind)在 ArgsBuilder 类的实例化点是静态的。例如

 def foo(n) 
builder = ArgsBuilder.new(binding)
n = 17
builder.delegate(:bar)
end
def bar(n)
n
end

foo(42)
#=> 42

但是

 def foo(n) 
n = 17
ArgsBuilder.new(binding).delegate(:bar)
end

foo(42)
#=> 17

这并不意味着可变对象不能被改变

 def foo(n)
builder = ArgsBuilder.new(binding)
n.upcase!
builder.delegate(:bar)
end

foo('a')
#=> "A"

显然,您可以通过将调用移至 build!

来改变这一点

关于ruby - 如何传递方法发送的所有参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54770287/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com