3-15 《元编程》第6章 3-16 hook method

Code That Writes Code 程序员

6.1 Coding your way to the weekendexpress

 

6.2 Kernel#eval, Binding#eval 安全

Binding:this

Objects of class Binding(类Binding的对象) encapsulate (密封)the execution context at some particular place in the code and retain this context for future use.lua

 

若是你想要一段已经执行的代码在从此反复使用,能够用Binding对象封装它。spa

The variables, methods, value of self, and possibly an iterator block(迭代块) that can be accessed in this context are all retained. code

变量,方法,自身的value,甚至迭代块均可以用Binding对象封装储存。对象

Binding objects can be created using Kernel#binding继承

 

eval(string [, filename [,lineno]]) → obj事件

Evaluates the Ruby expression(s) in string, in the binding's context.

Binding对象的eval方法,能够评估字符串内的Ruby表达式,并返回表达式的值。

If the optional filename and lineno parameters are present, they will be used when reporting syntax errors.

 

class Myclass
  def my_method
    @x = 1
    binding
  end
end
 
p b = Myclass.new.my_method
p b.eval("@x")
p eval("@x", b)

#结果同样 1

 

class Anotherclass
  def my_method
    # eval "self", TOPLEVEL_BINDING    #=> main
    eval("xx + yy", TOPLEVEL_BINDING)
  end
end
 
xx = 123
yy = 321
obj = Anotherclass.new
p obj.my_method #=> 444

TOPLEVEL_BINDING: 是预约义常量,表示顶层做用域的Binding对象。

 

6.24 Strings of Code Vs Blocks 

 eval只能执行代码字符串,instance_eval和class_eval能够执行代码字符串和block

array = [1,2,3]
x = 'd'
array.instance_eval("self[1] = x")
p array #=> [1, "d", 3]
尽可能用block,代码字符串安全性低容易被攻击。同时也难以阅读和修改。

 

流行的作法是禁止使用eval方法,同时用Dynamic methods和Dynamic Dispatch替代

 

污染对象 

Ruby把外部传入的对象标记为污染对象。Object#taint -> obj.

判断: #tainted? ->true/false

去掉污染 #untaint 

 

谨慎使用安全级别p148页

可使用proc {}.call 做为洁净室

 


 

6.3Hook Method: 

Class#inherited是一个实例方法,当一个类被继承时,Ruby会调用这个方法,Class#inherited方法什么也不作,但程序员能够覆写它的行为,像这样的方法称为钩子方法。

inherited(subclass):Callback invoked whenever a subclass of the current class is created.

更多的钩子方法:

Module#included,#prepended,#method_added, #method_removed, #method_undefined (只对实例方法有用),#singleton_method_added...

 

这种钩子方法写在模块里,用类方法的方式定义:

module M1
  def self.included(othermod)
    puts "m1 was included into #{othermod}"
  end
end
 
class C
  include M1
end
#=>m1 was included into C
 

另一种方式钩住同一个事件,:#include方法能够覆写 ,但注意写在类C中。

个人理解类C.调用include方法,就是self.include。先是在自身调用覆写的include方法,而后用super关键字调用原始方法。

⚠️ 类方法是不能被继承的只能本身用。

⚠️ 类包含模块后默认是得到实例方法。除非用#extend

module M
  def hello
    puts "world"
  end
end
 
class C
  def self.include(mod)
    puts "Called: C.include(#{mod})"
    super  #由于覆写了include,因此须要用super调用原始的include功能,不然M不会被C包含
  end 
  include(M)
end
 
C.new.hello✅

 类方法和钩子方法结合的技巧:P160页。 

相关文章
相关标签/搜索