3-18/19 (自我練習)30多個《Ruby元編程》的spell(pattern)小例子。

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]

相關文章
相關標籤/搜索