当有人提到通过编写inspect
输出并通过加载将信息保存到外部文件的想法时eval
,我看到很多人会批评这个想法,而是建议使用 YAML。编写输出的问题是什么inspect
,为什么首选 YAML?对于人类可读性,我认为 rubyinspect
或pp
format 优于 YAML。
3 回答
假设没有任何东西覆盖inspect
,这有什么用?:
#<Foo:0xa34feb8 @bar="wat">
与此相比:
--- !ruby/object:Foo
bar: wat
在非平凡的情况下,YAML 更有可能产生有用的输出。它也是可移植的,并且可以用作在不同系统之间发送序列化数据的更可靠的方式。
安全是主要问题。因为eval
将运行传递给它的任何代码,恶意黑客可以将代码注入您的数据文件,并控制您的程序。这对于您自己的小型脚本可能并不重要,但在 ruby on rails 服务器中,安全性将很重要。假设我们有以下代码:
f=File.new("foobar.txt")
f.puts Foo.new.tap {|foo| foo.bar="bork"}.inspect
这将,假设Foo
has not overwritten inspect
,将给出如下内容:
#<Foo:0xff456a5 @bar="bork">
显然,这不是有效的 Ruby 语法。奇怪的是,eval
没有抛出错误,只是返回nil
。这只会使这成为一个更糟糕的主意,因为您期望成为的变量Foo
现在只是nil
(臭名昭著的NoMethodError: undefined method 'bork' for nil:NilClass
错误)。
另一个大问题是安全问题。假设您的代码将数据保存到文件中,比如说foo.txt
,并将inspect
ed 哈希映射bar
s 存储到它们各自的baz
es 中。需要知道这些映射以计划 FOO 约定的不同程序读取并发送eval
此文件。想象一下,这个文件在黑客可以访问的地方(仔细想想,它几乎在任何地方)。如果这些程序在同时存储所有 foo 财务数据的 RoR 服务器上运行,黑客可能会造成大规模混乱。如果这个黑客将代码注入到foo.txt
系统中,也就是说,将恶意病毒下载到系统中并安装它,但最后仍然留下原始程序的哈希值,它就会在不被注意的情况下执行。即使你eval
的数据带有$SAFE=4
,黑客仍然可以通过抛出错误等方式破坏foo刨程序的稳定性。
总而言之,虽然inspect
-eval
方法适用于基本类,例如Hash
, String
,Array
等,但它依赖于类来给出其自身的精确句法表示。对于大多数应用程序(如果不是所有应用程序)来说,使用inspect
-是个坏主意eval
。YAML 是首选,因为它具有定义的数据语法,这意味着混入的可执行代码会导致错误,而不是被盲目地执行。此外,许多开发人员inspect
用于调试,并且不希望对象提供自身的文件转储。
YAML 的其他好处是它可以轻松地序列化复杂的对象。使用 YAML 可以轻松实现 foos 和 bar 的复杂对象树,但使用inspect
会产生巨大的复杂性。归根结底,这可以认为是 JSON 问题——因为eval
使用了数据执行中的可执行代码。inspect
对于您自己的小型实用程序可能很好,但永远不会在生产代码中,或者对广阔的世界开放的代码中。
我推荐 YAML,因为:
- 对于我们人类来说,它很容易理解,而不仅仅是一种语言。
- 它是一个标准,因此可以跨多种语言移植。
- 它支持标量、数组、散列以及字符串和数字。它还具有一些很酷的命名空间功能和别名,因此您可以重用定义并将数据视为单独的块。
- 再次参见#1 和#2。这些很重要。