Oh my! Lambda!

subha shree
4 min readSep 14, 2019

--

Image Source: Google

Ruby Lambda when and how ??????

Most of us would have seen ’n’ number of posts on how to use lambda( * I have seen at least 10+ posts *), but eventually will end up writing common methods. I have never used block call or yield, as it looks like a complicated feature that my brain never wants to learn it( “why to complicate things ! :D”).

Unfortunately, I have to use it in my work, to avoid duplicate issues. Then I told myself, if not now then when!

Image Source: Google

Before jumping into the code, we should be aware of what is lambda and its syntax.

Source: https://www.rubyguides.com/2016/02/ruby-procs-and-lambdas/

Note: ‘->’ is equivalent to lambda literal

Let’s dive into the code.

This code is about calculating a sum of scores depending on a given condition. The condition should be applied to every element and it differs for every class.

class WithoutLambdaExample
def self.run_examples
scores = [1, 2, 3, 4]
ClassA.calculate_score(scores)
scores = [4, 5, 6, 7]
ClassB.calculate_score(scores)
scores = [8, 9, 10, 11]
ClassC.calculate_score(scores)
scores = [12, 13, 15, 14]
ClassD.calculate_score(scores)
end
end
class ClassA
THRESHOLD = 5
FACTOR = 2
def self.calculate_score(scores)
score_point = process_score(scores)
puts "Class A: score point #{score_point}"
end
def self.process_score(scores)
sum = 0
unless scores.empty?
scores.each do |score|
sum += score if Utils.allowed_score(score) && (score * FACTOR > THRESHOLD)
end
end
sum
end
end
class ClassB
THRESHOLD = 10
FACTOR = 2.5
def self.calculate_score(scores)
score_point = process_score(scores)
puts "Class B: score point #{score_point}"
end
def self.process_score(scores)
sum = 0
unless scores.empty?
scores.each do |score|
sum += score if Utils.allowed_score(score) && (score + FACTOR < THRESHOLD)
end
end
sum
end
end
class ClassC
THRESHOLD = 5
FACTOR = 3
def self.calculate_score(scores)
score_point = process_score(scores)
puts "Class C: score point #{score_point}"
end
def self.process_score(scores)
sum = 0
unless scores.empty?
scores.each do |score|
sum += score if Utils.allowed_score(score) && (score - FACTOR >= THRESHOLD)
end
end
sum
end
end
class ClassD
THRESHOLD = 8
FACTOR = 3.5
def self.calculate_score(scores)
score_point = process_score(scores)
puts "Class D: score point #{score_point}"
end
def self.process_score(scores)
sum = 0
unless scores.empty?
scores.each do |score|
sum += score if Utils.allowed_score(score) && (score / FACTOR < THRESHOLD)
end
end
sum
end
end
class Utils
LOW_RANGE = 2
HIGH_RANGE = 15
def self.allowed_score(score)
score >= LOW_RANGE && score <= HIGH_RANGE
end
end

Now you have seen that condition alone changes but calculating steps remain the same.

How these repeating steps can be moved to a common method?

We can pass FACTOR and THRESHOLD, but how about operators?

Is there a way that I can pass this condition alone from the calling method and make it simple?

To answer all the above questions, we have our LAMBDA for it.

class LambdaExample
def self.run_examples
scores = [1, 2, 3, 4]
ClassA.calculate_score(scores)
scores = [4, 5, 6, 7]
ClassB.calculate_score(scores)
scores = [8, 9, 10, 11]
ClassC.calculate_score(scores)
scores = [12, 13, 15, 14]
ClassD.calculate_score(scores)
end
end
class ClassA
THRESHOLD = 5
FACTOR = 2
def self.calculate_score(scores)
condition_block = lambda { |score| (score * FACTOR) > THRESHOLD }
score_point = Processor.process_score(scores, &condition_block)
puts "Class A: score point #{score_point}"
end
end
class ClassB
THRESHOLD = 10
FACTOR = 2.5
def self.calculate_score(scores)
condition_block = lambda { |score| (score + FACTOR) < THRESHOLD }
score_point = Processor.process_score(scores, &condition_block)
puts "Class B: score point #{score_point}"
end
end
class ClassC
THRESHOLD = 5
FACTOR = 3
def self.calculate_score(scores)
condition_block = lambda { |score| (score - FACTOR) >= THRESHOLD }
score_point = Processor.process_score(scores, &condition_block)
puts "Class C: score point #{score_point}"
end
end
class ClassD
THRESHOLD = 8
FACTOR = 3.5
def self.calculate_score(scores)
condition_block = lambda { |score| (score / FACTOR) < THRESHOLD }
score_point = Processor.process_score(scores, &condition_block)
puts "Class D: score point #{score_point}"
end
end
class Processor
LOW_RANGE = 2
HIGH_RANGE = 15
def self.process_score(scores, &condition_block)
sum = 0
unless scores.empty?
scores.each do |score|
sum += score if allowed_score(score) && !condition_block.nil? && condition_block.call(score)
end
end
sum
end
def self.allowed_score(score)
score >= LOW_RANGE && score <= HIGH_RANGE
end
end

Now repeating steps are moved into a common method called process_score, having score and lambda as arguments.

Image source: Google

We can do this in different ways, but this post is exclusively for how we can make use of lambda.

Thanks for reading! Suggestions are welcome!

Note: This is my first post in medium :D

--

--