Compare commits

..

No commits in common. "master" and "v0.1.0" have entirely different histories.

13 changed files with 83 additions and 282 deletions

1
.gitignore vendored
View File

@ -15,4 +15,3 @@ spec/reports
test/tmp test/tmp
test/version_tmp test/version_tmp
tmp tmp
.idea

View File

@ -1,14 +1,14 @@
script: "bundle exec rspec spec" script: "bundle exec rspec spec"
language: ruby language: ruby
rvm: rvm:
- 1.9.3 - 1.9.3
- 2.0.0 - 2.0.0
- 2.1.0
- 2.1.1
- 2.1.2
- jruby-19mode - jruby-19mode
- rbx-19mode
gemfile:
- Gemfile
notifications:
recipients:
- nicholas@bruning.com.au
services: services:
- mongodb - mongodb

View File

@ -1,8 +0,0 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard :rspec, cmd: "bundle exec rspec" do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
end

View File

@ -2,11 +2,10 @@
[![Build [![Build
Status](https://travis-ci.org/thetron/mongoid-enum.png)](https://travis-ci.org/thetron/mongoid-enum) 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 Heavily inspired by [DHH's
ActiveRecord::Enum](https://github.com/rails/rails/commit/db41eb8a6ea88b854bf5cd11070ea4245e1639c5), this little library is ActiveRecord::Enum](https://github.com/rails/rails/commit/db41eb8a6ea88b854bf5cd11070ea4245e1639c5), this little library is
there to help you cut down the cruft in your models and make the just there to help you cut down the cruft in your models and make the
world a happier place at the same time. world a happier place at the same time.
A single line will get you fields, accessors, validations and scopes, A single line will get you fields, accessors, validations and scopes,
@ -17,27 +16,25 @@ and a few other bits-and-bobs.
Add this to your Gemfile: Add this to your Gemfile:
```ruby gem "mongoid-enum"
gem "mongoid-enum"
```
And then run `bundle install`. And then run `bundle install`.
# Usage # Usage
```ruby ````
class Payment class Payment
include Mongoid::Document include Mongoid::Document
include Mongoid::Enum include Mongoid::Enum
enum :status, [:pending, :approved, :declined] enum :status, [:pending, :approved, :declined],
end end
``` ````
Aaaaaaand then you get things like: Aaaaaaand then you get things like:
```ruby ````
payment = Payment.create payment = Payment.create
payment.status payment.status
@ -52,7 +49,7 @@ payment.pending?
Payment.approved Payment.approved
# => Mongoid::Criteria for payments with status == :approved # => Mongoid::Criteria for payments with status == :approved
``` ````
# Features # Features
@ -67,16 +64,16 @@ convenience.
## Accessors ## Accessors
Your enums will get getters-and-setters with the same name. So using the Your enums will get getters-and-setters with the same name. So using the
`Payment` example above: 'Payment' example above:
```ruby ````
payment.status = :declined payment.status = :declined
payment.status payment.status
# => :declined # => :declined
``` ````
And you also get bang(!) and query(?) methods for each of the values in And you also get bang(!) and query(?) methods for each of the values in
your enum (see [this example](#usage). your enum (see [this example](#Usage).
## Constants ## Constants
@ -85,16 +82,16 @@ For each enum, you'll also get a constant named after it. This is to
help you elsewhere in your app, should you need to display, or leverage help you elsewhere in your app, should you need to display, or leverage
the list of values. Using the above example: the list of values. Using the above example:
```ruby ````
Payment::STATUS Payment::STATUS
# => [:pending, :approved, :declined] # => [:pending, :approved, :declined]
``` ````
## Validations ## Validations
Enum values are automatically validated against the list. You can Enum values are automatically validated against the list. You can
disable this behaviour (see [below](#options)). disable this behaviour (see (below)[#Options]).
## Scopes ## Scopes
@ -102,11 +99,11 @@ disable this behaviour (see [below](#options)).
A scope added for each of your enum's values. Using the example above, A scope added for each of your enum's values. Using the example above,
you'd automatically get: you'd automatically get:
```ruby ````
Payment.pending # => Mongoid::Criteria Payment.pending # => Mongoid::Criteria
Payment.approved # => Mongoid::Criteria Payment.approved # => Mongoid::Criteria
Payment.declined # => Mongoid::Criteria Payment.declined # => Mongoid::Criteria
``` ````
# Options # Options
@ -117,37 +114,25 @@ If not specified, the default will be the first in your list of values
(`:pending` in the example above). You can override this with the (`:pending` in the example above). You can override this with the
`:default` option: `:default` option:
```ruby enum :roles, [:manager, :administrator], :default => ""
enum :roles, [:manager, :administrator], :default => ""
```
## Multiple values ## Multiple values
Sometimes you'll need to store multiple values from your list, this Sometimes you'll need to store multiple values from your list, this
couldn't be easier: couldn't be easier:
```ruby enum, :roles => [:basic, :manager, :administrator], :multiple => true
enum :roles, [:basic, :manager, :administrator], :multiple => true
# ... user = User.create
user.roles << :basic
user.roles << :manager
user.save!
user = User.create user.manager? # => true
user.roles << :basic user.administrator? # => false
user.roles << :manager user.roles # => [:basic, :manager]
user.save!
user.manager? # => true
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
@ -156,13 +141,4 @@ your field are always from your list of options. If you need more
complex validations, or you just want to throw caution to the wind, you complex validations, or you just want to throw caution to the wind, you
can turn them off: can turn them off:
```ruby enum :status => [:up, :down], :validation => false
enum :status, [:up, :down], :validate => false
```
# Issues and Feature Requests
If you have any problems, or you have a suggestion, please [submit an
issue](https://github.com/thetron/mongoid-enum/issues) (and a failing
test, if you can). Pull requests and feature requests are alwasy welcome
and greatly appreciated.

View File

@ -1,93 +1,41 @@
require "mongoid/enum/version" require "mongoid/enum/version"
require "mongoid/enum/validators/multiple_validator" require "mongoid/enum/validators/multiple_validator"
require "mongoid/enum/configuration"
module Mongoid module Mongoid
module Enum module Enum
extend ActiveSupport::Concern extend ActiveSupport::Concern
module ClassMethods module ClassMethods
def enum(name, values, options = {}) def enum(name, values, options = {})
field_name = :"#{Mongoid::Enum.configuration.field_name_prefix}#{name}" field_name = :"_#{name}"
options = default_options(values).merge(options)
set_values_constant name, values
create_field field_name, options
create_validations field_name, values, options
define_value_scopes_and_accessors field_name, values, options
define_field_accessor name, field_name, 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_name = name.to_s.upcase
multiple = options[:multiple] || false
default = options[:default].nil? && values.first || options[:default]
required = options[:required].nil? || options[:required]
const_set const_name, values const_set const_name, values
end
def create_field(field_name, options) type = multiple && Array || Symbol
type = options[:multiple] && Array || Symbol field field_name, :type => type, :default => default
field field_name, :type => type, :default => options[:default] alias_attribute name, field_name
end
def create_validations(field_name, values, options) if multiple
if options[:multiple] && options[:validate] validates field_name, :'mongoid/enum/validators/multiple' => { :in => values, :allow_nil => !required }
validates field_name, :'mongoid/enum/validators/multiple' => { :in => values.map(&:to_sym), :allow_nil => !options[:required] } else
#FIXME: Shouldn't this be `elsif options[:validate]` ??? validates field_name, :inclusion => {:in => values}, :allow_nil => !required
elsif validate
validates field_name, :inclusion => {:in => values.map(&:to_sym)}, :allow_nil => !options[:required]
end end
end
def define_value_scopes_and_accessors(field_name, values, options)
values.each do |value| values.each do |value|
scope value, ->{ where(field_name => value) } scope value, where(field_name => value)
if options[:multiple] if multiple
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"
else else
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
end end
def define_field_accessor(name, field_name, options)
if options[:multiple]
define_array_field_accessor name, field_name
else
define_string_field_accessor name, field_name
end
end
def define_array_field_accessor(name, field_name)
class_eval "def #{name}=(vals) self.write_attribute(:#{field_name}, Array(vals).compact.map(&:to_sym)) end"
class_eval "def #{name}() self.read_attribute(:#{field_name}) end"
end
def define_string_field_accessor(name, field_name)
class_eval "def #{name}=(val) self.write_attribute(:#{field_name}, val && val.to_sym || nil) end"
class_eval "def #{name}() self.read_attribute(:#{field_name}) 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 end
end end

View File

@ -1,19 +0,0 @@
module Mongoid
module Enum
class Configuration
attr_accessor :field_name_prefix
def initialize
self.field_name_prefix = "_"
end
end
def self.configuration
@configuration ||= Configuration.new
end
def self.configure
yield(configuration) if block_given?
end
end
end

View File

@ -1,5 +1,5 @@
module Mongoid module Mongoid
module Enum module Enum
VERSION = "0.4.6" VERSION = "0.1.0"
end end
end end

View File

@ -6,11 +6,11 @@ require 'mongoid/enum/version'
Gem::Specification.new do |spec| Gem::Specification.new do |spec|
spec.name = "mongoid-enum" spec.name = "mongoid-enum"
spec.version = Mongoid::Enum::VERSION spec.version = Mongoid::Enum::VERSION
spec.authors = ["Mike Sutton"] spec.authors = ["Nicholas Bruning"]
spec.email = ["tech@wizewerx.com"] spec.email = ["nicholas@bruning.com.au"]
spec.description = %q{Forked from https://github.com/thetron/mongoid-enum/commits?author=thetron.} spec.description = %q{Heavily inspired by DDH's ActiveRecord::Enum, this little library is just there to help you cut down the cruft in your models and make the world a happier place at the same time.}
spec.summary = %q{Sweet enum sugar for your Mongoid documents} spec.summary = %q{Sweet enum sugar for your Mongoid documents}
spec.homepage = "https://git.wizewerx.tech/foss/mongoid-enum" spec.homepage = ""
spec.license = "MIT" spec.license = "MIT"
spec.files = `git ls-files`.split($/) spec.files = `git ls-files`.split($/)
@ -18,10 +18,12 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"] spec.require_paths = ["lib"]
spec.add_runtime_dependency "mongoid", "~> 8.0" spec.add_dependency "mongoid", "~>3.1"
spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "bundler", "~> 1.3"
spec.add_development_dependency "rake" spec.add_development_dependency "rake"
spec.add_development_dependency "rspec", "~> 3.1" spec.add_development_dependency "rspec", "~> 2.14"
spec.add_development_dependency "guard-rspec", "~> 4.6.2" spec.add_development_dependency "guard-rspec", "~> 4.0.3"
spec.add_development_dependency "mongoid-rspec", "~> 3.0" spec.add_development_dependency "database_cleaner", "~> 1.2.0"
spec.add_development_dependency "mongoid-rspec", "~> 1.5.1"
end end

View File

@ -1,11 +0,0 @@
require 'spec_helper'
describe Mongoid::Enum::Configuration do
subject { Mongoid::Enum::Configuration.new }
describe "field_name_prefix" do
it "has '_' as default value" do
expect(subject.field_name_prefix).to eq "_"
end
end
end

View File

@ -16,14 +16,14 @@ describe Mongoid::Enum::Validators::MultipleValidator do
context "and value is nil" do context "and value is nil" do
before(:each) { validator.validate_each(record, attribute, nil) } before(:each) { validator.validate_each(record, attribute, nil) }
it "validates" do it "validates" do
expect(record.errors[attribute].empty?).to be true expect(record.errors[attribute].empty?).to be_true
end end
end end
context "and value is []" do context "and value is []" do
before(:each) { validator.validate_each(record, attribute, []) } before(:each) { validator.validate_each(record, attribute, []) }
it "validates" do it "validates" do
expect(record.errors[attribute].empty?).to be true expect(record.errors[attribute].empty?).to be_true
end end
end end
end end
@ -32,14 +32,14 @@ describe Mongoid::Enum::Validators::MultipleValidator do
context "and value is nil" do context "and value is nil" do
before(:each) { validator.validate_each(record, attribute, nil) } before(:each) { validator.validate_each(record, attribute, nil) }
it "won't validate" do it "won't validate" do
expect(record.errors[attribute].any?).to be true expect(record.errors[attribute].any?).to be_true
expect(record.errors[attribute]).to eq ["is not in #{values.join ", "}"] expect(record.errors[attribute]).to eq ["is not in #{values.join ", "}"]
end end
end end
context "and value is []" do context "and value is []" do
before(:each) { validator.validate_each(record, attribute, []) } before(:each) { validator.validate_each(record, attribute, []) }
it "won't validate" do it "won't validate" do
expect(record.errors[attribute].any?).to be true expect(record.errors[attribute].any?).to be_true
expect(record.errors[attribute]).to eq ["is not in #{values.join ", "}"] expect(record.errors[attribute]).to eq ["is not in #{values.join ", "}"]
end end
end end
@ -49,7 +49,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? } let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [values.sample]) } before(:each) { validator.validate_each(record, attribute, [values.sample]) }
it "validates" do it "validates" do
expect(record.errors[attribute].empty?).to be true expect(record.errors[attribute].empty?).to be_true
end end
end end
@ -57,7 +57,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? } let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [:amet]) } before(:each) { validator.validate_each(record, attribute, [:amet]) }
it "won't validate" do it "won't validate" do
expect(record.errors[attribute].any?).to be true expect(record.errors[attribute].any?).to be_true
end end
end end
@ -65,7 +65,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? } let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [values.first, values.last]) } before(:each) { validator.validate_each(record, attribute, [values.first, values.last]) }
it "validates" do it "validates" do
expect(record.errors[attribute].empty?).to be true expect(record.errors[attribute].empty?).to be_true
end end
end end
@ -73,7 +73,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? } let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [values.first, values.last, :amet]) } before(:each) { validator.validate_each(record, attribute, [values.first, values.last, :amet]) }
it "won't validate" do it "won't validate" do
expect(record.errors[attribute].any?).to be true expect(record.errors[attribute].any?).to be_true
end end
end end
end end

View File

@ -1,5 +1,4 @@
require 'spec_helper' require 'spec_helper'
require 'mongoid/enum/configuration'
class User class User
include Mongoid::Document include Mongoid::Document
@ -22,27 +21,10 @@ describe Mongoid::Enum do
expect(klass).to have_field(field_name) expect(klass).to have_field(field_name)
end end
it "uses prefix defined in configuration" do
old_field_name_prefix = Mongoid::Enum.configuration.field_name_prefix
Mongoid::Enum.configure do |config|
config.field_name_prefix = "___"
end
UserWithoutPrefix = Class.new do
include Mongoid::Document
include Mongoid::Enum
enum :status, [:awaiting_approval, :approved, :banned]
end
expect(UserWithoutPrefix).to have_field "___status"
Mongoid::Enum.configure do |config|
config.field_name_prefix = old_field_name_prefix
end
end
it "is aliased" do it "is aliased" do
expect(instance).to respond_to alias_name expect(instance).to respond_to alias_name
expect(instance).to respond_to :"#{alias_name}=" expect(instance).to respond_to :"#{alias_name}="
expect(instance).to respond_to :"#{alias_name}" expect(instance).to respond_to :"#{alias_name}?"
end end
describe "type" do describe "type" do
@ -68,42 +50,14 @@ describe Mongoid::Enum do
end end
end end
describe "'required' option" do
context "when true" do
let(:instance) { User.new status: nil }
it "is not valid with nil value" do
expect(instance).to_not be_valid
end
end
context "when false" do
let(:instance) { User.new roles: nil }
it "is valid with nil value" do
expect(instance).to be_valid
end
end
end
describe "constant" do describe "constant" do
it "is set to the values" do it "is set to the values" do
expect(klass::STATUS).to eq values expect(klass::STATUS).to eq values
end end
end end
describe "accessors" do describe "accessors"do
context "when singular" do context "when singular" do
describe "setter" do
it "accepts strings" do
instance.status = 'banned'
expect(instance.status).to eq :banned
end
it "accepts symbols" do
instance.status = :banned
expect(instance.status).to eq :banned
end
end
describe "{{value}}!" do describe "{{value}}!" do
it "sets the value" do it "sets the value" do
instance.save instance.save
@ -131,33 +85,6 @@ describe Mongoid::Enum do
end end
context "when multiple" do context "when multiple" do
describe "setter" do
it "accepts strings" do
instance.roles = "author"
expect(instance.roles).to eq [:author]
end
it "accepts symbols" do
instance.roles = :author
expect(instance.roles).to eq [:author]
end
it "accepts arrays of strings" do
instance.roles = ['author', 'editor']
instance.save
puts instance.errors.full_messages
instance.reload
expect(instance.roles).to include(:author)
expect(instance.roles).to include(:editor)
end
it "accepts arrays of symbols" do
instance.roles = [:author, :editor]
expect(instance.roles).to include(:author)
expect(instance.roles).to include(:editor)
end
end
describe "{{value}}!" do describe "{{value}}!" do
context "when field is nil" do context "when field is nil" do
it "creates an array containing the value" do it "creates an array containing the value" do
@ -184,15 +111,15 @@ describe Mongoid::Enum do
instance.save instance.save
instance.author! instance.author!
instance.editor! instance.editor!
expect(instance.editor?).to be true expect(instance.editor?).to be_true
expect(instance.author?).to be true expect(instance.author?).to be_true
end end
end end
context "when {{enum}} does not contain {{value}}" do context "when {{enum}} does not contain {{value}}" do
it "returns false" do it "returns false" do
instance.save instance.save
expect(instance.author?).to be false expect(instance.author?).to be_false
end end
end end
end end
@ -247,21 +174,4 @@ describe Mongoid::Enum do
end end
end end
end end
describe ".configuration" do
it "returns Configuration object" do
expect(Mongoid::Enum.configuration)
.to be_instance_of Mongoid::Enum::Configuration
end
it "returns same object when called multiple times" do
expect(Mongoid::Enum.configuration).to be Mongoid::Enum.configuration
end
end
describe ".configure" do
it "yields configuration if block is given" do
expect { |b| Mongoid::Enum.configure &b }
.to yield_with_args Mongoid::Enum.configuration
end
end
end end

View File

@ -1,18 +1,22 @@
$: << File.expand_path("../../lib", __FILE__) $: << File.expand_path("../../lib", __FILE__)
require 'database_cleaner'
require 'mongoid' require 'mongoid'
require "mongoid/rspec" require 'mongoid-rspec'
require 'mongoid/enum' require 'mongoid/enum'
ENV['MONGOID_ENV'] = "test" ENV['MONGOID_ENV'] = "test"
RSpec.configure do |config| RSpec.configure do |config|
config.include Mongoid::Matchers config.include Mongoid::Matchers
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do config.after(:each) do
DatabaseCleaner.clean
Mongoid.purge! Mongoid.purge!
end end
end end
Mongoid.load!(File.expand_path("../support/mongoid.yml", __FILE__), :test) Mongoid.load!(File.expand_path("../support/mongoid.yml", __FILE__), :test)
Mongo::Logger.logger.level = ::Logger::INFO

View File

@ -1,5 +1,5 @@
test: test:
clients: sessions:
default: default:
database: mongoid-enum_test database: mongoid-enum_test
hosts: hosts: