Ruby meta programming

Argument Array(数组参数)

1
2
3
4
5
def  m(*args)
args.map{|arg| arg.reverse}
end

m('ab', 'bc', 'cd') #=> [‘ba’,’cb’,’dc’]

Around Alias(环绕别名)

1
2
3
4
5
6
7
8
class String
alias :old_reverse :reverse
def reverse
“x#{old_reverse}x”
end
end

“abc”.reverse #=> “xcbax”

Blank Slate(白板)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#移除一个对象的所有方法,以便把它们转换成幽灵方法。
class C
def method_missing(name, *args)
“a Ghost Method
end
end

obj = C.new
obj.to_s #=> “#<C:0x357258>”

class C
instance_methods.each do |m|
undef_method unless m.to_s = ~/method_missing | respond_to? | ^/
end
end

obj.to_s #=> “a Ghost Method”

Class Extension(类扩展)

1
2
3
4
5
6
7
8
9
10
11
#通过向类的eigenclass中混入模块来定义类方法。
class C; end
module M
def my_method
‘a class method
end
end
class << C
include M
end
C.my_method #=> “a class method”

Class Extension Mixin(类扩展混入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#使一个模块可以通过钩子方法扩展它的包含者。
module M
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def my_method
‘a class method
end
end
end

class C
include M
end

C.my_method #=> ‘a class method’

Class Instance Variable(类实例变量)

1
2
3
4
5
6
7
8
#在一个Class对象中的实例变量中存储类级别的状态。
class C
@my_class_instance_variable = “some value”
def self.class_attribute
@my_class_instance_variable
end
end
C.class_attribute #=> “some value”

Class Macro(类宏)

1
2
3
4
5
6
7
8
9
10
#在类定义中使用一个类方法。
class C; end
class << C
def my_macro(arg)
“my_macro(#{arg}) called”
end
end
class C
my_macro :x #=> “my_macro(x) called”
end

Clean Room(洁净室)

1
2
3
4
5
#使用对象作为执行块的上下文环境。
class CleanRoom
def a_useful_method(x); x*2; end
end
CleanRoom.new.instance_eval {a_useful_method(3)} #=> 6

Code Processor(代码处理器)

1
2
3
4
5
6
7
8
#处理从外部获得的字符串代码。
File.readlines(“test_xxx.txt”).each do |line|
puts ”#{ line.chomp} ==> #{eval(line) }”
end

#>> 1+1 ==> 2
#>> 3*2 ==> 6
#>> Math.log10(100) ==> 2.0

Context Probe(上下文指针)

1
2
3
4
5
6
7
8
9
#执行块来获取对象上下文的信息
class C
def initialize
@x = “a private instance variable”
end
end

obj = C.new
obj.instance_eval{@x} #=> “a private instance variable”

Deferred Evaluation(延迟加载)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#在proc或lambda中存储一段代码及其上下文,用于以后执行。
class C
def store(&block)
@my_code_capsule = block
end

def exec
@my_code_capsule.call
end
end

obj = C,new
obj.store{$x=1}
$x = 0
obj.execute
$x #=> 1

Dynamic Dispatch(动态派发)

1
2
3
4
#在运行时决定调用哪个方法。
method_to_call= :reverse
obj = “abc”
obj.send(method_to_call) #=> “cba”

Dynamic Method(动态方法)

1
2
3
4
5
6
7
8
9
10
11
#在运行时才决定如何定义一个方法。
class c; end

C.class_eval do
define_method :my_method do
“a dynamic method
end
end

obj = C.new
obj.my_method #=> “a dynamic method”

Dynamic Proxy(动态代理)

1
2
3
4
5
6
7
8
9
10
11
12
13
#把不能对应某个方法名的消息转发给另外一个对象。
class MyDynamicProxy
def initialize(target)
@target = target
end

def method_missing(name, *args, &block)
result: #{@target.send(name, *args, &block)}”
end
end

obj = MyDynamicProxy.new(“a string”)
obj.reverse #=> “result: gnirts a”

Flat Scope(扁平作用域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#使用闭包在两个作用域之间共享变量。
class C
def an_attribute
@attr
end
end

obj = C.new
a_variable = 100

#Flat scope
obj.instance_eval do
@attr= a_variable
end
obj.an_attribute #=> 100

Ghost Method(幽灵方法)

1
2
3
4
5
6
7
8
9
#相应一个没有关联方法的消息。
class C
def method_missing(name, *args)
name.to_s.reverse
end
end

obj = C.new
obj.my_ghost_method #=> “dohtom_tsohg_ym”

Hook Method(钩子方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#通过覆写某个特殊方法来截取对象的模型事件。
$INHERITORS = []
class C
def self.inherited(subclass)
$INHERITORS << subclass
end
end

class D < C
end
class E < C
end
class F < E
$INHERITORS #=> [D, E, F]

Kernel Method(内核方法)

1
2
3
4
5
6
7
#在Kernel模块中定义一个方法,使之对所有对象都可用。
module Kernel
def a_method
“a kernel method”
end
end
a_method #=> “a kernel method”

Lazy Instance Variable(惰性实例变量)

1
2
3
4
5
6
7
8
9
#当第一次访问一个实例变量时才对之进行初始化。
class C
def attribute
@attribute = @attribute || “some value”
end
end

obj = C.new
obj.attribute #=> “some value”

Mimic Method(拟态方法)

1
2
3
4
5
6
7
8
9
10
11
#把一个方法伪装成另外一种语言构件。
def BaseClass(name)
name == “String” ? String : Object
end

class C < BaseClass(string) #一个看起来像类的方法
attr_accessor :an_attribute #一个看起来像关键字的方法
end

obj = C.new
obj.anattibute=1 #一个看起来像属性的方法

Monkey Patch(猴子补丁)

1
2
3
4
5
6
7
8
#修改已有类的特性。
“abc”.reverse #=> “cba”
class String
def reverse
“override”
end
end
“abc”.reverse #=> “override”

Named Arguments(有名参数)

1
2
3
4
5
#把方法参数收集到一个哈希表中,以便通过名字访问。
def my_method(args)
args[:args2]
end
my_method(arg1 => 1, arg2 => 2, arg3 => 3) #=> 2

Namespace(命名空间)

1
2
3
4
5
6
7
8
9
10
#在一个模块中定义常量,以防命名冲突。
module M
class Array
def to_s
“myclass”
end
end
end
Array.new #=> []
M::Array.new #=> “myclass”

Nil Guard(空指针保护)

1
2
3
#用“或”操作符覆写一个空引用。
x = nil
y = x || “a value” #=> “a value”

Object Extension(对象扩展)

1
2
3
4
5
6
7
8
9
10
11
12
#通过给一个对象的eigenclass混入模块来定义单件方法。
obj = Object.new
module M
def my_method
‘a singleton method’
end
end

class << obj
include M
end
obj.my_method #=> “a singleton method”

Open Class(打开类)

1
2
3
4
5
6
7
8
#修改已有的类。
class String
def my_method
“my method”
end
end

“abc”.my_method #=> “my method”

Pattern Dispatch(模式派发)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#根据名字来选择需要调用的方法。
$x = 0
class C
def my_first_method
$x += 1
end

def my_second_method
$x += 2
end
end

obj = C.new
obj.methods.each do |m|
obj.send(m) if m.to_s =~/^my_/
end
$x #=> 3

Sandbox(沙箱)

1
2
3
4
5
6
7
8
9
10
11
12
13
#在一个安全的环境中执行未授信的代码。
def sandbox(&code)
proc {
$SAFE = 2
yield
}.call
end

begin
sandbox(File.delete ‘a_file)
rescue Exception => e
e #=> #<SecurityError: Insecure operation `delete’ at level 2>
end

Scope Gate(作用域门)

1
2
3
4
5
6
7
8
9
10
11
12
#用class、module或def关键字来隔离作用域
a = 1
defined? a #=> “local-variable”

module MyModule
b – 1
defined? a #=> nil
defined? b #=> “local-variable”
end

defined? a #=> “local-variable”
defined? b #=> nil

Self Yield

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#把self 传给当前类

class Person
attr_accessor :name, :surname

def initialize
yield self
end
end

e.g.:

def tap
yield self
self
end

Shared Scope(共享作用域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#在同一个扁平作用域的多个上下文中共享变量。
lambda {
shared = 10
self.class.class_eval do
define_method :counter do
shared
end

define_method :down do
shared -= 1
end
end
}.call

counter #=> 10
3.times {down}
counter #=> 7

Singleton Method(单件方法)

1
2
3
4
5
6
7
8
9
#在一个对象上定义一个方法。

obj = “abc”
class << obj
def my_singleton_method
"x”
end
end
obj.my_singleton_method #=> “x”

String of Code(代码字符串)

1
2
3
#执行一段表示Ruby代码的字符串。
string_of_code = “1+1
eval(string_of_code) #=> 2

Symbol to Proc(符号到Proc)

1
2
3
4
5
6
7
8
9
#把一个符号转换为调用单个方法的代码块
[1, 2, 3, 4].map(&:even?) #=> [false, true, false, true]

#原理:
class Symbol
def to_proc
Proc.new {|x| x.send(self)}
end
end