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/version_tmp
tmp
.idea

View File

@ -1,14 +1,14 @@
script: "bundle exec rspec spec"
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1.0
- 2.1.1
- 2.1.2
- jruby-19mode
- rbx-19mode
gemfile:
- Gemfile
notifications:
recipients:
- nicholas@bruning.com.au
services:
- 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
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
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.
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:
```ruby
gem "mongoid-enum"
```
gem "mongoid-enum"
And then run `bundle install`.
# Usage
```ruby
````
class Payment
include Mongoid::Document
include Mongoid::Enum
enum :status, [:pending, :approved, :declined]
enum :status, [:pending, :approved, :declined],
end
```
````
Aaaaaaand then you get things like:
```ruby
````
payment = Payment.create
payment.status
@ -52,7 +49,7 @@ payment.pending?
Payment.approved
# => Mongoid::Criteria for payments with status == :approved
```
````
# Features
@ -67,16 +64,16 @@ convenience.
## Accessors
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
```
````
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
@ -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
the list of values. Using the above example:
```ruby
````
Payment::STATUS
# => [:pending, :approved, :declined]
```
````
## Validations
Enum values are automatically validated against the list. You can
disable this behaviour (see [below](#options)).
disable this behaviour (see (below)[#Options]).
## 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,
you'd automatically get:
```ruby
````
Payment.pending # => Mongoid::Criteria
Payment.approved # => Mongoid::Criteria
Payment.declined # => Mongoid::Criteria
```
````
# 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
`:default` option:
```ruby
enum :roles, [:manager, :administrator], :default => ""
```
enum :roles, [:manager, :administrator], :default => ""
## Multiple values
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
# ...
user = User.create
user.roles << :basic
user.roles << :manager
user.save!
user = User.create
user.roles << :basic
user.roles << :manager
user.save!
user.manager? # => true
user.administrator? # => false
user.roles # => [:basic, :manager]
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
@ -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
can turn them off:
```ruby
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.
enum :status => [:up, :down], :validation => false

View File

@ -1,93 +1,41 @@
require "mongoid/enum/version"
require "mongoid/enum/validators/multiple_validator"
require "mongoid/enum/configuration"
module Mongoid
module Enum
extend ActiveSupport::Concern
module ClassMethods
def enum(name, values, options = {})
field_name = :"#{Mongoid::Enum.configuration.field_name_prefix}#{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)
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]
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
type = multiple && Array || Symbol
field field_name, :type => type, :default => default
alias_attribute name, field_name
def create_validations(field_name, values, options)
if options[:multiple] && options[:validate]
validates field_name, :'mongoid/enum/validators/multiple' => { :in => values.map(&:to_sym), :allow_nil => !options[:required] }
#FIXME: Shouldn't this be `elsif options[:validate]` ???
elsif validate
validates field_name, :inclusion => {:in => values.map(&:to_sym)}, :allow_nil => !options[:required]
if multiple
validates field_name, :'mongoid/enum/validators/multiple' => { :in => values, :allow_nil => !required }
else
validates field_name, :inclusion => {:in => values}, :allow_nil => !required
end
end
def define_value_scopes_and_accessors(field_name, values, options)
values.each do |value|
scope value, ->{ where(field_name => value) }
scope value, where(field_name => value)
if options[:multiple]
define_array_accessor(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"
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
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

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 Enum
VERSION = "0.4.6"
VERSION = "0.1.0"
end
end

View File

@ -6,11 +6,11 @@ require 'mongoid/enum/version'
Gem::Specification.new do |spec|
spec.name = "mongoid-enum"
spec.version = Mongoid::Enum::VERSION
spec.authors = ["Mike Sutton"]
spec.email = ["tech@wizewerx.com"]
spec.description = %q{Forked from https://github.com/thetron/mongoid-enum/commits?author=thetron.}
spec.authors = ["Nicholas Bruning"]
spec.email = ["nicholas@bruning.com.au"]
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.homepage = "https://git.wizewerx.tech/foss/mongoid-enum"
spec.homepage = ""
spec.license = "MIT"
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.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 "rake"
spec.add_development_dependency "rspec", "~> 3.1"
spec.add_development_dependency "guard-rspec", "~> 4.6.2"
spec.add_development_dependency "mongoid-rspec", "~> 3.0"
spec.add_development_dependency "rspec", "~> 2.14"
spec.add_development_dependency "guard-rspec", "~> 4.0.3"
spec.add_development_dependency "database_cleaner", "~> 1.2.0"
spec.add_development_dependency "mongoid-rspec", "~> 1.5.1"
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
before(:each) { validator.validate_each(record, attribute, nil) }
it "validates" do
expect(record.errors[attribute].empty?).to be true
expect(record.errors[attribute].empty?).to be_true
end
end
context "and value is []" do
before(:each) { validator.validate_each(record, attribute, []) }
it "validates" do
expect(record.errors[attribute].empty?).to be true
expect(record.errors[attribute].empty?).to be_true
end
end
end
@ -32,14 +32,14 @@ describe Mongoid::Enum::Validators::MultipleValidator do
context "and value is nil" do
before(:each) { validator.validate_each(record, attribute, nil) }
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 ", "}"]
end
end
context "and value is []" do
before(:each) { validator.validate_each(record, attribute, []) }
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 ", "}"]
end
end
@ -49,7 +49,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [values.sample]) }
it "validates" do
expect(record.errors[attribute].empty?).to be true
expect(record.errors[attribute].empty?).to be_true
end
end
@ -57,7 +57,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [:amet]) }
it "won't validate" do
expect(record.errors[attribute].any?).to be true
expect(record.errors[attribute].any?).to be_true
end
end
@ -65,7 +65,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [values.first, values.last]) }
it "validates" do
expect(record.errors[attribute].empty?).to be true
expect(record.errors[attribute].empty?).to be_true
end
end
@ -73,7 +73,7 @@ describe Mongoid::Enum::Validators::MultipleValidator do
let(:allow_nil) { rand(2).zero? }
before(:each) { validator.validate_each(record, attribute, [values.first, values.last, :amet]) }
it "won't validate" do
expect(record.errors[attribute].any?).to be true
expect(record.errors[attribute].any?).to be_true
end
end
end

View File

@ -1,5 +1,4 @@
require 'spec_helper'
require 'mongoid/enum/configuration'
class User
include Mongoid::Document
@ -22,27 +21,10 @@ describe Mongoid::Enum do
expect(klass).to have_field(field_name)
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
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
describe "type" do
@ -68,42 +50,14 @@ describe Mongoid::Enum do
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
it "is set to the values" do
expect(klass::STATUS).to eq values
end
end
describe "accessors" do
describe "accessors"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
it "sets the value" do
instance.save
@ -131,33 +85,6 @@ describe Mongoid::Enum do
end
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
context "when field is nil" do
it "creates an array containing the value" do
@ -184,15 +111,15 @@ describe Mongoid::Enum do
instance.save
instance.author!
instance.editor!
expect(instance.editor?).to be true
expect(instance.author?).to be true
expect(instance.editor?).to be_true
expect(instance.author?).to be_true
end
end
context "when {{enum}} does not contain {{value}}" do
it "returns false" do
instance.save
expect(instance.author?).to be false
expect(instance.author?).to be_false
end
end
end
@ -247,21 +174,4 @@ describe Mongoid::Enum do
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

View File

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

View File

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