Last active
August 22, 2017 11:25
-
-
Save henrik/8163fa7ae4ac9a7478ac5c06a1f6bd16 to your computer and use it in GitHub Desktop.
Ruby switch/case that complains if you forget to cover a case. Inspired by types in Elm. Just a for-fun experiment; not intended for real use.
This file contains hidden or 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
# By Henrik Nyh <https://henrik.nyh.se> under the MIT license. | |
class Enum | |
class Switch | |
def initialize(value_to_match_against, *values) | |
@checked_values = values.map { |v| [ v, false ] }.to_h | |
values.each do |value| | |
define_singleton_method(value) { |&block| | |
@checked_values[value] = true | |
@block_to_call = block if value == value_to_match_against | |
} | |
end | |
end | |
def verify_we_covered_all_cases_and_call_block_for_matching_value | |
unchecked_values = @checked_values.reject { |_k, v| v }.keys | |
if unchecked_values.any? | |
raise "Did not cover these cases: #{unchecked_values.inspect}" | |
end | |
@block_to_call.call if @block_to_call | |
end | |
end | |
def initialize(*values) | |
@values = values | |
end | |
def switch(value) | |
s = Switch.new(value, *@values) | |
yield s | |
s.verify_we_covered_all_cases_and_call_block_for_matching_value | |
end | |
end | |
def Enum(*values) | |
Enum.new(*values) | |
end | |
states = Enum(:hungry, :thirsty) | |
# This works: | |
states.switch(:thirsty) do |s| | |
s.hungry { puts "hungry!" } | |
s.thirsty { puts "thirsty!" } | |
end | |
# This raises, catching the fact that you didn't define the "hungry" case: | |
states.switch(:thirsty) do |s| | |
#s.hungry { puts "hungry!" } | |
s.thirsty { puts "thirsty!" } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
👏