mongoid-rspec 3.0.0 → 4.0.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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +1 -1
  3. data/README.md +217 -111
  4. data/Rakefile +8 -5
  5. data/lib/matchers/accept_nested_attributes.rb +22 -23
  6. data/lib/matchers/allow_mass_assignment.rb +12 -12
  7. data/lib/matchers/associations.rb +36 -37
  8. data/lib/matchers/be_dynamic_document.rb +26 -0
  9. data/lib/matchers/be_mongoid_document.rb +26 -0
  10. data/lib/matchers/be_stored_in.rb +55 -0
  11. data/lib/matchers/have_field.rb +90 -0
  12. data/lib/matchers/have_timestamps.rb +61 -0
  13. data/lib/matchers/indexes/have_index_for.rb +16 -0
  14. data/lib/matchers/indexes/v3/have_index_for.rb +59 -0
  15. data/lib/matchers/indexes/v4/have_index_for.rb +54 -0
  16. data/lib/matchers/validations.rb +30 -11
  17. data/lib/matchers/validations/associated.rb +1 -1
  18. data/lib/matchers/validations/confirmation_of.rb +0 -7
  19. data/lib/matchers/validations/custom_validation_of.rb +1 -4
  20. data/lib/matchers/validations/exclusion_of.rb +5 -5
  21. data/lib/matchers/validations/format_of.rb +2 -2
  22. data/lib/matchers/validations/inclusion_of.rb +5 -5
  23. data/lib/matchers/validations/length_of.rb +13 -35
  24. data/lib/matchers/validations/numericality_of.rb +32 -16
  25. data/lib/matchers/validations/presence_of.rb +1 -1
  26. data/lib/matchers/validations/uniqueness_of.rb +7 -10
  27. data/lib/mongoid/rspec.rb +17 -5
  28. data/lib/mongoid/rspec/version.rb +2 -2
  29. data/spec/models/article.rb +6 -6
  30. data/spec/models/comment.rb +1 -1
  31. data/spec/models/log.rb +3 -3
  32. data/spec/models/message.rb +11 -0
  33. data/spec/models/movie_article.rb +1 -2
  34. data/spec/models/person.rb +1 -1
  35. data/spec/models/profile.rb +2 -2
  36. data/spec/models/record.rb +1 -1
  37. data/spec/models/user.rb +11 -11
  38. data/spec/spec_helper.rb +9 -9
  39. data/spec/unit/accept_nested_attributes_spec.rb +1 -1
  40. data/spec/unit/associations_spec.rb +11 -7
  41. data/spec/unit/be_dynamic_document_spec.rb +21 -0
  42. data/spec/unit/be_mongoid_document_spec.rb +25 -0
  43. data/spec/unit/be_stored_in.rb +54 -0
  44. data/spec/unit/document_spec.rb +5 -14
  45. data/spec/unit/have_index_for_spec.rb +46 -0
  46. data/spec/unit/have_timestamps_spec.rb +71 -0
  47. data/spec/unit/validations_spec.rb +22 -15
  48. data/spec/validators/ssn_validator.rb +6 -6
  49. metadata +63 -29
  50. data/.document +0 -5
  51. data/.gitignore +0 -6
  52. data/.ruby-gemset +0 -1
  53. data/.ruby-version +0 -1
  54. data/.travis.yml +0 -10
  55. data/Gemfile +0 -4
  56. data/lib/matchers/collections.rb +0 -9
  57. data/lib/matchers/document.rb +0 -173
  58. data/lib/matchers/indexes.rb +0 -69
  59. data/lib/matchers/validations/with_message.rb +0 -27
  60. data/mongoid-rspec.gemspec +0 -26
  61. data/spec/unit/collections_spec.rb +0 -7
  62. data/spec/unit/indexes_spec.rb +0 -17
@@ -2,8 +2,19 @@ module Mongoid
2
2
  module Matchers
3
3
  module Validations
4
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]
5
+ ALLOWED_OPTIONS =
6
+ %i[
7
+ allow_nil
8
+ equal_to
9
+ even
10
+ greater_than
11
+ greater_than_or_equal_to
12
+ less_than
13
+ less_than_or_equal_to
14
+ nil
15
+ odd
16
+ only_integer
17
+ ].freeze
7
18
 
