红宝石块作为数组元素,用于在public_send中拼接



我正在尝试使用元编程构建一个通用方法,它使用splat操作从arraysend到对象的method,以下是工作片段:

ALLOWED_DATA_TYPES = {
'Integer' => [['to_i']],
'Csv' => [['split', ',']]
}
ALLOWED_DATA_TYPES.each do |type, methods|
define_method("#{type.downcase}_ified_value") do
manipulated_value = value
methods.each { |method| manipulated_value = manipulated_value.public_send(*method) }
return manipulated_value
end
end

到目前为止,它运行良好,直到我们决定添加另一种数据类型并且它需要在array上调用方法,例如

"1,2,3".split(',').map(&:to_f)

现在我被困住了,因为它是一个障碍。从技术上讲,以下代码工作正常:

"1,2,3".public_send('split', ',').public_send(:map, &:to_f)
# => [1.0, 2.0, 3.0]

但是将该block添加到数组是抛出错误

[['split', ','], ['map', &:to_f]]
# => SyntaxError: syntax error, unexpected &, expecting ']'

我知道我可以创建一个proc并用 amp&调用它,但我希望你明白它正在失去一致性,我需要一些东西,它只能与使用#define_method定义的splat运算符一起使用

我现在没有想法了,请帮忙。

你不走运,&不是运算符 - 它是一种特殊的语法,只允许在函数参数(定义和调用(中使用。您可以做到这一点的一种方法是为块保留数组的最后一个元素;但是您始终必须使用它(即使它只是nil(。

methods.each { |*method, proc| manipulated_value = manipulated_value.public_send(*method, &proc) }

这应该适用于[['split', ',', nil], ['map', :to_f]].

题外话,但请注意,这三行可以使用inject更简洁地重写:

manipulated_value = value
methods.each { |*method, proc| manipulated_value = manipulated_value.public_send(*method, &proc) }
return manipulated_value

成为

methods.inject(value) { |manipulated_value, (*method, proc)| manipulated_value.public_send(*method, &proc) }

最新更新