active_storage_validations 1.1.4 → 1.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +56 -18
  3. data/config/locales/da.yml +33 -0
  4. data/config/locales/de.yml +5 -0
  5. data/config/locales/en.yml +5 -0
  6. data/config/locales/es.yml +5 -0
  7. data/config/locales/fr.yml +5 -0
  8. data/config/locales/it.yml +5 -0
  9. data/config/locales/ja.yml +5 -0
  10. data/config/locales/nl.yml +5 -0
  11. data/config/locales/pl.yml +5 -0
  12. data/config/locales/pt-BR.yml +5 -0
  13. data/config/locales/ru.yml +5 -0
  14. data/config/locales/sv.yml +10 -1
  15. data/config/locales/tr.yml +5 -0
  16. data/config/locales/uk.yml +5 -0
  17. data/config/locales/vi.yml +5 -0
  18. data/config/locales/zh-CN.yml +5 -0
  19. data/lib/active_storage_validations/attached_validator.rb +3 -3
  20. data/lib/active_storage_validations/base_size_validator.rb +66 -0
  21. data/lib/active_storage_validations/concerns/errorable.rb +2 -2
  22. data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +6 -15
  23. data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +5 -13
  24. data/lib/active_storage_validations/matchers/base_size_validator_matcher.rb +134 -0
  25. data/lib/active_storage_validations/matchers/concerns/attachable.rb +48 -0
  26. data/lib/active_storage_validations/matchers/concerns/contextable.rb +20 -8
  27. data/lib/active_storage_validations/matchers/concerns/validatable.rb +9 -3
  28. data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +5 -2
  29. data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +6 -15
  30. data/lib/active_storage_validations/matchers/processable_image_validator_matcher.rb +78 -0
  31. data/lib/active_storage_validations/matchers/size_validator_matcher.rb +4 -139
  32. data/lib/active_storage_validations/matchers/total_size_validator_matcher.rb +40 -0
  33. data/lib/active_storage_validations/matchers.rb +2 -0
  34. data/lib/active_storage_validations/metadata.rb +20 -2
  35. data/lib/active_storage_validations/size_validator.rb +4 -49
  36. data/lib/active_storage_validations/total_size_validator.rb +49 -0
  37. data/lib/active_storage_validations/version.rb +1 -1
  38. data/lib/active_storage_validations.rb +2 -1
  39. metadata +31 -38
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'concerns/active_storageable.rb'
4
+ require_relative 'concerns/attachable.rb'
4
5
  require_relative 'concerns/contextable.rb'
5
6
  require_relative 'concerns/messageable.rb'
6
7
  require_relative 'concerns/rspecable.rb'
@@ -8,12 +9,13 @@ require_relative 'concerns/validatable.rb'
8
9
 
9
10
  module ActiveStorageValidations
10
11
  module Matchers
11
- def validate_attached_of(name)
12
- AttachedValidatorMatcher.new(name)
12
+ def validate_attached_of(attribute_name)
13
+ AttachedValidatorMatcher.new(attribute_name)
13
14
  end
14
15
 
15
16
  class AttachedValidatorMatcher
16
17
  include ActiveStorageable
18
+ include Attachable
17
19
  include Contextable
18
20
  include Messageable
19
21
  include Rspecable
@@ -47,7 +49,7 @@ module ActiveStorageValidations
47
49
  private
48
50
 
49
51
  def is_valid_when_file_attached?
50
- attach_dummy_file unless file_attached?
52
+ attach_file unless file_attached?
51
53
  validate
52
54
  is_valid?
53
55
  end
@@ -66,16 +68,6 @@ module ActiveStorageValidations
66
68
  has_an_error_message_which_is_custom_message?
67
69
  end
68
70
 
69
- def attach_dummy_file
70
- dummy_file = {
71
- io: Tempfile.new('.'),
72
- filename: 'dummy.txt',
73
- content_type: 'text/plain'
74
- }
75
-
76
- @subject.public_send(@attribute_name).attach(dummy_file)
77
- end
78
-
79
71
  def file_attached?
80
72
  @subject.public_send(@attribute_name).attached?
