Ruby法术手册为《Ruby元编程》书中的精华,记录下笔记以便之后慢慢回味。

环绕别名

Around Alias

从一个重新定义的方法中调用原始的、被重命名的版本。

1
2
3
4
5
6
7
8
9
class String
alias_method :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:0x00.....

class D < BasicObject
def method_missing(name, *args)
"a Ghost Mehtod"
end
end

blank_slate = D.new
blank_slate.to_s. # => "a Ghost Method"

类扩展

Class Extension

通过向类的单件类中加入模块来定义类方法,是对象扩展的一个特例

1
2
3
4
5
6
7
8
9
10
11
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 Instance Variable

在一个Class对象的实例变量中存储类级别的状态

1
2
3
4
5
6
7
class C
@my_class_instance_variable = "some value"
def self.class_attribute
@my_class_instance_variable
end
end
C.class_attribute # => "some value"

类宏

在类定义中使用一个类方法。

1
2
3
4
5
6
7
8
9
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

洁净室

使用对象作为执行块的上下文环境

实际上就是通过 instance_eval 限定执行块的作用域。

1
2
3
4
class CleanRoom
def a_useful_method(x); x * 2; end
end
CleanRoom.new.instance_eval { a_useful_method(3) } # => 6

代码处理器

处理从外部获得的字符串代码

1
2
3
4
5
6
File.readlines("a_file_containing_lines_of_ruby.txt" ).each do |line|
puts "#{line.chomp} ==> #{eval(line)}"
end
# >> 1 + 1 ==> 2
# >> 3 * 2 ==> 6
# >> Math.log10(100) ==> 2.0

上下文探针

执行块来获取对象上下文中的信息。

1
2
3
4
5
6
7
class C
def initialize
@x = "a private instance variable"
end
end
obj = C.new
obj.instance_eval { @x } # => "a private instance variable"

延迟执行

在 proc 或 lambda中存储一段代码及其上下文,用于以后执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class C
def store(&block)
@my_code_capsule = block
end
def execute
@my_code_capsule.call
end
end

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

动态派发

在运行时决定调用哪个方法

1
2
3
method_to_call = :reverse
obj = "abc"
obj.send(method_to_call) # => "cba"

动态方法

在运行时才决定如何定义一个方法

1
2
3
4
5
6
7
8
9
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"

动态代理

把不能对应某个方法名的消息转发给另外一个对象。

1
2
3
4
5
6
7
8
9
10
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"

扁平作用域

使用闭包在两个作用域之间共享变量

1
2
3
4
5
6
7
8
9
10
11
12
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

幽灵方法

响应一个没有关联方法的消息

1
2
3
4
5
6
7
class C
def method_missing(name, *args)
name.to_s.reverse
end
end
obj = C.new
obj.my_ghost_method # => "dohtem_tsohg_ym"

钩子方法

覆写一个方法来截获对象模型事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$INHERITORS = []
class C
def self.inherited(subclass)
$INHERITORS << subclass
end
end
class D < C
end

class E < C
end

class F < E
end

$INHERITORS # => [D, E, F]

内核方法

在 Kernel 模块中定义一个方法,使之对所有对象都可用。

1
2
3
4
5
6
module Kernel
def a_method
"a kernel method"
end
end
a_method # => "a kernel method"

惰性实例变量

当第一次访问一个实例变量时才对之进行初始化。

1
2
3
4
5
6
7
class C
def attribute
@attribute = @attribute || "some value"
end
end
obj = C.new
obj.attribute # => "some value"

拟态方法

把一个方法伪装成另外一种语言构件。

1
2
3
4
5
6
7
8
def BaseClass(name)
name == "string" ? String : Object
end
class C < BaseClass "string" # a method that looks like a class
attr_accessor :an_attribute # 伪装成关键字的方法
end
obj = C.new
obj.an_attribute = 1 # 伪装成属性的方法

猴子打补丁

修改已有类的特性,书中说应该少用。

1
2
3
4
5
6
7
"abc".reverse # => "cba"
class String
def reverse
"override"
end
end
"abc".reverse # => "override"

命名空间

在一个模块中定义常量,以防止命名冲突。

1
2
3
4
5
6
7
8
9
module MyNamespace
class Array
def to_s
"my class"
end
end
end
Array.new # => []
MyNamespace::Array.new # => my class

空指针保护

用“或”操作符覆写一个空应用。

1
2
x = nil
y = x || "a value" # => "a value"

对象扩展

通过给一个对象 eigenclass 混入模块来定义单件方法。

1
2
3
4
5
6
7
8
9
10
obj = Object.new
module M
def my_method
'a singleton method'
end
end
class << obj
include M
end
obj.my_method # => "a singleton method"

打开类

修改已有的类

1
2
3
4
5
6
class String
def my_string_method
"my method"
end
end
"abc".my_string_method # => "my method"

下包含包装器

调用一个用prepend方式覆写的方法

1
2
3
4
5
6
7
8
9
10
11
module M
def reverse
"x{super}x"
end
end

String.class_eval do
prepend M
end

"abc".reverse # => "xcbax

细化

为类打补丁,作用范围仅到文件结束,或仅限于包含的模块的作用与中。

1
2
3
4
5
6
7
8
9
10
11
module MyRefinement
refine String do
def reverse
"my reverse"
end
end
end

"abc".reverse # => "cba"
using MyRefinement
"abc".reverse # => "my reverse"

细化封装器

在细化中调用非细化的方法

1
2
3
4
5
6
7
8
9
10
module StringRefinement
refine String do
def reverse
"x{super}x"
end
end
end

using StringRefinement
"abc".reverse # => "xcbax"

沙盒

在一个安全的环境中执行为授信的代码

1
2
3
4
5
6
7
8
9
10
11
def sandbox(&code)
proc {
$SAFE = 2
yield
}.call
end

begin
sandbox { File.delete 'a_file' }
rescue Exception => ex
ex # => #<SecurityError: Insecure operation `delete

作用域门

用 class、module 或 def 关键字来隔离作用域

1
2
3
4
5
6
7
8
9
10
11
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

把 self 传给当前块

1
2
3
4
5
6
7
8
9
10
11
class Person
attr_accessor :name, :surname
def initialize
yield self
end
end

joe = Person.new do |p|
p.name = 'Joe'
p.surname = 'Smith'
end

共享作用域

在同一个扁平作用域的多个上下文中共享变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

单件方法

在一个对象上定义一个方法

1
2
3
4
5
6
7
obj = "abc"
class << obj
def my_singleton_method
"x"
end
end
obj.my_singleton_method # => "x"

代码字符串

执行一段表示 Ruby 代码的字符串。

1
2
my_string_of_code = "1 + 1"
eval(my_string_of_code) # => 2

符号到 Proc

把一个符号转换为调用单个方法的代码块。

1
[1, 2, 3, 4].map(&:even?) # => [false, true, false, true]