动态发送多种方法和参数

时间:2016-05-02 07:20:36

标签: ruby

我怎么能用方法

动态正则表达式解析

当前方法

@product.price = line.gsub(/,/, '').scan(/\d{3,9}/).first
@product.model = line.rm_dirty.split(":").last.strip
@product.location = line.split(":").last.strip

预期的方法#将字符串操作传递给另一个函数

然而,我总是得到NoMethodError: undefined method `gsub(/,/, '')'

def fetch_by_keyword_and_regex(regex_str)
  @line.send(regex_str)
end

fetch_by_keyword_and_regex("gsub(/,/, '').scan(/\d{3,9}/).first")

3 个答案:

答案 0 :(得分:1)

如果你想让这个更加动态,你可以发送一个块:

line_sub = lambda { |line|
  line.gsub(/,/, '').scan(/\d{3,9}/).first
}

然后你可以在任何事情上使用它:

line_sub.call(@line)

这很像JavaScript声明var line_sub = function(line) { ... }

send方法只允许按名称进行特定的方法调用:

@ line.send(:sub,/,/,'')。send(:scan,/ \ d {3,9} /)。send(:first)

这是你可以在数组中表达的东西,例如:

line_process = [
  [ :sub, /,/, '' ],
  [ :scan, /\d{3,9}/ ],
  [ :first ]
]

然后使用它:

line_process.inject(@line) do |obj, args|
  obj.send(*args)
end

这太乱了,所以我尽可能避免它。 Ruby的块传递语义对于元编程来说更加清晰。

答案 1 :(得分:0)

您必须使用Ruby的一个评估函数,即evalinstance_evalinstance_exec,但不建议这样做。

我会yield该对象:(假设您的实际实现/用例更复杂)

def fetch(regex_str)
  yield @line
end

fetch { |l| l.gsub(/,/, '').scan(/\d{3,9}/).first }

答案 2 :(得分:0)

如果我理解正确,我会完全质疑这种方法。原因:

1)当不那么钝的方法无法满足需要时,元编程应该作为最后的手段,

2)所讨论的变量东西是代码/功能,并且应该这样表达 - 将其表示为字符串然后评估它等等,是多余的,过于复杂,并且

3)这种方法在某种程度上会隐藏于人类读者,并且肯定会隐藏在代码编辑器,分析工具等中,真正发生的事情。

一种替代方法是哈希,其键是属性名称,值是应用于值的代码,实质上是属性处理功能的查找表,例如

ATTRIBUTE_PROCESSORS = {
  price:    ->(line) { line.gsub(/,/, '').scan(/\d{3,9}/).first },
  model:    ->(line) { line.rm_dirty.split(":").last.strip },
  location: ->(line) { line.split(":").last.strip }
}

......并且这样称呼它:

ATTRIBUTE_PROCESSORS[:price].(line)

这样做的另一个好处是所有属性处理都是共处的,因此您可以轻松地发现重复,并在适当的时候进行重构。