81
73
  end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Big thank you to the paperclip validation matchers:
4
+ # https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_size_matcher.rb
5
+
6
+ require_relative 'concerns/active_storageable.rb'
7
+ require_relative 'concerns/allow_blankable.rb'
8
+ require_relative 'concerns/attachable.rb'
9
+ require_relative 'concerns/contextable.rb'
10
+ require_relative 'concerns/messageable.rb'
11
+ require_relative 'concerns/rspecable.rb'
12
+ require_relative 'concerns/validatable.rb'
13
+
14
+ module ActiveStorageValidations
15
+ module Matchers
16
+ class BaseSizeValidatorMatcher
17
+ # BaseSizeValidatorMatcher is an abstract class and shouldn't be instantiated directly.
18
+
19
+ include ActiveStorageable
20
+ include AllowBlankable
21
+ include Attachable
22
+ include Contextable
23
+ include Messageable
24
+ include Rspecable
25
+ include Validatable
26
+
27
+ def initialize(attribute_name)
28
+ initialize_allow_blankable
29
+ initialize_contextable
30
+ initialize_messageable
31
+ initialize_rspecable
32
+ @attribute_name = attribute_name
33
+ @min = @max = nil
34
+ end
35
+
36
+ def less_than(size)
37
+ @max = size - 1.byte
38
+ self
39
+ end
40
+
41
+ def less_than_or_equal_to(size)
42
+ @max = size
43
+ self
44
+ end
45
+
46
+ def greater_than(size)
47
+ @min = size + 1.byte
48
+ self
49
+ end
50
+
51
+ def greater_than_or_equal_to(size)
52
+ @min = size
53
+ self
54
+ end
55
+
56
+ def between(range)
57
+ @min, @max = range.first, range.last
58
+ self
59
+ end
60
+
61
+ def matches?(subject)
62
+ @subject = subject.is_a?(Class) ? subject.new : subject
63
+
64
+ is_a_valid_active_storage_attribute? &&
65
+ is_context_valid? &&
66
+ is_allowing_blank? &&
67
+ is_custom_message_valid? &&
68
+ not_lower_than_min? &&
69
+ higher_than_min? &&
70
+ lower_than_max? &&
71
+ not_higher_than_max?
72
+ end
73
+
74
+ protected
75
+
76
+ def build_failure_message(message)
77
+ return unless @failure_message_artefacts.present?
78
+
79
+ message << " but there seem to have issues with the matcher methods you used, since:"
80
+ @failure_message_artefacts.each do |error_case|
81
+ message << " validation failed when provided with a #{error_case[:size]} bytes test file"
82
+ end
83
+ message << " whereas it should have passed"
84
+ end
85
+
86
+ def not_lower_than_min?
87
+ @min.nil? || !passes_validation_with_size(@min - 1)
88
+ end
89
+
90
+ def higher_than_min?
91
+ @min.nil? || passes_validation_with_size(@min + 1)
92
+ end
93
+
94
+ def lower_than_max?
95
+ @max.nil? || @max == Float::INFINITY || passes_validation_with_size(@max - 1)
96
+ end
97
+
98
+ def not_higher_than_max?
99
+ @max.nil? || @max == Float::INFINITY || !passes_validation_with_size(@max + 1)
100
+ end
101
+
102
+ def passes_validation_with_size(size)
103
+ mock_size_for(io, size) do
104
+ attach_file
105
+ validate
106
+ detach_file
107
+ is_valid? || add_failure_message_artefact(size)
108
+ end
109
+ end
110
+
111
+ def add_failure_message_artefact(size)
112
+ @failure_message_artefacts << { size: size }
113
+ false
114
+ end
115
+
116
+ def is_custom_message_valid?
117
+ return true unless @custom_message
118
+
119
+ mock_size_for(io, -1.kilobytes) do
120
+ attach_file
121
+ validate
122
+ detach_file
123
+ has_an_error_message_which_is_custom_message?
124
+ end
125
+ end
126
+
127
+ def mock_size_for(io, size)
128
+ Matchers.stub_method(io, :size, size) do
129
+ yield
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,48 @@
1
+ module ActiveStorageValidations
2
+ module Matchers
3
+ module Attachable
4
+ private
5
+
6
+ def attach_file(file = dummy_file)
7
+ @subject.public_send(@attribute_name).attach(file)
8
+ @subject.public_send(@attribute_name)
9
+ end
10
+
11
+ def dummy_file
12
+ {
13
+ io: io,
14
+ filename: 'test.png',
15
+ content_type: 'image/png'
16
+ }
17
+ end
18
+
19
+ def processable_image
20
+ {
21
+ io: File.open(Rails.root.join('public', 'image_1920x1080.png')),
22
+ filename: 'image_1920x1080_file.png',
23
+ content_type: 'image/png'
24
+ }
25
+ end
26
+
27
+ def not_processable_image
28
+ {
29
+ io: Tempfile.new('.'),
30
+ filename: 'processable.txt',
31
+ content_type: 'text/plain'
32
+ }
33
+ end
34
+
35
+ def io
36
+ @io ||= Tempfile.new('Hello world!')
37
+ end
38
+
39
+ def detach_file
40
+ @subject.attachment_changes.delete(@attribute_name.to_s)
41
+ end
42
+
43
+ def file_attached?
44
+ @subject.public_send(@attribute_name).attached?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -17,19 +17,31 @@ module ActiveStorageValidations
17
17
  private