8
19
  def initialize(field)
9
20
  super(field, :numericality)
@@ -12,9 +23,15 @@ module Mongoid
12
23
 
13
24
  def to_allow(options)
14
25
  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?
26
+ options[:allow_nil] = options.delete(:nil) if options.key?(:nil)
27
+
28
+ if !options.is_a?(Hash) || options.empty? || (options.keys - ALLOWED_OPTIONS).any?
29
+ message =
30
+ 'validate_numericality_of#to_allow requires a Hash parameter containing' \
31
+ "any of the following keys: #{ALLOWED_OPTIONS.map(&:inspect).join(', ')}"
32
+ raise ArgumentError, message
33
+ end
34
+
18
35
  @options.merge!(options)
19
36
  self
20
37
  end
@@ -22,11 +39,10 @@ module Mongoid
22
39
  def matches?(actual)
23
40
  return false unless result = super(actual)
24
41
 
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
42
+ @options.each do |comparator, expected_value|
43
+ result &= (@validator.options[comparator] == expected_value)
29
44
  end
45
+
30
46
  @positive_result_message <<= options_message(@validator.options)
31
47
  @negative_result_message <<= options_message(@validator.options)
32
48
  result
@@ -45,19 +61,19 @@ module Mongoid
45
61
  case key
46
62
  when :allow_nil
47
63
  when :only_integer
48
- type_msg << "integer" if value
64
+ type_msg << 'integer' if value
49
65
  when :odd, :even
50
- type_msg << "#{key.to_s}-numbered" if value
66
+ type_msg << "#{key}-numbered" if value
51
67
  else
52
- comp_msg << "#{key.to_s.gsub("_", " ")} #{value.inspect}"
68
+ comp_msg << "#{key.to_s.tr('_', ' ')} #{value.inspect}"
53
69
  end
54
70
  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(" ")
71
+ allow_nil = (options[:allow_nil] ? 'nil' : 'non-nil') if options.key?(:allow_nil)
72
+ ['', 'allowing', allow_nil, type_msg.any? ? type_msg.to_sentence : nil, 'values', comp_msg.any? ? comp_msg.to_sentence : nil].compact.join(' ')
57
73
  end
58
74
 
59
75
  def method_missing(m, *args, &block)
60
- if @@allowed_options.include?(m.to_sym)
76
+ if ALLOWED_OPTIONS.include?(m.to_sym)
61
77
  raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
62
78
  send :to_allow, m.to_sym => args.first
63
79
  else
@@ -71,4 +87,4 @@ module Mongoid
71
87
  end
72
88
  end
73
89
  end
74
- end
90
+ end
@@ -6,4 +6,4 @@ module Mongoid
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -2,7 +2,6 @@ module Mongoid
2
2
  module Matchers
3
3
  module Validations
4
4
  class ValidateUniquenessOfMatcher < HaveValidationMatcher
5
- include WithMessage
6
5
  def initialize(field)
7
6
  super(field, :uniqueness)
8
7
  end
@@ -11,7 +10,7 @@ module Mongoid
11
10
  @scope = [scope].flatten.map(&:to_sym)
12
11
  self
13
12
  end
14
- alias_method :scoped_on, :scoped_to
13
+ alias scoped_on scoped_to
15
14
 
16
15
  def case_insensitive
17
16
  @case_insensitive = true
@@ -29,7 +28,6 @@ module Mongoid
29
28
  check_scope if @scope
30
29
  check_allow_blank if @allow_blank
31
30
  check_case_sensitivity if @case_insensitive
32
- check_expected_message if @expected_message
33
31
 
34
32
  @result
35
33
  end
@@ -37,9 +35,8 @@ module Mongoid
37
35
  def description
38
36
  options_desc = []
39
37
  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
38
+ options_desc << ' allowing blank values' if @allow_blank
39
+ options_desc << ' allowing case insensitive values' if @case_insensitive
43
40
  super << options_desc.to_sentence
44
41
  end
45
42
 
@@ -47,9 +44,9 @@ module Mongoid
47
44
 
48
45
  def check_allow_blank
49
46
  if @validator.options[:allow_blank] == @allow_blank
50
- @positive_result_message << " with blank values allowed"
47
+ @positive_result_message << ' with blank values allowed'
51
48
  else
