mongoid-rspec 4.0.1 → 4.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 801c33ba9bd350eeb1595c57509601084b983ae5
4
- data.tar.gz: 1f47a9a328b9d58e5cdaaebf7dbfd91420ed4ca7
2
+ SHA256:
3
+ metadata.gz: 711f91347b02d3d6982a72b6946bb781ea07dba16f858109da01166c7a768ecf
4
+ data.tar.gz: 58e81131678e670e5a7b63385122fa316afadb18d49749c3544a4e5e1898d3fc
5
5
  SHA512:
6
- metadata.gz: 91cf1c6e8b0d356bbece0657fe9f5cf1df218f8ec5fa9171a96dd2cef02781654390bcd47f6bea9e62192564d144c1489541dcb54bcc016c596e73578f1b4d18
7
- data.tar.gz: af5c81412000da22a464b6982dab00e652b34c052ca46cc3fb596439c3e7dde204851b769dbd28b788ffcd67e2331dc847455b613b226ae2cf2a7e2f2a4a0d82
6
+ metadata.gz: 7aab1843f0f0b8778916039f3ef8b0f89e815bbc9cfafe0d7244a903df8c524ec6e990914478d6cd403b5b9e81e885b007850fe58cbf78841d989a472e98cdb2
7
+ data.tar.gz: 3e068496db19d24acfd05ff8ac630ecd41ccab1606e6597ddf0d0bf5969296dd7e1f2f5cf3a7a847801b44c84363e784908024a392317b7d1a95825f2c66bf9f
data/README.md CHANGED
@@ -1,10 +1,17 @@
1
1
  # [mongoid-rspec](https://github.com/mongoid/mongoid-rspec "A collection of RSpec-compatible matchers that help to test Mongoid documents.")
2
2
 