18
18
 
19
19
  def is_context_valid?
20
- return true if !@context && !(attribute_validator && attribute_validator.options[:on])
20
+ return true if !@context && attribute_validators.none? { |validator| validator.options[:on] }
21
21
 
22
- raise ArgumentError, "This validator matcher needs the #on option to work since its validator has one" if !@context
22
+ raise ArgumentError, "This validator matcher needs the #on option to work since its validator has one" if !@context && attribute_validators.all? { |validator| validator.options[:on] }
23
23
  raise ArgumentError, "This validator matcher option only allows a symbol or an array" if !(@context.is_a?(Symbol) || @context.is_a?(Array))
24
24
 
25
- if @context.is_a?(Array) && attribute_validator.options[:on].is_a?(Array)
26
- @context.to_set == attribute_validator.options[:on].to_set
27
- elsif @context.is_a?(Symbol) && attribute_validator.options[:on].is_a?(Symbol)
28
- @context == attribute_validator.options[:on]
29
- else
30
- false
25
+ if @context.is_a?(Array)
26
+ (validator_contexts & @context.map(&:to_s)) == validator_contexts || raise_context_not_listed_error
27
+ elsif @context.is_a?(Symbol)
28
+ validator_contexts.include?(@context.to_s) || raise_context_not_listed_error
31
29
  end
32
30
  end
31
+
32
+ def validator_contexts
33
+ attribute_validators.map do |validator|
34
+ case validator.options[:on]
35
+ when Array then validator.options[:on].map { |context| context.to_s }
36
+ when NilClass then nil
37
+ else validator.options[:on].to_s
38
+ end
39
+ end.flatten.compact
40
+ end
41
+
42
+ def raise_context_not_listed_error
43
+ raise ArgumentError, "One of the provided contexts to the #on method is not found in any of the listed contexts for this attribute"
44
+ end
33
45
  end
34
46
  end
35
47
  end
@@ -26,7 +26,7 @@ module ActiveStorageValidations
26
26
  def available_errors
27
27
  [
28
28
  *validator_class::ERROR_TYPES,
29
- *error_from_custom_message
29
+ *errors_from_custom_messages
30
30
  ].compact
31
31
  end
32
32
 
@@ -40,8 +40,14 @@ module ActiveStorageValidations
40
40
  end
41
41
  end
42
42
 
43
- def error_from_custom_message
44
- attribute_validator.options[:message]
43
+ def attribute_validators
44
+ @subject.class.validators_on(@attribute_name).select do |validator|
45
+ validator.class == validator_class
46
+ end
47
+ end
48
+
49
+ def errors_from_custom_messages
50
+ attribute_validators.map { |validator| validator.options[:message] }
45
51
  end
46
52
  end
47
53
  end
