active_storage_validations 0.9.5 → 0.9.8

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: efa69aeeea1b171286c6ca464e38146dedef79d22853c35ec6ea0ce0ca089812
4
- data.tar.gz: e186561942afb6b295839565323d0bbed704de9e413b79ecc1fb194ada643ca5
3
+ metadata.gz: c9b366848f85ac520038a9efe0bee0514338f4d28b8f292ef87ad06d1ee0da28
4
+ data.tar.gz: 651195be6d5d23bf20c4600656e799005e3e1fc118ac21cc5fe023b24f43ae73
5
5
  SHA512:
6
- metadata.gz: c31ec657e1121427f19d7617d5efbeab639c6ebd87c0333c36510064e7b4d8125ffd8e4f5afa86121e626dd608d2ad1b859a3515c8bc7683e0793291a30c7fd2
7
- data.tar.gz: 3141abc08b6b33d90f9874a74e93f6aaddb0ebbd52bdd36ee292a1e0ff7d37cf65a8ced082d316f48cc8e0132320c4f83304d9823971906526096264129c0145
6
+ metadata.gz: f6231454bce1c4b09bf4dba3a83238f09b3fa0593c0c04146342ac6dd035048f890edcb594d24747f9d5e55d5ef86a35eba7fa93b109f101906b0f5b4f373c06
7
+ data.tar.gz: 6a5a9a0abd3f7abbddd92d8f1e5601859bbcc06e17f049046e5c9e2744760aa4fd7fa77462c22fb8d076cc4aef801e9b814a6b8663edb08e9c32a497ec041908
data/README.md CHANGED
@@ -26,16 +26,17 @@ For example you have a model like this and you want to add validation.
26
26
  class User < ApplicationRecord
27
27
  has_one_attached :avatar
28
28
  has_many_attached :photos
29
+ has_one_attached :image
29
30
 
30
31
  validates :name, presence: true
31
32
 
32
33
  validates :avatar, attached: true, content_type: 'image/png',
33
34
  dimension: { width: 200, height: 200 }
34
- validates :photos, attached: true, content_type: ['image/png', 'image/jpg', 'image/jpeg'],
35
+ validates :photos, attached: true, content_type: ['image/png', 'image/jpeg'],
35
36
  dimension: { width: { min: 800, max: 2400 },
36
37
  height: { min: 600, max: 1800 }, message: 'is not given between dimension' }
37
38
  validates :image, attached: true,
38
- content_type: ['image/png', 'image/jpg'],
39
+ content_type: ['image/png', 'image/jpeg'],
39
40
  aspect_ratio: :landscape
40
41
  end
41
42
  ```
@@ -44,13 +45,15 @@ or
44
45
 
45
46
  ```ruby
46
47
  class Project < ApplicationRecord
48
+ has_one_attached :logo
47
49
  has_one_attached :preview
48
50
  has_one_attached :attachment
49
51
  has_many_attached :documents
50
52
 
51
53
  validates :title, presence: true
52
54
 
53
- validates :preview, attached: true, size: { less_than: 100.megabytes , message: 'is not given between size' }
55
+ validates :logo, attached: true, size: { less_than: 100.megabytes , message: 'is too large' }
56
+ validates :preview, attached: true, size: { between: 1.kilobyte..100.megabytes , message: 'is not given between size' }
54
57
  validates :attachment, attached: true, content_type: { in: 'application/pdf', message: 'is not a PDF' }
55
58
  validates :documents, limit: { min: 1, max: 3 }
56
59
  end
@@ -58,14 +61,15 @@ end
58
61
 
59
62
  ### More examples
60
63
 
61
- - Content type validation using symbols. In order to infer the correct mime type from the symbol, the types must be registered with `MimeMagic::EXTENSIONS`.
64
+ - Content type validation using symbols. In order to infer the correct mime type from the symbol, the types must be registered with `Marcel::EXTENSIONS` (`MimeMagic::EXTENSIONS` for Rails <= 6.1.3).
62
65
 
63
66
  ```ruby
64
67
  class User < ApplicationRecord
65
68
  has_one_attached :avatar
66
69
  has_many_attached :photos
67
70
 
68
- validates :avatar, attached: true, content_type: :png # MimeMagic.by_extension(:png).to_s => 'image/png'
71
+ validates :avatar, attached: true, content_type: :png # Marcel::Magic.by_extension(:png).to_s => 'image/png'
72
+ # Rails <= 6.1.3; MimeMagic.by_extension(:png).to_s => 'image/png'
69
73
  # or
70
74
  validates :photos, attached: true, content_type: [:png, :jpg, :jpeg]
71
75
  # or
@@ -176,6 +180,8 @@ gem 'active_storage_validations'
176
180
 
177
181
  # Optional, to use :dimension validator or :aspect_ratio validator
178
182
  gem 'mini_magick', '>= 4.9.5'
183
+ # Or
184
+ gem 'ruby-vips', '>= 2.1.0'
179
185
  ```