52
- @negative_result_message << " with no blank values allowed"
49
+ @negative_result_message << ' with no blank values allowed'
53
50
  @result = false
54
51
  end
55
52
  end
@@ -66,9 +63,9 @@ module Mongoid
66
63
 
67
64
  def check_case_sensitivity
68
65
  if @validator.options[:case_sensitive] == false
69
- @positive_result_message << " with case insensitive values"
66
+ @positive_result_message << ' with case insensitive values'
70
67
  else
71
- @negative_result_message << " without case insensitive values"
68
+ @negative_result_message << ' without case insensitive values'
72
69
  @result = false
73
70
  end
74
71
  end
@@ -1,18 +1,19 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
 
3
3
  require 'mongoid'
4
+ require 'mongoid-compatibility'
4
5
  require 'rspec/core'
5
6
  require 'rspec/expectations'
6
7
  require 'rspec/mocks'
7
- require "active_model"
8
- require 'matchers/document'
8
+ require 'active_support/core_ext/hash/keys'
9
+ require 'active_support/core_ext/hash/transform_values' if Mongoid::Compatibility::Version.mongoid4_or_newer?
10
+ require 'active_support/core_ext/object/blank'
11
+ require 'active_support/core_ext/string/inflections'
12
+
9
13
  require 'matchers/associations'
10
- require 'matchers/collections'
11
- require 'matchers/indexes'
12
14
  require 'matchers/allow_mass_assignment'
13
15
  require 'matchers/accept_nested_attributes'
14
16
  require 'matchers/validations'
15
- require 'matchers/validations/with_message'
16
17
  require 'matchers/validations/associated'
17
18
  require 'matchers/validations/confirmation_of'
18
19
  require 'matchers/validations/exclusion_of'
@@ -24,6 +25,17 @@ require 'matchers/validations/presence_of'
24
25
  require 'matchers/validations/uniqueness_of'
25
26
  require 'matchers/validations/acceptance_of'
26
27
  require 'matchers/validations/custom_validation_of'
28
+ require 'matchers/be_mongoid_document'
29
+ require 'matchers/be_dynamic_document'
30
+ require 'matchers/be_stored_in'
31
+ require 'matchers/have_field'
32
+ require 'matchers/indexes/have_index_for'
33
+ if Mongoid::Compatibility::Version.mongoid3?
34
+ require 'matchers/indexes/v3/have_index_for'
35
+ else
36
+ require 'matchers/indexes/v4/have_index_for'
37
+ end
38
+ require 'matchers/have_timestamps'
27
39
 
28
40
  module Mongoid
29
41
  module Matchers
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
- module Rspec
3
- VERSION = '3.0.0'
2
+ module RSpec
3
+ VERSION = '4.0.0'.freeze
4
4
  end
5
5
  end
@@ -9,21 +9,21 @@ class Article
9
9
  field :number_of_comments, type: Integer
10
10
  field :status, type: Symbol
11
11
 
12
- embeds_many :comments, cascade_callbacks: true
13
- embeds_one :permalink
12
+ embeds_many :comments, cascade_callbacks: true, inverse_of: :article
13
+ embeds_one :permalink, inverse_of: :linkable
14
14
  belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
15
15
 
16
16
  validates :title, presence: true
17
17
 
18
18
  validates_inclusion_of :status, in: [:pending], on: :create
19
- validates_inclusion_of :status, in: [:approved, :rejected ], on: :update
19
+ validates_inclusion_of :status, in: %i[approved rejected], on: :update
20
20
 
21
21
  validates_length_of :title, within: 8..16
22
22
  validates_length_of :content, minimum: 200
23
23
 
24
- index({ title: 1 }, { unique: true, background: true, drop_dups: true })
25
- index({ published: 1 })
26
- index({ 'permalink._id' => 1 })
24
+ index({ title: 1 }, unique: true, background: true, drop_dups: true)
25
+ index(published: 1)
26
+ index('permalink._id' => 1)
27
27
 
28
28
  accepts_nested_attributes_for :permalink
29
29
  end
@@ -3,4 +3,4 @@ class Comment
3
3
 
4
4
  embedded_in :article, inverse_of: :comments, polymorphic: true
5
5
  belongs_to :user, inverse_of: :comments
6
- end
6
+ end
@@ -1,9 +1,9 @@
1
1
  class Log
