mongoid4-rspec 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +6 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +21 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +207 -0
- data/Rakefile +17 -0
- data/lib/matchers/accept_nested_attributes.rb +67 -0
- data/lib/matchers/allow_mass_assignment.rb +101 -0
- data/lib/matchers/associations.rb +316 -0
- data/lib/matchers/collections.rb +9 -0
- data/lib/matchers/document.rb +163 -0
- data/lib/matchers/indexes.rb +84 -0
- data/lib/matchers/validations.rb +81 -0
- data/lib/matchers/validations/acceptance_of.rb +9 -0
- data/lib/matchers/validations/associated.rb +19 -0
- data/lib/matchers/validations/confirmation_of.rb +9 -0
- data/lib/matchers/validations/custom_validation_of.rb +47 -0
- data/lib/matchers/validations/exclusion_of.rb +49 -0
- data/lib/matchers/validations/format_of.rb +71 -0
- data/lib/matchers/validations/inclusion_of.rb +49 -0
- data/lib/matchers/validations/length_of.rb +147 -0
- data/lib/matchers/validations/numericality_of.rb +74 -0
- data/lib/matchers/validations/presence_of.rb +9 -0
- data/lib/matchers/validations/uniqueness_of.rb +82 -0
- data/lib/matchers/validations/with_message.rb +27 -0
- data/lib/mongoid-rspec.rb +33 -0
- data/lib/mongoid-rspec/version.rb +5 -0
- data/mongoid-rspec.gemspec +25 -0
- data/mongoid4-rspec.gemspec +25 -0
- data/spec/models/article.rb +29 -0
- data/spec/models/comment.rb +6 -0
- data/spec/models/log.rb +4 -0
- data/spec/models/movie_article.rb +8 -0
- data/spec/models/permalink.rb +5 -0
- data/spec/models/person.rb +10 -0
- data/spec/models/profile.rb +16 -0
- data/spec/models/record.rb +5 -0
- data/spec/models/site.rb +9 -0
- data/spec/models/user.rb +36 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/unit/accept_nested_attributes_spec.rb +12 -0
- data/spec/unit/associations_spec.rb +42 -0
- data/spec/unit/collections_spec.rb +7 -0
- data/spec/unit/document_spec.rb +21 -0
- data/spec/unit/indexes_spec.rb +13 -0
- data/spec/unit/validations_spec.rb +52 -0
- data/spec/validators/ssn_validator.rb +16 -0
- metadata +137 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateNumericalityOfMatcher < HaveValidationMatcher
|
5
|
+
@@allowed_options = [:equal_to, :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to,
|
6
|
+
:even, :odd, :only_integer, :allow_nil, :nil]
|
7
|
+
|
8
|
+
def initialize(field)
|
9
|
+
super(field, :numericality)
|
10
|
+
@options = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_allow(options)
|
14
|
+
options[:equal_to] = options if options.is_a?(Numeric)
|
15
|
+
options[:allow_nil] = options.delete(:nil) if options.has_key?(:nil)
|
16
|
+
raise ArgumentError, "validate_numericality_of#to_allow requires a Hash parameter containing any of the following keys: " <<
|
17
|
+
@@allowed_options.map(&:inspect).join(", ") if !options.is_a?(Hash) or options.empty? or (options.keys - @@allowed_options).any?
|
18
|
+
@options.merge!(options)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches?(actual)
|
23
|
+
return false unless result = super(actual)
|
24
|
+
|
25
|
+
@@allowed_options.each do |comparator|
|
26
|
+
if @options.has_key?(comparator) and !([:even, :odd, :only_integer].include?(comparator) and !@validator.options.include?(comparator))
|
27
|
+
result &= (@validator.options[comparator] == @options[comparator])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@positive_result_message <<= options_message(@validator.options)
|
31
|
+
@negative_result_message <<= options_message(@validator.options)
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
super << options_message(@options)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def options_message(options)
|
42
|
+
type_msg = []
|
43
|
+
comp_msg = []
|
44
|
+
options.each_pair do |key, value|
|
45
|
+
case key
|
46
|
+
when :allow_nil
|
47
|
+
when :only_integer
|
48
|
+
type_msg << "integer" if value
|
49
|
+
when :odd, :even
|
50
|
+
type_msg << "#{key.to_s}-numbered" if value
|
51
|
+
else
|
52
|
+
comp_msg << "#{key.to_s.gsub("_", " ")} #{value.inspect}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
allow_nil = (options[:allow_nil] ? "nil" : "non-nil") if options.has_key?(:allow_nil)
|
56
|
+
["", "allowing", allow_nil, type_msg.any? ? type_msg.to_sentence : nil, "values", comp_msg.any? ? comp_msg.to_sentence : nil].compact.join(" ")
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_missing(m, *args, &block)
|
60
|
+
if @@allowed_options.include?(m.to_sym)
|
61
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
|
62
|
+
send :to_allow, m.to_sym => args.first
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_numericality_of(field)
|
70
|
+
ValidateNumericalityOfMatcher.new(field)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateUniquenessOfMatcher < HaveValidationMatcher
|
5
|
+
include WithMessage
|
6
|
+
def initialize(field)
|
7
|
+
super(field, :uniqueness)
|
8
|
+
end
|
9
|
+
|
10
|
+
def scoped_to(*scope)
|
11
|
+
@scope = [scope].flatten.map(&:to_sym)
|
12
|
+
self
|
13
|
+
end
|
14
|
+
alias_method :scoped_on, :scoped_to
|
15
|
+
|
16
|
+
def case_insensitive
|
17
|
+
@case_insensitive = true
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def allow_blank?(allow_blank)
|
22
|
+
@allow_blank = allow_blank
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def matches?(actual)
|
27
|
+
return false unless @result = super(actual)
|
28
|
+
|
29
|
+
check_scope if @scope
|
30
|
+
check_allow_blank if @allow_blank
|
31
|
+
check_case_sensitivity if @case_insensitive
|
32
|
+
check_expected_message if @expected_message
|
33
|
+
|
34
|
+
@result
|
35
|
+
end
|
36
|
+
|
37
|
+
def description
|
38
|
+
options_desc = []
|
39
|
+
options_desc << " scoped to #{@scope.inspect}" if @scope
|
40
|
+
options_desc << " allowing blank values" if @allow_blank
|
41
|
+
options_desc << " allowing case insensitive values" if @case_insensitive
|
42
|
+
options_desc << " with message '#{@expected_message}'" if @expected_message
|
43
|
+
super << options_desc.to_sentence
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def check_allow_blank
|
49
|
+
if @validator.options[:allow_blank] == @allow_blank
|
50
|
+
@positive_result_message << " with blank values allowed"
|
51
|
+
else
|
52
|
+
@negative_result_message << " with no blank values allowed"
|
53
|
+
@result = false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def check_scope
|
58
|
+
message = " scope to #{@validator.options[:scope]}"
|
59
|
+
if [@validator.options[:scope]].flatten.map(&:to_sym) == @scope
|
60
|
+
@positive_result_message << message
|
61
|
+
else
|
62
|
+
@negative_result_message << message
|
63
|
+
@result = false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_case_sensitivity
|
68
|
+
if @validator.options[:case_sensitive] == false
|
69
|
+
@positive_result_message << " with case insensitive values"
|
70
|
+
else
|
71
|
+
@negative_result_message << " without case insensitive values"
|
72
|
+
@result = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_uniqueness_of(field)
|
78
|
+
ValidateUniquenessOfMatcher.new(field)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
module WithMessage
|
5
|
+
def with_message(message)
|
6
|
+
@expected_message = message
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def check_expected_message
|
13
|
+
actual_message = @validator.options[:message]
|
14
|
+
if actual_message.nil?
|
15
|
+
@negative_result_message << " with no custom message"
|
16
|
+
@result = false
|
17
|
+
elsif actual_message == @expected_message
|
18
|
+
@positive_result_message << " with custom message '#{@expected_message}'"
|
19
|
+
else
|
20
|
+
@negative_result_message << " got message '#{actual_message}'"
|
21
|
+
@result = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/expectations'
|
6
|
+
require 'rspec/mocks'
|
7
|
+
require "active_model"
|
8
|
+
require 'matchers/document'
|
9
|
+
require 'matchers/associations'
|
10
|
+
require 'matchers/collections'
|
11
|
+
require 'matchers/indexes'
|
12
|
+
require 'matchers/allow_mass_assignment'
|
13
|
+
require 'matchers/accept_nested_attributes'
|
14
|
+
require 'matchers/validations'
|
15
|
+
require 'matchers/validations/with_message'
|
16
|
+
require 'matchers/validations/associated'
|
17
|
+
require 'matchers/validations/confirmation_of'
|
18
|
+
require 'matchers/validations/exclusion_of'
|
19
|
+
require 'matchers/validations/format_of'
|
20
|
+
require 'matchers/validations/inclusion_of'
|
21
|
+
require 'matchers/validations/length_of'
|
22
|
+
require 'matchers/validations/numericality_of'
|
23
|
+
require 'matchers/validations/presence_of'
|
24
|
+
require 'matchers/validations/uniqueness_of'
|
25
|
+
require 'matchers/validations/acceptance_of'
|
26
|
+
require 'matchers/validations/custom_validation_of'
|
27
|
+
|
28
|
+
module Mongoid
|
29
|
+
module Matchers
|
30
|
+
include Mongoid::Matchers::Associations
|
31
|
+
include Mongoid::Matchers::Validations
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mongoid-rspec/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mongoid-rspec"
|
7
|
+
s.version = Mongoid::Rspec::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Evan Sagge"]
|
10
|
+
s.email = %q{evansagge@gmail.com}
|
11
|
+
s.homepage = %q{http://github.com/evansagge/mongoid-rspec}
|
12
|
+
s.summary = %q{RSpec matchers for Mongoid}
|
13
|
+
s.description = %q{RSpec matches for Mongoid models, including association and validation matchers}
|
14
|
+
|
15
|
+
s.rubyforge_project = "mongoid-rspec"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'rake'
|
23
|
+
s.add_dependency 'mongoid', '~> 4.0.0.beta2'
|
24
|
+
s.add_dependency 'rspec', '>= 2.14'
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mongoid-rspec/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mongoid4-rspec"
|
7
|
+
s.version = Mongoid::Rspec::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Francesco Boffa", "Evan Sagge"]
|
10
|
+
s.email = %q{fra.boffa@gmail.com evansagge@gmail.com}
|
11
|
+
s.homepage = %q{http://github.com/aomega08/mongoid4-rspec}
|
12
|
+
s.summary = %q{RSpec matchers for Mongoid 4}
|
13
|
+
s.description = %q{RSpec matches for Mongoid 4 models, including association and validation matchers}
|
14
|
+
|
15
|
+
s.rubyforge_project = "mongoid-rspec"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'rake'
|
23
|
+
s.add_dependency 'mongoid', '~> 4.0.0.beta2'
|
24
|
+
s.add_dependency 'rspec', '>= 2.14'
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Article
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps
|
4
|
+
|
5
|
+
field :title, localize: true
|
6
|
+
field :content
|
7
|
+
field :published, type: Boolean, default: false
|
8
|
+
field :allow_comments, type: Boolean, default: true
|
9
|
+
field :number_of_comments, type: Integer
|
10
|
+
field :status, type: Symbol
|
11
|
+
|
12
|
+
embeds_many :comments, cascade_callbacks: true
|
13
|
+
embeds_one :permalink
|
14
|
+
belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
|
15
|
+
|
16
|
+
validates :title, presence: true
|
17
|
+
|
18
|
+
validates_inclusion_of :status, in: [:pending], on: :create
|
19
|
+
validates_inclusion_of :status, in: [:approved, :rejected ], on: :update
|
20
|
+
|
21
|
+
validates_length_of :title, within: 8..16
|
22
|
+
validates_length_of :content, minimum: 200
|
23
|
+
|
24
|
+
index({ title: 1 }, { unique: true, background: true, drop_dups: true })
|
25
|
+
index({ published: 1 })
|
26
|
+
index({ 'permalink._id' => 1 })
|
27
|
+
|
28
|
+
accepts_nested_attributes_for :permalink
|
29
|
+
end
|
data/spec/models/log.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
class MovieArticle < Article
|
2
|
+
|
3
|
+
field :rating, type: Float
|
4
|
+
field :classification, type: Integer
|
5
|
+
|
6
|
+
validates :rating, numericality: { greater_than: 0, less_than_or_equal_to: 5 }
|
7
|
+
validates :classification, numericality: { even: true, only_integer: true, allow_nil: false }
|
8
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Profile
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :first_name
|
5
|
+
field :last_name
|
6
|
+
field :age
|
7
|
+
field :hobbies, type: Array, default: []
|
8
|
+
|
9
|
+
embedded_in :user, inverse_of: :profile
|
10
|
+
|
11
|
+
validates :age, numericality: { greater_than: 0 }
|
12
|
+
validates :terms_of_service, acceptance: true
|
13
|
+
validates :hobbies, length: { minimum: 1, message: "requires at least one hobby" }
|
14
|
+
|
15
|
+
index({ first_name: 1, last_name: 1 })
|
16
|
+
end
|
data/spec/models/site.rb
ADDED
data/spec/models/user.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class User
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps::Created
|
4
|
+
|
5
|
+
field :login
|
6
|
+
field :email
|
7
|
+
field :role
|
8
|
+
field :age, type: Integer
|
9
|
+
field :password, type: String
|
10
|
+
field :provider_uid
|
11
|
+
field :locale
|
12
|
+
|
13
|
+
belongs_to :site, inverse_of: :users
|
14
|
+
has_many :articles, foreign_key: :author_id, order: :title
|
15
|
+
has_many :comments, dependent: :destroy, autosave: true
|
16
|
+
has_and_belongs_to_many :children, class_name: "User"
|
17
|
+
has_one :record, autobuild: true
|
18
|
+
|
19
|
+
embeds_one :profile
|
20
|
+
|
21
|
+
validates :login, presence: true, uniqueness: { scope: :site }, format: { with: /\A[\w\-]+\z/ }, exclusion: { in: ["super", "index", "edit"] }
|
22
|
+
validates :email, uniqueness: { case_sensitive: false, scope: :site, message: "is already taken" }, confirmation: true
|
23
|
+
validates :role, presence: true, inclusion: { in: ["admin", "moderator", "member"] }
|
24
|
+
validates :profile, presence: true, associated: true
|
25
|
+
validates :age, presence: true, numericality: true, inclusion: { in: 23..42 }, on: [:create, :update]
|
26
|
+
validates :password, presence: true, on: [:create, :update]
|
27
|
+
validates :password, exclusion: { in: ->(user) { ['password'] } }
|
28
|
+
validates :provider_uid, presence: true
|
29
|
+
validates :locale, inclusion: { in: ->(user) { [:en, :ru] } }
|
30
|
+
|
31
|
+
accepts_nested_attributes_for :articles, :comments
|
32
|
+
|
33
|
+
def admin?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))
|
3
|
+
MODELS = File.join(File.dirname(__FILE__), "models")
|
4
|
+
$LOAD_PATH.unshift(MODELS)
|
5
|
+
VALIDATORS = File.join(File.dirname(__FILE__), "validators")
|
6
|
+
$LOAD_PATH.unshift(VALIDATORS)
|
7
|
+
|
8
|
+
require "rubygems"
|
9
|
+
require "bundler"
|
10
|
+
Bundler.setup
|
11
|
+
|
12
|
+
require 'mongoid'
|
13
|
+
require 'rspec'
|
14
|
+
require 'rspec/core'
|
15
|
+
require 'rspec/expectations'
|
16
|
+
|
17
|
+
Mongoid.configure do |config|
|
18
|
+
config.connect_to("mongoid-rspec-test")
|
19
|
+
end
|
20
|
+
|
21
|
+
Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
|
22
|
+
|
23
|
+
require 'mongoid-rspec'
|
24
|
+
|
25
|
+
RSpec.configure do |config|
|
26
|
+
config.include RSpec::Matchers
|
27
|
+
config.include Mongoid::Matchers
|
28
|
+
config.mock_with :rspec
|
29
|
+
config.after :all do
|
30
|
+
Mongoid::Config.purge!
|
31
|
+
end
|
32
|
+
end
|