@@ -5,6 +5,7 @@
5
5
 
6
6
  require_relative 'concerns/active_storageable.rb'
7
7
  require_relative 'concerns/allow_blankable.rb'
8
+ require_relative 'concerns/attachable.rb'
8
9
  require_relative 'concerns/contextable.rb'
9
10
  require_relative 'concerns/messageable.rb'
10
11
  require_relative 'concerns/rspecable.rb'
@@ -12,13 +13,14 @@ require_relative 'concerns/validatable.rb'
12
13
 
13
14
  module ActiveStorageValidations
14
15
  module Matchers
15
- def validate_content_type_of(name)
16
- ContentTypeValidatorMatcher.new(name)
16
+ def validate_content_type_of(attribute_name)
17
+ ContentTypeValidatorMatcher.new(attribute_name)
17
18
  end
18
19
 
19
20
  class ContentTypeValidatorMatcher
20
21
  include ActiveStorageable
21
22
  include AllowBlankable
23
+ include Attachable
22
24
  include Contextable
23
25
  include Messageable
24
26
  include Rspecable
@@ -99,6 +101,7 @@ module ActiveStorageValidations
99
101
  def type_allowed?(type)
100
102
  attach_file_of_type(type)
101
103
  validate
104
+ detach_file
102
105
  is_valid?
103
106
  end
104
107
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'concerns/active_storageable.rb'
4
4
  require_relative 'concerns/allow_blankable.rb'
5
+ require_relative 'concerns/attachable'
5
6
  require_relative 'concerns/contextable.rb'
6
7
  require_relative 'concerns/messageable.rb'
7
8
  require_relative 'concerns/rspecable.rb'
@@ -9,13 +10,14 @@ require_relative 'concerns/validatable.rb'
9
10
 
10
11
  module ActiveStorageValidations
11
12
  module Matchers
12
- def validate_dimensions_of(name)
13
- DimensionValidatorMatcher.new(name)
13
+ def validate_dimensions_of(attribute_name)
14
+ DimensionValidatorMatcher.new(attribute_name)
14
15
  end
15
16
 
16
17
  class DimensionValidatorMatcher
17
18
  include ActiveStorageable
18
19
  include AllowBlankable
20
+ include Attachable
19
21
  include Contextable
20
22
  include Messageable
21
23
  include Rspecable
@@ -162,6 +164,7 @@ module ActiveStorageValidations
162
164
  def passes_validation_with_dimensions(width, height)
163
165
  mock_dimensions_for(attach_file, width, height) do
164
166
  validate
167
+ detach_file
165
168
  is_valid? || add_failure_message_artefact(width, height)
166
169
  end
167
170
  end
@@ -176,6 +179,7 @@ module ActiveStorageValidations
176
179
 
177
180
  mock_dimensions_for(attach_file, -1, -1) do
178
181
  validate
182
+ detach_file
179
183
  has_an_error_message_which_is_custom_message?
180
184
  end
181
185
  end
@@ -185,19 +189,6 @@ module ActiveStorageValidations
185
189
  yield
186
190
  end
187
191
  end
188
-
189
- def attach_file
190
- @subject.public_send(@attribute_name).attach(dummy_file)
191
- @subject.public_send(@attribute_name)
192
- end
193
-
194
- def dummy_file
195
- {
196
- io: Tempfile.new('Hello world!'),
197
- filename: 'test.png',
198
- content_type: 'image/png'
199
- }
200
- end
201
192
  end
202
193
  end
