ultra-fast-box 0.0.1

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 (140) hide show
  1. checksums.yaml +7 -0
  2. data/shoulda-matchers-8.0.1/LICENSE +22 -0
  3. data/shoulda-matchers-8.0.1/README.md +567 -0
  4. data/shoulda-matchers-8.0.1/docs/errors/NonCaseSwappableValueError.md +111 -0
  5. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/callback_matcher.rb +121 -0
  6. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +70 -0
  7. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/flash_store.rb +86 -0
  8. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/permit_matcher.rb +445 -0
  9. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +96 -0
  10. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_template_matcher.rb +84 -0
  11. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +145 -0
  12. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +115 -0
  13. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +148 -0
  14. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_matcher.rb +207 -0
  15. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_params.rb +62 -0
  16. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
  17. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +228 -0
  18. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_matcher.rb +163 -0
  19. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +107 -0
  20. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller.rb +24 -0
  21. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
  22. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
  23. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +232 -0
  24. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
  25. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
  26. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
  27. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
  28. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
  29. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher.rb +695 -0
  30. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
  31. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +78 -0
  32. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/errors.rb +52 -0
  33. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +125 -0
  34. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/helpers.rb +37 -0
  35. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +45 -0
  36. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +67 -0
  37. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +45 -0
  38. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +44 -0
  39. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
  40. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +53 -0
  41. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  42. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
  43. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
  44. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
  45. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
  46. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers.rb +14 -0
  47. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +180 -0
  48. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +128 -0
  49. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +567 -0
  50. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +185 -0
  51. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +272 -0
  52. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +664 -0
  53. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +575 -0
  54. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +711 -0
  55. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +428 -0
  56. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +62 -0
  57. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher.rb +195 -0
  58. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_message_finder.rb +63 -0
  59. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validator.rb +127 -0
  60. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model.rb +96 -0
  61. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +217 -0
  62. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matcher.rb +2134 -0
  63. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +74 -0
  64. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +62 -0
  65. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -0
  66. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +105 -0
  67. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +101 -0
  68. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +89 -0
  69. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +142 -0
  70. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +71 -0
  71. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
  72. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +76 -0
  73. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +42 -0
  74. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +65 -0
  75. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  76. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +784 -0
  77. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
  78. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_attached_matcher.rb +343 -0
  79. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +366 -0
  80. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +287 -0
  81. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +104 -0
  82. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +95 -0
  83. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
  84. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
  85. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
  86. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/serialize_matcher.rb +203 -0
  87. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/model.rb +58 -0
  88. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/namespace.rb +39 -0
  89. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +49 -0
  90. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +55 -0
  91. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness.rb +14 -0
  92. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +1197 -0
  93. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record.rb +37 -0
  94. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/configuration.rb +31 -0
  95. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double.rb +103 -0
  96. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_collection.rb +60 -0
  97. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +31 -0
  98. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/method_call.rb +44 -0
  99. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/object_double.rb +43 -0
  100. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +32 -0
  101. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/stub_implementation.rb +31 -0
  102. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/world.rb +63 -0
  103. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak.rb +38 -0
  104. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/error.rb +29 -0
  105. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
  106. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher.rb +540 -0
  107. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent.rb +11 -0
  108. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration.rb +70 -0
  109. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
  110. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
  111. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/action_controller.rb +33 -0
  112. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
  113. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
  114. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
  115. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/rails.rb +31 -0
  116. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/routing.rb +29 -0
  117. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries.rb +16 -0
  118. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/rails.rb +12 -0
  119. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/registry.rb +28 -0
  120. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
  121. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
  122. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
  123. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
  124. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
  125. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
  126. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
  127. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations.rb +43 -0
  128. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_collection.rb +99 -0
  129. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_context.rb +36 -0
  130. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/rails_shim.rb +190 -0
  131. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/routing.rb +10 -0
  132. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util/word_wrap.rb +211 -0
  133. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util.rb +110 -0
  134. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/version.rb +6 -0
  135. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/warn.rb +28 -0
  136. data/shoulda-matchers-8.0.1/lib/shoulda/matchers.rb +25 -0
  137. data/shoulda-matchers-8.0.1/lib/shoulda-matchers.rb +1 -0
  138. data/shoulda-matchers-8.0.1/shoulda-matchers.gemspec +43 -0
  139. data/ultra-fast-box.gemspec +12 -0
  140. metadata +179 -0
