Spell,也称pattern,idiom
# Around Alias:从一个重新定义的方法中调用原始的,被重命名的版本。
# old_reverse是未改变的原始方法,reverse/new_reverse是改变的方法。
class String
def new_reverse
"x:#{old_reverse}"
end
alias_method :old_reverse, :reverse
alias_method :reverse, :new_reverse
end
puts "abc".reverse #x:cba
# Blank Slate:移除一个对象的所有方法,以便把它们转换成ghost method
class C
def method_missing(name, *args)
'a Ghost Method'
end
p ancestors #[C, Object, Kernel, BasicObject]
end
puts C.new.to_s #返回一个string记录了对象的类和encoding-id#<C:0x00007f9ef0006950>
class D < BasicObject
def method_missing(name, *args)
"a Ghost Method"
end
end
blank_slate = D.new
puts blank_slate.to_s #返回method_missing方法的return: a Ghost Method
D继承了BasicObject。而BasicObject,只有10来个最基本的方法,包括method_missing。
所以 blank_slate这个实例调用什么方法,都会调用method_missing。
# Class Extension: 通过向singleton class中加入Module来定义class method,是对象扩展的一个特例
class C; end
module M
def my_method
'a class method'
end
end
#用extend方法: class C; extend M; end
class << C
include M
end
p C.my_method #=> "a class method"
# Class Instance Variable 在一个Class对象的实例变量中存储类级别的状态
# 类实例变量不过是正好属于Class类对象的普通实例变量而已
class C
@my_class_instance_variable = 'some value'
def self.class_attribute
@my_class_instance_variable
end
end
p C.class_attribute #=> "some value"
# Class Macro:在类定义中使用类方法
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:使用一个对象作为执行一个代码块的环境
class CleanRoom
def a_useful_method(x)
x * 2
end
end
obj = CleanRoom.new
puts obj.instance_eval { "#{self}: #{a_useful_method(3)}" }
#=> #<CleanRoom:0x00007f938883ce30>: 6
# Clean Room:使用一个对象作为执行一个代码块的环境
# 一般用BasicObject当洁净室使用。因为它是白板类
class CleanRoom
def a_useful_method(x)
x * 2
end
end
obj = CleanRoom.new
puts obj.instance_eval { "#{self}: #{a_useful_method(3)}" }
#=> #<CleanRoom:0x00007f938883ce30>: 6
# Code Processor:处理从外部获得的代码字符串
File.readlines("hook.rb").each do |line|
puts "#{line.chomp}==>#{eval(line)}"
end
# 1 + 1==>2
# 2*2==>4
# chomp(separator=$/)->new_str: Returns a new String with the given record separator removed from the end of str (if present).
# hook.rb有两行代码第一行1 + 1,第二行2*2
# Context Probe:执行一个代码块来获取一个对象上下文中的信息。
instance_eval的定义:判断block和receiver的上下文环境context。为了可以设置上下文环境,当代码块执行时,self变为receiver,给予代码块存取receiver的实例变量和私有方法的权利。
class C
def initialize
@x = "a private instance variable"
end
end
obj = C.new
obj.instance_eval {
puts self #=> #<C:0x00007f82398251c8>
puts @x ##返回@x的值
}
# Deferred Evaluation:延期执行 在proc或lambda中存储一段代码及其上下文,用于以后执行。
class C
def store(&block)
@my_code_capsule = block
end
def execute
@my_code_capsule.call
end
end
obj = C.new
obj.store { $x = "hello"}
$x = "bye"
obj.execute
p $x #=> "hello" 上一行代码执行了之前储存在proc对象中的代码块。
# Dynamic Dispatch:在运行时决定调用哪个方法
# send(symbol [, args...]) → obj
method_to_call = :reverse
obj = "abc"
puts obj.send(method_to_call)
# Dynamic Proxy: 把不能对应某个方法名的消息转发给另外一个对象。
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")
p obj
puts obj.reverse #=> result: gnirts a
# Dynamic Method:在运行时定义一个方法
class C; end
C.class_eval do
define_method(:my_method) do
"a dynamic method"
end
end
obj = C.new
p obj.my_method
# Flat Scope:
使用closure(代码块)获得环境中的绑定,然后使用方法调用代替作用域门,把包传递给这个方法,起到在两个作用域之间共享变量的效果。
class C
@c = 1 #和C的对象无关。这是C自身的instance_variable
def an_attribute #在方法被访问后,@attr才声明,这种方法也叫惰性实例变量
@attr ||= []
end
end
obj = C.new
a_variable = 100
# flat scope: 使用方法调用来替代作用域门(def , class, module)
obj.instance_eval do
@c = 10 # 给obj 声明并赋值了一个instance_variable,和C的instance_variable无关
@attr = a_variable
end
puts obj.an_attribute #=>100
p obj.instance_variables #=> [:@c, :@attr]
# Shared Scope:
在同一个扁平化的作用域中,多个指定的方法中共享变量
lambda {
shared = 10
self.class.class_eval do
define_method :counter do
shared
end
define_method :down do
shared -= 1
end
end
}.call
p counter
3.times { down }
p counter
def define_methods
shared = 10
define_method :counter do
shared
end
define_method :down do
shared -= 1
end
end
define_methods #调用这个方法,生成counter,和 down
# Ghost Method:响应一个没有关联的消息
对象调用一个方法,先右到自己的真正的类,然后向上看祖先类,如果直到BasicObject也没有发现对应的方法,则调用method_missing.
class C
def method_missing(name, *args)
puts name.to_s.reverse
print "#{args.to_s.reverse}"
end
end
obj = C.new
obj.my_ghost_method("hello, wizard")
# dohtem_tsohg_ym
# ]"draziw ,olleh"[%
# Hook Method: 覆写一个方法来截获对象模型事件
还有included,extended等钩子方法。
$INHERITORS = []
class C
def self.inherited(subclass)
$INHERITORS.append(subclass)
end
end
class Ds < C; end
class Es < Ds; end
p $INHERITORS
# Kernel Method:在Kernel模块中定义一个方法,所有对象都可以用
module Kernel
def a_method
"a kernel method"
end
end
p self #=> main
p a_method
obj = [] #任何对象都可以用的方法。
p obj.a_method
Kernel#exit ,退出Ruby
Initiates the termination of the Ruby script by raising theSystemExit
exception. This exception may be caught.
启动Ruby 的结束脚本
begin
exit
puts "never get here"
rescue SystemExit
puts "rescued a SystemExit exception" 输出
end
puts "after begin block" #也输出
# Lazy Instance Variable
# 等第一次访问一个实例变量时才对它进行初始化
class C
def attribute
@attribute = @attributre || "some value"
end
end
obj = C.new
p obj.attribute #=> "some value"
p obj.instance_variable_get("@attribute") #=> "some value"
She was a splendid mimic and loved to imitate Winston Churchill.
# Mimic Method:把一个方法伪装成另外一种语言构件
if an animal mimics something, it looks or sounds very like it
def BaseClass(name)
name == "String" ? String : Object
end
#BaseClass "String"是方法的使用,返回String
class C < BaseClass "String"#一个看起来像类的方法
attr_accessor :an_attribute#一个看起来像关键字的方法。
p ancestors #=> [C, String, Comparable, Object, Kernel, BasicObject]
end
obj = C.new
p obj.an_attribute = 1#一个看起来像属性的方法
# Monkey patch:修改了已有的类的特征
p "abc".reverse #=>"cba"
class String
def reverse
"override"
end
end
p "abc".reverse #=> "override"
# Namespace :在一个模块中定义常量,以防止命名冲突
module MyNamespace
class Array
def to_s
"my class"
end
end
end
p Array.new.to_s
p MyNamespace::Array.new.to_s
#引用常量的类名用双冒号
# Nil Guard:用或操作符覆写一个空引用nil。空指针保护
x = nil
y = x || "a value"
# 一般用于初始化实例变量,不过实例变量要等方法被访问时才会初始化,这也称惰性实例变量
class C
def element
@a ||= [] #=>相当于:@a || @a = []
end
end
# Object Extension:通过给一个对象的单件类混入模块来定义单件方法
# 也可以直接使用Object#extend方法
obj = Object.new
module M
def my_method
'a singleton method'
end
end
class << obj
include M
end
obj.my_method #=> 'a singleton method'
# Prepended Wrapper:调用一个Prepend方式覆写的方法
下包含包装器
module M
def reverse
"x#{super}"
end
end
String.class_eval do
prepend M
end
p "abc".class.ancestors
p "abc".reverse
#[M, String, Comparable, Object, Kernel, BasicObject]
#"xcba"
# Refinement:(精细化) 为类打补丁,作用范围仅限到文件结束,或仅限于包含模块的作用域中。
to improve a method, plan, system etc by gradually making slight changes to it
module MyRefinement
refine String do
def reverse
"my reverse"
end
end
end
p "abc".reverse #=> "cba"
using MyRefinement #在文件结束
p "abc".reverse #=> "my reverse"
# 或者在模块的作用域内
module My_refine
using MyRefinement
p "abc".reverse #=> "my reverse"
end
# Refinement Wrapper: 在细化中调用非细化的方法。
module StringRefinement
refine String do
def reverse
"Refinement Wrapper: #{super}x"
end
end
end
using StringRefinement
p "abc".reverse #=> "Refinement Wrapper: cbax"
# 沙盒Sandbox:在一个安全环境下执行未受信的代码
def sandbox(&code)
proc {
$SAFE = 1 #$SAFE=2 to 4 are obsolete被淘汰了。?这方面知识欠缺。
yield
}.call
end
begin
sandbox { File.delete 'a_file'}
rescue Exception => ex
ex #=> No such file or directory @ apply2files - a_file
end
# Scope Gate:用class, def, module关键字隔开作用域
a = 1
puts defined? a #local-variable
module MyModule
b = 1
puts defined? b #=> local-variable
p defined? a #=> nil
end
p defined? a #=> local-variable
p defined? b #=> nil
问题:如何找像defined?关键字的信息。使用搜索发现在Ruby的旧文档里有案例,然后再找2.5的文档。使用site:搜索。找到:
http://ruby-doc.org/core-2.5.0/doc/syntax/miscellaneous_rdoc.html
defined?
is a keyword that returns a string describing its argument:
p defined?(UNDEFINED_CONSTANT) # prints nil
p defined?(RUBY_VERSION) # prints "constant"
p defined?(1 + 1) # prints "method"
# Self Yield: 把self传给当前block
class Person
attr_accessor :name, :surname
def initialize
yield self
end
end
joe = Person.new do |p|
p.name = 'Joe'
p.surname = 'Smith'
end
p joe#=>#<Person:0x00007fdc560042b0 @name="Joe", @surname="Smith">
Ruby中有不少方法也是自动把receiver传入块。如:instance_eval ,class_eval, Object#tap
# Singleton Method:
给一个对象定义一个单例方法,也可以extend一个模块。
class Klass
end
k = Klass.new
class << k
def hello
"Hello from Mod.\n"
end
end
p k.hello
# String of code
执行一段表示Ruby代码的字符串
my_string_of_code = "1+1"
p eval(my_string_of_code)#=》2
# Symbol To Proc
# 把一个调用单个方法的块转换成一个符号,一样的写法,目的是更省事
p [1,2,3].map{|x| x.even? }
p [1,2,3].map &:even?.to_proc #变成proc对象,然后再用&变成代码块
p [1,2,3].map(&:even?)
#=> [false, true, false]