2
2
  include Mongoid::Document
3
3
  include Mongoid::Timestamps
4
- include Mongoid::Attributes::Dynamic
4
+ include Mongoid::Attributes::Dynamic if Mongoid::Compatibility::Version.mongoid4_or_newer?
5
5
 
6
- store_in collection: "logs"
6
+ store_in collection: 'logs'
7
7
 
8
- index({ created_at: 1 }, { bucket_size: 100, expire_after_seconds: 3600 } )
8
+ index({ created_at: 1 }, bucket_size: 100, expire_after_seconds: 3600)
9
9
  end
@@ -0,0 +1,11 @@
1
+ class Message
2
+ include Mongoid::Document
3
+
4
+ field :identifier
5
+ field :from
6
+ field :to
7
+
8
+ validates :identifier, uniqueness: { message: 'uniqueness' }
9
+ validates :from, presence: { message: 'required' }
10
+ validates :to, format: { with: /[a-z]+/, message: 'format' }
11
+ end
@@ -1,8 +1,7 @@
1
1
  class MovieArticle < Article
2
-
3
2
  field :rating, type: Float
4
3
  field :classification, type: Integer
5
4
 
6
5
  validates :rating, numericality: { greater_than: 0, less_than_or_equal_to: 5 }
7
6
  validates :classification, numericality: { even: true, only_integer: true, allow_nil: false }
8
- end
7
+ end
@@ -7,4 +7,4 @@ class Person
7
7
  field :ssn
8
8
 
9
9
  validates :ssn, ssn: true
10
- end
10
+ end
@@ -10,7 +10,7 @@ class Profile
10
10
 
11
11
  validates :age, numericality: { greater_than: 0 }
12
12
  validates :terms_of_service, acceptance: true
13
- validates :hobbies, length: { minimum: 1, message: "requires at least one hobby" }
13
+ validates :hobbies, length: { minimum: 1, message: 'requires at least one hobby' }
14
14
 
15
- index({ first_name: 1, last_name: 1 })
15
+ index(first_name: 1, last_name: 1)
16
16
  end
@@ -2,4 +2,4 @@ class Record
2
2
  include Mongoid::Document
3
3
 
4
4
  belongs_to :user, inverse_of: :record
5
- end
5
+ end
@@ -13,21 +13,21 @@ class User
13
13
  belongs_to :site, inverse_of: :users
14
14
  has_many :articles, foreign_key: :author_id, order: :title
15
15
  has_many :comments, dependent: :destroy, autosave: true
16
- has_and_belongs_to_many :children, class_name: "User"
17
- has_one :record, autobuild: true
16
+ has_and_belongs_to_many :children, class_name: 'User'
17
+ has_one :record, autobuild: true, inverse_of: :user
18
18
 