@@ -0,0 +1,185 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ # The `validate_confirmation_of` matcher tests usage of the
5
+ # `validates_confirmation_of` validation.
6
+ #
7
+ # class User
8
+ # include ActiveModel::Model
9
+ # attr_accessor :email
10
+ #
11
+ # validates_confirmation_of :email
12
+ # end
13
+ #
14
+ # # RSpec
15
+ # RSpec.describe User, type: :model do
16
+ # it { should validate_confirmation_of(:email) }
17
+ # end
18
+ #
19
+ # # Minitest (Shoulda)
20
+ # class UserTest < ActiveSupport::TestCase
21
+ # should validate_confirmation_of(:email)
22
+ # end
23
+ #
24
+ # #### Qualifiers
25
+ #
26
+ # ##### on
27
+ #
28
+ # Use `on` if your validation applies only under a certain context.
29
+ #
30
+ # class User
31
+ # include ActiveModel::Model
32
+ # attr_accessor :password
33
+ #
34
+ # validates_confirmation_of :password, on: :create
35
+ # end
36
+ #
37
+ # # RSpec
38
+ # RSpec.describe User, type: :model do
39
+ # it { should validate_confirmation_of(:password).on(:create) }
40
+ # end
41
+ #
42
+ # # Minitest (Shoulda)
43
+ # class UserTest < ActiveSupport::TestCase
44
+ # should validate_confirmation_of(:password).on(:create)
45
+ # end
46
+ #
47
+ # ##### with_message
48
+ #
49
+ # Use `with_message` if you are using a custom validation message.
50
+ #
51
+ # class User
52
+ # include ActiveModel::Model
53
+ # attr_accessor :password
54
+ #
55
+ # validates_confirmation_of :password,
56
+ # message: 'Please re-enter your password'
57
+ # end
58
+ #
59
+ # # RSpec
60
+ # RSpec.describe User, type: :model do
61
+ # it do
62
+ # should validate_confirmation_of(:password).
63
+ # with_message('Please re-enter your password')
64
+ # end
65
+ # end
66
+ #
67
+ # # Minitest (Shoulda)
68
+ # class UserTest < ActiveSupport::TestCase
69
+ # should validate_confirmation_of(:password).
70
+ # with_message('Please re-enter your password')
71
+ # end
72
+ #
73
+ # #### Multiple attributes
74
+ #
75
+ # You can pass multiple attributes to assert that each one has the
76
+ # validation. Any qualifier chained on the matcher is applied to
77
+ # every attribute uniformly.
78
+ #
79
+ # class User
80
+ # include ActiveModel::Model
81
+ # attr_accessor :password, :password_confirmation, :email, :email_confirmation
82
+ #
83
+ # validates_confirmation_of :password, :email
84
+ # end
85
+ #
86
+ # # RSpec
87
+ # RSpec.describe User, type: :model do
88
+ # it { should validate_confirmation_of(:password, :email) }
89
+ # end
90
+ #
91
+ # # Minitest (Shoulda)
92
+ # class UserTest < ActiveSupport::TestCase
93
+ # should validate_confirmation_of(:password, :email)
94
+ # end
95
+ #
96
+ # @return [ValidateConfirmationOfMatcher]
97
+ #
98
+ def validate_confirmation_of(*attrs)
99
+ MatcherCollection.build(attrs) { |attr| ValidateConfirmationOfMatcher.new(attr) }
100
+ end
101
+
102
+ # @private
103
+ class ValidateConfirmationOfMatcher < ValidationMatcher
104
+ include Helpers
105
+
106
+ attr_reader :attribute, :confirmation_attribute
107
+
108
+ def initialize(attribute)
109
+ super
110
+ @expected_message = :confirmation
111
+ @confirmation_attribute = "#{attribute}_confirmation"
112
+ end
113
+
114
+ def simple_description
115
+ "validate that :#{@confirmation_attribute} matches :#{@attribute}"
116
+ end
117
+
118
+ def matches?(subject)
119
+ super(subject)
120
+
121
+ disallows_different_value &&
122
+ allows_same_value &&
123
+ allows_missing_confirmation
124
+ end
125
+
126
+ def does_not_match?(subject)
127
+ super(subject)
128
+
129
+ allows_different_value ||
130
+ disallows_same_value ||
131
+ disallows_missing_confirmation
132
+ end
133
+
134
+ private
135
+
136
+ def allows_different_value
137
+ allows_value_of('different value') do |matcher|
138
+ qualify_matcher(matcher, 'some value')
139
+ end
140
+ end
141
+
142
+ def disallows_different_value
143
+ disallows_value_of('different value') do |matcher|
144
+ qualify_matcher(matcher, 'some value')
145
+ end
146
+ end
147
+
148
+ def allows_same_value
149
+ allows_value_of('same value') do |matcher|
150
+ qualify_matcher(matcher, 'same value')
151
+ end
152
+ end
153
+
154
+ def disallows_same_value
155
+ disallows_value_of('same value') do |matcher|
156
+ qualify_matcher(matcher, 'same value')
157
+ end
158
+ end
159
+
160
+ def allows_missing_confirmation
161
+ allows_value_of('any value') do |matcher|
162
+ qualify_matcher(matcher, nil)
163
+ end
164
+ end
165
+
166
+ def disallows_missing_confirmation
167
+ disallows_value_of('any value') do |matcher|
168
+ qualify_matcher(matcher, nil)
169
+ end
170
+ end
171
+
172
+ def qualify_matcher(matcher, confirmation_attribute_value)
173
+ matcher.values_to_preset = {
174
+ confirmation_attribute => confirmation_attribute_value,
175
+ }
176
+ matcher.with_message(
177
+ @expected_message,
178
+ against: confirmation_attribute,
179
+ values: { attribute: },
180
+ )
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,272 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ # The `validate_exclusion_of` matcher tests usage of the
5
+ # `validates_exclusion_of` validation, asserting that an attribute cannot
6
+ # take a blocklist of values, and inversely, can take values outside of
7
+ # this list.
8
+ #
9
+ # If your blocklist an array of values, use `in_array`:
10
+ #
11
+ # class Game
12
+ # include ActiveModel::Model
13
+ # attr_accessor :supported_os
14
+ #
15
+ # validates_exclusion_of :supported_os, in: ['Mac', 'Linux']
16
+ # end
17
+ #
18
+ # # RSpec
19
+ # RSpec.describe Game, type: :model do
20
+ # it do
21
+ # should validate_exclusion_of(:supported_os).
22
+ # in_array(['Mac', 'Linux'])
23
+ # end
24
+ # end
25
+ #
26
+ # # Minitest (Shoulda)
27
+ # class GameTest < ActiveSupport::TestCase
28
+ # should validate_exclusion_of(:supported_os).
29
+ # in_array(['Mac', 'Linux'])
30
+ # end
31
+ #
32
+ # If your blocklist is a range of values, use `in_range`:
33
+ #
34
+ # class Game
35
+ # include ActiveModel::Model
36
+ # attr_accessor :floors_with_enemies
37
+ #
38
+ # validates_exclusion_of :floors_with_enemies, in: 5..8
39
+ # end
40
+ #
41
+ # # RSpec
42
+ # RSpec.describe Game, type: :model do
43
+ # it do
44
+ # should validate_exclusion_of(:floors_with_enemies).
45
+ # in_range(5..8)
46
+ # end
47
+ # end
48
+ #
49
+ # # Minitest (Shoulda)
50
+ # class GameTest < ActiveSupport::TestCase
51
+ # should validate_exclusion_of(:floors_with_enemies).
52
+ # in_range(5..8)
53
+ # end
54
+ #
55
+ # #### Qualifiers
56
+ #
57
+ # ##### on
58
+ #
59
+ # Use `on` if your validation applies only under a certain context.
60
+ #
61
+ # class Game
62
+ # include ActiveModel::Model
63
+ # attr_accessor :weapon
64
+ #
65
+ # validates_exclusion_of :weapon,
66
+ # in: ['pistol', 'paintball gun', 'stick'],
67
+ # on: :create
68
+ # end
69
+ #
70
+ # # RSpec
71
+ # RSpec.describe Game, type: :model do
72
+ # it do
73
+ # should validate_exclusion_of(:weapon).
74
+ # in_array(['pistol', 'paintball gun', 'stick']).
75
+ # on(:create)
76
+ # end
77
+ # end
78
+ #
79
+ # # Minitest (Shoulda)
80
+ # class GameTest < ActiveSupport::TestCase
81
+ # should validate_exclusion_of(:weapon).
82
+ # in_array(['pistol', 'paintball gun', 'stick']).
83
+ # on(:create)
84
+ # end
85
+ #
86
+ # ##### with_message
87
+ #
88
+ # Use `with_message` if you are using a custom validation message.
89
+ #
90
+ # class Game
91
+ # include ActiveModel::Model
92
+ # attr_accessor :weapon
93
+ #
94
+ # validates_exclusion_of :weapon,
95
+ # in: ['pistol', 'paintball gun', 'stick'],
96
+ # message: 'You chose a puny weapon'
97
+ # end
98
+ #
99
+ # # RSpec
100
+ # RSpec.describe Game, type: :model do
101
+ # it do
102
+ # should validate_exclusion_of(:weapon).
103
+ # in_array(['pistol', 'paintball gun', 'stick']).
104
+ # with_message('You chose a puny weapon')
105
+ # end
106
+ # end
107
+ #
108
+ # # Minitest (Shoulda)
109
+ # class GameTest < ActiveSupport::TestCase
110
+ # should validate_exclusion_of(:weapon).
111
+ # in_array(['pistol', 'paintball gun', 'stick']).
112
+ # with_message('You chose a puny weapon')
113
+ # end
114
+ #
115
+ # #### Multiple attributes
116
+ #
117
+ # You can pass multiple attributes to assert that each one has the
118
+ # validation. Any qualifier chained on the matcher is applied to
119
+ # every attribute uniformly.
120
+ #
121
+ # class Article
122
+ # include ActiveModel::Model
123
+ # attr_accessor :slug, :handle
124
+ #
125
+ # validates_exclusion_of :slug, :handle, in: %w[admin root]
126
+ # end
127
+ #
128
+ # # RSpec
129
+ # RSpec.describe Article, type: :model do
130
+ # it { should validate_exclusion_of(:slug, :handle).in_array(%w[admin root]) }
131
+ # end
132
+ #
133
+ # # Minitest (Shoulda)
134
+ # class ArticleTest < ActiveSupport::TestCase
135
+ # should validate_exclusion_of(:slug, :handle).in_array(%w[admin root])
136
+ # end
137
+ #
138
+ # @return [ValidateExclusionOfMatcher]
139
+ #
140
+ def validate_exclusion_of(*attrs)
141
+ MatcherCollection.build(attrs) { |attr| ValidateExclusionOfMatcher.new(attr) }
142
+ end
143
+
144
+ # @private
145
+ class ValidateExclusionOfMatcher < ValidationMatcher
146
+ def initialize(attribute)
147
+ super(attribute)
148
+ @expected_message = :exclusion
149
+ @array = nil
150
+ @range = nil
151
+ end
152
+
153
+ def in_array(array)
154
+ @array = array
155
+ self
156
+ end
157
+
158
+ def in_range(range)
159
+ @range = range
160
+ @minimum = range.first
161
+ @maximum = range.max
162
+ self
163
+ end
164
+
165
+ def simple_description
166
+ if @range
167
+ "validate that :#{@attribute} lies outside the range " +
168
+ Shoulda::Matchers::Util.inspect_range(@range)
169
+ else
170
+ description = "validate that :#{@attribute}"
171
+
172
+ description <<
173
+ if @array.many?
174
+ " is neither #{inspected_array}"
175
+ else
176
+ " is not #{inspected_array}"
177
+ end
178
+
179
+ description
180
+ end
181
+ end
182
+
183
+ def matches?(subject)
184
+ super(subject)
185
+
186
+ if @range
187
+ allows_lower_value &&
188
+ disallows_minimum_value &&
189
+ disallows_maximum_value &&
190
+ allows_higher_value
191
+ elsif @array
192
+ disallows_all_values_in_array?
193
+ end
194
+ end
195
+
196
+ def does_not_match?(subject)
197
+ super(subject)
198
+
199
+ if @range
200
+ disallows_lower_value ||
201
+ allows_minimum_value ||
202
+ allows_maximum_value ||
203
+ disallows_higher_value
204
+ elsif @array
205
+ allows_any_values_in_array?
206
+ end
207
+ end
208
+
209
+ private
210
+
211
+ def allows_any_values_in_array?
212
+ @array.any? do |value|
213
+ allows_value_of(value, @expected_message)
214
+ end
215
+ end
216
+
217
+ def disallows_all_values_in_array?
218
+ @array.all? do |value|
219
+ disallows_value_of(value, @expected_message)
220
+ end
221
+ end
222
+
223
+ def allows_lower_value
224
+ @minimum == 0 || allows_value_of(@minimum - 1, @expected_message)
225
+ end
226
+
227
+ def disallows_lower_value
228
+ @minimum != 0 && disallows_value_of(@minimum - 1, @expected_message)
229
+ end
230
+
231
+ def allows_minimum_value
232
+ allows_value_of(@minimum, @expected_message)
233
+ end
234
+
235
+ def disallows_minimum_value
236
+ disallows_value_of(@minimum, @expected_message)
237
+ end
238
+
239
+ def allows_maximum_value
240
+ allows_value_of(@maximum, @expected_message)
241
+ end
242
+
243
+ def disallows_maximum_value
244
+ disallows_value_of(@maximum, @expected_message)
245
+ end
246
+
247
+ def allows_higher_value
248
+ allows_value_of(@maximum + 1, @expected_message)
249
+ end
250
+
251
+ def disallows_higher_value
252
+ disallows_value_of(@maximum + 1, @expected_message)
253
+ end
254
+
255
+ def inspect_message
256
+ if @range
257
+ @range.inspect
258
+ else
259
+ @array.inspect
260
+ end
261
+ end
262
+
263
+ def inspected_array
264
+ Shoulda::Matchers::Util.inspect_values(@array).to_sentence(
265
+ two_words_connector: ' nor ',
266
+ last_word_connector: ', nor ',
267
+ )
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end