博客地址 :《Ruby 元编程》读书笔记 (十二)
相关文章:
《Ruby 元编程》读书笔记 (一) 《Ruby 元编程》读书笔记 (二) 《Ruby 元编程》读书笔记 (三) 《Ruby 元编程》读书笔记 (四) 《Ruby 元编程》读书笔记 (五) 《Ruby 元编程》读书笔记 (六) 《Ruby 元编程》读书笔记 (七) 《Ruby 元编程》读书笔记 (八) 《Ruby 元编程》读书笔记 (九) 《Ruby 元编程》读书笔记 (十) 《Ruby 元编程》读书笔记 (十一)
传神的头图↓↓↓
Kernal#eval方法与之前的BasicObject#instance_eval和Module#class_eval一样,都属于*eval家族,都可以赋予程序在运行中进行动态变化的能力。与后两者想比Kernal#eval更加直接,不需要代码块、直接就可以执行字符串代码(String of Code)。
PS:BasicObject#instance_eval也是可以执行字符串代码的。
array = [10, 20]
element = 30
eval(“array << element”) #=> [10, 20, 30]
array.instance_eval "self << element" #=> [10, 20, 30]
以<<打头,后面跟一个“结束序列标识”,之后就可以是正式的文档内容了,可以任意换行,直到遇到了独立出现的”结束序号标识”。
puts <<GROCERY_LIST
Grocery list
------------
1. Salad mix.
2. Strawberries.*
3. Cereal.
4. Milk.*
* Organic
GROCERY_LIST
上面代码的输出格式如下:
Grocery list
------------
1. Salad mix.
2. Strawberries.*
3. Cereal.
4. Milk.*
* Organic
=> nil
Binding 是一个用对象标识的完整作用域 (上下文环境)。可以通过创建 Binding 对象来捕获并带走当前的作用域。之后,通过 eval 方法在这个 Binding 对象所携带的作用域内执行代码。
使用Kernel#binding方法可以用来创建Binding对象
class MyClass
def my_method
@x = 1
binding
end
end
b = MyClass.new.my_method
eval “@x”, b #=> 1
上面代码,在 MyClass 类中定义了一个 my_method 方法来返回一个当前的绑定。最后将这个返回的绑定,作为参数传递给 eval 方法。这样“@x”就可以在返回的绑定作用域中执行了。
关于绑定还有另外一个知识点,Ruby还提供了一个名为TOPLEVEL_BINDING的预定义常量,表示顶级作用域Binding对象。该常量可以在程序的任何位置访问到。言外之意,你可以在程序的任何位置,通过Kernal#eval方法在顶级作用域中执行代码。
class AnotherClass
def my_method
eval “self”, TOPLEVEL_BINDING
end
end
AnotherClass.new.my_method #=> main
Kernal#eval执行这样可以灵活执行字符串代码的特性,给编程带来了灵活性之外,也带来了潜在的风险,如果字符串代码来源于不可信的用户输入,如果不做安全检查,保不齐什么时候就会是一段破坏性的恶意代码。
面对这样的风险,可以选择规避 eval 的使用,换用其它相对安全的方式代替,例如动态方法和动态派发。此外,还可以通过在 Ruby 中通过修改$SAFE 全局变量值,来控制程序的安全性级别,具体就是在你要执行可信的字符串代码前,将安全级别降低,可以使用Object#untaint方法,执行完之后在切换安全级别。这有点像操作系统中使用临界资源的步骤(请求锁,释放锁)
通过 Object#tainted?方法可以判断一个对象是不是被污染了(是否来自一个不可信的输入源)。
-待续-
=============== 最后贴一下自己的公众账号
可以十日不将军,不可一日不拱卒,日拱一卒 (rigongyizu365)