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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +6 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +21 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +20 -0
  9. data/README.md +207 -0
  10. data/Rakefile +17 -0
  11. data/lib/matchers/accept_nested_attributes.rb +67 -0
  12. data/lib/matchers/allow_mass_assignment.rb +101 -0
  13. data/lib/matchers/associations.rb +316 -0
  14. data/lib/matchers/collections.rb +9 -0
  15. data/lib/matchers/document.rb +163 -0
  16. data/lib/matchers/indexes.rb +84 -0
  17. data/lib/matchers/validations.rb +81 -0
  18. data/lib/matchers/validations/acceptance_of.rb +9 -0
  19. data/lib/matchers/validations/associated.rb +19 -0
  20. data/lib/matchers/validations/confirmation_of.rb +9 -0
  21. data/lib/matchers/validations/custom_validation_of.rb +47 -0
  22. data/lib/matchers/validations/exclusion_of.rb +49 -0
  23. data/lib/matchers/validations/format_of.rb +71 -0
  24. data/lib/matchers/validations/inclusion_of.rb +49 -0
  25. data/lib/matchers/validations/length_of.rb +147 -0
  26. data/lib/matchers/validations/numericality_of.rb +74 -0
  27. data/lib/matchers/validations/presence_of.rb +9 -0
  28. data/lib/matchers/validations/uniqueness_of.rb +82 -0
  29. data/lib/matchers/validations/with_message.rb +27 -0
  30. data/lib/mongoid-rspec.rb +33 -0
  31. data/lib/mongoid-rspec/version.rb +5 -0
  32. data/mongoid-rspec.gemspec +25 -0
  33. data/mongoid4-rspec.gemspec +25 -0
  34. data/spec/models/article.rb +29 -0
  35. data/spec/models/comment.rb +6 -0
  36. data/spec/models/log.rb +4 -0
  37. data/spec/models/movie_article.rb +8 -0
  38. data/spec/models/permalink.rb +5 -0
  39. data/spec/models/person.rb +10 -0
  40. data/spec/models/profile.rb +16 -0
  41. data/spec/models/record.rb +5 -0
  42. data/spec/models/site.rb +9 -0
  43. data/spec/models/user.rb +36 -0
  44. data/spec/spec_helper.rb +32 -0
  45. data/spec/unit/accept_nested_attributes_spec.rb +12 -0
  46. data/spec/unit/associations_spec.rb +42 -0
  47. data/spec/unit/collections_spec.rb +7 -0
  48. data/spec/unit/document_spec.rb +21 -0
  49. data/spec/unit/indexes_spec.rb +13 -0
  50. data/spec/unit/validations_spec.rb +52 -0
  51. data/spec/validators/ssn_validator.rb +16 -0
  52. 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,9 @@
1
+ module Mongoid
2
+ module Matchers
3
+ module Validations
4
+ def validate_presence_of(field)
5
+ HaveValidationMatcher.new(field, :presence)
6
+ end
7
+ end
8
+ end
9
+ 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,5 @@
1
+ module Mongoid
2
+ module Rspec
3
+ VERSION = "1.11.0"
4
+ end
5
+ 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
@@ -0,0 +1,6 @@
1
+ class Comment
2
+ include Mongoid::Document
3
+
4
+ embedded_in :article, inverse_of: :comments, polymorphic: true
5
+ belongs_to :user, inverse_of: :comments
6
+ end
@@ -0,0 +1,4 @@
1
+ class Log
2
+ include Mongoid::Document
3
+ store_in collection: "logs"
4
+ end
@@ -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,5 @@
1
+ class Permalink
2
+ include Mongoid::Document
3
+
4
+ embedded_in :linkable, inverse_of: :link
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'ssn_validator.rb'
2
+
3
+ class Person
4
+ include Mongoid::Document
5
+
6
+ field :name
7
+ field :ssn
8
+
9
+ validates :ssn, ssn: true
10
+ 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
@@ -0,0 +1,5 @@
1
+ class Record
2
+ include Mongoid::Document
3
+
4
+ belongs_to :user, inverse_of: :record
5
+ end
@@ -0,0 +1,9 @@
1
+ class Site
2
+ include Mongoid::Document
3
+
4
+ field :name
5
+
6
+ has_many :users, inverse_of: :site, order: :email.desc
7
+
8
+ validates :name, presence: true, uniqueness: true
9
+ end
@@ -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
@@ -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