• 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]

     
     
     
  • 相关阅读:
    Power Desginer系列00【转载】
    Power Desginer系列02【转载】
    【转】华为路由器、交换机设备模拟器
    【图片教程】大学易站注册发布教程!
    【转】使用BT3、BT4光盘系统、虚拟机vmware破解无线上网
    【技术贴】设置 Eclipse 智能代码提示,大幅度减少 alt+/ 使用频率,打每个字都出现代码提
    【技术贴】ASPNET登录失败。MSsql2005拒绝了对对象 ''xxx'' (数据库 ''xx
    【技术贴】火狐的悬停激活标签扩展插件下载。Tab Focus
    【技术贴】桌面图标变色了怎么办?桌面图标快捷方式失真、模糊的解决办法!
    【转】【CN五一装机版】GhostXP_SP3电脑公司通用版v19.2装机版NTFS
  • 原文地址:https://www.cnblogs.com/chentianwei/p/8596597.html
Copyright © 2020-2023  润新知