diff --git a/.travis.yml b/.travis.yml index 6a850d7..429adb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ script: "bundle exec rspec spec" + language: ruby + rvm: - 1.9.3 - 2.0.0 diff --git a/README.md b/README.md index 9ef9dc0..2ef7ad4 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://travis-ci.org/thetron/mongoid-enum.png)](https://travis-ci.org/thetron/mongoid-enum) +[![Code Climate](https://codeclimate.com/github/thetron/mongoid-enum.png)](https://codeclimate.com/github/thetron/mongoid-enum) Heavily inspired by [DHH's ActiveRecord::Enum](https://github.com/rails/rails/commit/db41eb8a6ea88b854bf5cd11070ea4245e1639c5), this little library is @@ -126,7 +127,7 @@ Sometimes you'll need to store multiple values from your list, this couldn't be easier: ```ruby -enum, :roles => [:basic, :manager, :administrator], :multiple => true +enum :roles, [:basic, :manager, :administrator], :multiple => true # ... @@ -140,6 +141,14 @@ user.administrator? # => false user.roles # => [:basic, :manager] ``` +Since the underlying datatype for storing values is an array, if you +need to specify default(s), ensure you use an array: + +```ruby +enum :roles, [:noob, :author, :editor], :multiple => true, :default => [:author, :editor] # two defaults +enum :roles, [:noob, :author, :editor], :multiple => true, :default => [] # no default +``` + ## Validations Validations are baked in by default, and ensure that the value(s) set in @@ -148,7 +157,7 @@ complex validations, or you just want to throw caution to the wind, you can turn them off: ```ruby -enum :status => [:up, :down], :validate => false +enum :status, [:up, :down], :validate => false ``` # Issues and Feature Requests diff --git a/lib/mongoid/enum.rb b/lib/mongoid/enum.rb index 981b337..ac9a5f0 100644 --- a/lib/mongoid/enum.rb +++ b/lib/mongoid/enum.rb @@ -5,38 +5,69 @@ module Mongoid module Enum extend ActiveSupport::Concern module ClassMethods + def enum(name, values, options = {}) field_name = :"_#{name}" - const_name = name.to_s.upcase - multiple = options[:multiple] || false - default = options[:default].nil? && values.first || options[:default] - required = options[:required].nil? || options[:required] - validate = options[:validate].nil? || options[:validate] + options = default_options(values).merge(options) - const_set const_name, values + set_values_constant name, values - type = multiple && Array || Symbol - field field_name, :type => type, :default => default + create_field field_name, options alias_attribute name, field_name - if multiple && validate - validates field_name, :'mongoid/enum/validators/multiple' => { :in => values, :allow_nil => !required } - elsif validate - validates field_name, :inclusion => {:in => values}, :allow_nil => !required - end + create_validations field_name, values, options + define_value_scopes_and_accessors field_name, values, options + end + private + def default_options(values) + { + :multiple => false, + :default => values.first, + :required => true, + :validate => true + } + end + + def set_values_constant(name, values) + const_name = name.to_s.upcase + const_set const_name, values + end + + def create_field(field_name, options) + type = options[:multiple] && Array || Symbol + field field_name, :type => type, :default => options[:default] + end + + def create_validations(field_name, values, options) + if options[:multiple] && options[:validate] + validates field_name, :'mongoid/enum/validators/multiple' => { :in => values, :allow_nil => !options[:required] } + elsif validate + validates field_name, :inclusion => {:in => values}, :allow_nil => !options[:required] + end + end + + def define_value_scopes_and_accessors(field_name, values, options) values.each do |value| scope value, ->{ where(field_name => value) } - if multiple - class_eval "def #{value}?() self.#{field_name}.include?(:#{value}) end" - class_eval "def #{value}!() update_attributes! :#{field_name} => (self.#{field_name} || []) + [:#{value}] end" + if options[:multiple] + define_array_accessor(field_name, value) else - class_eval "def #{value}?() self.#{field_name} == :#{value} end" - class_eval "def #{value}!() update_attributes! :#{field_name} => :#{value} end" + define_string_accessor(field_name, value) end end end + + def define_array_accessor(field_name, value) + class_eval "def #{value}?() self.#{field_name}.include?(:#{value}) end" + class_eval "def #{value}!() update_attributes! :#{field_name} => (self.#{field_name} || []) + [:#{value}] end" + end + + def define_string_accessor(field_name, value) + class_eval "def #{value}?() self.#{field_name} == :#{value} end" + class_eval "def #{value}!() update_attributes! :#{field_name} => :#{value} end" + end end end end