shoulda-matchers 5.1.0 → 5.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 +4 -4
- data/LICENSE +1 -1
- data/README.md +3 -3
- data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers.rb +1 -0
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +29 -4
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +115 -21
- data/lib/shoulda/matchers/rails_shim.rb +14 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/shoulda-matchers.gemspec +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97aebe50b9fb389687c99bc5dc1229a27abc5255f15e2330c9d1409d957fb689
|
4
|
+
data.tar.gz: 7cd8151aae87feb29121f4b4c152f963e5cc1c7a136e0a2115344af225fb1dcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 351c2bc9565abf151db5eeef3d17280989cdc8ec1841b0a099de8be8533767324494b04bfcc4464290852f5b022f6595fb5759e79c4534f50b6e464c94e44679
|
7
|
+
data.tar.gz: 529b6d0815299c10c0f52664371e37b948ec4b8403c0096065f11649fb1849851454634f736e747820f06e27fc4d48a0616d9adfbc34b560f14a8dad364e4268
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -19,7 +19,7 @@ complex, and error-prone.
|
|
19
19
|
|
20
20
|
## Quick links
|
21
21
|
|
22
|
-
📖 **[Read the documentation for the latest version][rubydocs].**
|
22
|
+
📖 **[Read the documentation for the latest version][rubydocs].**
|
23
23
|
📢 **[See what's changed in recent versions][changelog].**
|
24
24
|
|
25
25
|
[rubydocs]: https://matchers.shoulda.io/docs
|
@@ -117,7 +117,7 @@ Otherwise, add `shoulda-matchers` to your Gemfile:
|
|
117
117
|
|
118
118
|
```ruby
|
119
119
|
group :test do
|
120
|
-
gem 'shoulda-matchers', '~>
|
120
|
+
gem 'shoulda-matchers', '~> 5.0'
|
121
121
|
end
|
122
122
|
```
|
123
123
|
|
@@ -492,7 +492,7 @@ Albuk][guialbuk].
|
|
492
492
|
|
493
493
|
## Copyright/License
|
494
494
|
|
495
|
-
Shoulda Matchers is copyright © 2006-
|
495
|
+
Shoulda Matchers is copyright © 2006-2022 Tammer Saleh and [thoughtbot,
|
496
496
|
inc][thoughtbot-website]. It is free and opensource software and may be
|
497
497
|
redistributed under the terms specified in the [LICENSE](LICENSE) file.
|
498
498
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
module Qualifiers
|
5
|
+
# @private
|
6
|
+
module AllowBlank
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@expects_to_allow_blank = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def allow_blank
|
13
|
+
@expects_to_allow_blank = true
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def expects_to_allow_blank?
|
20
|
+
@expects_to_allow_blank
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -78,6 +78,27 @@ module Shoulda
|
|
78
78
|
# should validate_presence_of(:nickname).allow_nil
|
79
79
|
# end
|
80
80
|
#
|
81
|
+
# #### allow_blank
|
82
|
+
#
|
83
|
+
# Use `allow_blank` to assert that the attribute allows blank.
|
84
|
+
#
|
85
|
+
# class Robot
|
86
|
+
# include ActiveModel::Model
|
87
|
+
# attr_accessor :nickname
|
88
|
+
#
|
89
|
+
# validates_presence_of :nickname, allow_blank: true
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# # RSpec
|
93
|
+
# RSpec.describe Robot, type: :model do
|
94
|
+
# it { should validate_presence_of(:nickname).allow_blank }
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# # Minitest (Shoulda)
|
98
|
+
# class RobotTest < ActiveSupport::TestCase
|
99
|
+
# should validate_presence_of(:nickname).allow_blank
|
100
|
+
# end
|
101
|
+
#
|
81
102
|
# ##### on
|
82
103
|
#
|
83
104
|
# Use `on` if your validation applies only under a certain context.
|
@@ -133,6 +154,7 @@ module Shoulda
|
|
133
154
|
# @private
|
134
155
|
class ValidatePresenceOfMatcher < ValidationMatcher
|
135
156
|
include Qualifiers::AllowNil
|
157
|
+
include Qualifiers::AllowBlank
|
136
158
|
|
137
159
|
def initialize(attribute)
|
138
160
|
super
|
@@ -144,7 +166,8 @@ module Shoulda
|
|
144
166
|
|
145
167
|
possibly_ignore_interference_by_writer
|
146
168
|
|
147
|
-
if secure_password_being_validated?
|
169
|
+
if secure_password_being_validated? &&
|
170
|
+
Shoulda::Matchers::RailsShim.active_model_lt_7?
|
148
171
|
ignore_interference_by_writer.default_to(when: :blank?)
|
149
172
|
|
150
173
|
disallowed_values.all? do |value|
|
@@ -152,6 +175,7 @@ module Shoulda
|
|
152
175
|
end
|
153
176
|
else
|
154
177
|
(!expects_to_allow_nil? || allows_value_of(nil)) &&
|
178
|
+
(!expects_to_allow_blank? || allows_value_of('')) &&
|
155
179
|
disallowed_values.all? do |value|
|
156
180
|
disallows_original_or_typecast_value?(value)
|
157
181
|
end
|
@@ -171,6 +195,7 @@ module Shoulda
|
|
171
195
|
end
|
172
196
|
else
|
173
197
|
(expects_to_allow_nil? && disallows_value_of(nil)) ||
|
198
|
+
(expects_to_allow_blank? && disallows_value_of('')) ||
|
174
199
|
disallowed_values.any? do |value|
|
175
200
|
allows_original_or_typecast_value?(value)
|
176
201
|
end
|
@@ -208,7 +233,7 @@ validation for you? Instead of using `validate_presence_of`, try
|
|
208
233
|
end
|
209
234
|
|
210
235
|
def possibly_ignore_interference_by_writer
|
211
|
-
if secure_password_being_validated?
|
236
|
+
if secure_password_being_validated? && RailsShim.active_model_lt_7?
|
212
237
|
ignore_interference_by_writer.default_to(when: :blank?)
|
213
238
|
end
|
214
239
|
end
|
@@ -241,11 +266,11 @@ validation for you? Instead of using `validate_presence_of`, try
|
|
241
266
|
else
|
242
267
|
values = []
|
243
268
|
|
244
|
-
if attribute_accepts_string_values?
|
269
|
+
if attribute_accepts_string_values? && !expects_to_allow_blank?
|
245
270
|
values << ''
|
246
271
|
end
|
247
272
|
|
248
|
-
if !expects_to_allow_nil?
|
273
|
+
if !expects_to_allow_nil? && !expects_to_allow_blank?
|
249
274
|
values << nil
|
250
275
|
end
|
251
276
|
|
@@ -116,7 +116,7 @@ module Shoulda
|
|
116
116
|
## ##### with_prefix
|
117
117
|
#
|
118
118
|
# Use `with_prefix` to test that the enum is defined with a `_prefix`
|
119
|
-
# option (Rails
|
119
|
+
# option (Rails 6+ only). Can take either a boolean or a symbol:
|
120
120
|
#
|
121
121
|
# class Issue < ActiveRecord::Base
|
122
122
|
# enum status: [:open, :closed], _prefix: :old
|
@@ -163,6 +163,30 @@ module Shoulda
|
|
163
163
|
# with_suffix
|
164
164
|
# end
|
165
165
|
#
|
166
|
+
# ##### without_scopes
|
167
|
+
#
|
168
|
+
# Use `without_scopes` to test that the enum is defined with
|
169
|
+
# '_scopes: false' option (Rails 5 only). Can take either a boolean or a
|
170
|
+
# symbol:
|
171
|
+
#
|
172
|
+
# class Issue < ActiveRecord::Base
|
173
|
+
# enum status: [:open, :closed], _scopes: false
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# # RSpec
|
177
|
+
# RSpec.describe Issue, type: :model do
|
178
|
+
# it do
|
179
|
+
# should define_enum_for(:status).
|
180
|
+
# without_scopes
|
181
|
+
# end
|
182
|
+
# end
|
183
|
+
#
|
184
|
+
# # Minitest (Shoulda)
|
185
|
+
# class ProcessTest < ActiveSupport::TestCase
|
186
|
+
# should define_enum_for(:status).
|
187
|
+
# without_scopes
|
188
|
+
# end
|
189
|
+
#
|
166
190
|
# @return [DefineEnumForMatcher]
|
167
191
|
#
|
168
192
|
def define_enum_for(attribute_name)
|
@@ -173,7 +197,7 @@ module Shoulda
|
|
173
197
|
class DefineEnumForMatcher
|
174
198
|
def initialize(attribute_name)
|
175
199
|
@attribute_name = attribute_name
|
176
|
-
@options = { expected_enum_values: [] }
|
200
|
+
@options = { expected_enum_values: [], scopes: true }
|
177
201
|
end
|
178
202
|
|
179
203
|
def description
|
@@ -226,13 +250,19 @@ module Shoulda
|
|
226
250
|
self
|
227
251
|
end
|
228
252
|
|
253
|
+
def without_scopes
|
254
|
+
options[:scopes] = false
|
255
|
+
self
|
256
|
+
end
|
257
|
+
|
229
258
|
def matches?(subject)
|
230
259
|
@record = subject
|
231
260
|
|
232
261
|
enum_defined? &&
|
233
262
|
enum_values_match? &&
|
234
263
|
column_type_matches? &&
|
235
|
-
enum_value_methods_exist?
|
264
|
+
enum_value_methods_exist? &&
|
265
|
+
scope_presence_matches?
|
236
266
|
end
|
237
267
|
|
238
268
|
def failure_message
|
@@ -294,6 +324,10 @@ module Shoulda
|
|
294
324
|
expectation << "_#{expected_suffix}".inspect
|
295
325
|
end
|
296
326
|
|
327
|
+
if exclude_scopes?
|
328
|
+
expectation << ' with no scopes'
|
329
|
+
end
|
330
|
+
|
297
331
|
expectation
|
298
332
|
else
|
299
333
|
simple_description
|
@@ -387,37 +421,81 @@ module Shoulda
|
|
387
421
|
end
|
388
422
|
|
389
423
|
def enum_value_methods_exist?
|
390
|
-
|
391
|
-
|
424
|
+
if instance_methods_exist?
|
425
|
+
true
|
426
|
+
else
|
427
|
+
message = missing_methods_message
|
428
|
+
|
429
|
+
message << " (we can't tell which)"
|
430
|
+
|
431
|
+
@failure_message_continuation = message
|
432
|
+
|
433
|
+
false
|
392
434
|
end
|
435
|
+
end
|
393
436
|
|
394
|
-
|
437
|
+
def scope_presence_matches?
|
438
|
+
if exclude_scopes?
|
439
|
+
if singleton_methods_exist?
|
440
|
+
message = "#{attribute_name.inspect} does map to these values "
|
441
|
+
message << 'but class scope methods were present'
|
442
|
+
|
443
|
+
@failure_message_continuation = message
|
444
|
+
|
445
|
+
false
|
446
|
+
else
|
447
|
+
true
|
448
|
+
end
|
449
|
+
elsif singleton_methods_exist?
|
395
450
|
true
|
396
451
|
else
|
397
|
-
|
398
|
-
|
452
|
+
if enum_defined?
|
453
|
+
message = 'But the class scope methods are not present'
|
454
|
+
else
|
455
|
+
message = missing_methods_message
|
399
456
|
|
400
|
-
|
401
|
-
|
402
|
-
message << 'configured with either a different prefix or '
|
403
|
-
message << 'suffix, or no prefix or suffix at all'
|
404
|
-
else
|
405
|
-
message << 'configured with either a different prefix or no '
|
406
|
-
message << 'prefix at all'
|
407
|
-
end
|
408
|
-
elsif expected_suffix
|
409
|
-
message << 'configured with either a different suffix or no '
|
410
|
-
message << 'suffix at all'
|
457
|
+
message << 'or the class scope methods are not present'
|
458
|
+
message << " (we can't tell which)"
|
411
459
|
end
|
412
460
|
|
413
|
-
message << " (we can't tell which)"
|
414
|
-
|
415
461
|
@failure_message_continuation = message
|
416
462
|
|
417
463
|
false
|
418
464
|
end
|
419
465
|
end
|
420
466
|
|
467
|
+
def missing_methods_message
|
468
|
+
message = "#{attribute_name.inspect} does map to these "
|
469
|
+
message << 'values, but the enum is '
|
470
|
+
|
471
|
+
if expected_prefix
|
472
|
+
if expected_suffix
|
473
|
+
message << 'configured with either a different prefix or '
|
474
|
+
message << 'suffix, or no prefix or suffix at all'
|
475
|
+
else
|
476
|
+
message << 'configured with either a different prefix or no '
|
477
|
+
message << 'prefix at all'
|
478
|
+
end
|
479
|
+
elsif expected_suffix
|
480
|
+
message << 'configured with either a different suffix or no '
|
481
|
+
message << 'suffix at all'
|
482
|
+
else
|
483
|
+
''
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
def singleton_methods_exist?
|
488
|
+
expected_singleton_methods.all? do |method|
|
489
|
+
model.singleton_methods.include?(method)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def instance_methods_exist?
|
494
|
+
expected_instance_methods.all? do |method|
|
495
|
+
record.methods.include?(method)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
421
499
|
def expected_singleton_methods
|
422
500
|
expected_enum_value_names.map do |name|
|
423
501
|
[expected_prefix, name, expected_suffix].
|
@@ -427,6 +505,18 @@ module Shoulda
|
|
427
505
|
end
|
428
506
|
end
|
429
507
|
|
508
|
+
def expected_instance_methods
|
509
|
+
methods = expected_enum_value_names.map do |name|
|
510
|
+
[expected_prefix, name, expected_suffix].
|
511
|
+
select(&:present?).
|
512
|
+
join('_')
|
513
|
+
end
|
514
|
+
|
515
|
+
methods.flat_map do |m|
|
516
|
+
["#{m}?".to_sym, "#{m}!".to_sym]
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
430
520
|
def expected_prefix
|
431
521
|
if options.include?(:prefix)
|
432
522
|
if options[:prefix] == true
|
@@ -447,6 +537,10 @@ module Shoulda
|
|
447
537
|
end
|
448
538
|
end
|
449
539
|
|
540
|
+
def exclude_scopes?
|
541
|
+
!options[:scopes]
|
542
|
+
end
|
543
|
+
|
450
544
|
def to_hash(value)
|
451
545
|
if value.is_a?(Array)
|
452
546
|
value.each_with_index.inject({}) do |hash, (item, index)|
|
@@ -19,6 +19,20 @@ module Shoulda
|
|
19
19
|
Gem::Version.new('0')
|
20
20
|
end
|
21
21
|
|
22
|
+
def active_model_version
|
23
|
+
Gem::Version.new(::ActiveModel::VERSION::STRING)
|
24
|
+
rescue NameError
|
25
|
+
Gem::Version.new('0')
|
26
|
+
end
|
27
|
+
|
28
|
+
def active_model_gte_7?
|
29
|
+
Gem::Requirement.new('>= 7').satisfied_by?(active_model_version)
|
30
|
+
end
|
31
|
+
|
32
|
+
def active_model_lt_7?
|
33
|
+
Gem::Requirement.new('< 7').satisfied_by?(active_model_version)
|
34
|
+
end
|
35
|
+
|
22
36
|
def generate_validation_message(
|
23
37
|
record,
|
24
38
|
attribute,
|
data/shoulda-matchers.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
|
27
27
|
s.metadata = {
|
28
28
|
'bug_tracker_uri' => 'https://github.com/thoughtbot/shoulda-matchers/issues',
|
29
|
-
'changelog_uri' => 'https://github.com/thoughtbot/shoulda-matchers/blob/
|
29
|
+
'changelog_uri' => 'https://github.com/thoughtbot/shoulda-matchers/blob/main/CHANGELOG.md',
|
30
30
|
'documentation_uri' => 'https://matchers.shoulda.io/docs',
|
31
31
|
'homepage_uri' => 'https://matchers.shoulda.io',
|
32
32
|
'source_code_uri' => 'https://github.com/thoughtbot/shoulda-matchers',
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shoulda-matchers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tammer Saleh
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date:
|
17
|
+
date: 2022-09-17 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: activesupport
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb
|
81
81
|
- lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb
|
82
82
|
- lib/shoulda/matchers/active_model/qualifiers.rb
|
83
|
+
- lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb
|
83
84
|
- lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb
|
84
85
|
- lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb
|
85
86
|
- lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb
|
@@ -173,7 +174,7 @@ licenses:
|
|
173
174
|
- MIT
|
174
175
|
metadata:
|
175
176
|
bug_tracker_uri: https://github.com/thoughtbot/shoulda-matchers/issues
|
176
|
-
changelog_uri: https://github.com/thoughtbot/shoulda-matchers/blob/
|
177
|
+
changelog_uri: https://github.com/thoughtbot/shoulda-matchers/blob/main/CHANGELOG.md
|
177
178
|
documentation_uri: https://matchers.shoulda.io/docs
|
178
179
|
homepage_uri: https://matchers.shoulda.io
|
179
180
|
source_code_uri: https://github.com/thoughtbot/shoulda-matchers
|