Tips FROM
The RuBY CLOSUREs BOOK
I'm Guo Xiang
I work for
https://leanpub.com/therubyclosuresbook
1. Free VARIABLES
In computer programming, the term free variable refers to variables used in a function that are neither local variables nor parameters of that function.
source: https://en.wikipedia.org/wiki/Free_variables_and_bound_variables
1. Free VARIABLES
snorlax_sighted = lambda do |coordinates|
lambda do
puts "SNORLAX!!! Chiong to #{coordinates}"
end
end
1. Free VARIABLES
snorlax_sighted = lambda do |coordinates|
lambda do
puts "SNORLAX!!! Chiong to #{coordinates}"
end
end
1. Free VARIABLES
snorlax_sighted = lambda do |coordinates|
lambda do
puts "SNORLAX!!! Chiong to #{coordinates}"
end
end
2. Closures
snorlax_sighted = lambda do |coordinates|
lambda do
puts "SNORLAX!!! Chiong to #{coordinates}"
end
end
2. Closures
"a) a function ... b) whose body references some variable that is defined in a parent scope"
source: The Ruby Closures Book
3. Yield
Title Text
def snorlax
yield "Hyper Beam", "Sleep"
end
=> snorlax do |attack_1, attack_2|
=> puts "Snorlax attacks: #{attack_1}, #{attack_2}"
=> end
3. Yield
Title Text
def snorlax
yield "Hyper Beam", "Sleep"
end
=> snorlax
irb(main):008:0> snorlax
LocalJumpError: no block given (yield)
from (irb):6:in `snorlax'
from (irb):8
3. Yield
Title Text
irb(main):023:0> method :puts
=> #<Method: Object(Kernel)#puts>
irb(main):025:0> method :yield
NameError: undefined method `yield' for class `Object`
from (irb):25:in `method'
from (irb):25
3. block_given?
Title Text
def snorlax
if block_given?
yield "Hyper Beam", "Sleep"
end
end
=> snorlax
nil
3. Yield
Title Text
def snorlax
yield "Hyper Beam", "Sleep"
end
irb=> snorlax do |attack_1|
irb=> puts attack_1
irb=> end
Hyper Beam
3. Yield
Title Text
def snorlax
yield "Hyper Beam"
end
irb=> snorlax do |attack_1, attack_2|
irb=> puts attack_1
irb=> puts attack_2
irb=> end
Hyper Beam
irb=> nil
Ex1. Implement Times
Title Text
class Fixnum
def times
count = 0
while count < self
puts count
yield
count += 1
end
self
end
end
5.times { puts "Yay!" }
Ex1. Implement Times
Title Text
class Fixnum
def times
count = 0
while count < self
puts count
yield
count += 1
end
self
end
end
5.times { puts "Yay!" }
Ex1. Implement Times
Title Text
class Fixnum
def times
count = 0
while count < self
puts count
yield
count += 1
end
self
end
end
5.times { puts "Yay!" }
Ex1. Implement Times
Title Text
class Fixnum
def times
count = 0
while count < self
puts count
yield
count += 1
end
self
end
end
5.times { puts "Yay!" }
Ex1. Implement Times
Title Text
class Fixnum
def times
count = 0
while count < self
puts count
yield
count += 1
end
self
end
end
5.times { puts "Yay!" }
ex2. Implement EACH
Title Text
class Array
def each
index = 0
while index < self.length
puts "Yielding: #{self[index]}"
yield self[index]
index += 1
end
end
end
[1, 2, 3].each { |x| puts "Yay!" * x }
ex2. Implement EACH
Title Text
class Array
def each
index = 0
while index < self.length
puts "Yielding: #{self[index]}"
yield self[index]
index += 1
end
end
end
[1, 2, 3].each { |x| puts "Yay!" * x }
ex2. Implement EACH
Title Text
class Array
def each
index = 0
while index < self.length
puts "Yielding: #{self[index]}"
yield self[index]
index += 1
end
end
end
[1, 2, 3].each { |x| puts "Yay!" * x }
ex2. Implement EACH
Title Text
class Array
def each
index = 0
while index < self.length
puts "Yielding: #{self[index]}"
yield self[index]
index += 1
end
end
end
[1, 2, 3].each { |x| puts "Yay!" * x }
ex2. Implement EACH
Title Text
class Array
def each
index = 0
while index < self.length
puts "Yielding: #{self[index]}"
yield self[index]
index += 1
end
end
end
[1, 2, 3].each { |x| puts "Yay!" * x }
4. INSTANCE_EVAL To the RESCUE!
MyRouter.new do
get "/users"
post "/user/:id"
end
=> GET: /users
=> POST: /users/:id
4. INSTANCE_EVAL To the RESCUE!
class MyRouter
def initialize(&block)
instance_eval(&block)
end
def get(endpoint)
puts "GET: #{endpoint}"
end
def post(endpoint)
puts "POST: #{endpoint}"
end
end
4. INSTANCE_EVAL To the RESCUE!
MyRouter.new do
self.get "/users"
self.post "/user/:id"
end
=> GET: /users
=> POST: /users/:id
5. Calling PROCS
my_proc = proc { |x, y| x + y }
my_proc.call('Snor', 'lax')
=> "Snorlax"
5. Calling PROCS
my_proc = proc { |x, y| x + y }
my_proc.('Snor', 'lax')
=> "Snorlax"
class MyKlass
def call(pokemon)
"I choose you #{pokemon}"
end
end
MyKlass.new.("Snorlax")
=> "I choose you Snorlax"
5. Calling PROCS
my_proc = proc { |x, y| x + y }
my_proc['Snor', 'lax']
=> "Snorlax"
5. Calling PROCS
my_proc = proc { |x, y| x + y }
my_proc === ['Snor', 'lax']
=> "Snorlax"
case ['Snor', 'lax']
when my_proc
puts "I found a Snorlax"
else
# Do nothing
end
=> "I found a Snorlax"
6. `symbol#to_proc`
words = %w{one two three}
words.each(&:upcase!)
=> ["ONE", "TWO", "THREE"]
words.each(&(:upcase!))
6. `symbol#to_proc`
words = %w{one two three}
my_proc = proc { |x| x.upcase! }
words.map(&my_proc)
words.map { |x| x.upcase! }
=> ["ONE", "TWO", "THREE"]
class Pokemon
def to_proc
proc { |x| x.downcase! }
end
end
words.map(&(Pokemon.new))
=> ["one", "two", "three"]
6. `symbol#to_proc`
words = %w{one two three}
my_proc = proc { |x| x.upcase! }
words.map(&my_proc)
words.map { |x| x.upcase! }
=> ["ONE", "TWO", "THREE"]
class Pokemon
def to_proc
proc { |x| x.downcase! }
end
end
words.map(&(Pokemon.new))
=> ["one", "two", "three"]
6. `symbol#to_proc`
words = %w{one two three}
words.map(&:upcase)
class Symbol
def to_proc
proc do |object|
puts "Sending #{self} to #{object}"
object.public_send(self)
end
end
end
words.map(&:upcase)
6. `symbol#to_proc`
words = %w{one two three}
words.map(&:upcase)
class Symbol
def to_proc
proc do |object|
puts "Sending #{self} to #{object}"
object.public_send(self)
end
end
end
words.map(&:upcase)
6. `symbol#to_proc`
words = %w{one two three}
words.map(&:upcase)
class Symbol
def to_proc
proc do |object|
puts "Sending #{self} to #{object}"
object.public_send(self)
end
end
end
words.map(&:upcase)
6. `symbol#to_proc`
numbers = [1, 2, 3]
numbers.inject(0) { |result, element| result + element }
class Symbol
def to_proc
proc do |obj, args|
puts "obj: #{obj}"
puts "args: #{args}"
obj.public_send(self, *args)
end
end
end
7. `Proc#curry`
my_proc = proc { |a, b, c| a * b * c }.curry
my_proc.call(1).call(2).call(3)
=> 6
7. `Proc#curry`
I consider this method (Proc#curry) to be trivial and should be treated like an Easter egg for functional programming kids. matz.
8. LAMBDAS VS PROC
lambda { |x, y| x + y }.(1, 2)
=> 3
lambda { |x, y| x + y }.(1)
=> wrong number of arguments (given 1, expected 2)
proc { |x, y| x + y }.(1, 2)
=> 3
proc { |x, y| x + y }.(1)
=> TypeError: nil can't be coerced into Fixnum
8. LAMBDAS VS PROC
def snorlax(proc_or_lambda)
puts "I see a snorlax"
proc_or_lambda.call
puts "Snorlax ran away"
end
snorlax(lambda { puts "Throw pokeball"; return })
=> I see a snorlax
=> Throw pokeball
=> Snorlax ran away
snorlax(proc { puts "Throw pokeball"; return })
=> LocalJumpError: unexpected return
def test
puts "Looking for snorlax"
snorlax(proc { puts "Throw pokeball"; return })
puts "Looking for another snorlax"
end
=> Looking for snorlax
=> I see a snorlax
=> Throw pokeball
8. LAMBDAS VS PROC
def snorlax(proc_or_lambda)
puts "I see a snorlax"
proc_or_lambda.call
puts "Snorlax ran away"
end
snorlax(lambda { puts "Throw pokeball"; return })
=> I see a snorlax
=> Throw pokeball
=> Snorlax ran away
snorlax(proc { puts "Throw pokeball"; return })
=> LocalJumpError: unexpected return
def test
puts "Looking for snorlax"
snorlax(proc { puts "Throw pokeball"; return })
puts "Looking for another snorlax"
end
=> Looking for snorlax
=> I see a snorlax
=> Throw pokeball
8. LAMBDAS VS PROC
def snorlax(proc_or_lambda)
puts "I see a snorlax"
proc_or_lambda.call
puts "Snorlax ran away"
end
snorlax(lambda { puts "Throw pokeball"; return })
=> I see a snorlax
=> Throw pokeball
=> Snorlax ran away
snorlax(proc { puts "Throw pokeball"; return })
=> LocalJumpError: unexpected return
def test
puts "Looking for snorlax"
snorlax(proc { puts "Throw pokeball"; return })
puts "Looking for another snorlax"
end
=> Looking for snorlax
=> I see a snorlax
=> Throw pokeball
8. LAMBDAS VS PROC
def snorlax(proc_or_lambda)
puts "I see a snorlax"
proc_or_lambda.call
puts "Snorlax ran away"
end
snorlax(lambda { puts "Throw pokeball"; return })
=> I see a snorlax
=> Throw pokeball
=> Snorlax ran away
snorlax(proc { puts "Throw pokeball"; return })
=> LocalJumpError: unexpected return
def test
puts "Looking for snorlax"
snorlax(proc { puts "Throw pokeball"; return })
puts "Looking for another snorlax"
end
=> Looking for snorlax
=> I see a snorlax
=> Throw pokeball
More examples in the booK
Questions?
TIPS FROM THE RUBY CLOSURES BOOK
By tgxworld
TIPS FROM THE RUBY CLOSURES BOOK
- 1,010