180
186
 
181
187
  And then execute:
@@ -292,6 +298,22 @@ To run tests in root folder of gem:
292
298
  * `BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake test` to run for Rails 5.2
293
299
  * `BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake test` to run for Rails 6.0
294
300
  * `BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle exec rake test` to run for Rails 6.1
301
+ * `BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test` to run for Rails main branch
302
+
303
+ Snippet to run in console:
304
+
305
+ ```
306
+ BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle
307
+ BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle
308
+ BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle
309
+ BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle
310
+ BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle
311
+ BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake test
312
+ BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake test
313
+ BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle exec rake test
314
+ BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle exec rake test
315
+ BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test
316
+ ```
295
317
 
296
318
  ## Known issues
297
319
 
@@ -344,7 +366,18 @@ You are welcome to contribute.
344
366
  - https://github.com/jayshepherd
345
367
  - https://github.com/ohbarye
346
368
  - https://github.com/randsina
347
- - https://github.com/...
369
+ - https://github.com/vietqhoang
370
+ - https://github.com/kemenaran
371
+ - https://github.com/jrmhaig
372
+ - https://github.com/tagliala
373
+ - https://github.com/evedovelli
374
+ - https://github.com/JuanVqz
375
+ - https://github.com/luiseugenio
376
+ - https://github.com/equivalent
377
+ - https://github.com/NARKOZ
378
+ - https://github.com/stephensolis
379
+ - https://github.com/kwent
380
+ = https://github.com/Animesh-Ghosh
348
381
 
349
382
  ## License
350
383
 
@@ -2,21 +2,21 @@ pt-BR:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "tem um tipo de arquivo inválido"
5
- file_size_out_of_range: "tamanho %{file_size} está fora da faixa de tamanho válida"
6
- limit_out_of_range: "número total está fora do limite"
5
+ file_size_out_of_range: "tem tamanho %{file_size} e está fora da faixa de tamanho válida"
6
+ limit_out_of_range: "o número total está fora do limite"
7
7
  image_metadata_missing: "não é uma imagem válida"
8
- dimension_min_inclusion: "deve ser maior ou igual a %{width} x %{height} pixel"
9
- dimension_max_inclusion: "deve ser menor ou igual a %{width} x %{height} pixel"
10
- dimension_width_inclusion: "largura não está entre %{min} e %{max} pixel"
11
- dimension_height_inclusion: "altura não está entre %{min} e %{max} pixel"
12
- dimension_width_greater_than_or_equal_to: "largura deve ser maior ou igual a %{length} pixel"
13
- dimension_height_greater_than_or_equal_to: "altura deve ser maior ou igual a %{length} pixel"
14
- dimension_width_less_than_or_equal_to: "largura deve ser menor ou igual a %{length} pixel"
15
- dimension_height_less_than_or_equal_to: "altura deve ser menor ou igual a %{length} pixel"
16
- dimension_width_equal_to: "largura deve ser igual a %{length} pixel"
17
- dimension_height_equal_to: "altura deve ser igual a %{length} pixel"
8
+ dimension_min_inclusion: "deve ser maior ou igual a %{width} x %{height} pixels"
9
+ dimension_max_inclusion: "deve ser menor ou igual a %{width} x %{height} pixels"
10
+ dimension_width_inclusion: "deve ter largura entre %{min} e %{max} pixels"
11
+ dimension_height_inclusion: "deve ter altura entre %{min} e %{max} pixels"
12
+ dimension_width_greater_than_or_equal_to: "deve ter largura maior ou igual a %{length} pixels"
13
+ dimension_height_greater_than_or_equal_to: "deve ter altura maior ou igual a %{length} pixels"
14
+ dimension_width_less_than_or_equal_to: "deve ter largura menor ou igual a %{length} pixels"
15
+ dimension_height_less_than_or_equal_to: "deve ter altura menor ou igual a %{length} pixels"
16
+ dimension_width_equal_to: "deve ter largura igual a %{length} pixels"
17
+ dimension_height_equal_to: "deve ter altura igual a %{length} pixels"
18
18
  aspect_ratio_not_square: "não é uma imagem quadrada"
