active_storage_validations 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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