Chapter 3: Methods

Blank Slates

The meaning of the Blank Slate is to create an Object for other classes to inherit which is almost blank to avoid method clash. Now as of Ruby 1.9, the best solution is to inherit BasicObject.

Chapter 4: Blocks

Roadmap

  • 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

define block

do end or {}.

blocks are closures

Pass bindings through a Scope Gate

my_var = "Success"

MyClass = Class.new do
  "#{my_var} in the class definition"
  
  define_method :my_method do 
    "#{my_var} in the method"
  end
end

MyClass.new.my_method

instance_eval() and instance_exec()

Callable Objects

package code first, call it later.

  • Proc
  • lambda
  • method

Proc Objects

Blocks are not object, when you want to store a block and execute it later, you need an object.

Methods of converting block to Proc.

Method 1

def my_method(&the_proc) 
  the_proc
end

p = my_method {|name| "Hello, #{name}!" } 
p.class # => Proc
p.call("Bill") # => "Hello, Bill!"

You can use the & operator to convert the Proc to a block

names.map(&:to_s) Links

names.map &:to_s

# We can expand it to
names.map &:to_s.to_proc

# Replacing "to_proc" with the result of calling the method
names.map &->(name, args = nil) { name.send(:to_s, *args) }

# "map" passes a single argument to the block, so we can simplify
names.map &->(name) { name.send(:to_s) }

# Calling the method directly we get
names.map &->(name) { name.to_s }

# Since "&" transforms Procs and Lambdas to blocks, it's equivalent to
names.map { |name| name.to_s }

Why does explicit return make a difference in a Proc?

https://stackoverflow.com/questions/1435743/why-does-explicit-return-make-a-difference-in-a-proc

def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end

def bar
  b = Proc.new { "return from bar from inside proc" }
  b.call # control leaves bar here
  return "return from bar" 
end

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

Ruby has three constructs:

  • A block is not an object and is created by { ... } or do ... end.
  • A proc is a Proc object created by Proc.new or proc.
  • A lambda is a Proc created by lambda (or proc in Ruby 1.8).

Ruby has three keywords that return from something:

  • return terminates the method or lambda it is in.
  • next terminates the block, proc, or lambda it is in.
  • break terminates the method that yielded to the block or invoked the proc or lambda it is in.

In lambdas, return behaves like next, for whatever reason. next and break are named the way they are because they are most commonly used with methods like each, where terminating the block will cause the iteration to resume with the next element of the collection, and terminating each will cause you to break out of the loop.

If you use return inside the definition of foo, you will return from foo, even if it is inside a block or a proc. To return from a block, you can use the next keyword instead.

def foo
  f = Proc.new { next "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end
puts foo # prints "return from foo"