19
- aspect_ratio_not_portrait: "não contém uma imagem no formato retrato"
20
- aspect_ratio_not_landscape: "não contém uma imagem no formato paisagem"
19
+ aspect_ratio_not_portrait: "não está no formato retrato"
20
+ aspect_ratio_not_landscape: "não está no formato paisagem"
21
21
  aspect_ratio_is_not: "não contém uma proporção de %{aspect_ratio}"
22
22
  aspect_ratio_unknown: "não tem uma proporção definida"
@@ -8,7 +8,6 @@ module ActiveStorageValidations
8
8
  PRECISION = 3
9
9
 
10
10
  def initialize(options)
11
- require 'mini_magick' unless defined?(MiniMagick)
12
11
  super(options)
13
12
  end
14
13
 
@@ -18,7 +17,7 @@ module ActiveStorageValidations
18
17
  raise ArgumentError, 'You must pass "aspect_ratio: :OPTION" option to the validator'
19
18
  end
20
19
 
21
- if Rails::VERSION::MAJOR >= 6
20
+ if Rails.gem_version >= Gem::Version.new('6.0.0')
22
21
  def validate_each(record, attribute, _value)
23
22
  return true unless record.send(attribute).attached?
24
23
 
@@ -37,14 +36,14 @@ module ActiveStorageValidations
37
36
  # Rails 5
38
37
  def validate_each(record, attribute, _value)
39
38
  return true unless record.send(attribute).attached?
40
-
39
+
41
40
  files = Array.wrap(record.send(attribute))
42
-
41
+
43
42
  files.each do |file|
44
43
  # Analyze file first if not analyzed to get all required metadata.
45
44
  file.analyze; file.reload unless file.analyzed?
46
45
  metadata = file.metadata
47
-
46
+
48
47
  next if is_valid?(record, attribute, metadata)
49
48
  break
50
49
  end
@@ -7,8 +7,6 @@ module ActiveStorageValidations
7
7
  AVAILABLE_CHECKS = %i[width height min max].freeze
8
8
 
9
9
  def initialize(options)
10
- require 'mini_magick' unless defined?(MiniMagick)
11
-
12
10
  [:width, :height].each do |length|
13
11
  if options[length] and options[length].is_a?(Hash)
14
12
  if range = options[length][:in]
@@ -34,7 +32,7 @@ module ActiveStorageValidations
34
32
  end
35
33
 
36
34
 
37
- if Rails::VERSION::MAJOR >= 6
35
+ if Rails.gem_version >= Gem::Version.new('6.0.0')
38
36
  def validate_each(record, attribute, _value)
39
37
  return true unless record.send(attribute).attached?
40
38
 
@@ -91,29 +89,32 @@ module ActiveStorageValidations
91
89
 
92
90
  # Validation based on checks :width and :height.
93
91
  else
92
+ width_or_height_invalid = false
94
93
  [:width, :height].each do |length|
95
94
  next unless options[length]
96
95
  if options[length].is_a?(Hash)
97
96
  if options[length][:in] && (file_metadata[length] < options[length][:min] || file_metadata[length] > options[length][:max])
98
97
  add_error(record, attribute, options[:message].presence || :"dimension_#{length}_inclusion", min: options[length][:min], max: options[length][:max])
99
- return false
98
+ width_or_height_invalid = true
100
99
  else
101
100
  if options[length][:min] && file_metadata[length] < options[length][:min]
102
101
  add_error(record, attribute, options[:message].presence || :"dimension_#{length}_greater_than_or_equal_to", length: options[length][:min])
103
- return false
102
+ width_or_height_invalid = true
104
103
  end
105
104
  if options[length][:max] && file_metadata[length] > options[length][:max]
106
105
  add_error(record, attribute, options[:message].presence || :"dimension_#{length}_less_than_or_equal_to", length: options[length][:max])
107
- return false
106
+ width_or_height_invalid = true
108
107
  end
109
108
  end
110
109
  else
111
110
  if file_metadata[length] != options[length]
112
111
  add_error(record, attribute, options[:message].presence || :"dimension_#{length}_equal_to", length: options[length])
113
- return false
112
+ width_or_height_invalid = true
114
113
  end
115
114
  end
116
115
  end
116
+
117
+ return false if width_or_height_invalid
117
118
  end
118
119
 
119
120
  true # valid file
@@ -35,7 +35,7 @@ module ActiveStorageValidations
35
35
  def failure_message
36
36
  <<~MESSAGE
37
37
  Expected #{@attribute_name}
