MetaProgramming Chapter6
Ruby 元编程 第六章
该文档包含Ruby方法的介绍。
阅读文档,你将学到:
Kernel#eval
NOTE: 直接执行字符串中的代码,并返回结果
array = [1, 2]
i = 3
eval("array << i")
NOTE: “eval <<-“的用法
eval <<-end_evl
i = 1
i += 2
end_eval
绑定对象
class A
def a_method1
@a = "A的实例变量,在a_method1方法中,binding为方法内的作用域"
binding
end
end
a = A.new.a_method1
eval "@a", a
NOTE: TOPLEVEL_BINDING:顶级作用域, 通过 self 输出该作用域绑定的对象
class B
def b_method1
eval "self", TOPLEVEL_BINDING
end
end
b = B.new.b_method1
Pry
NOTE: Pry定义了Object#pry方法,在规定的对象作用域中打开一个交互。
在当前绑定对象上调用pry方法,实现调试功能
require "pry";binding.pry
self
NOTE: C#c_method1方法中调用pry方法,进入当前作用域
class C
def c_method1
@c = "C的实例变量"
require "pry";binding.pry
puts @c
end
end
c = C.new
c.c_method1
self
irb:命令行工具
NOTE: irb 解析控制台输入,再把每一行代码传给eval方法
让我们来看一下irb源代码的workspace.rb文件中,eval的调用方法
eavl(statements, @binding, file, line)
statements = "表示一行ruby代码"
@binding = "表示一个Binding对象,irb通过该参数在不同上下文环境中执行代码"
file = "当前代码所在文件作为参数传入"
line = "当前代码所在行号作为参数传入"
x = 1 / 0
eval和instance_eval,class_eval的对比
NOTE: eval只能执行代码字符串,instance_eval和class_eval 既能执行代码块,也能执行代码字符串
a = ['a', 'b']
x = 'c'
@y = 'd'
a.instance_eval "self"
a.instance_eval "self[1] = x"
a.instance_exec(@y) {|y| self[1] = y}
eval 的问题
NOTE: 通过eval可以在机器上执行任何代码,
为防止代码注入,用动态方法和动态派发来替换
污染对象和安全级别
ERB
钩子方法
钩子方法的介绍
NOTE: 某些方法与特定的事件绑定,称为 钩子方法
Class#inherited
class E
def self.inherited(subclass)
puts "#{self} was inherited by #{subclass}"
end
end
class F < E
end
更多的钩子
NOTE: 下面来介绍Module#included, Module#prepended
module M1
def self.included(m)
puts "#{m}包含有M1的方法"
end
end
module M2
def self.prepended(m)
puts "#{m}包含有M2的方法"
end
end
class G
include M1
prepend M2
end
class SuperSpeaker
def speak
puts 'Super class speaking...'
end
end
module Chinese
def self.sha
puts "Chinese的类方法"
end
def speak
puts '在说中文...'
super
end
end
module Thai
def speak
puts 'ฉันกำลังพูด...'
super
end
end
class Speaker < SuperSpeaker
include Chinese
prepend Thai
def speak
puts 'Subclass speaking...'
super
end
end
speaker = Speaker.new
speaker.speak
p Speaker.ancestors
include prepend extend
- include Mo1 :将module实例方法加入到当前类的后面
- prepend Mo2 :将module实例方法加入到当前类的前面
- extend Mo3 :将module类方法加入到当前类的单间方法中
module Mo1
def self.included(m)
puts "将module实例方法加入到#{m}的后面"
end
def self.m1_class_method
puts "Mo1的类方法"
end
def m1_method
puts "Mo1"
end
end
module Mo2
def self.prepended(m)
puts "将module实例方法加入到"#{m}的前面"
end
def m2_method
puts "Mo2"
end
end
module Mo3
def self.extended(m)
puts "#{m}类方法中包含有M2的方法"
end
def m3_method
puts "Mo3"
end
end
class K
include Mo1
prepend Mo2
extend Mo3
end
K.m3_method
k = K.new
k.m1_method
k.m2_method
K.ancestors