203
194
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'concerns/active_storageable.rb'
4
+ require_relative 'concerns/allow_blankable.rb'
5
+ require_relative 'concerns/attachable.rb'
6
+ require_relative 'concerns/contextable.rb'
7
+ require_relative 'concerns/messageable.rb'
8
+ require_relative 'concerns/rspecable.rb'
9
+ require_relative 'concerns/validatable.rb'
10
+
11
+ module ActiveStorageValidations
12
+ module Matchers
13
+ def validate_processable_image_of(name)
14
+ ProcessableImageValidatorMatcher.new(name)
15
+ end
16
+
17
+ class ProcessableImageValidatorMatcher
18
+ include ActiveStorageable
19
+ include AllowBlankable
20
+ include Attachable
21
+ include Contextable
22
+ include Messageable
23
+ include Rspecable
24
+ include Validatable
25
+
26
+ def initialize(attribute_name)
27
+ initialize_allow_blankable
28
+ initialize_contextable
29
+ initialize_messageable
30
+ initialize_rspecable
31
+ @attribute_name = attribute_name
32
+ end
33
+
34
+ def description
35
+ "validate that :#{@attribute_name} is a processable image"
36
+ end
37
+
38
+ def failure_message
39
+ "is expected to validate the processable image of :#{@attribute_name}"
40
+ end
41
+
42
+ def matches?(subject)
43
+ @subject = subject.is_a?(Class) ? subject.new : subject
44
+
45
+ is_a_valid_active_storage_attribute? &&
46
+ is_context_valid? &&
47
+ is_custom_message_valid? &&
48
+ is_valid_when_image_processable? &&
49
+ is_invalid_when_image_not_processable?
50
+ end
51
+
52
+ private
53
+
54
+ def is_valid_when_image_processable?
55
+ attach_file(processable_image)
56
+ validate
57
+ detach_file
58
+ is_valid?
59
+ end
60
+
61
+ def is_invalid_when_image_not_processable?
62
+ attach_file(not_processable_image)
63
+ validate
64
+ detach_file
65
+ !is_valid?
66
+ end
67
+
68
+ def is_custom_message_valid?
69
+ return true unless @custom_message
70
+
71
+ attach_file(not_processable_image)
72
+ validate
73
+ detach_file
74
+ has_an_error_message_which_is_custom_message?
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,38 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Big thank you to the paperclip validation matchers:
4
- # https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_size_matcher.rb
5
-
6
- require_relative 'concerns/active_storageable.rb'
7
- require_relative 'concerns/allow_blankable.rb'
8
- require_relative 'concerns/contextable.rb'
9
- require_relative 'concerns/messageable.rb'
10
- require_relative 'concerns/rspecable.rb'
11
- require_relative 'concerns/validatable.rb'
3
+ require_relative 'base_size_validator_matcher'
12
4
 
13
5
  module ActiveStorageValidations
14
6
  module Matchers
15
- def validate_size_of(name)
16
- SizeValidatorMatcher.new(name)
7
+ def validate_size_of(attribute_name)
8
+ SizeValidatorMatcher.new(attribute_name)
17
9
  end
18
10
 
19
- class SizeValidatorMatcher
20
- include ActiveStorageable
21
- include AllowBlankable
22
- include Contextable
23
- include Messageable
24
- include Rspecable
25
- include Validatable
26
-
27
- def initialize(attribute_name)
28
- initialize_allow_blankable
29
- initialize_contextable
30
- initialize_messageable
31
- initialize_rspecable
32
- @attribute_name = attribute_name
33
- @min = @max = nil
34
- end
35
-
11
+ class SizeValidatorMatcher < BaseSizeValidatorMatcher
36
12
  def description
37
13
  "validate file size of :#{@attribute_name}"
38
14
  end
@@ -42,117 +18,6 @@ module ActiveStorageValidations
42
18
  build_failure_message(message)
43
19
  message.join("\n")
44
20
  end
