active_validation 4.0.10 → 4.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +70 -2
- data/active_validation.gemspec +2 -0
- data/config/locales/en.yml +26 -0
- data/lib/active_validation.rb +5 -3
- data/lib/active_validation/validators/boolean_validator.rb +1 -0
- data/lib/active_validation/validators/csv_validator.rb +94 -0
- data/lib/active_validation/validators/file_size_validator.rb +85 -0
- data/lib/active_validation/version.rb +1 -1
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13401eb32dc1430b9fdf5bfba438388b30cfe377
|
4
|
+
data.tar.gz: ec4688cf3c3dafb36fa78c9cb3e3d3581d3ffc57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb066efd1bb2bb378090cde1da22eb361fdf1a47640870d608c79cfe7807b04dd3eb66013b586c11f0438bd43c81b1a5f32a6e4f1f591333db0b4ad23c2685a8
|
7
|
+
data.tar.gz: 1542bd9f3a210d2c5cdb50b10d35aaed128e05ba83fd43777012111183fecc5216819635edfa439c19a20241780e869550a787a625cc9b2725ef1ed69ec2c048
|
data/README.md
CHANGED
@@ -34,10 +34,12 @@ Or install it yourself as:
|
|
34
34
|
* [Boolean](#booleanvalidator)
|
35
35
|
* [Coordinates](#coordinatesvalidator)
|
36
36
|
* [Credit Card](#creditcardvalidator)
|
37
|
+
* [Csv](#csvvalidator)
|
37
38
|
* [Currency](#currencyvalidator)
|
38
39
|
* [CUSIP](#cusipvalidator)
|
39
40
|
* [Email](#emailvalidator)
|
40
41
|
* [Equality](#equalityvalidator)
|
42
|
+
* [FileSize](#filesizevalidator)
|
41
43
|
* [Hex](#hexvalidator)
|
42
44
|
* [IMEI](#imeivalidator)
|
43
45
|
* [IP](#ipvalidator)
|
@@ -309,6 +311,40 @@ describe Invoice do
|
|
309
311
|
end
|
310
312
|
```
|
311
313
|
|
314
|
+
## CsvValidator
|
315
|
+
|
316
|
+
Options: :columns :columns_in, :columns_less_than, :columns_less_than_or_equal_to,
|
317
|
+
:columns_greater_than, :columns_greater_than_or_equal_to, :rows, :rows_in, :rows_less_than,
|
318
|
+
:rows_less_than_or_equal_to, :rows_greater_than, :rows_greater_than_or_equal_to
|
319
|
+
|
320
|
+
With an ActiveRecord model:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
class Product < ActiveRecord::Base
|
324
|
+
attr_accessor :csv, :name
|
325
|
+
validates :csv, csv: { columns: 6, rows_less_than: 20 }
|
326
|
+
end
|
327
|
+
```
|
328
|
+
|
329
|
+
Or any ruby class:
|
330
|
+
|
331
|
+
```ruby
|
332
|
+
class Product
|
333
|
+
include ActiveModel::Validations
|
334
|
+
attr_accessor :csv, :name
|
335
|
+
validates :csv, csv: { columns_less_than: 6, rows: 20 }
|
336
|
+
end
|
337
|
+
```
|
338
|
+
|
339
|
+
RSpec matcher is also available for your convenience:
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
describe Product do
|
343
|
+
it { should ensure_valid_csv_format_of(:csv) }
|
344
|
+
it { should_not ensure_valid_csv_format_of(:name) }
|
345
|
+
end
|
346
|
+
```
|
347
|
+
|
312
348
|
## CurrencyValidator
|
313
349
|
|
314
350
|
**Ex:** 123.00 or .1
|
@@ -394,10 +430,10 @@ end
|
|
394
430
|
**Ex:** user@example.com or user+123@example-site.com
|
395
431
|
|
396
432
|
**Rules:**
|
397
|
-
* Characters in username: a-z 0-9
|
433
|
+
* Characters in username: a-z 0-9 -.+_
|
398
434
|
* Must include: @
|
399
435
|
* Characters in domain: a-z 0-9 -
|
400
|
-
* Must include extension: .
|
436
|
+
* Must include extension: .com, .org, .museum
|
401
437
|
|
402
438
|
With an ActiveRecord model:
|
403
439
|
|
@@ -477,6 +513,38 @@ describe Auction do
|
|
477
513
|
end
|
478
514
|
```
|
479
515
|
|
516
|
+
## FileSizeValidator
|
517
|
+
|
518
|
+
Options: :in, :less_than, :less_than_or_equal_to, :greater_than, :greater_than_or_equal_to
|
519
|
+
|
520
|
+
With an ActiveRecord model:
|
521
|
+
|
522
|
+
```ruby
|
523
|
+
class Product < ActiveRecord::Base
|
524
|
+
attr_accessor :file, :name
|
525
|
+
validates :file, file_size: { in: 5.megabytes..10.megabytes }
|
526
|
+
end
|
527
|
+
```
|
528
|
+
|
529
|
+
Or any ruby class:
|
530
|
+
|
531
|
+
```ruby
|
532
|
+
class Product
|
533
|
+
include ActiveModel::Validations
|
534
|
+
attr_accessor :file, :name
|
535
|
+
validates :file, file_size: { in: 5.megabytes..10.megabytes }
|
536
|
+
end
|
537
|
+
```
|
538
|
+
|
539
|
+
RSpec matcher is also available for your convenience:
|
540
|
+
|
541
|
+
```ruby
|
542
|
+
describe Product do
|
543
|
+
it { should ensure_valid_csv_format_of(:file) }
|
544
|
+
it { should_not ensure_valid_csv_format_of(:name) }
|
545
|
+
end
|
546
|
+
```
|
547
|
+
|
480
548
|
## HexValidator
|
481
549
|
|
482
550
|
**Ex:** #a9a9a9 or #999 or aaaaaa or AAA
|
data/active_validation.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = %w[lib]
|
22
22
|
|
23
|
+
spec.add_runtime_dependency 'actionpack'
|
23
24
|
spec.add_runtime_dependency 'activemodel'
|
24
25
|
spec.add_runtime_dependency 'activesupport'
|
25
26
|
|
@@ -27,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
27
28
|
spec.add_development_dependency 'coveralls'
|
28
29
|
spec.add_development_dependency 'rake'
|
29
30
|
spec.add_development_dependency 'rspec'
|
31
|
+
spec.add_development_dependency 'rspec-rails'
|
30
32
|
spec.add_development_dependency 'shoulda'
|
31
33
|
spec.add_development_dependency 'fasterer'
|
32
34
|
spec.add_development_dependency 'reek'
|
data/config/locales/en.yml
CHANGED
@@ -11,10 +11,30 @@ en:
|
|
11
11
|
latitude: 'is not a valid latitude'
|
12
12
|
longitude: 'is not a valid longitude'
|
13
13
|
credit_card: 'is not a valid credit card format'
|
14
|
+
csv:
|
15
|
+
columns: 'is not %{count}'
|
16
|
+
columns_in: 'is not between %{min} and %{max}'
|
17
|
+
columns_less_than: 'is not less than %{count}'
|
18
|
+
columns_less_than_or_equal_to: 'is not less than or equal to %{count}'
|
19
|
+
columns_greater_than: 'is not greater than %{count}'
|
20
|
+
columns_greater_than_or_equal_to: 'is not greater than or equal to %{count}'
|
21
|
+
not_valid: 'is not a valid csv'
|
22
|
+
rows: 'is not %{count}'
|
23
|
+
rows_in: 'is not between %{min} and %{max}'
|
24
|
+
rows_less_than: 'is not less than %{count}'
|
25
|
+
rows_less_than_or_equal_to: 'is not less than or equal to %{count}'
|
26
|
+
rows_greater_than: 'is not greater than %{count}'
|
27
|
+
rows_greater_than_or_equal_to: 'is not greater than or equal to %{count}'
|
14
28
|
currency: 'is not in valid currency format'
|
15
29
|
cusip: 'is not in valid CUSIP format'
|
16
30
|
email: 'is not in valid email format'
|
17
31
|
equality: 'is not %{operator} %{attr}'
|
32
|
+
file_size:
|
33
|
+
in: 'is not between %{min} and %{max}'
|
34
|
+
less_than: 'is not less than %{count}'
|
35
|
+
less_than_or_equal_to: 'is not less than or equal to %{count}'
|
36
|
+
greater_than: 'is not greater than %{count}'
|
37
|
+
greater_than_or_equal_to: 'is not greater than or equal to %{count}'
|
18
38
|
hex: 'is not in valid hex color format'
|
19
39
|
imei: 'is not in valid IMEI format'
|
20
40
|
ip: 'is not in valid IP format'
|
@@ -52,6 +72,9 @@ en:
|
|
52
72
|
ensure_valid_credit_card_format_of:
|
53
73
|
failure_message_for_should: '%{model} should ensure valid credit card format of attribute %{attr}'
|
54
74
|
failure_message_for_should_not: '%{model} should not ensure valid credit card format of attribute %{attr}'
|
75
|
+
ensure_valid_csv_format_of:
|
76
|
+
failure_message_for_should: '%{model} should ensure valid csv format of attribute %{attr}'
|
77
|
+
failure_message_for_should_not: '%{model} should not ensure valid csv format of attribute %{attr}'
|
55
78
|
ensure_valid_currency_format_of:
|
56
79
|
failure_message_for_should: '%{model} should ensure valid currency format of attribute %{attr}'
|
57
80
|
failure_message_for_should_not: '%{model} should not ensure valid currency format of attribute %{attr}'
|
@@ -64,6 +87,9 @@ en:
|
|
64
87
|
ensure_valid_equality_format_of:
|
65
88
|
failure_message_for_should: '%{model} should ensure equality of %{operator} on attribute %{attr}'
|
66
89
|
failure_message_for_should_not: '%{model} should not ensure equality of %{operator} on attribute %{attr}'
|
90
|
+
ensure_valid_file_size_format_of:
|
91
|
+
failure_message_for_should: '%{model} should ensure valid file size format of attribute %{attr}'
|
92
|
+
failure_message_for_should_not: '%{model} should not ensure valid file size format of attribute %{attr}'
|
67
93
|
ensure_valid_hex_format_of:
|
68
94
|
failure_message_for_should: '%{model} should ensure valid hex format of attribute %{attr}'
|
69
95
|
failure_message_for_should_not: '%{model} should not ensure valid hex format of attribute %{attr}'
|
data/lib/active_validation.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
require 'action_dispatch'
|
1
2
|
require 'active_model'
|
2
3
|
require 'active_support'
|
3
4
|
require 'active_support/core_ext/time/zones'
|
4
5
|
require 'active_validation/version'
|
6
|
+
require 'csv'
|
5
7
|
|
6
8
|
ACTIVE_VALIDATION_VALIDATORS ||= %w[
|
7
|
-
alpha alpha_numeric base64 boolean coordinate credit_card currency cusip email equality
|
8
|
-
ip isbn isin mac_address name password phone sedol slug ssn time_zone
|
9
|
-
username uuid
|
9
|
+
alpha alpha_numeric base64 boolean coordinate credit_card csv currency cusip email equality
|
10
|
+
file_size hex imei ip isbn isin mac_address name password phone sedol slug ssn time_zone
|
11
|
+
tracking_number type url username uuid
|
10
12
|
].freeze
|
11
13
|
|
12
14
|
ACTIVE_VALIDATION_VALIDATORS.each do |file_name|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class CsvValidator < ActiveModel::EachValidator
|
2
|
+
|
3
|
+
CHECKS ||= {
|
4
|
+
columns: :==,
|
5
|
+
columns_in: :===,
|
6
|
+
columns_less_than: :<,
|
7
|
+
columns_less_than_or_equal_to: :<=,
|
8
|
+
columns_greater_than: :>,
|
9
|
+
columns_greater_than_or_equal_to: :>=,
|
10
|
+
rows: :==,
|
11
|
+
rows_in: :===,
|
12
|
+
rows_less_than: :<,
|
13
|
+
rows_less_than_or_equal_to: :<=,
|
14
|
+
rows_greater_than: :>,
|
15
|
+
rows_greater_than_or_equal_to: :>=
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def validate_each(record, attribute, value)
|
19
|
+
assert_valid_options!
|
20
|
+
values = parse_values(record, attribute, value)
|
21
|
+
|
22
|
+
if values.nil?
|
23
|
+
record.errors.add(attribute, 'not a valid csv')
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
options.slice(*CHECKS.keys).each do |option, option_value|
|
28
|
+
option_value = option_value.call(record) if option_value.is_a?(Proc)
|
29
|
+
|
30
|
+
next unless values.any? { |val| !valid_size?(val, option, option_value) }
|
31
|
+
error_text = filtered_options(values).merge!(detect_error_options(option_value))
|
32
|
+
error_text = options[:message] ||
|
33
|
+
I18n.t("active_validation.errors.messages.csv.#{option}", error_text)
|
34
|
+
record.errors[attribute] << (options[:message] || error_text)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def assert_valid_options!
|
41
|
+
unless (CHECKS.keys & options.keys).present?
|
42
|
+
raise ArgumentError,
|
43
|
+
"You must at least pass in one of these options - #{CHECKS.map(&:inspect).join(', ')}"
|
44
|
+
end
|
45
|
+
|
46
|
+
check_options(Numeric, options.slice(*(CHECKS.keys - %i[columns_in rows_in])))
|
47
|
+
check_options(Range, options.slice(:columns_in, :rows_in))
|
48
|
+
end
|
49
|
+
|
50
|
+
def valid_extension?(record, attribute, value)
|
51
|
+
value.path.end_with?('.csv')
|
52
|
+
rescue
|
53
|
+
record.errors[attribute] <<
|
54
|
+
(options[:message] || I18n.t('active_validation.errors.messages.csv.not_valid'))
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_values(record, attribute, value)
|
59
|
+
return nil unless valid_extension?(record, attribute, value)
|
60
|
+
[CSV.read(value.path)]
|
61
|
+
rescue CSV::MalformedCSVError
|
62
|
+
record.errors[attribute] <<
|
63
|
+
(options[:message] || I18n.t('active_validation.errors.messages.csv.not_valid'))
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_options(klass, options)
|
68
|
+
options.each do |option, value|
|
69
|
+
next if value.is_a?(klass) || value.is_a?(Proc)
|
70
|
+
raise ArgumentError,
|
71
|
+
":#{option} must be a #{klass.name.to_s.downcase} or a proc"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def valid_size?(value, option, option_value)
|
76
|
+
size = /columns/.match?(option) ? value.first.length : value.length
|
77
|
+
|
78
|
+
return false if size.zero?
|
79
|
+
return option_value.send(CHECKS[option], size) if option_value.is_a?(Range)
|
80
|
+
size.send(CHECKS[option], option_value)
|
81
|
+
end
|
82
|
+
|
83
|
+
def filtered_options(value)
|
84
|
+
filtered = options.except(*CHECKS.keys)
|
85
|
+
filtered[:value] = value
|
86
|
+
filtered
|
87
|
+
end
|
88
|
+
|
89
|
+
def detect_error_options(option_value)
|
90
|
+
return { count: option_value } unless option_value.is_a?(Range)
|
91
|
+
{ min: option_value.min, max: option_value.max }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class FileSizeValidator < ActiveModel::EachValidator
|
2
|
+
|
3
|
+
CHECKS ||= {
|
4
|
+
in: :===,
|
5
|
+
less_than: :<,
|
6
|
+
less_than_or_equal_to: :<=,
|
7
|
+
greater_than: :>,
|
8
|
+
greater_than_or_equal_to: :>=
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
def validate_each(record, attribute, value)
|
12
|
+
assert_valid_options!
|
13
|
+
values = parse_values(value)
|
14
|
+
return if values.empty?
|
15
|
+
|
16
|
+
options.slice(*CHECKS.keys).each do |option, option_value|
|
17
|
+
option_value = option_value.call(record) if option_value.is_a?(Proc)
|
18
|
+
|
19
|
+
next unless values.any? { |val| !valid_size?(val.size, option, option_value) }
|
20
|
+
error_text = filtered_options(values).merge!(detect_error_options(option_value))
|
21
|
+
error_text = options[:message] ||
|
22
|
+
I18n.t("active_validation.errors.messages.file_size.#{option}", error_text)
|
23
|
+
record.errors[attribute] << (options[:message] || error_text)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def assert_valid_options!
|
30
|
+
unless (CHECKS.keys & options.keys).present?
|
31
|
+
raise ArgumentError,
|
32
|
+
"You must at least pass in one of these options - #{CHECKS.map(&:inspect).join(', ')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
check_options(Numeric, options.slice(*(CHECKS.keys - %i[in])))
|
36
|
+
check_options(Range, options.slice(:in))
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_values(value)
|
40
|
+
return [] unless value.present?
|
41
|
+
|
42
|
+
value = JSON.parse(value) if value.is_a?(String)
|
43
|
+
return [] unless value.present?
|
44
|
+
|
45
|
+
value = OpenStruct.new(value) if value.is_a?(Hash)
|
46
|
+
[value].reject(&:blank?)
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_options(klass, options)
|
50
|
+
options.each do |option, value|
|
51
|
+
next if value.is_a?(klass) || value.is_a?(Proc)
|
52
|
+
raise ArgumentError,
|
53
|
+
":#{option} must be a #{klass.name.to_s.downcase} or a proc"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def valid_size?(size, option, option_value)
|
58
|
+
return false if size.nil?
|
59
|
+
return option_value.send(CHECKS[option], size) if option_value.is_a?(Range)
|
60
|
+
size.send(CHECKS[option], option_value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def filtered_options(value)
|
64
|
+
filtered = options.except(*CHECKS.keys)
|
65
|
+
filtered[:value] = value
|
66
|
+
filtered
|
67
|
+
end
|
68
|
+
|
69
|
+
def detect_error_options(option_value)
|
70
|
+
return { count: human_size(option_value) } unless option_value.is_a?(Range)
|
71
|
+
{ min: human_size(option_value.min), max: human_size(option_value.max) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def human_size(size)
|
75
|
+
if defined?(ActiveSupport::NumberHelper)
|
76
|
+
ActiveSupport::NumberHelper.number_to_human_size(size)
|
77
|
+
else
|
78
|
+
opts = { locale: options[:locale], raise: true }
|
79
|
+
format = I18n.t(:'number.human.storage_units.format', opts)
|
80
|
+
unit = I18n.t(:'number.human.storage_units.units.byte', opts.merge(count: size.to_i))
|
81
|
+
format.gsub(/%n/, size.to_i.to_s).gsub(/%u/, unit).html_safe
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_validation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juan Gomez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: actionpack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: activemodel
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec-rails
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: shoulda
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,10 +212,12 @@ files:
|
|
184
212
|
- lib/active_validation/validators/boolean_validator.rb
|
185
213
|
- lib/active_validation/validators/coordinate_validator.rb
|
186
214
|
- lib/active_validation/validators/credit_card_validator.rb
|
215
|
+
- lib/active_validation/validators/csv_validator.rb
|
187
216
|
- lib/active_validation/validators/currency_validator.rb
|
188
217
|
- lib/active_validation/validators/cusip_validator.rb
|
189
218
|
- lib/active_validation/validators/email_validator.rb
|
190
219
|
- lib/active_validation/validators/equality_validator.rb
|
220
|
+
- lib/active_validation/validators/file_size_validator.rb
|
191
221
|
- lib/active_validation/validators/hex_validator.rb
|
192
222
|
- lib/active_validation/validators/imei_validator.rb
|
193
223
|
- lib/active_validation/validators/ip_validator.rb
|