I am trying to build a generic method using meta programming where it uses manipulating method
s from array
and send
to the object using splat
, following is the working snippet:
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
It was working great so far, until we decided to add another datatype and it needs to call method on array
, for e.g.
"1,2,3".split(',').map(&:to_f)
Now I am stuck, because it's a block. Technically, following code is working alright:
"1,2,3".public_send('split', ',').public_send(:map, &:to_f)
# => [1.0, 2.0, 3.0]
But adding that block
to array is throwing error
[['split', ','], ['map', &:to_f]]
# => SyntaxError: syntax error, unexpected &, expecting ']'
I know I can create a proc
and call it with amp &
but I hope u get it that it is loosing consistency, I need something that will just work with splat
operator as defined using #define_method
I am out of ideas now, please help.
You're out of luck, &
is not an operator - it is a special syntax that is only allowed in function parameters (both definition and invocation). One way you could do it is to reserve the last element of the array for the block; but then you always have to use it (even if it is just nil
).
methods.each { |*method, proc| manipulated_value = manipulated_value.public_send(*method, &proc) }
This should work with [['split', ',', nil], ['map', :to_f]]
.
Off-topic, but note that these three lines can be more succintly rewritten using inject
:
manipulated_value = value
methods.each { |*method, proc| manipulated_value = manipulated_value.public_send(*method, &proc) }
return manipulated_value
becomes
methods.inject(value) { |manipulated_value, (*method, proc)| manipulated_value.public_send(*method, &proc) }