45
-
46
- def less_than(size)
47
- @max = size - 1.byte
48
- self
49
- end
50
-
51
- def less_than_or_equal_to(size)
52
- @max = size
53
- self
54
- end
55
-
56
- def greater_than(size)
57
- @min = size + 1.byte
58
- self
59
- end
60
-
61
- def greater_than_or_equal_to(size)
62
- @min = size
63
- self
64
- end
65
-
66
- def between(range)
67
- @min, @max = range.first, range.last
68
- self
69
- end
70
-
71
- def matches?(subject)
72
- @subject = subject.is_a?(Class) ? subject.new : subject
73
-
74
- is_a_valid_active_storage_attribute? &&
75
- is_context_valid? &&
76
- is_allowing_blank? &&
77
- is_custom_message_valid? &&
78
- not_lower_than_min? &&
79
- higher_than_min? &&
80
- lower_than_max? &&
81
- not_higher_than_max?
82
- end
83
-
84
- protected
85
-
86
- def build_failure_message(message)
87
- return unless @failure_message_artefacts.present?
88
-
89
- message << " but there seem to have issues with the matcher methods you used, since:"
90
- @failure_message_artefacts.each do |error_case|
91
- message << " validation failed when provided with a #{error_case[:size]} bytes test file"
92
- end
93
- message << " whereas it should have passed"
94
- end
95
-
96
- def not_lower_than_min?
97
- @min.nil? || !passes_validation_with_size(@min - 1)
98
- end
99
-
100
- def higher_than_min?
101
- @min.nil? || passes_validation_with_size(@min + 1)
102
- end
103
-
104
- def lower_than_max?
105
- @max.nil? || @max == Float::INFINITY || passes_validation_with_size(@max - 1)
106
- end
107
-
108
- def not_higher_than_max?
109
- @max.nil? || @max == Float::INFINITY || !passes_validation_with_size(@max + 1)
110
- end
111
-
112
- def passes_validation_with_size(size)
113
- mock_size_for(io, size) do
114
- attach_file
115
- validate
116
- is_valid? || add_failure_message_artefact(size)
117
- end
118
- end
119
-
120
- def add_failure_message_artefact(size)
121
- @failure_message_artefacts << { size: size }
122
- false
123
- end
124
-
125
- def is_custom_message_valid?
126
- return true unless @custom_message
127
-
128
- mock_size_for(io, -1.kilobytes) do
129
- attach_file
130
- validate
131
- has_an_error_message_which_is_custom_message?
132
- end
133
- end
134
-
135
- def mock_size_for(io, size)
136
- Matchers.stub_method(io, :size, size) do
137
- yield
138
- end
139
- end
140
-
141
- def attach_file
142
- @subject.public_send(@attribute_name).attach(dummy_file)
143
- end
144
-
145
- def dummy_file
146
- {
147
- io: io,
148
- filename: 'test.png',
149
- content_type: 'image/png'
150
- }
151
- end
152
-
153
- def io
154
- @io ||= Tempfile.new('Hello world!')
155
- end
156
21
  end
157
22
  end
158
23
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_size_validator_matcher'
4
+
5
+ module ActiveStorageValidations
6
+ module Matchers
7
+ def validate_total_size_of(attribute_name)
8
+ TotalSizeValidatorMatcher.new(attribute_name)
9
+ end
10
+
11
+ class TotalSizeValidatorMatcher < BaseSizeValidatorMatcher
12
+ def description
13
+ "validate total file size of :#{@attribute_name}"
14
+ end
15
+
16
+ def failure_message
17
+ message = ["is expected to validate total file size of :#{@attribute_name}"]
18
+ build_failure_message(message)
19
+ message.join("\n")
20
+ end
21
+
22
+ protected
23
+
24
+ def attach_file
25
+ # We attach blobs instead of io for has_many_attached relation
26
+ @subject.public_send(@attribute_name).attach([dummy_blob])
27
+ @subject.public_send(@attribute_name)
28
+ end
29
+
30
+ def dummy_blob
31
+ ActiveStorage::Blob.create_and_upload!(
32
+ io: io,
33
+ filename: 'test.png',
34
+ content_type: 'image/png',
35
+ service_name: 'test'
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,9 +2,11 @@
2
2
 
3
3
  require 'active_storage_validations/matchers/aspect_ratio_validator_matcher'
4
4
  require 'active_storage_validations/matchers/attached_validator_matcher'
5
+ require 'active_storage_validations/matchers/processable_image_validator_matcher'
5
6
  require 'active_storage_validations/matchers/content_type_validator_matcher'
6
7
  require 'active_storage_validations/matchers/dimension_validator_matcher'
7
8
  require 'active_storage_validations/matchers/size_validator_matcher'
9
+ require 'active_storage_validations/matchers/total_size_validator_matcher'
8
10
 
9
11
  module ActiveStorageValidations
10
12
  module Matchers