3
- [![Build Status](https://travis-ci.org/mongoid/mongoid-rspec.svg?branch=master)](https://travis-ci.org/mongoid/mongoid-rspec)
4
3
  [![Gem Version](https://badge.fury.io/rb/mongoid-rspec.svg)](https://badge.fury.io/rb/mongoid-rspec)
4
+ [![Test Status](https://github.com/mongoid/mongoid-rspec/workflows/Test/badge.svg)](https://github.com/mongoid/mongoid-rspec/actions)
5
+ [![Rubocop Status](https://github.com/mongoid/mongoid-rspec/workflows/Rubocop/badge.svg)](https://github.com/mongoid/mongoid-rspec/actions)
5
6
 
6
7
  The mongoid-rspec library provides a collection of RSpec-compatible matchers that help to test Mongoid documents.
7
8
 
9
+ [Tested](https://github.com/mongoid/mongoid-locker/actions) against:
10
+ - MRI: `2.6.x`, `2.7.x`, `3.0.x`, `3.1.x`, `3.2.x`
11
+ - Mongoid: `4`, `5`, `6`, `7`, `8`, `9`
12
+
13
+ See [.github/workflows/rspec.yml](.github/workflows/rspec.yml) for the latest test matrix.
14
+
8
15
  ## Installation
9
16
 
10
17
  Drop this line into your Gemfile:
@@ -18,7 +25,7 @@ end
18
25
 
19
26
  ## Compatibility
20
27
 
21
- This gem is compatible with Mongoid 3, 4, 5, 6 and 7.
28
+ This gem is compatible with Mongoid 3, 4, 5, 6, 7, 8, 9.
22
29
 
23
30
  ## Configuration
24
31
 
@@ -181,7 +188,7 @@ end
181
188
 
182
189
  ```ruby
183
190
  class Article
184
- index({ title: 1 }, { unique: true, background: true, drop_dups: true })
191
+ index({ title: 1 }, { unique: true, background: true })
185
192
  index({ title: 1, created_at: -1 })
186
193
  index({ category: 1 })
187
194
  end
@@ -190,7 +197,7 @@ RSpec.describe Article, type: :model do
190
197
  it do
191
198
  is_expected
192
199
  .to have_index_for(title: 1)
193
- .with_options(unique: true, background: true, drop_dups: true)
200
+ .with_options(unique: true, background: true)
194
201
  end
195
202
  it { is_expected.to have_index_for(title: 1, created_at: -1) }
196
203
  it { is_expected.to have_index_for(category: 1) }
@@ -201,9 +208,9 @@ end
201
208
 
202
209
  ```ruby
203
210
  RSpec.describe Article do
204
- it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) }
205
- it { is_expected.to have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
206
- it { is_expected.not_to have_field(:allow_comments).of_type(Boolean).with_default_value_of(false) }
211
+ it { is_expected.to have_field(:published).of_type(Mongoid::Boolean).with_default_value_of(false) }
212
+ it { is_expected.to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(true) }
213
+ it { is_expected.not_to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(false) }
207
214
  it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
208
215
  end
209
216
 
@@ -249,6 +256,27 @@ RSpec.describe Article do
249
256
  it { is_expected.to embed_many(:comments) }
250
257
  end
251
258
 
259
+ # when the touch option is provided, then we can also verify that it is set
260
+
261
+ # by default, with_touch matches true when no parameters are provided
262
+ describe Article do
263
+ it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index.with_touch }
264
+ end
265
+
266
+ # parameters are supported for explicit matching
267
+ describe Comment do
268
+ it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments).with_polymorphism.with_touch(true) }
269
+ end
270
+
271
+ describe Permalink do
272
+ it { is_expected.to be_embedded_in(:linkable).as_inverse_of(:link).with_touch(false) }
273
+ end
274
+
275
+ # touch can also take a symbol representing a field on the parent to touch
276
+ describe Record do
277
+ it { is_expected.to belong_to(:user).as_inverse_of(:record).with_touch(:record_updated_at) }
278
+ end
279
+
252
280
  RSpec.describe Comment do
253
281
  it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments) }
254
282
  it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
@@ -261,6 +289,10 @@ end
261
289
  RSpec.describe Site do
262
290
  it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.asc).with_counter_cache }
263
291
  end
292
+
293
+ RSpec.describe Message do
294
+ it { is_expected.to belong_to(:user).with_optional }
295
+ end
264
296
  ```
265
297
 
266
298
  ### Validation Matchers
@@ -311,6 +343,22 @@ RSpec.describe Person do
311
343
  # should redefine the kind method to return :custom, i.e. "def self.kind() :custom end"
312
344
  it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
313
345
  end
346
+
347
+ # If you're using validators with if/unless conditionals, spec subject must be object instance
348
+ # This is supported on Mongoid 4 and newer
349
+ Rspec.describe User do
350
+ context 'when user has `admin` role' do
351
+ subject { User.new(role: 'admin') }
352
+
353
+ it { is_expected.to validate_length_of(:password).greater_than(20) }
354
+ end
355
+
356
+ context 'when user does not have `admin` role' do
357
+ subject { User.new(role: 'member') }
358
+
359
+ it { is_expected.not_to validate_length_of(:password) }
360
+ end
361
+ end
314
362
  ```
315
363
 
316
364
  ### Mass Assignment Matcher
data/Rakefile CHANGED
@@ -14,7 +14,4 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
14
14
  spec.rcov = true
15
15
  end
16
16
 
17
- require 'rubocop/rake_task'
18
- RuboCop::RakeTask.new(:rubocop)
19
-
20
- task default: %i[rubocop spec]
17
+ task default: %i[spec]
@@ -51,7 +51,7 @@ module Mongoid
51
51
  @association[:order] = association_field_name.to_s
52
52
  @expectation_message << " ordered by #{@association[:order].inspect}"
53
53
 
54
- if association_field_name.is_a? Mongoid::Criteria::Queryable::Key
54
+ if association_field_name.is_a? association_kind_of
55
55
  @association[:order_operator] = association_field_name.operator
56
56
  @expectation_message << " #{order_way(@association[:order_operator])}"
57
57
  end
@@ -119,6 +119,18 @@ module Mongoid
119
119
  self
120
120
  end
121
121
 
122
+ def with_touch(touch = true)
123
+ @association[:touch] = touch
124
+ @expectation_message << " which specifies touch as #{@association[:touch]}"
125
+ self
126
+ end
127
+
128
+ def with_optional
129
+ @association[:optional] = true
130
+ @expectation_message << " which specifies optional as #{@association[:optional]}"
131
+ self
132
+ end
133
+
122
134
  def matches?(actual)
123
135
  @actual = actual.is_a?(Class) ? actual : actual.class
124
136
  metadata = @actual.relations[@association[:name]]
@@ -266,6 +278,24 @@ module Mongoid
266
278
  end
267
279
  end
268
280
 
281
+ unless @association[:touch].nil?
282
+ if metadata.options[:touch] != @association[:touch]
283
+ @negative_result_message = "#{@positive_result_message} which sets touch as #{metadata.options[:touch].inspect}"
284
+ return false
285
+ else
286
+ @positive_result_message = "#{@positive_result_message} which sets touch as #{metadata.options[:touch].inspect}"
287
+ end
288
+ end
289
+
290
+ if @association[:optional]
291
+ if metadata.options[:optional] != true
292
+ @negative_result_message = "#{@positive_result_message} which did not set optional"
293
+ return false
294
+ else
295
+ @positive_result_message = "#{@positive_result_message} which set optional"
296
+ end
297
+ end
298
+
269
299
  true
270
300
  end
271
301
 
@@ -311,6 +341,10 @@ module Mongoid
311
341
  def order_way(operator)
312
342
  [nil, 'ascending', 'descending'][operator]
313
343
  end
344
+
345
+ def association_kind_of
346
+ Mongoid::Compatibility::Version.mongoid5_or_older? ? Origin::Key : Mongoid::Criteria::Queryable::Key
347
+ end
314
348
  end
315
349
 
316
350
  def embed_one(association_name)
@@ -44,7 +44,7 @@ module Mongoid
44
44
  private
45
45
 
46
46
  MAPPINGS = {
47
- dropDups: :drop_dups
47
+ dropDups: :drop_dups # Deprecated from MongoDB 3.0
48
48
  }.freeze
49
49
 
50
50
  def denormalising_options(opts)
@@ -12,7 +12,8 @@ module Mongoid
12
12
  @klass = actual.is_a?(Class) ? actual : actual.class
13
13
 
14
14
  @validator = @klass.validators_on(@field).detect do |v|
15
- (v.kind.to_s == @type) && (!v.options[:on] || on_options_matches?(v))
15
+ (v.kind.to_s == @type) && (!v.options[:on] || on_options_matches?(v)) &&
16
+ if_condition_matches?(actual, v) && unless_condition_matches?(actual, v)
16
17
  end
17
18
 
18
19
  if @validator
@@ -59,6 +60,31 @@ module Mongoid
59
60
 
60
61
  private
61
62
 
63
+ def if_condition_matches?(actual, validator)
64
+ return true unless validator.options[:if]
65
+
66
+ check_condition actual, validator.options[:if]
67
+ end
68
+
69
+ def unless_condition_matches?(actual, validator)
70
+ return true unless validator.options[:unless]
71
+
72
+ !check_condition actual, validator.options[:unless]
73
+ end
74
+
75
+ def check_condition(actual, filter)
76
+ raise ArgumentError, 'Spec subject must be object instance when testing validators with if/unless condition.' if actual.is_a?(Class)
77
+
78
+ case filter
79
+ when Symbol
80
+ actual.send filter
81
+ when ::Proc
82
+ actual.instance_exec(&filter)
83
+ else
84
+ raise ArgumentError, "Unexpected filter: #{filter.inspect}"
85
+ end
86
+ end
87
+
62
88
  def check_on
63
89
  validator_on_methods = [@validator.options[:on]].flatten
64
90
 
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module RSpec
3
- VERSION = '4.0.1'.freeze
3
+ VERSION = '4.2.0'.freeze
4
4
  end
5
5
  end
data/lib/mongoid/rspec.rb CHANGED
@@ -6,7 +6,7 @@ require 'rspec/core'
6
6
  require 'rspec/expectations'
7
7
  require 'rspec/mocks'
8
8
  require 'active_support/core_ext/hash/keys'
9
- require 'active_support/core_ext/hash/transform_values' if Mongoid::Compatibility::Version.mongoid4_or_newer?
9
+ require 'active_support/core_ext/hash/transform_values' if Mongoid::Compatibility::Version.mongoid4_or_newer? && ActiveSupport.version < Gem::Version.new('6')
10
10
  require 'active_support/core_ext/object/blank'
11
11
  require 'active_support/core_ext/string/inflections'
12
12
 
metadata CHANGED
@@ -1,70 +1,118 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Sagge
8
8
  - Rodrigo Pinto
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-06-18 00:00:00.000000000 Z
12
+ date: 2024-06-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: activesupport
15
+ name: appraisal
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: mongoid-danger
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '0.2'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '0.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
16
44
  requirement: !ruby/object:Gem::Requirement
17
45
  requirements:
18
46
  - - ">="
19
47
  - !ruby/object:Gem::Version
20
- version: 3.0.0
21
- type: :runtime
48
+ version: '0'
49
+ type: :development
22
50
  prerelease: false
23
51
  version_requirements: !ruby/object:Gem::Requirement
24
52
  requirements:
25
53
  - - ">="
26
54
  - !ruby/object:Gem::Version
27
- version: 3.0.0
55
+ version: '0'
28
56
  - !ruby/object:Gem::Dependency
29
- name: mongoid
57
+ name: rails
30
58
  requirement: !ruby/object:Gem::Requirement
31
59
  requirements:
32
60
  - - ">="
33
61
  - !ruby/object:Gem::Version
34
- version: '3.1'
35
- type: :runtime
62
+ version: '0'
63
+ type: :development
36
64
  prerelease: false
37
65
  version_requirements: !ruby/object:Gem::Requirement
38
66
  requirements:
39
67
  - - ">="
40
68
  - !ruby/object:Gem::Version
41
- version: '3.1'
69
+ version: '0'
42
70
  - !ruby/object:Gem::Dependency
43
71
  name: rspec
44
72
  requirement: !ruby/object:Gem::Requirement
45
73
  requirements:
46
- - - "~>"
74
+ - - ">="
47
75
  - !ruby/object:Gem::Version
48
- version: '3.3'
49
- type: :runtime
76
+ version: '0'
77
+ type: :development
50
78
  prerelease: false
51
79
  version_requirements: !ruby/object:Gem::Requirement
52
80
  requirements:
53
- - - "~>"
81
+ - - ">="
54
82
  - !ruby/object:Gem::Version
55
- version: '3.3'
83
+ version: '0'
56
84
  - !ruby/object:Gem::Dependency
57
- name: rake
85
+ name: rubocop
58
86
  requirement: !ruby/object:Gem::Requirement
59
87
  requirements:
60
88
  - - "~>"
61
89
  - !ruby/object:Gem::Version
62
- version: '10.0'
90
+ version: 1.36.0
63
91
  type: :development
64
92
  prerelease: false
65
93
  version_requirements: !ruby/object:Gem::Requirement
66
94
  requirements:
67
95
  - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 1.36.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: mongoid
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '3.0'
105
+ - - "<"
106
+ - !ruby/object:Gem::Version
107
+ version: '10.0'
108
+ type: :runtime
109
+ prerelease: false
110
+ version_requirements: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '3.0'
115
+ - - "<"
68
116
  - !ruby/object:Gem::Version
69
117
  version: '10.0'
70
118
  - !ruby/object:Gem::Dependency
@@ -118,33 +166,12 @@ files:
118
166
  - lib/mongoid-rspec.rb
119
167
  - lib/mongoid/rspec.rb
120
168
  - lib/mongoid/rspec/version.rb
121
- - spec/models/article.rb
122
- - spec/models/comment.rb
123
- - spec/models/log.rb
124
- - spec/models/message.rb
125
- - spec/models/movie_article.rb
126
- - spec/models/permalink.rb
127
- - spec/models/person.rb
128
- - spec/models/profile.rb
129
- - spec/models/record.rb
130
- - spec/models/site.rb
131
- - spec/models/user.rb
132
- - spec/spec_helper.rb
133
- - spec/unit/accept_nested_attributes_spec.rb
134
- - spec/unit/associations_spec.rb
135
- - spec/unit/be_dynamic_document_spec.rb
136
- - spec/unit/be_mongoid_document_spec.rb
137
- - spec/unit/be_stored_in.rb
138
- - spec/unit/document_spec.rb
139
- - spec/unit/have_index_for_spec.rb
140
- - spec/unit/have_timestamps_spec.rb
141
- - spec/unit/validations_spec.rb
142
- - spec/validators/ssn_validator.rb
143
169
  homepage: http://github.com/mongoid-rspec/mongoid-rspec
144
170
  licenses:
145
171
  - MIT
146
- metadata: {}
147
- post_install_message:
172
+ metadata:
173
+ rubygems_mfa_required: 'true'
174
+ post_install_message:
148
175
  rdoc_options: []
149
176
  require_paths:
150
177
  - lib
@@ -152,38 +179,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
179
  requirements:
153
180
  - - ">="
154
181
  - !ruby/object:Gem::Version
155
- version: '2.2'
182
+ version: '2.6'
156
183
  required_rubygems_version: !ruby/object:Gem::Requirement
157
184
  requirements:
158
185
  - - ">="
159
186
  - !ruby/object:Gem::Version
160
187
  version: 1.3.6
161
188
  requirements: []
162
- rubyforge_project: mongoid-rspec
163
- rubygems_version: 2.6.13
164
- signing_key:
189
+ rubygems_version: 3.5.10
190
+ signing_key:
165
191
  specification_version: 4
166
192
  summary: RSpec matchers for Mongoid
167
- test_files:
168
- - spec/models/article.rb
169
- - spec/models/comment.rb
170
- - spec/models/log.rb
171
- - spec/models/message.rb
172
- - spec/models/movie_article.rb
173
- - spec/models/permalink.rb
174
- - spec/models/person.rb
175
- - spec/models/profile.rb
176
- - spec/models/record.rb
177
- - spec/models/site.rb
178
- - spec/models/user.rb
179
- - spec/spec_helper.rb
180
- - spec/unit/accept_nested_attributes_spec.rb
181
- - spec/unit/associations_spec.rb
182
- - spec/unit/be_dynamic_document_spec.rb
183
- - spec/unit/be_mongoid_document_spec.rb
184
- - spec/unit/be_stored_in.rb
185
- - spec/unit/document_spec.rb
186
- - spec/unit/have_index_for_spec.rb
187
- - spec/unit/have_timestamps_spec.rb
188
- - spec/unit/validations_spec.rb
189
- - spec/validators/ssn_validator.rb
193
+ test_files: []
@@ -1,32 +0,0 @@
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
- field :deletion_date, type: DateTime, default: nil
12
-
13
- embeds_many :comments, cascade_callbacks: true, inverse_of: :article
14
- embeds_one :permalink, inverse_of: :linkable
15
- belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
16
-
17
- validates :title, presence: true
18
-
19
- validates_inclusion_of :status, in: [:pending], on: :create
20
- validates_inclusion_of :status, in: %i[approved rejected], on: :update
21
-
22
- validates_length_of :title, within: 8..16
23
- validates_length_of :content, minimum: 200
24
-
25
- validates_absence_of :deletion_date if Mongoid::Compatibility::Version.mongoid4_or_newer?
26
-
27
- index({ title: 1 }, unique: true, background: true, drop_dups: true)
28
- index(published: 1)
29
- index('permalink._id' => 1)
30
-
31
- accepts_nested_attributes_for :permalink
32
- end
@@ -1,6 +0,0 @@
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
data/spec/models/log.rb DELETED
@@ -1,9 +0,0 @@
1
- class Log
2
- include Mongoid::Document
3
- include Mongoid::Timestamps
4
- include Mongoid::Attributes::Dynamic if Mongoid::Compatibility::Version.mongoid4_or_newer?
5
-
6
- store_in collection: 'logs'
7
-
8
- index({ created_at: 1 }, bucket_size: 100, expire_after_seconds: 3600)
9
- end
@@ -1,11 +0,0 @@
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,7 +0,0 @@
1
- class MovieArticle < Article
2
- field :rating, type: Float
3
- field :classification, type: Integer
4
-
5
- validates :rating, numericality: { greater_than: 0, less_than_or_equal_to: 5 }
6
- validates :classification, numericality: { even: true, only_integer: true, allow_nil: false }
7
- end
@@ -1,5 +0,0 @@
1
- class Permalink
2
- include Mongoid::Document
3
-
4
- embedded_in :linkable, inverse_of: :link
5
- end
@@ -1,10 +0,0 @@
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
@@ -1,16 +0,0 @@
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
@@ -1,5 +0,0 @@
1
- class Record
2
- include Mongoid::Document
3
-
4
- belongs_to :user, inverse_of: :record
5
- end
data/spec/models/site.rb DELETED
@@ -1,13 +0,0 @@
1
- class Site
2
- include Mongoid::Document
3
-
4
- field :name
5
-
6
- if Mongoid::Compatibility::Version.mongoid6_or_older?
7
- has_many :users, inverse_of: :site, order: :email.desc, counter_cache: true
8
- else
9
- has_many :users, inverse_of: :site, order: :email.desc
10
- end
11
-
12
- validates :name, presence: true, uniqueness: true
13
- end
data/spec/models/user.rb DELETED
@@ -1,37 +0,0 @@
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, inverse_of: :user
18
-
19
- embeds_one :profile, inverse_of: :user
20
-
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
- validates :profile, presence: true, associated: true
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
- validates :provider_uid, presence: true
30
- validates :locale, inclusion: { in: ->(_user) { %i[en ru] } }
31
-
32
- accepts_nested_attributes_for :articles, :comments
33
-
34
- def admin?
35
- false
36
- end
37
- end
data/spec/spec_helper.rb DELETED
@@ -1,36 +0,0 @@
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
- require 'mongoid/compatibility'
17
-
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
-
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
- config.after :suite do
33
- print "\n# Mongoid v#{Mongoid::VERSION}"
34
- end
35
- config.disable_monkey_patching!
36
- end
@@ -1,12 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'AcceptsNestedAttributes' do
4
- describe User do
5
- it { is_expected.to accept_nested_attributes_for(:articles) }
6
- it { is_expected.to accept_nested_attributes_for(:comments) }
7
- end
8
-
9
- describe Article do
10
- it { is_expected.to accept_nested_attributes_for(:permalink) }
11
- end
12
- end
@@ -1,48 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'Associations' do
4
- describe User do
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
8
-
9
- it { is_expected.to have_one(:record).as_inverse_of(:user).with_autobuild }
10
-
11
- it { is_expected.to have_many(:comments).with_dependent(:destroy).with_autosave }
12
-
13
- it { is_expected.to embed_one(:profile).as_inverse_of(:user) }
14
-
15
- it { is_expected.to have_and_belong_to_many(:children).of_type(User) }
16
- end
17
-
18
- describe Profile do
19
- it { is_expected.to be_embedded_in(:user).as_inverse_of(:profile) }
20
- end
21
-
22
- describe Article do
23
- it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }
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) }
26
- end
27
-
28
- describe Comment do
29
- it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments).with_polymorphism }
30
- it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
31
- end
32
-
33
- describe Record do
34
- it { is_expected.to belong_to(:user).as_inverse_of(:record) }
35
- end
36
-
37
- describe Permalink do
38
- it { is_expected.to be_embedded_in(:linkable).as_inverse_of(:link) }
39
- end
40
-
41
- describe Site do
42
- if Mongoid::Compatibility::Version.mongoid6?
43
- it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc).with_counter_cache }
44
- elsif Mongoid::Compatibility::Version.mongoid7_or_newer?
45
- it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc) }
46
- end
47
- end
48
- end
@@ -1,21 +0,0 @@
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
@@ -1,25 +0,0 @@
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
@@ -1,54 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::BeStoredIn do
4
- subject do
5
- Class.new do
6
- include Mongoid::Document
7
- store_in collection: 'citizens', database: 'other', client: 'secondary'
8
- end
9
- end
10
-
11
- it 'detects storage options' do
12
- is_expected.to be_stored_in(collection: 'citizens', database: 'other', client: 'secondary')
13
- end
14
-
15
- it 'detects even part of storage options' do
16
- is_expected.to be_stored_in(database: 'other')
17
- is_expected.to be_stored_in(client: 'secondary')
18
- is_expected.to be_stored_in(collection: 'citizens')
19
- is_expected.to be_stored_in(collection: 'citizens', database: 'other')
20
- is_expected.to be_stored_in(database: 'other', client: 'secondary')
21
- is_expected.to be_stored_in(collection: 'citizens', client: 'secondary')
22
- end
23
-
24
- it 'detects differences' do
25
- is_expected.not_to be_stored_in(collection: 'aliens')
26
- end
27
-
28
- context 'when models has storage options defined via blocks, procs or lambdas' do
29
- subject do
30
- Class.new do
31
- include Mongoid::Document
32
- store_in database: -> { Thread.current[:database] }
33
- end
34
- end
35
-
36
- before do
37
- Thread.current[:database] = 'db1981'
38
- end
39
-
40
- it 'detects storage options' do
41
- is_expected.to be_stored_in(database: 'db1981')
42
- end
43
-
44
- it 'reflects changes in storage options' do
45
- is_expected.to be_stored_in(database: 'db1981')
46
- Thread.current[:database] = 'db2200'
47
- is_expected.to be_stored_in(database: 'db2200')
48
- end
49
-
50
- it 'detects differences' do
51
- is_expected.not_to be_stored_in(database: 'other')
52
- end
53
- end
54
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'Document' do
4
- describe User do
5
- it { is_expected.to have_fields(:email, :login) }
6
- end
7
-
8
- describe Article do
9
- klass_boolean = Mongoid::Compatibility::Version.mongoid4_or_newer? ? Mongoid::Boolean : Boolean
10
- it { is_expected.to have_field(:published).of_type(klass_boolean).with_default_value_of(false) }
11
- it { is_expected.to have_field(:allow_comments).of_type(klass_boolean).with_default_value_of(true) }
12
- it { is_expected.to belong_to(:author) }
13
- it { is_expected.to have_field(:title).localized }
14
- it { is_expected.not_to have_field(:allow_comments).of_type(klass_boolean).with_default_value_of(false) }
15
- it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
16
- end
17
- end
@@ -1,46 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::HaveIndexFor do
4
- subject do
5
- Class.new do
6
- include Mongoid::Document
7
-
8
- field :fizz, as: :buzz, type: String
9
-
10
- index(foo: 1)
11
- index({ bar: 1 }, unique: true, background: true, drop_dups: true)
12
- index(foo: 1, bar: -1)
13
- index('baz._id' => 1)
14
- index(buzz: 1)
15
- end
16
- end
17
-
18
- it 'detects an index for singular field key' do
19
- is_expected.to have_index_for(foo: 1)
20
- end
21
-
22
- it 'detects an index for multipple fields key' do
23
- is_expected.to have_index_for(foo: 1, bar: -1)
24
- end
25
-
26
- it 'detects an index with options' do
27
- is_expected
28
- .to have_index_for(bar: 1)
29
- .with_options(unique: true, background: true, drop_dups: true)
30
- end
31
-
32
- it 'detects an index with only part of options' do
33
- is_expected
34
- .to have_index_for(bar: 1)
35
- .with_options(unique: true)
36
- end
37
-
38
- it 'detects an index for string key' do
39
- is_expected.to have_index_for('baz._id' => 1)
40
- end
41
-
42
- it 'detect an index for aliased fields' do
43
- is_expected.to have_index_for(fizz: 1)
44
- is_expected.to have_index_for(buzz: 1) if Mongoid::Compatibility::Version.mongoid4_or_newer?
45
- end
46
- end
@@ -1,71 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::HaveTimestamps do
4
- context 'when model includes Mongoid::Timestamps' do
5
- subject do
6
- Class.new do
7
- include Mongoid::Document
8
- include Mongoid::Timestamps
9
- end
10
- end
11
-
12
- it { is_expected.to have_timestamps }
13
- end
14
-
15
- context 'when model includes Mongoid::Timestamps::Short' do
16
- subject do
17
- Class.new do
18
- include Mongoid::Document
19
- include Mongoid::Timestamps::Short
20
- end
21
- end
22
-
23
- it { is_expected.to have_timestamps.shortened }
24
- end
25
-
26
- context 'when model includes Mongoid::Timestamps::Updated' do
27
- subject do
28
- Class.new do
29
- include Mongoid::Document
30
- include Mongoid::Timestamps::Updated
31
- end
32
- end
33
-
34
- it { is_expected.to have_timestamps.for(:updating) }
35
- end
36
-
37
- context 'when model includes Mongoid::Timestamps::Updated::Short' do
38
- subject do
39
- Class.new do
40
- include Mongoid::Document
41
- include Mongoid::Timestamps::Updated::Short
42
- end
43
- end
44
-
45
- it { is_expected.to have_timestamps.for(:updating).shortened }
46
- it { is_expected.to have_timestamps.shortened.for(:updating) }
47
- end
48
-
49
- context 'when model includes Mongoid::Timestamps::Created' do
50
- subject do
51
- Class.new do
52
- include Mongoid::Document
53
- include Mongoid::Timestamps::Created
54
- end
55
- end
56
-
57
- it { is_expected.to have_timestamps.for(:creating) }
58
- end
59
-
60
- context 'when model includes Mongoid::Timestamps::Created::Short' do
61
- subject do
62
- Class.new do
63
- include Mongoid::Document
64
- include Mongoid::Timestamps::Created::Short
65
- end
66
- end
67
-
68
- it { is_expected.to have_timestamps.for(:creating).shortened }
69
- it { is_expected.to have_timestamps.shortened.for(:creating) }
70
- end
71
- end
@@ -1,61 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'Validations' do
4
- describe Site do
5
- it { is_expected.to validate_presence_of(:name) }
6
- it { is_expected.to validate_uniqueness_of(:name) }
7
- end
8
-
9
- describe User do
10
- it { is_expected.to validate_presence_of(:login) }
11
- it { is_expected.to validate_uniqueness_of(:login).scoped_to(:site) }
12
- it { is_expected.to validate_uniqueness_of(:email).case_insensitive.with_message('is already taken') }
13
- it { is_expected.to validate_format_of(:login).to_allow('valid_login').not_to_allow('invalid login') }
14
- it { is_expected.to validate_associated(:profile) }
15
- it { is_expected.to validate_exclusion_of(:login).to_not_allow('super', 'index', 'edit') }
16
- it { is_expected.to validate_exclusion_of(:password).to_not_allow('password') }
17
- it { is_expected.to validate_inclusion_of(:role).to_allow('admin', 'member') }
18
- it { is_expected.to validate_inclusion_of(:role).to_allow(%w[admin member]) }
19
- it { is_expected.to validate_confirmation_of(:email) }
20
- it { is_expected.to validate_presence_of(:age).on(:create, :update) }
21
- it { is_expected.to validate_numericality_of(:age).on(:create, :update) }
22
- it { is_expected.to validate_inclusion_of(:age).to_allow(23..42).on(%i[create update]) }
23
- it { is_expected.to validate_presence_of(:password).on(:create) }
24
- it { is_expected.to validate_confirmation_of(:password).with_message('Password confirmation must match given password') }
25
- it { is_expected.to validate_presence_of(:provider_uid).on(:create) }
26
- it { is_expected.to validate_inclusion_of(:locale).to_allow(%i[en ru]) }
27
- end
28
-
29
- describe Profile do
30
- it { is_expected.to validate_numericality_of(:age).greater_than(0) }
31
- it { is_expected.not_to validate_numericality_of(:age).greater_than(0).only_integer(true) }
32
- it { is_expected.to validate_acceptance_of(:terms_of_service) }
33
- it { is_expected.to validate_length_of(:hobbies).with_minimum(1).with_message('requires at least one hobby') }
34
- end
35
-
36
- describe Article do
37
- it { is_expected.to validate_length_of(:title).within(8..16) }
38
- it { is_expected.not_to validate_length_of(:content).greater_than(200).less_than(16) }
39
- it { is_expected.to validate_length_of(:content).greater_than(200) }
40
- it { is_expected.to validate_inclusion_of(:status).to_allow([:pending]).on(:create) }
41
- it { is_expected.to validate_inclusion_of(:status).to_allow(%i[approved rejected]).on(:update) }
42
- it { is_expected.to validate_absence_of(:deletion_date) } if Mongoid::Compatibility::Version.mongoid4_or_newer?
43
- end
44
-
45
- describe MovieArticle do
46
- it { is_expected.to validate_numericality_of(:rating).greater_than(0) }
47
- it { is_expected.to validate_numericality_of(:rating).to_allow(greater_than: 0).less_than_or_equal_to(5) }
48
- it { is_expected.to validate_numericality_of(:classification).to_allow(even: true, only_integer: true, nil: false) }
49
- end
50
-
51
- describe Person do
52
- it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
53
- it { is_expected.not_to custom_validate(:name) }
54
- end
55
-
56
- describe Message do
57
- it { is_expected.to validate_uniqueness_of(:identifier).with_message('uniqueness') }
58
- it { is_expected.to validate_presence_of(:from).with_message('required') }
59
- it { is_expected.to validate_format_of(:to).with_message('format') }
60
- end
61
- end
@@ -1,16 +0,0 @@
1
- class SsnValidator < ActiveModel::EachValidator
2
- def validate_each(record, attribute, value)
3
- unless valid_ssn?(record, attribute, value)
4
- record.errors[attribute] << "#{value} is not a valid Social Security Number"
5
- end
6
- end
7
-
8
- def self.kind
9
- :custom
10
- end
11
-
12
- def valid_ssn?(_record, _attribute, _value)
13
- # irrelevant here how validation is done
14
- true
15
- end
16
- end