Spell,也稱pattern,idiomhtml
# 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。ruby
# 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:使用一個對象做爲執行一個代碼塊的環境app
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:使用一個對象做爲執行一個代碼塊的環境ide
# 通常用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的值
} lua
# Deferred Evaluation:延期執行 在proc或lambda中存儲一段代碼及其上下文,用於之後執行。spa
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:
在同一個扁平化的做用域中,多個指定的方法中共享變量code
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. htm
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]