Ruby BLocks and more

Abhishek  Yadav

Jan 2019

Agenda

  • Lambdas, closures, and blocks
  • Iterators, Enumerable
  • map, reduce
  • Lazy

 

  • Function like
  • Closure
  • Anonymous

Lambda

l1 = lambda { |x| "hello world " + x }

l2 = ->(x) { "hello world " + x }

l3 = lambda do |x|
  "hello world " +x
end

# invoke:-



l1.call("Abhi")

l2.("Abhi")

l3["Abhi"]
m='Mr' 

l4 = ->(x) { "hello #{m} #{x}" }


# invoke:-



l4.("Rick") # => "hello Mr Rick"

m='Miss'

l4.("Rachel") # => "hello Miss Rachel"

 

  • Function like
  • Closure
  • Anonymous

Lambda


def salutation(name)
  %w(Mr Miss).sample
end

def with_respect(name)
  s = salutation(name)
  yield (s + name)
end


# invoke:-



with_respect('Rick') { |x| "Hello #{x}" }

 

  • Function like √
  • Closure √
  • Anonymous √

     
  • Can be invoked only once
  • Not an object

Blocks

This part



def foo
  yield
end

foo { "hello world" }


# ^^ is somewhat similar to -

def bar(l)
  l.call
end

bar ->{ "Hello world" }


 

  • Function like √
  • Closure √
  • Anonymous √

     
  • Can be invoked with yield

Blocks



# Invoke with argument
 
def foo
  mood = ['🙂', '😠'].sample
  yield mood # call the block with the mood
end

foo { |mood| "hello world #{mood}" }



# Not an object.

x = { |mood| "hello world #{mood}" } # => error

 

  • Function like √
  • Closure √
  • Anonymous √

     
  • Can be invoked with yield
  • Not an object - Cant be assigned to a variable

Blocks



# Invoke with argument

def foo
  mood = ['🙂', '😠'].sample
  yield mood # call the block with the mood
end

def outer_foo
  foo do |mood|
   return if mood == '😠'
   "hello world #{mood}"
  end
  puts "ok!"
end


 

  • Function like √
  • Closure √
  • Anonymous √

     
  • Can be invoked with yield
  • Not an object - Cant be assigned to a variable
  • Has non local return

Blocks



# Invoke with argument

def foo
  mood = ['🙂', '😠'].sample
  yield mood # call the block with the mood
end

def outer_foo
  foo { |mood|
    return if mood == '😠'
    "hello world #{mood}"
  }
  puts "ok!"
end


 

  • Function like √
  • Closure √
  • Anonymous √

     
  • Can be invoked with yield
  • Not an object - Cant be assigned to a variable
  • Has non local return

Blocks



# Invoke with argument

x = 123
def foo
  puts x  # <- error
end




# method_missing
# define_method
  • Function like √
  • Closure x
  • Anonymous x

     
  • Used for OOP
  • Can access instance variables
  • Are attached dynamically
  • Can be defined dynamically (metaprogramming)

Methods



# Invoke with argument

x = 123
def foo
  puts x  # <- error
end




# method_missing
# define_method
  • Function like √
  • Closure x
  • Anonymous x

     
  • Used for OOP
  • Can access instance variables
  • Are attached dynamically
  • Can be defined dynamically (metaprogramming)

Methods

class Foo
  def step1
    puts 'start'
    1 + 1
    puts 'end'
  end

  def step2
    puts 'start'
    2 + 2
    puts 'end'
  end

  def step3
    puts 'start'
    3 + 3
    puts 'end'
  end
end
  • Use blocks when there is common 'surround' code

Log example

class Foo1
  def step1
    with_log { 1 + 1 }
  end

  def step2
    with_log { 2 + 2 }
  end

  def step3
    with_log { 3 + 3 }
  end

  def with_log
    puts 'start'
    yield
    puts 'end'
  end
end
  • Use blocks when there is common 'surround' code

Log example

class Foo2
  def step1
    with_log(:step1) { 1 + 1 }
  end

  def step2
    with_log(:step2) { 2 + 2 }
  end

  def step3
    with_log(:step3) { 3 + 3 }
  end

  def with_log(step)
    puts "start #{step}"
    yield
    puts "end #{step}"
  end
end
  • Use blocks when there is common 'surround' code

Log example



# This pattern gets repeated,
# with some variations to our logic

data['OrderedItems'].each do |ordered_item|
  ordered_item['TestContent'].each do |test_content|
    # Our logic here
  end
end

  • When we need to iterate over something cumbersome

Custom iterators



# This pattern gets repeated,
# with some variations to our logic

  def my_each(data)
    data['OrderedItems'].each do |ordered_item|
      ordered_item['TestContent'].each do |test_content|
        yield(test_content)
      end
    end
  end


  values = []
  my_each(results) do |test_data|
   values << test_data['Value']
  end
  
  • When we need to iterate over something cumbersome

Custom iterators

class MyArr
  def initialize
    @arr = []
  end

  def push(val)
    @arr << val
  end

  def myeach
    @arr.each do |val|
      yield val
    end
  end
end
  • When we need to iterate over something cumbersome
  • Use Enumerator where possible

Custom iterators


def my_each1(data)
  arr = MyArr.new
  data['OrderedItems'].each do |ordered_item|
    ordered_item['TestContent'].each do |test|
      if block_given?
        yield(test)
      else
        arr.push(test)
      end
    end
  end
  arr.to_enum(:myeach)
end

> my_each1(data).map { |x| x['Value'] }


  • Map and reduce
  • Lazy

More...

Ruby BLocks and more

By Abhishek Yadav

Ruby BLocks and more

  • 821