string_validator 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +146 -0
- data/lib/string_validator/sanitizers.rb +82 -0
- data/lib/string_validator/validators.rb +228 -0
- data/lib/string_validator/version.rb +5 -0
- data/lib/string_validator.rb +18 -0
- metadata +55 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: a5a08752d7f73d74fa45b4dec5d17815e71bb547c30a1364540923bb10e5649a
|
|
4
|
+
data.tar.gz: 75c37d3612370ccefa9504d2b466b0a06a9e618363c2a6d0bd53df43663f4136
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 192ae47895b814e8b8bbbb268009e8f9a6ed77135e8718f6948758fb92eb25bd46317d59ba3b40e04c1c14e44774aeb47e4081cbbeede870063ba51d3213b360
|
|
7
|
+
data.tar.gz: 1da02180de5a833956a6ae3a6aae356bc5518240f9a9452a981fb0e4f0adf92a15e61dd30d83975e8d7bc0b01eb0784ce3cf1a5d9f32c851c4a731b3e670a4e0
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2025-02-16
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Initial release
|
|
8
|
+
- Validators: `is_email?`, `is_url?`, `is_ip?`, `is_empty?`, `is_length?`, `is_alpha?`, `is_alphanumeric?`, `is_numeric?`, `is_int?`, `is_float?`, `is_boolean?`, `is_json?`, `is_base64?`, `is_hex_color?`, `is_uuid?`, `is_ascii?`, `is_slug?`, `is_mac_address?`, `is_credit_card?`, `is_md5?`, `is_hexadecimal?`, `contains?`, `equals?`, `is_in?`
|
|
9
|
+
- Sanitizers: `escape`, `unescape`, `trim`, `blacklist`, `whitelist`, `strip_low`, `to_boolean`, `to_int`, `to_float`
|
|
10
|
+
- `StringValidator.valid?(str, :validator_name, **options)` for safe validation with NotStringError
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# StringValidator
|
|
2
|
+
|
|
3
|
+
A Ruby port of [validator.js](https://github.com/validatorjs/validator.js) — a comprehensive library of **string validators** and **sanitizers** for Ruby and Rails.
|
|
4
|
+
|
|
5
|
+
Validator.js has 23k+ GitHub stars and 18M+ weekly npm downloads. Until now, Ruby had no single gem offering the same API. Use this for API params, form input, background jobs, or any place you need to validate or sanitize strings.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add to your Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem "string_validator"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then run:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install globally:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install string_validator
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
All methods are on the `StringValidator` module. Input must be a String (validator.js is strings-only too).
|
|
30
|
+
|
|
31
|
+
### Validators
|
|
32
|
+
|
|
33
|
+
Return `true` or `false`.
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
require "string_validator"
|
|
37
|
+
|
|
38
|
+
StringValidator.is_email?("foo@bar.com") # => true
|
|
39
|
+
StringValidator.is_email?("invalid") # => false
|
|
40
|
+
|
|
41
|
+
StringValidator.is_url?("https://example.com") # => true
|
|
42
|
+
StringValidator.is_url?("not a url") # => false
|
|
43
|
+
|
|
44
|
+
StringValidator.is_ip?("192.168.1.1") # => true
|
|
45
|
+
StringValidator.is_ip?("::1", version: 6) # => true
|
|
46
|
+
|
|
47
|
+
StringValidator.is_empty?(" ") # => false
|
|
48
|
+
StringValidator.is_empty?(" ", ignore_whitespace: true) # => true
|
|
49
|
+
|
|
50
|
+
StringValidator.is_length?("hello", min: 1, max: 10) # => true
|
|
51
|
+
|
|
52
|
+
StringValidator.is_alpha?("abc") # => true
|
|
53
|
+
StringValidator.is_alphanumeric?("user123") # => true
|
|
54
|
+
StringValidator.is_numeric?("42.5") # => true
|
|
55
|
+
StringValidator.is_int?("42", min: 0, max: 100) # => true
|
|
56
|
+
StringValidator.is_float?("3.14") # => true
|
|
57
|
+
|
|
58
|
+
StringValidator.is_boolean?("true") # => true
|
|
59
|
+
StringValidator.is_boolean?("yes", loose: true) # => true
|
|
60
|
+
|
|
61
|
+
StringValidator.is_json?('{"a":1}') # => true
|
|
62
|
+
StringValidator.is_base64?("SGVsbG8=") # => true
|
|
63
|
+
StringValidator.is_hex_color?("#ff0000") # => true
|
|
64
|
+
StringValidator.is_uuid?("550e8400-e29b-41d4-a716-446655440000") # => true
|
|
65
|
+
StringValidator.is_ascii?("Hello") # => true
|
|
66
|
+
StringValidator.is_slug?("my-post-title") # => true
|
|
67
|
+
StringValidator.is_mac_address?("01:02:03:04:05:ab") # => true
|
|
68
|
+
StringValidator.is_credit_card?("4111111111111111") # => true (Luhn check)
|
|
69
|
+
StringValidator.is_md5?("d41d8cd98f00b204e9800998ecf8427e") # => true
|
|
70
|
+
StringValidator.is_hexadecimal?("0a1f") # => true
|
|
71
|
+
|
|
72
|
+
StringValidator.contains?("hello world", "world") # => true
|
|
73
|
+
StringValidator.equals?("foo", "foo") # => true
|
|
74
|
+
StringValidator.is_in?("red", %w[red green blue]) # => true
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Sanitizers
|
|
78
|
+
|
|
79
|
+
Return a transformed string (or the original if not a string).
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
StringValidator.escape("<script>alert('x')</script>")
|
|
83
|
+
# => "<script>alert('x')</script>"
|
|
84
|
+
|
|
85
|
+
StringValidator.trim(" hello ") # => "hello"
|
|
86
|
+
StringValidator.blacklist("hello world", "ol") # => "he wrd"
|
|
87
|
+
StringValidator.whitelist("abc123", "0123456789") # => "123"
|
|
88
|
+
StringValidator.whitelist("abc123", "a-c0-9") # => "abc123"
|
|
89
|
+
StringValidator.strip_low("hello\x00world") # => "helloworld"
|
|
90
|
+
|
|
91
|
+
StringValidator.to_boolean("true") # => true
|
|
92
|
+
StringValidator.to_boolean("false") # => false
|
|
93
|
+
StringValidator.to_boolean("yes", strict: false) # => true
|
|
94
|
+
StringValidator.to_int("42") # => 42
|
|
95
|
+
StringValidator.to_float("3.14") # => 3.14
|
|
96
|
+
|
|
97
|
+
StringValidator.unescape("<tag>") # => "<tag>"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Rails / ActiveModel
|
|
101
|
+
|
|
102
|
+
Use in custom validators or in models:
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
# app/validators/email_validator.rb
|
|
106
|
+
class EmailValidator < ActiveModel::EachValidator
|
|
107
|
+
def validate_each(record, attribute, value)
|
|
108
|
+
return if value.blank?
|
|
109
|
+
unless StringValidator.is_email?(value.to_s)
|
|
110
|
+
record.errors.add(attribute, options[:message] || "is not a valid email")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Or inline:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
validate :email_format
|
|
120
|
+
|
|
121
|
+
def email_format
|
|
122
|
+
return if email.blank?
|
|
123
|
+
errors.add(:email, "invalid") unless StringValidator.is_email?(email)
|
|
124
|
+
end
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Safe validation helper
|
|
128
|
+
|
|
129
|
+
Raises `StringValidator::NotStringError` if the input is not a String:
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
StringValidator.valid?("user@example.com", :is_email?) # => true
|
|
133
|
+
StringValidator.valid?(nil, :is_email?) # => raises NotStringError
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Supported Ruby
|
|
137
|
+
|
|
138
|
+
Ruby 3.0+.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
MIT. See [LICENSE](LICENSE.txt).
|
|
143
|
+
|
|
144
|
+
## Credits
|
|
145
|
+
|
|
146
|
+
API and behavior are inspired by [validator.js](https://github.com/validatorjs/validator.js) (MIT). This gem is an independent Ruby implementation for the Ruby community.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StringValidator
|
|
4
|
+
module Sanitizers
|
|
5
|
+
HTML_ESCAPE = {
|
|
6
|
+
"&" => "&",
|
|
7
|
+
"<" => "<",
|
|
8
|
+
">" => ">",
|
|
9
|
+
'"' => """,
|
|
10
|
+
"'" => "'",
|
|
11
|
+
"/" => "/"
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
def escape(str)
|
|
15
|
+
return str unless str.is_a?(String)
|
|
16
|
+
str.gsub(/[&<>"'\/]/, HTML_ESCAPE)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def trim(str, chars = nil)
|
|
20
|
+
return str unless str.is_a?(String)
|
|
21
|
+
if chars
|
|
22
|
+
str.gsub(/\A[#{Regexp.escape(chars)}]+|[#{Regexp.escape(chars)}]+\z/, "")
|
|
23
|
+
else
|
|
24
|
+
str.strip
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def blacklist(str, chars)
|
|
29
|
+
return str unless str.is_a?(String)
|
|
30
|
+
str.delete(chars)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def whitelist(str, chars)
|
|
34
|
+
return str unless str.is_a?(String)
|
|
35
|
+
str.each_char.select { |c| chars.include?(c) }.join
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def strip_low(str, keep_new_lines: false)
|
|
39
|
+
return str unless str.is_a?(String)
|
|
40
|
+
if keep_new_lines
|
|
41
|
+
str.each_char.select { |c| c.ord >= 32 || c == "\n" }.join
|
|
42
|
+
else
|
|
43
|
+
str.each_char.select { |c| c.ord >= 32 }.join
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_boolean(str, strict: true)
|
|
48
|
+
return str unless str.is_a?(String)
|
|
49
|
+
s = str.downcase.strip
|
|
50
|
+
return true if s == "true" || s == "1"
|
|
51
|
+
return false if s == "false" || s == "0"
|
|
52
|
+
return true if !strict && %w[yes y].include?(s)
|
|
53
|
+
return false if !strict && %w[no n].include?(s)
|
|
54
|
+
str
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_int(str, radix: 10)
|
|
58
|
+
return str unless str.is_a?(String)
|
|
59
|
+
Integer(str, radix)
|
|
60
|
+
rescue ArgumentError
|
|
61
|
+
str
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_float(str)
|
|
65
|
+
return str unless str.is_a?(String)
|
|
66
|
+
Float(str)
|
|
67
|
+
rescue ArgumentError
|
|
68
|
+
str
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def unescape(str)
|
|
72
|
+
return str unless str.is_a?(String)
|
|
73
|
+
str
|
|
74
|
+
.gsub("&", "&")
|
|
75
|
+
.gsub("<", "<")
|
|
76
|
+
.gsub(">", ">")
|
|
77
|
+
.gsub(""", '"')
|
|
78
|
+
.gsub("'", "'")
|
|
79
|
+
.gsub("/", "/")
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
require "json"
|
|
5
|
+
require "base64"
|
|
6
|
+
|
|
7
|
+
module StringValidator
|
|
8
|
+
module Validators
|
|
9
|
+
# RFC 5322 simplified email regex (validator.js compatible)
|
|
10
|
+
EMAIL_REGEX = /\A[^\s@]+@[^\s@]+\.[^\s@]+\z/
|
|
11
|
+
|
|
12
|
+
def is_email?(str, allow_display_name: false, require_tld: true)
|
|
13
|
+
return false unless str.is_a?(String)
|
|
14
|
+
s = str.strip
|
|
15
|
+
s = s.gsub(/\A.*<([^>]+)>\z/, '\1') if allow_display_name
|
|
16
|
+
return false if s.include?("..") || s.start_with?(".") || s.include?("@.")
|
|
17
|
+
return false if require_tld && !s.include?(".")
|
|
18
|
+
s.match?(EMAIL_REGEX)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def is_url?(str, protocols: %w[http https ftp], require_protocol: false, require_tld: true)
|
|
22
|
+
return false unless str.is_a?(String)
|
|
23
|
+
s = str.strip
|
|
24
|
+
return false if s.include?(" ")
|
|
25
|
+
if require_protocol
|
|
26
|
+
return false unless protocols.any? { |p| s.downcase.start_with?("#{p}:") }
|
|
27
|
+
end
|
|
28
|
+
begin
|
|
29
|
+
uri = ::URI.parse(s)
|
|
30
|
+
return false if uri.host.nil? && uri.opaque.nil?
|
|
31
|
+
if require_tld && uri.host && !uri.host.include?(".")
|
|
32
|
+
return false
|
|
33
|
+
end
|
|
34
|
+
true
|
|
35
|
+
rescue ::URI::InvalidURIError
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def is_ip?(str, version: nil)
|
|
41
|
+
return false unless str.is_a?(String)
|
|
42
|
+
case version
|
|
43
|
+
when 4, "4"
|
|
44
|
+
str.match?(/\A(?:(?:25[0-5]|2[0-4]\d|1?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1?\d\d?)\z/)
|
|
45
|
+
when 6, "6"
|
|
46
|
+
str.match?(/\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\z/) ||
|
|
47
|
+
str.match?(/\A::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\z/) ||
|
|
48
|
+
str.match?(/\A(?:[0-9a-fA-F]{1,4}:){1,7}:\z/) # simplified IPv6
|
|
49
|
+
else
|
|
50
|
+
is_ip?(str, version: 4) || is_ip?(str, version: 6)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def is_empty?(str, ignore_whitespace: false)
|
|
55
|
+
return false unless str.is_a?(String)
|
|
56
|
+
s = ignore_whitespace ? str.strip : str
|
|
57
|
+
s.empty?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def is_length?(str, min: 0, max: nil)
|
|
61
|
+
return false unless str.is_a?(String)
|
|
62
|
+
len = str.length
|
|
63
|
+
return false if len < min
|
|
64
|
+
return false if max && len > max
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def is_alpha?(str, locale: "en-US")
|
|
69
|
+
return false unless str.is_a?(String)
|
|
70
|
+
return str.match?(/\A[a-zA-Z]+\z/) if locale.to_s.downcase.start_with?("en")
|
|
71
|
+
str.match?(/\A\p{L}+\z/)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def is_alphanumeric?(str, locale: "en-US")
|
|
75
|
+
return false unless str.is_a?(String)
|
|
76
|
+
return str.match?(/\A[a-zA-Z0-9]+\z/) if locale.to_s.downcase.start_with?("en")
|
|
77
|
+
str.match?(/\A[\p{L}0-9]+\z/)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def is_numeric?(str, no_symbols: false)
|
|
81
|
+
return false unless str.is_a?(String)
|
|
82
|
+
return str.match?(/\A\d+\z/) if no_symbols
|
|
83
|
+
str.match?(/\A[-+]?\d*\.?\d+\z/)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def is_int?(str, min: nil, max: nil, allow_leading_zeroes: true)
|
|
87
|
+
return false unless str.is_a?(String)
|
|
88
|
+
return false if !allow_leading_zeroes && str.match?(/\A0\d+\z/)
|
|
89
|
+
return false unless str.match?(/\A[-+]?\d+\z/)
|
|
90
|
+
n = str.to_i
|
|
91
|
+
return false if min && n < min
|
|
92
|
+
return false if max && n > max
|
|
93
|
+
true
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def is_float?(str, min: nil, max: nil)
|
|
97
|
+
return false unless str.is_a?(String)
|
|
98
|
+
return false unless str.match?(/\A[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?\z/)
|
|
99
|
+
n = str.to_f
|
|
100
|
+
return false if min && n < min
|
|
101
|
+
return false if max && n > max
|
|
102
|
+
true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def is_boolean?(str, loose: false)
|
|
106
|
+
return false unless str.is_a?(String)
|
|
107
|
+
strict = %w[true false 0 1]
|
|
108
|
+
loose_list = strict + %w[yes no]
|
|
109
|
+
list = loose ? loose_list : strict
|
|
110
|
+
list.include?(str.downcase)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def is_json?(str, allow_primitives: false)
|
|
114
|
+
return false unless str.is_a?(String)
|
|
115
|
+
return true if allow_primitives && %w[true false null].include?(str.strip)
|
|
116
|
+
::JSON.parse(str)
|
|
117
|
+
true
|
|
118
|
+
rescue ::JSON::ParserError
|
|
119
|
+
false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def is_base64?(str, url_safe: false)
|
|
123
|
+
return false unless str.is_a?(String)
|
|
124
|
+
regex = url_safe ? /\A[A-Za-z0-9_-]*\z/ : /\A[A-Za-z0-9+\/=]*\z/
|
|
125
|
+
return false unless str.match?(regex)
|
|
126
|
+
return true if str.empty?
|
|
127
|
+
s = url_safe ? str.tr("-_", "+/") : str
|
|
128
|
+
::Base64.strict_decode64(s)
|
|
129
|
+
true
|
|
130
|
+
rescue ::ArgumentError
|
|
131
|
+
false
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def is_hex_color?(str, require_hashtag: false)
|
|
135
|
+
return false unless str.is_a?(String)
|
|
136
|
+
return false if require_hashtag && !str.start_with?("#")
|
|
137
|
+
str.match?(/\A#?([0-9a-fA-F]{3}){1,2}\z/)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def is_uuid?(str, version: nil)
|
|
141
|
+
return false unless str.is_a?(String)
|
|
142
|
+
uuid_regex = /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\z/
|
|
143
|
+
return str.match?(uuid_regex) if version.nil?
|
|
144
|
+
v = version.to_s
|
|
145
|
+
return false unless str.match?(uuid_regex)
|
|
146
|
+
str[14] == v
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def is_ascii?(str)
|
|
150
|
+
return false unless str.is_a?(String)
|
|
151
|
+
str.ascii_only?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def is_slug?(str)
|
|
155
|
+
return false unless str.is_a?(String)
|
|
156
|
+
str.match?(/\A[a-z0-9]+(?:-[a-z0-9]+)*\z/)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def is_mac_address?(str, no_separators: false)
|
|
160
|
+
return false unless str.is_a?(String)
|
|
161
|
+
if no_separators
|
|
162
|
+
str.match?(/\A[0-9a-fA-F]{12}\z/)
|
|
163
|
+
else
|
|
164
|
+
str.match?(/\A[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}\z/) ||
|
|
165
|
+
str.match?(/\A[0-9a-fA-F]{2}(-[0-9a-fA-F]{2}){5}\z/) ||
|
|
166
|
+
str.match?(/\A[0-9a-fA-F]{2}(\.[0-9a-fA-F]{2}){5}\z/) ||
|
|
167
|
+
str.match?(/\A[0-9a-fA-F]{2}( [0-9a-fA-F]{2}){5}\z/)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def contains?(str, seed, ignore_case: false, min_occurrences: 1)
|
|
172
|
+
return false unless str.is_a?(String)
|
|
173
|
+
s = str
|
|
174
|
+
s = s.downcase if ignore_case
|
|
175
|
+
se = ignore_case ? seed.downcase : seed
|
|
176
|
+
count = s.scan(Regexp.escape(se)).size
|
|
177
|
+
count >= min_occurrences
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def equals?(str, comparison)
|
|
181
|
+
return false unless str.is_a?(String)
|
|
182
|
+
str == comparison.to_s
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def is_in?(str, values)
|
|
186
|
+
return false unless str.is_a?(String)
|
|
187
|
+
Array(values).map(&:to_s).include?(str)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def is_credit_card?(str, provider: nil)
|
|
191
|
+
return false unless str.is_a?(String)
|
|
192
|
+
digits = str.gsub(/\D/, "")
|
|
193
|
+
return false unless digits.length >= 13 && digits.length <= 19
|
|
194
|
+
return false unless luhn_valid?(digits)
|
|
195
|
+
return true if provider.nil? || provider.to_s.empty?
|
|
196
|
+
case provider.to_s.downcase
|
|
197
|
+
when "visa" then digits.start_with?("4")
|
|
198
|
+
when "mastercard", "master" then digits.match?(/\A5[1-5]\d{14}\z/) || digits.match?(/\A2(?:2[2-9]|[3-6]\d|7[01])\d{12}\z/)
|
|
199
|
+
when "amex" then digits.match?(/\A3[47]\d{13}\z/)
|
|
200
|
+
when "discover" then digits.start_with?("6011", "65", "644", "645", "646", "647", "648", "649") || digits.match?(/\A62\d{14}\z/)
|
|
201
|
+
else true
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def is_md5?(str)
|
|
206
|
+
return false unless str.is_a?(String)
|
|
207
|
+
str.match?(/\A[0-9a-fA-F]{32}\z/)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def is_hexadecimal?(str)
|
|
211
|
+
return false unless str.is_a?(String)
|
|
212
|
+
str.match?(/\A[0-9a-fA-F]+\z/)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
private
|
|
216
|
+
|
|
217
|
+
def luhn_valid?(digits)
|
|
218
|
+
sum = 0
|
|
219
|
+
digits.reverse.chars.each_with_index do |c, i|
|
|
220
|
+
n = c.to_i
|
|
221
|
+
n *= 2 if i.odd?
|
|
222
|
+
n -= 9 if n > 9
|
|
223
|
+
sum += n
|
|
224
|
+
end
|
|
225
|
+
(sum % 10).zero?
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "string_validator/version"
|
|
4
|
+
require "string_validator/validators"
|
|
5
|
+
require "string_validator/sanitizers"
|
|
6
|
+
|
|
7
|
+
module StringValidator
|
|
8
|
+
extend Validators
|
|
9
|
+
extend Sanitizers
|
|
10
|
+
|
|
11
|
+
class Error < StandardError; end
|
|
12
|
+
class NotStringError < Error; end
|
|
13
|
+
|
|
14
|
+
def self.valid?(str, validator_name, **options)
|
|
15
|
+
raise NotStringError, "input must be a String" unless str.is_a?(String)
|
|
16
|
+
public_send(validator_name, str, **options)
|
|
17
|
+
end
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: string_validator
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Raj Panchal
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-02-16 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: A comprehensive library of string validators (is_email?, is_url?, is_ip?,
|
|
14
|
+
etc.) and sanitizers (escape, trim, etc.) for Ruby. Brings validator.js-style API
|
|
15
|
+
to Ruby/Rails.
|
|
16
|
+
email:
|
|
17
|
+
- rajpanchal2810@gmail.com
|
|
18
|
+
executables: []
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- CHANGELOG.md
|
|
23
|
+
- LICENSE.txt
|
|
24
|
+
- README.md
|
|
25
|
+
- lib/string_validator.rb
|
|
26
|
+
- lib/string_validator/sanitizers.rb
|
|
27
|
+
- lib/string_validator/validators.rb
|
|
28
|
+
- lib/string_validator/version.rb
|
|
29
|
+
homepage: https://github.com/rajpanchal01/string_validator
|
|
30
|
+
licenses:
|
|
31
|
+
- MIT
|
|
32
|
+
metadata:
|
|
33
|
+
homepage_uri: https://github.com/rajpanchal01/string_validator
|
|
34
|
+
source_code_uri: https://github.com/rajpanchal01/string_validator
|
|
35
|
+
changelog_uri: https://github.com/rajpanchal01/string_validator/blob/main/CHANGELOG.md
|
|
36
|
+
post_install_message:
|
|
37
|
+
rdoc_options: []
|
|
38
|
+
require_paths:
|
|
39
|
+
- lib
|
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: 3.0.0
|
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '0'
|
|
50
|
+
requirements: []
|
|
51
|
+
rubygems_version: 3.0.9
|
|
52
|
+
signing_key:
|
|
53
|
+
specification_version: 4
|
|
54
|
+
summary: String validators and sanitizers for Ruby - port of validator.js
|
|
55
|
+
test_files: []
|