A little background first. I've been working on a fairly large Rails application which quickly grew into a breeding ground for "smelly" code. One antipattern we were using a lot was storing objects in an STI lookup table and having lots of scattered logic based on the name of the object.
Here's a dumbed down example of what we had:
class Lookup < ActiveRecord::Base
end
class AlarmStatus < Lookup
has_many :alarm_logs
end
class AlarmLog < ActiveRecord::Base
belongs_to :alarm_status
end
Then all over our application we would do things like:
case @alarm_log.alarm_status.name
when "active"
# Do something
when "verified"
# Do something
when "inactive"
# Do something
end
This is obviously bad for a lot of reasons, but let's just say it was everywhere. After a few months of this, a consultant came along and pointed out our "code smell" and made some suggestions on how to refactor, which included a Ruby implementation of Java's Enum class.
We ended up using this frequently in our app, and have extracted into a ruby gem called classy_enum. The premise of classy_enum is that you get the power of OOP mixed with the strictness of an enumerated type, which is pretty much what we were trying to mimic with our STI Lookup model.
Example of defining an enum:
class Priority < ClassyEnum::Base
enum_classes :low, :medium, :high
def send_email?
false
end
end
class PriorityHigh < Priority
def send_email?
true
end
end
The gem's README has some other usage examples, including how to integrate it with a Rails project.
I may be asking for a lot here, but I would love some feedback from anyone willing to give it. It seems like a really cool solution to our problem and I can't imagine we're the only ones who have attempted to solve this before. Here's a list of questions that would be really useful for us:
- Is this a common problem?
- Does our solution make sense? Is there a better way to do it?
- Is the documentation clear?
- Would you use this in your application? Why or why not?
- How could we improve it?
- How is the code quality?