从Ruby中的字符串执行代码?

Aru*_*run 0 ruby

我正在使用元数据方法来处理一些代码.假设以下是一个字符串:

if $bmi >= 18.5 && $bmi <= 24.9 then return 'healthy' elsif $bmi >= 25 && $bmi <= 29.9 then return 'overweight' elsif $bmi > 30 then return 'obese' end
Run Code Online (Sandbox Code Playgroud)

$ bmi被正确替换,但我希望代码执行.

Max*_*Max 6

eval方法将您的字符串评估为Ruby代码.但...

eval很脆弱

您的字符串包含return关键字,该关键字始终从方法调用返回.如果你eval在方法中使用该字符串,那么它之后的任何代码都将永远不会运行,因为该方法将返回.如果你eval在方法之外,你会得到一个LocalJumpError例外,因为return它只在方法中有效.我可以想象这会导致代码中出现各种神秘错误.

评估是危险的

你说元数据来自你的身边,但你仍然在你的代码中打开一个巨大的失败点,eval因为它可以做任何事情.那一个调用eval可以擦除整个磁盘,它可以下载并运行一个漏洞,它甚至可以将你的脚本重写成一个仇恨人类的恶意AI.当你只想进行一些数值比较时,使用这种强大的方法确实没有意义.

评估令人困惑

实际上,你可能很好用eval.您的代码将起作用,世界将不会结束.但即便如此,它也很糟糕,因为它创造了完全无法读取的代码.任何阅读你的剧本的程序员(包括你自己,六个月后你回来修理一些东西)都会达到这个目标,eval并想"呃......这究竟是做什么的?" 在这种情况下,您应该始终在数据库中存储尽可能少的逻辑,并在代码中执行其余的计算.在这种情况下你会怎么做?我可以想到几个选择.

仅存储间隔

使用DB模式

table BMIIntervals (
  MinValue    Double,
  Description String
)
Run Code Online (Sandbox Code Playgroud)

您可以存储行

18.5, 'healthy'
25,   'overweight'
30,   'obese'
Run Code Online (Sandbox Code Playgroud)

然后你可以轻松地在Ruby中进行计算:

intervals = db.query("SELECT * FROM BMIIntervals ORDER BY MinValue DESC")
intervals.each { |row| return row[1] if $bmi >= row[0] }
return nil
Run Code Online (Sandbox Code Playgroud)

仅存储计算名称

或者如果BMI间隔是固定的,并且元数据说明要做什么样的计算,您可以简单地在Ruby中定义计算:

module MetadataFuncs
  def self.bmi
    return 'obese' if $bmi > 30
    return 'overweight' if $bmi >= 25
    return 'healthy' if $bmi >= 18.5
  end
end
Run Code Online (Sandbox Code Playgroud)

然后你的元数据字符串将是正确的"bmi",而不是eval(metadata)你可以做到的MetadataFuncs.send(metadata).通过这种方式,您可以确切地知道元数据可能调用的代码,即使没有查看数据库中的数据.