- 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
endtop_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