shoulda-matchers 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 188abbfbc6cac3e26997733b3d88b34ea74e9747e25f137738190bf15d033751
4
- data.tar.gz: 73136b35573cffac784cadd7e3193e8e9a0934f0e69fa751f536ed589db01024
3
+ metadata.gz: 97aebe50b9fb389687c99bc5dc1229a27abc5255f15e2330c9d1409d957fb689
4
+ data.tar.gz: 7cd8151aae87feb29121f4b4c152f963e5cc1c7a136e0a2115344af225fb1dcd
5
5
  SHA512:
6
- metadata.gz: 55f3ccad9ce3d4affcb6ccc38020872bc000710f887765d7b78962bcdd339d79a2a1316e3a9d2cb33c62887e66bab9e54801d79c872f6cab7a2459a32ddce4bf
7
- data.tar.gz: e5a862e62f25dfe284f0325f20600bbc4a3567ef78a0b7742685d1a9af9d03147ab650a259be287bd4566719444c7d998c0106874b7c3ac43efbd79996191838
6
+ metadata.gz: 351c2bc9565abf151db5eeef3d17280989cdc8ec1841b0a099de8be8533767324494b04bfcc4464290852f5b022f6595fb5759e79c4534f50b6e464c94e44679
7
+ data.tar.gz: 529b6d0815299c10c0f52664371e37b948ec4b8403c0096065f11649fb1849851454634f736e747820f06e27fc4d48a0616d9adfbc34b560f14a8dad364e4268
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2006-2021 Tammer Saleh and thoughtbot, inc.
1
+ Copyright (c) 2006-2022 Tammer Saleh and thoughtbot, inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
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', '~> 4.0'
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-2021 Tammer Saleh and [thoughtbot,
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
@@ -9,5 +9,6 @@ module Shoulda
9
9
  end
10
10
 
11
11
  require_relative 'qualifiers/allow_nil'
12
+ require_relative 'qualifiers/allow_blank'
12
13
  require_relative 'qualifiers/ignore_interference_by_writer'
13
14
  require_relative 'qualifiers/ignoring_interference_by_writer'
@@ -239,7 +239,7 @@ module Shoulda
239
239
  #
240
240
  # @return [ValidateLengthOfMatcher]
241
241
  #
242
- # # ##### allow_blank
242
+ # ##### allow_blank
243
243
  #
244
244
  # Use `allow_blank` to assert that the attribute allows blank.
245
245
  #
@@ -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 5 only). Can take either a boolean or a symbol:
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
- passed = expected_singleton_methods.all? do |method|
391
- model.singleton_methods.include?(method)
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
- if passed
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
- message = "#{attribute_name.inspect} does map to these "
398
- message << 'values, but the enum is '
452
+ if enum_defined?
453
+ message = 'But the class scope methods are not present'
454
+ else
455
+ message = missing_methods_message
399
456
 
400
- if expected_prefix
401
- if expected_suffix
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,
@@ -1,6 +1,6 @@
1
1
  module Shoulda
2
2
  module Matchers
3
3
  # @private
4
- VERSION = '5.1.0'.freeze
4
+ VERSION = '5.2.0'.freeze
5
5
  end
6
6
  end
@@ -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/master/CHANGELOG.md',
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.1.0
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: 2021-12-22 00:00:00.000000000 Z
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/master/CHANGELOG.md
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