Metaprogramming Ruby - Blocks Note

2861 ワード

  • A review of the basics of blocks
  • An overview of scopes and how you can carry variables through scopes by using blocks as closures
  • How you can further manipulate scopes by passing a block to instance_eval
  • How you can convert blocks into callable objects that you can set aside and call later, such as Procs and lambdas

  • instance_eval, a little like python's unlocal.
    Blocks Are Closures
    yield: block's context is where the block is defined.
  • in block, we can access and change the variables which are defined before(out of) the block
  • out of block, we can't access a variable defined in the block. def just_yield yield end
    top_level_variable = 1
    
    just_yield do
      top_level_variable += 1
      local_to_block = 1
    end
    
    top_level_variable # => 2
    local_to_block # => Error!
    

  • Scope Gates
    def: leave previous scope and opens a new
  • Class definitions
  • Module definitions
  • Methods

  • Flattening the Scope
    use block to define class or method
    Sharing the Scope shared -- just a free variable def define_methods shared = 0
         Kernel.send :define_method, :counter do
           shared
         end
    
         Kernel.send :define_method, :inc do |x|
           shared += x
         end
       end
    
       define_methods
    
       counter # => 0 inc(4)
       counter # => 4
    

    instance_eval
    usage:
  • dynamic run block
  • Breaking Encapsulation, change the instance private variable. Often appears in testing.
  • Clean Room: Sometimes you create an object just to evaluate blocks inside it. A Clean Room is just an environment where you can evaluate your blocks

  • Callable objects
    lambda vs proc
  • proc returns from the scope where the proc itself was defined:
  • lambda checks arguments

  • Method Objects
    Unbound Methods
    UnboundMethods are like Methods that have been detached from their original class or module
    Like JavaSceipt get function from prototype, but the unboundmethods can not be called(You can redefine it to the new Class). eg: MyModule.instance_method(:my_method)
    redefine method
        module Loadable
          def self.exclude_from(base)
            base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
          end
        end
    

    useful methods
    block_given? local_variables, the variables can be saw in current place.
       a = 1
       l = lambda{ local_variables }
       [:l, :a, :_]
    

    $var, global variables. Proc#lambda? method: get method by name, (1.method :+).call(1) Method#to_proc: (1.method :+).to_proc.call(1), solve the scope arity: Returns an indication of the number of arguments accepted by a method