38
-
38
+
39
39
  Accept content types: #{allowed_types.join(", ")}
40
40
  #{accepted_types_and_failures}
41
41
 
@@ -57,7 +57,7 @@ module ActiveStorageValidations
57
57
  end
58
58
 
59
59
  def rejected_types
60
- @rejected_types || (Marcel::TYPES.keys - allowed_types)
60
+ @rejected_types || (content_type_keys - allowed_types)
61
61
  end
62
62
 
63
63
  def allowed_types_allowed?
@@ -96,6 +96,16 @@ module ActiveStorageValidations
96
96
  suffix = type.to_s.split('/').last
97
97
  { io: Tempfile.new('.'), filename: "test.#{suffix}", content_type: type }
98
98
  end
99
+
100
+ private
101
+
102
+ def content_type_keys
103
+ if Rails.gem_version < Gem::Version.new('6.1.0')
104
+ Mime::LOOKUP.keys
105
+ else
106
+ Marcel::TYPES.keys
107
+ end
108
+ end
99
109
  end
100
110
  end
101
111
  end
@@ -22,7 +22,7 @@ module ActiveStorageValidations
22
22
  end
23
23
 
24
24
  def self.mock_metadata(attachment, width, height)
25
- if Rails::VERSION::MAJOR >= 6
25
+ if Rails.gem_version >= Gem::Version.new('6.0.0')
26
26
  # Mock the Metadata class for rails 6
27
27
  mock = OpenStruct.new(metadata: { width: width, height: height })
28
28
  stub_method(ActiveStorageValidations::Metadata, :new, mock) do
@@ -3,9 +3,30 @@ module ActiveStorageValidations
3
3
  attr_reader :file
4
4
 
5
5
  def initialize(file)
6
+ require_image_processor
6
7
  @file = file
7
8
  end
8
9
 
10
+ def image_processor
11
+ Rails.application.config.active_storage.variant_processor
12
+ end
13
+
14
+ def exception_class
15
+ if image_processor == :vips && defined?(Vips)
16
+ Vips::Error
17
+ elsif defined?(MiniMagick)
18
+ MiniMagick::Error
19
+ end
20
+ end
21
+
22
+ def require_image_processor
23
+ if image_processor == :vips
24
+ require 'vips' unless defined?(Vips)
25
+ else
26
+ require 'mini_magick' unless defined?(MiniMagick)
27
+ end
28
+ end
29
+
9
30
  def metadata
10
31
  read_image do |image|
11
32
  if rotated_image?(image)
@@ -21,17 +42,16 @@ module ActiveStorageValidations
21
42
  def read_image
22
43
  is_string = file.is_a?(String)
23
44
  if is_string || file.is_a?(ActiveStorage::Blob)
24
- if is_string
25
- # If Rails 5.2 or 6.0, use `find_signed`
26
- if Rails::VERSION::MAJOR < 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR == 0)
27
- blob = ActiveStorage::Blob.find_signed(file)
28
- # If Rails 6.1 or higher, use `find_signed!`
29
- elsif Rails::VERSION::MAJOR > 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR >= 1)
30
- blob = ActiveStorage::Blob.find_signed!(file)
45
+ blob =
46
+ if is_string
47
+ if Rails.gem_version < Gem::Version.new('6.1.0')
48
+ ActiveStorage::Blob.find_signed(file)
49
+ else
50
+ ActiveStorage::Blob.find_signed!(file)
51
+ end
52
+ else
53
+ file
31
54
  end
32
- else
33
- blob = file
34
- end
35
55
 
