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頁。 

相關文章
相關標籤/搜索