lib/abstractivator/enum.rb in abstractivator-0.0.19 vs lib/abstractivator/enum.rb in abstractivator-0.0.20
- old
+ new
@@ -1,29 +1,74 @@
require 'active_support/inflector'
+require 'abstractivator/enumerable_ext'
+require 'delegate'
module Enum
def self.included(base)
base.extend ClassMethods
+ # base.extend Dsl
end
module ClassMethods
def values
- self.constants.map{|sym| self.const_get(sym)}
+ self.constants.map{|sym| self.const_get(sym)}.reject{|x| x == Enum::ClassMethods}
end
def name_for(value)
self.constants.detect{|sym| self.const_get(sym) == value}
end
def from_symbol(sym)
safe_constantize("#{self.name}::#{sym.to_s.upcase}")
end
+ private
+
def safe_constantize(str)
begin
str.constantize
rescue NameError
fail "'#{str}' has not been defined as a constant"
end
end
+ end
+end
+
+module EnumMember
+ attr_accessor :enum_type
+end
+
+class Object
+ include EnumMember
+end
+
+class WrappedEnumValue < SimpleDelegator
+ include EnumMember
+ attr_reader :class # pure evil
+ def initialize(value)
+ __setobj__(value)
+ @class = value.class
+ end
+end
+
+def define_enum(name, *fields)
+ const_set(name, make_enum(*fields))
+end
+
+def make_enum(*fields)
+ if fields.size == 1 && fields.first.is_a?(Hash) && fields.first.keys.all?{|f| f.is_a?(Symbol)}
+ fields = fields.first
+ Module.new do
+ include Enum
+ fields.each_pair do |k, v|
+ val = v.frozen? ? WrappedEnumValue.new(v) : v
+ val.enum_type = self
+ fld = k.to_s.upcase.to_sym
+ const_set(fld, val)
+ end
+ end
+ elsif fields.all?{|f| f.is_a?(Symbol)}
+ make_enum(fields.hash_map(&:to_s))
+ else
+ raise 'Arguments must be one or more symbols or a single symbol-keyed hash'
end
end