Oh my! Lambda!
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!
Before jumping into the code, we should be aware of what is lambda and its syntax.
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
endclass 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
endclass 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
endclass 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
endclass 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
endclass 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
endclass 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
endclass 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
endclass 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
endclass 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
endclass 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.
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