19
- embeds_one :profile
19
+ embeds_one :profile, inverse_of: :user
20
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"] }
21
+ validates :login, presence: true, uniqueness: { scope: :site }, format: { with: /\A[\w\-]+\z/ }, exclusion: { in: %w[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: %w[admin moderator member] }
24
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 :password, confirmation: { message: "Password confirmation must match given password" }
25
+ validates :age, presence: true, numericality: true, inclusion: { in: 23..42 }, on: %i[create update]
26
+ validates :password, presence: true, on: %i[create update]
27
+ validates :password, exclusion: { in: ->(_user) { ['password'] } }
28
+ validates :password, confirmation: { message: 'Password confirmation must match given password' }
29
29
  validates :provider_uid, presence: true
30
- validates :locale, inclusion: { in: ->(user) { [:en, :ru] } }
30
+ validates :locale, inclusion: { in: ->(_user) { %i[en ru] } }
31
31
 
32
32
  accepts_nested_attributes_for :articles, :comments
33
33
 
@@ -1,24 +1,24 @@
1
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")
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
+ MODELS = File.join(File.dirname(__FILE__), 'models')
4
4
  $LOAD_PATH.unshift(MODELS)
5
- VALIDATORS = File.join(File.dirname(__FILE__), "validators")
5
+ VALIDATORS = File.join(File.dirname(__FILE__), 'validators')
6
6
  $LOAD_PATH.unshift(VALIDATORS)
7
7
 
8
- require "rubygems"
9
- require "bundler"
8
+ require 'rubygems'
9
+ require 'bundler'
10
10
  Bundler.setup
11
11
 
12
12
  require 'mongoid'
13
13
  require 'rspec'
14
14
  require 'rspec/core'
15
15
  require 'rspec/expectations'
16
+ require 'mongoid/compatibility'
16
17
 
17
- Mongoid.configure do |config|
18
- config.connect_to("mongoid-rspec-test")
19
- end
18
+ Mongoid::Config.connect_to('mongoid-rspec-test') if Mongoid::Compatibility::Version.mongoid3_or_newer?
19
+ Mongo::Logger.logger.level = ::Logger::INFO if Mongoid::Compatibility::Version.mongoid5_or_newer?
20
20
 
21
- Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
21
+ Dir[File.join(MODELS, '*.rb')].sort.each { |file| require File.basename(file) }
22
22
 
23
23
  require 'mongoid-rspec'
24
24
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe "AcceptsNestedAttributes" do
3
+ RSpec.describe 'AcceptsNestedAttributes' do
4
4
  describe User do
5
5
  it { is_expected.to accept_nested_attributes_for(:articles) }
6
6
  it { is_expected.to accept_nested_attributes_for(:comments) }
@@ -1,14 +1,16 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe "Associations" do
3
+ RSpec.describe 'Associations' do
4
4
  describe User do
5
- it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }
5
+ if Mongoid::Compatibility::Version.mongoid6_or_newer?
6
+ it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }
7
+ end
6
8
 
7
- it { is_expected.to have_one(:record).with_autobuild }
9
+ it { is_expected.to have_one(:record).as_inverse_of(:user).with_autobuild }
8
10
 
9
11
  it { is_expected.to have_many(:comments).with_dependent(:destroy).with_autosave }
10
12
 
11
- it { is_expected.to embed_one(:profile) }
13
+ it { is_expected.to embed_one(:profile).as_inverse_of(:user) }
12
14
 
13
15
  it { is_expected.to have_and_belong_to_many(:children).of_type(User) }
14
16
  end
@@ -19,8 +21,8 @@ RSpec.describe "Associations" do
19
21
 
20
22
  describe Article do
21
23
  it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }
22
- it { is_expected.to embed_many(:comments).with_cascading_callbacks }
23
- it { is_expected.to embed_one(:permalink) }
24
+ it { is_expected.to embed_many(:comments).as_inverse_of(:article).with_cascading_callbacks }
25
+ it { is_expected.to embed_one(:permalink).as_inverse_of(:linkable) }
24
26
  end
25
27
 
26
28
  describe Comment do
@@ -37,6 +39,8 @@ RSpec.describe "Associations" do
37
39
  end
38
40
 
39
41
  describe Site do
40
- it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc).with_counter_cache }
42
+ if Mongoid::Compatibility::Version.mongoid6_or_newer?
43
+ it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc).with_counter_cache }
44
+ end
41
45
  end
42
46
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Mongoid::Matchers::BeDynamicDocument do
4
+ context 'when model does\'t include Mongoid::Document' do
5
+ subject do
6
+ Class.new
7
+ end
8
+
9
+ it { is_expected.not_to be_mongoid_document }
10
+ end
11
+
12
+ context 'when model doesn\'t include Mongoid::Document' do
13
+ subject do
14
+ Class.new do
15
+ include Mongoid::Document
16
+ end
17
+ end
18
+
19
+ it { is_expected.to be_mongoid_document }
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ if Mongoid::Compatibility::Version.mongoid4_or_newer?
3
+ RSpec.describe Mongoid::Matchers::BeMongoidDocument do
4
+ context 'when model does\'t include Mongoid::Attributes::Dynamic' do
5
+ subject do
6
+ Class.new do
7
+ include Mongoid::Document
8
+ end
9
+ end
10
+
11
+ it { is_expected.not_to be_dynamic_document }
12
+ end
13
+
14
+ context 'when model doesn\'t include Mongoid::Attributes::Dynamic' do
15
+ subject do
16
+ Class.new do
17
+ include Mongoid::Document
18
+ include Mongoid::Attributes::Dynamic
19
+ end
20
+ end
21
+
22
+ it { is_expected.to be_dynamic_document }
23
+ end
24
+ end
25
+ end