Metaprogramming Ruby - Blocks Note

  1. A review of the basics of blocks
  2. An overview of scopes and how you can carry variables through scopes by using blocks as closures
  3. How you can further manipulate scopes by passing a block to instance_eval
  4. 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.

  1. in block, we can access and change the variables which are defined before(out of) the block

  2. 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

  1. Class definitions
  2. Module definitions
  3. 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:

  1. dynamic run block
  2. Breaking Encapsulation, change the instance private variable.
    Often appears in testing.
  3. 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

  1. proc returns from the scope where the proc itself was defined:
  2. 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

你可能感兴趣的:(Metaprogramming Ruby - Blocks Note)