36
56
  tempfile = Tempfile.new(["ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter])
37
57
  tempfile.binmode
@@ -43,29 +63,50 @@ module ActiveStorageValidations
43
63
  tempfile.flush
44
64
  tempfile.rewind
45
65
 
46
- image = MiniMagick::Image.new(tempfile.path)
66
+ image = if image_processor == :vips && defined?(Vips) && Vips::get_suffixes.include?(File.extname(tempfile.path).downcase)
67
+ Vips::Image.new_from_file(tempfile.path)
68
+ elsif defined?(MiniMagick)
69
+ MiniMagick::Image.new(tempfile.path)
70
+ end
47
71
  else
48
- image = MiniMagick::Image.new(read_file_path)
72
+ image = if image_processor == :vips && defined?(Vips) && Vips::get_suffixes.include?(File.extname(read_file_path).downcase)
73
+ Vips::Image.new_from_file(read_file_path)
74
+ elsif defined?(MiniMagick)
75
+ MiniMagick::Image.new(read_file_path)
76
+ end
49
77
  end
50
78
 
51
- if image.valid?
79
+ if image && valid_image?(image)
52
80
  yield image
53
81
  else
54
- logger.info "Skipping image analysis because ImageMagick doesn't support the file"
82
+ logger.info "Skipping image analysis because ImageMagick or Vips doesn't support the file"
55
83
  {}
56
84
  end
57
- rescue LoadError
58
- logger.info "Skipping image analysis because the mini_magick gem isn't installed"
85
+ rescue LoadError, NameError
86
+ logger.info "Skipping image analysis because the mini_magick or ruby-vips gem isn't installed"
59
87
  {}
60
- rescue MiniMagick::Error => error
61
- logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
88
+ rescue exception_class => error
89
+ logger.error "Skipping image analysis due to an #{exception_class.name.split('::').map(&:downcase).join(' ').capitalize} error: #{error.message}"
62
90
  {}
63
91
  ensure
64
92
  image = nil
65
93
  end
66
94
 
95
+ def valid_image?(image)
96
+ image_processor == :vips && image.is_a?(Vips::Image) ? image.avg : image.valid?
97
+ rescue exception_class
98
+ false
99
+ end
100
+
67
101
  def rotated_image?(image)
68
- %w[ RightTop LeftBottom ].include?(image["%[orientation]"])
102
+ if image_processor == :vips && image.is_a?(Vips::Image)
103
+ image.get('exif-ifd0-Orientation').include?('Right-top') ||
104
+ image.get('exif-ifd0-Orientation').include?('Left-bottom')
105
+ else
106
+ %w[ RightTop LeftBottom ].include?(image["%[orientation]"])
107
+ end
108
+ rescue exception_class # field "exif-ifd0-Orientation" not found
109
+ false
69
110
  end
70
111
 
71
112
  def read_file_path
@@ -25,6 +25,9 @@ module ActiveStorageValidations
25
25
  next if content_size_valid?(file.blob.byte_size)
26
26
 
27
27
  errors_options[:file_size] = number_to_human_size(file.blob.byte_size)
28
+ errors_options[:min_size] = number_to_human_size(min_size)
29
+ errors_options[:max_size] = number_to_human_size(max_size)
30
+
28
31
  record.errors.add(attribute, :file_size_out_of_range, **errors_options)
29
32
  break
30
33
  end
@@ -43,5 +46,13 @@ module ActiveStorageValidations
43
46
  file_size >= options[:greater_than_or_equal_to]
44
47
  end
45
48
  end
49
+
50
+ def min_size
51
+ options[:between]&.min || options[:greater_than] || options[:greater_than_or_equal_to]
52
+ end
53
+
54
+ def max_size
55
+ options[:between]&.max || options[:less_than] || options[:less_than_or_equal_to]
56
+ end
46
57
  end
47
58
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorageValidations
4
- VERSION = '0.9.5'
4
+ VERSION = '0.9.8'
5
5
  end
metadata CHANGED
@@ -1,17 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_storage_validations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-26 00:00:00.000000000 Z
11
+ date: 2022-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: activejob
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 5.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 5.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: activestorage
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 5.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 5.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
15
57
  requirement: !ruby/object:Gem::Requirement
16
58
  requirements:
17
59
  - - ">="
@@ -52,6 +94,20 @@ dependencies:
52
94
  - - ">="
53
95
  - !ruby/object:Gem::Version
54
96
  version: 4.9.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby-vips
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.1.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.1.0
55
111
  - !ruby/object:Gem::Dependency
56
112
  name: pry
57
113
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +150,20 @@ dependencies:
94
150
  - - ">="
95
151
  - !ruby/object:Gem::Version
96
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: marcel
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
97
167
  description: Validations for Active Storage (presence)
98
168
  email:
99
169
  - igorkasyanchuk@gmail.com
@@ -138,7 +208,7 @@ homepage: https://github.com/igorkasyanchuk/active_storage_validations
138
208
  licenses:
139
209
  - MIT
140
210
  metadata: {}
141
- post_install_message:
211
+ post_install_message:
142
212
  rdoc_options: []
143
213
  require_paths:
144
214
  - lib
@@ -153,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
223
  - !ruby/object:Gem::Version
154
224
  version: '0'
155
225
  requirements: []
156
- rubygems_version: 3.0.3
157
- signing_key:
226
+ rubygems_version: 3.2.3
227
+ signing_key:
158
228
  specification_version: 4
159
229
  summary: Validations for Active Storage
160
230
  test_files: []