3-18/19 (自我练习)30多个《Ruby元编程》的spell(pattern)小例子。

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. "
  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]

 
 
 
原文地址:https://www.cnblogs.com/chentianwei/p/8596597.html