-
Notifications
You must be signed in to change notification settings - Fork 23
Closed
Labels
Description
@dblock Thanks for making this gem! :)
One use case I have for enums is that I want to use them in case statements. A nice feature in Rust is exhaustive matching. Obviously, this doesn't work in native Ruby because of the missing types. However, in ruby-enum, it can work, because we have the information about which cases should be handled.
A possible drawback of this is that such a check adds additional steps to each call of the case statement and makes the runtime of the code slower.
I implemented a quick version of this in a project of mine and would be happy to contribute it to this project. A default/else block could be added as well.
Let me know what you think about it :)
##
# Adds a method to an enum class that allows for exhaustive matching on a value.
#
# @example
# class Color
# include Ruby::Enum
# include Ruby::Enum::Ecase
#
# define :RED, :red
# define :GREEN, :green
# define :BLUE, :blue
# end
#
# Color.ecase(Color::RED, {
# [Color::RED, Color::GREEN] => -> { puts "red or green" },
# Color::BLUE => -> { puts "blue" },
# })
module Ruby::Enum::Ecase
def self.included(klass)
klass.extend(ClassMethods)
end
##
# @see Ruby::Enum::Ecase
module ClassMethods
class ValuesNotDefinedError < StandardError
end
class NotAllCasesHandledError < StandardError
end
def ecase(value, cases)
validate_cases(cases)
cases.each do |values, block|
values = [values] unless values.is_a?(Array)
block.call if values.include?(value)
end
end
private
def validate_cases(cases)
all_values = cases.keys.flatten
superfluous_values = all_values - values
missing_values = values - all_values
if superfluous_values.any?
raise ValuesNotDefinedError, "Value(s) not defined: #{superfluous_values.join(", ")}"
end
if missing_values.any? # rubocop:disable Style/GuardClause
raise NotAllCasesHandledError, "Not all cases handled: #{missing_values.join(", ")}"
end
end
end
end