Last active
May 12, 2022 16:05
-
-
Save garyharan/e576738a46742153c714a920909a74f0 to your computer and use it in GitHub Desktop.
Using a class comparison in a switch case condition
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Story time: Classy Switch Classes | |
# Say you have a bunch of messages coming in Slack and you'd like to add an automatic emoji | |
# of course your team is multicultural and you may want to cater to the diverse crowd you have. | |
# For the purpose of this exercise we will treat `message#emojis` and `message#replies` as arrays we can push to. | |
# You could write your code like this: | |
if message.text.include?("Good morning!") | |
message.emojis << ":goodmorning" | |
elsif message.text =~ /happy birthday|joyeux anniversare|feliz aniversario/i | |
message.emojis << ":birthdaycake:" | |
elsif message.text.downcase.include?("error") && message.sender == "production_bot" | |
message.emojis << ":redalert:" | |
message.replies << "If you need help with this error check the logs at this URL" | |
end | |
# As these conditions grow you may be compelled to rewrite it like this: | |
case message.text | |
when /Good morning/i | |
message.emojis << ":goodmorning" | |
when /happy birthday|joyeux anniversare|feliz aniversario/i | |
message.emojis << ":birthdaycake:" | |
when /error/i | |
if message.sender == "production_bot" | |
message.emojis << ":redalert:" | |
message.replies << "If you need help with this error check the logs at this URL" | |
end | |
end | |
# This looks like an improvement because it's more compact and switch cases in Ruby famously support | |
# regular expressions. | |
# | |
# However it does mean you now have a condition inside one of the blocks. | |
# | |
# Another issue with readability here is that users are looking at the logic rather than a story. | |
# | |
# When code tells a story you shouldn't have to read the details of a regular expression to know what is going on. | |
# | |
# We could be classier still with our fellow readers and use class comparison in our switch cases. The resulting | |
# code tells a much better story: | |
case message | |
when MorningGreeting | |
message.emojis << ":goodmorning" | |
when BirthdayWish | |
message.emojis << ":birthdaycake:" | |
when ProductionError | |
message.emojis << ":redalert:" | |
message.replies << "If you need help with this error check the logs at this URL" | |
end | |
# Then the classes to create this comparison can be written with all the conditions you need to compare on. | |
class MorningGreeting | |
def self.===(message) | |
message.text =~ /Good morning/i | |
end | |
end | |
class BirthdayWish | |
def self.===(message) | |
message.text =~ /happy birthday|joyeux anniversare|feliz aniversario/i | |
end | |
end | |
class ProductionError | |
def self.===(message) | |
message.text =~ /error/i && message.sender == "production_bot" | |
end | |
end | |
# Of course this is the start of strategy pattern... we could also encapsulate the resulting action in | |
# the class to that effect as follow: | |
case message | |
when MorningGreeting then MorningGreeting.react_to(message) | |
when BirthdayWish then BirthdayWish.react_to(message) | |
when ProductionError then ProductionError.react_to(message) | |
end | |
class MorningGreeting | |
def self.===(message) | |
message.text =~ /Good morning/i | |
end | |
def self.react_to(message) | |
message.emojis << ":goodmorning" | |
end | |
end | |
class BirthdayWish | |
def self.===(message) | |
message.text =~ /happy birthday|joyeux anniversare|feliz aniversario/i | |
end | |
def self.react_to(message) | |
message.emojis << ":birthdaycake:" | |
end | |
end | |
class ProductionError | |
def self.===(message) | |
message.text =~ /error/i && message.sender == "production_bot" | |
end | |
def self.react_to(message) | |
message.emojis << ":redalert:" | |
message.replies << "If you need help with this error check the logs at this URL" | |
end | |
end | |
# With that the dispatch switch case block becomes very readable and it makes it really easy to navigate the code. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment