Ruby中eval的替代品有哪些?

时间:2016-01-25 22:34:59

标签: ruby eval

我编写了以下递归函数,以便解析一些设置并正确填充我的一些日志文件对象。

当我针对Code Climate运行此代码时,它告诉我(当然)不鼓励使用eval。有没有办法可以重写这个方法,所以我不需要eval,也不需要case语句?没有什么可以想到的。

def parse(settings, logfile = nil)
  settings.each do |key, value|
    if value.is_a?(Hash)
      logfile = Logmsg::LogFile.new
      parse(value, logfile)
    else
      eval("logfile.#{key} = value")
    end
  end
end

有什么想法吗?

我正在尝试instance_variable_set元编程方法,但我仍然遇到一些问题。出于某种原因,由于

,我的测试现在都失败了
Argument Error: comparison of Fixnum with String failed

我仍然想弄明白。

2 个答案:

答案 0 :(得分:5)

由于赋值给对象的属性只是方法调用的语法糖(即obj.foo = bar与使用参数foo=调用obj上的bar方法相同),使用Object#public_send

logfile.public_send(:"#{key}=", value)

在较旧的代码中,您经常会看到send而不是public_send,但您应该使用后者,因为如果您尝试调用私有方法,则会引发错误。

答案 1 :(得分:0)

这行得通,只是有点大。

module Ev
    @@num = 0
    def self.b26(i)
        @out = ""
        while i > 0
            @out = (i % 26).chr + @out
            i /= 26
        end
        return @out
    end
    def self.getNames
        @@num += 1
        @name = "#{self.b26(@@num)}.rb"
        while File.exist?(@name)
            @name = "#{self.b26(@@num)}.rb"
        end
        return @name
    end
    def self.run(str)
        name = self.getNames
        file = File.open(name, "w+")
        file.write(str)
        file.close()
        require "./#{name}"
        File.delete(name)
    end
end

Ev.run("puts 2 + 2") # 4
Ev.run("puts 'Hello World!!!'") # puts 'Hello World!!!'
for x in 0..5
    Ev.run("puts #{x}")
end
# 0
# 1
# 2
# 3
# 4
# 5