no_regex 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a468f27fb587ec14c92c7a9164acc0afbe38f904fbc765bd206d589cc5e90c4e
4
+ data.tar.gz: 3c6b9c9d8c6179034637022cc010bfd19ff02968ca5a8bf174fb8ac548b7058f
5
+ SHA512:
6
+ metadata.gz: 1f380a614f7a93833d25e748240033b7ef88585140f0a4b2289c402f4336a1b974eff1ffcfa312ceec15831b07193941b7d3ec268cf6655ff44b16c61b35ea10
7
+ data.tar.gz: 21083b7f2f777552af3541f00e0a9f8a4cf99f65e0c98d29b7904f5f0509842118a88b94a06eb3e41e07600feddd8d31c10529fd5ce92a803231904aaeba4b6a
data/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # NoRegex
2
+
3
+ Write Ruby without regex! A gem that provides simple, readable methods to replace complex regular expressions for string validation and manipulation.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'no_regex'
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Convenient short alias for NoRegex
4
+ NR = NoRegex
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extensions for Integer class
4
+ class Integer
5
+ def is_positive?
6
+ self > 0
7
+ end
8
+
9
+ def is_negative?
10
+ self < 0
11
+ end
12
+
13
+ def is_zero?
14
+ self == 0
15
+ end
16
+
17
+ def is_even?
18
+ (self % 2).zero?
19
+ end
20
+
21
+ def is_odd?
22
+ !is_even?
23
+ end
24
+
25
+ def to_currency(symbol = "$")
26
+ "#{symbol}#{self}"
27
+ end
28
+
29
+ def to_formatted
30
+ self.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
31
+ end
32
+
33
+ def to_hex
34
+ "0x#{self.to_s(16).upcase}"
35
+ end
36
+
37
+ def to_binary
38
+ "0b#{self.to_s(2)}"
39
+ end
40
+
41
+ def to_words
42
+ # Simple implementation for numbers 0-999
43
+ return "zero" if self == 0
44
+
45
+ ones = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
46
+ teens = ["ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
47
+ tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
48
+
49
+ num = self.abs
50
+ result = []
51
+
52
+ if num >= 100
53
+ result << "#{ones[num / 100]} hundred"
54
+ num %= 100
55
+ end
56
+
57
+ if num >= 20
58
+ result << tens[num / 10]
59
+ num %= 10
60
+ elsif num >= 10
61
+ result << teens[num - 10]
62
+ num = 0
63
+ end
64
+
65
+ result << ones[num] if num > 0
66
+
67
+ word = result.join(" ").strip
68
+ self < 0 ? "negative #{word}" : word
69
+ end
70
+ end
71
+
72
+ # Extensions for Float class
73
+ class Float
74
+ def is_positive?
75
+ self > 0
76
+ end
77
+
78
+ def is_negative?
79
+ self < 0
80
+ end
81
+
82
+ def is_zero?
83
+ self.zero?
84
+ end
85
+
86
+ def to_currency(symbol = "$", decimals = 2)
87
+ "#{symbol}#{'%.2f' % self.round(decimals)}"
88
+ end
89
+
90
+ def to_percentage(decimals = 1)
91
+ "#{'%.1f' % (self * 100).round(decimals)}%"
92
+ end
93
+
94
+ def round_to(decimals)
95
+ (self * 10**decimals).round / 10.0**decimals
96
+ end
97
+
98
+ def is_integer?
99
+ self == self.to_i
100
+ end
101
+ end
102
+
103
+ # Extensions for NilClass
104
+ class NilClass
105
+ def is_blank?
106
+ true
107
+ end
108
+
109
+ def is_number?
110
+ false
111
+ end
112
+
113
+ def is_letters?
114
+ false
115
+ end
116
+
117
+ def is_email?
118
+ false
119
+ end
120
+ end
121
+
122
+ # Extensions for Array
123
+ class Array
124
+ def all_numbers?
125
+ return false if empty?
126
+ all? { |item| item.to_s.match?(/\A-?\d+(\.\d+)?\z/) }
127
+ end
128
+
129
+ def all_strings?
130
+ all? { |item| item.is_a?(String) }
131
+ end
132
+
133
+ def extract_numbers
134
+ select { |item| item.to_s.match?(/\A-?\d+(\.\d+)?\z/) }.map(&:to_f)
135
+ end
136
+
137
+ def extract_emails
138
+ select { |item| item.to_s.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i) }
139
+ end
140
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NoRegex
4
+ module PatternMethods
5
+ # Define methods that return regex patterns
6
+ def is_number?
7
+ # Examples: "12345", "0", "999"
8
+ /\A\d+\z/
9
+ end
10
+
11
+ def is_letters?
12
+ # Examples: "hello", "World", "ABC"
13
+ /\A[a-zA-Z]+\z/
14
+ end
15
+
16
+ def is_alphanumeric?
17
+ # Examples: "abc123", "Test99", "2024Year"
18
+ /\A[a-zA-Z0-9]+\z/
19
+ end
20
+
21
+ def is_email?
22
+ # Examples: "user@example.com", "john.doe+tag@company.co.uk"
23
+ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
24
+ end
25
+
26
+ def is_url?
27
+ # Examples: "https://example.com", "www.site.org", "subdomain.example.com/path"
28
+ /\A(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\z/
29
+ end
30
+
31
+ def is_phone_number?
32
+ # Examples: "+1 555-123-4567", "555 123 4567", "(555) 123-4567"
33
+ /\A\+?[\d\s\-\(\)]+\z/
34
+ end
35
+
36
+ def is_zip_code?
37
+ # Examples: "12345", "12345-6789"
38
+ /\A\d{5}(-\d{4})?\z/
39
+ end
40
+
41
+ def is_hex_color?
42
+ # Examples: "#FF5733", "FF5733", "#00ff00"
43
+ /\A#?[0-9A-Fa-f]{6}\z/
44
+ end
45
+
46
+ def is_username?
47
+ # Examples: "john_doe", "user123", "test-user"
48
+ /\A[a-zA-Z0-9_\-]+\z/
49
+ end
50
+
51
+ def is_decimal?
52
+ # Examples: "123.45", "0.5", "100"
53
+ /\A\d+(\.\d+)?\z/
54
+ end
55
+
56
+ def is_integer?
57
+ # Examples: "123", "-456", "0"
58
+ /\A-?\d+\z/
59
+ end
60
+
61
+ def is_positive_number?
62
+ # Examples: "1", "123", "999"
63
+ /\A[1-9]\d*\z/
64
+ end
65
+
66
+ def is_uuid?
67
+ # Examples: "550e8400-e29b-41d4-a716-446655440000", "123e4567-e89b-12d3-a456-426614174000"
68
+ /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
69
+ end
70
+
71
+ def is_credit_card?
72
+ # Examples: "1234567812345678", "1234 5678 1234 5678", "1234-5678-1234-5678"
73
+ /\A\d{4}[\s\-]?\d{4}[\s\-]?\d{4}[\s\-]?\d{4}\z/
74
+ end
75
+
76
+ def is_ssn?
77
+ # Examples: "123-45-6789", "123456789"
78
+ /\A\d{3}-?\d{2}-?\d{4}\z/
79
+ end
80
+
81
+ def is_ipv4?
82
+ # Examples: "192.168.1.1", "10.0.0.255", "8.8.8.8"
83
+ /\A(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\z/
84
+ end
85
+
86
+ def is_time_24h?
87
+ # Examples: "14:30", "09:45", "23:59"
88
+ /\A(?:[01]\d|2[0-3]):[0-5]\d\z/
89
+ end
90
+
91
+ def is_date_yyyy_mm_dd?
92
+ # Examples: "2024-01-15", "2023-12-31", "2022-06-01"
93
+ /\A\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])\z/
94
+ end
95
+
96
+ def has_no_spaces?
97
+ # Examples: "hello", "test123", "no-spaces-here"
98
+ /\A[^\s]+\z/
99
+ end
100
+
101
+ def has_no_special_chars?
102
+ # Examples: "Hello World", "Test 123", "abc"
103
+ /\A[a-zA-Z0-9\s]+\z/
104
+ end
105
+ end
106
+ end
107
+
108
+ # Make these methods available at the top level
109
+ extend NoRegex::PatternMethods
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Custom validators for Rails
4
+ if defined?(ActiveModel)
5
+ module NoRegex
6
+ # Base validator class
7
+ class BaseValidator < ActiveModel::EachValidator
8
+ def validate_each(record, attribute, value)
9
+ return if value.blank? && options[:allow_blank]
10
+ return if value.nil? && options[:allow_nil]
11
+
12
+ unless value.to_s.send(validation_method)
13
+ record.errors.add(attribute, options[:message] || default_message)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def validation_method
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def default_message
24
+ raise NotImplementedError
25
+ end
26
+ end
27
+
28
+ # Validator for checking if a value contains only numbers
29
+ class NumberValidator < BaseValidator
30
+ private
31
+ def validation_method; :is_number?; end
32
+ def default_message; "must be a number"; end
33
+ end
34
+
35
+ # Validator for checking if a value contains only letters
36
+ class LettersValidator < BaseValidator
37
+ private
38
+ def validation_method; :is_letters?; end
39
+ def default_message; "must contain only letters"; end
40
+ end
41
+
42
+ # Validator for checking if a value is alphanumeric
43
+ class AlphanumericValidator < BaseValidator
44
+ private
45
+ def validation_method; :is_alphanumeric?; end
46
+ def default_message; "must contain only letters and numbers"; end
47
+ end
48
+
49
+ # Validator for email format
50
+ class EmailFormatValidator < BaseValidator
51
+ private
52
+ def validation_method; :is_email?; end
53
+ def default_message; "must be a valid email address"; end
54
+ end
55
+
56
+ # Validator for URL format
57
+ class UrlFormatValidator < BaseValidator
58
+ private
59
+ def validation_method; :is_url?; end
60
+ def default_message; "must be a valid URL"; end
61
+ end
62
+
63
+ # Validator for phone number format
64
+ class PhoneNumberValidator < BaseValidator
65
+ private
66
+ def validation_method; :is_phone_number?; end
67
+ def default_message; "must be a valid phone number"; end
68
+ end
69
+
70
+ # Validator for username format
71
+ class UsernameValidator < BaseValidator
72
+ private
73
+ def validation_method; :is_username?; end
74
+ def default_message; "can only contain letters, numbers, underscores and hyphens"; end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extensions to the String class
4
+ class String
5
+ # Check methods - return true/false
6
+ def is_number?
7
+ match?(/\A\d+\z/)
8
+ end
9
+
10
+ def is_letters?
11
+ match?(/\A[a-zA-Z]+\z/)
12
+ end
13
+
14
+ def is_alphanumeric?
15
+ match?(/\A[a-zA-Z0-9]+\z/)
16
+ end
17
+
18
+ def is_email?
19
+ match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
20
+ end
21
+
22
+ def is_blank?
23
+ strip.empty?
24
+ end
25
+
26
+ def is_url?
27
+ match?(/\A(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\z/)
28
+ end
29
+
30
+ def is_phone_number?
31
+ match?(/\A\+?[\d\s\-\(\)]+\z/)
32
+ end
33
+
34
+ def is_zip_code?
35
+ match?(/\A\d{5}(-\d{4})?\z/)
36
+ end
37
+
38
+ def is_hex_color?
39
+ match?(/\A#?[0-9A-Fa-f]{6}\z/)
40
+ end
41
+
42
+ def is_username?
43
+ match?(/\A[a-zA-Z0-9_\-]+\z/)
44
+ end
45
+
46
+ def is_decimal?
47
+ match?(/\A\d+(\.\d+)?\z/)
48
+ end
49
+
50
+ def is_integer?
51
+ match?(/\A-?\d+\z/)
52
+ end
53
+
54
+ def is_positive_number?
55
+ match?(/\A[1-9]\d*\z/)
56
+ end
57
+
58
+ def is_uuid?
59
+ match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i)
60
+ end
61
+
62
+ def is_credit_card?
63
+ match?(/\A\d{4}[\s\-]?\d{4}[\s\-]?\d{4}[\s\-]?\d{4}\z/)
64
+ end
65
+
66
+ def is_ssn?
67
+ match?(/\A\d{3}-?\d{2}-?\d{4}\z/)
68
+ end
69
+
70
+ def is_ipv4?
71
+ match?(/\A(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\z/)
72
+ end
73
+
74
+ def is_time_24h?
75
+ match?(/\A(?:[01]\d|2[0-3]):[0-5]\d\z/)
76
+ end
77
+
78
+ def is_date_yyyy_mm_dd?
79
+ match?(/\A\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])\z/)
80
+ end
81
+
82
+ def has_no_spaces?
83
+ match?(/\A[^\s]+\z/)
84
+ end
85
+
86
+ def has_no_special_chars?
87
+ match?(/\A[a-zA-Z0-9\s]+\z/)
88
+ end
89
+
90
+ # Manipulation methods - return modified strings
91
+ def remove_dashes
92
+ gsub("-", "")
93
+ end
94
+
95
+ def remove_spaces
96
+ gsub(" ", "")
97
+ end
98
+
99
+ def remove_special_chars
100
+ gsub(/[^a-zA-Z0-9]/, "")
101
+ end
102
+
103
+ def remove_numbers
104
+ gsub(/\d/, "")
105
+ end
106
+
107
+ def remove_letters
108
+ gsub(/[a-zA-Z]/, "")
109
+ end
110
+
111
+ def keep_numbers
112
+ gsub(/[^\d]/, "")
113
+ end
114
+
115
+ def keep_letters
116
+ gsub(/[^a-zA-Z]/, "")
117
+ end
118
+
119
+ def to_snake_case
120
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
121
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
122
+ .tr("-", "_")
123
+ .downcase
124
+ end
125
+
126
+ def to_camel_case
127
+ parts = split(/[_\-\s]/)
128
+ parts[0].downcase + parts[1..-1].map(&:capitalize).join
129
+ end
130
+
131
+ # Extraction methods - return arrays or other data
132
+ def extract_numbers
133
+ scan(/\d+/)
134
+ end
135
+
136
+ def extract_emails
137
+ scan(/[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+/i)
138
+ end
139
+
140
+ def word_count
141
+ split.size
142
+ end
143
+
144
+ def truncate(length = 30, ellipsis = "...")
145
+ return self if self.length <= length
146
+ self[0...(length - ellipsis.length)] + ellipsis
147
+ end
148
+ end
149
+
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NoRegex
4
+ VERSION = "0.1.0"
5
+ end
6
+
data/lib/no_regex.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "no_regex/version"
4
+ require_relative "no_regex/string_extensions"
5
+ require_relative "no_regex/numeric_extensions"
6
+ require_relative "no_regex/pattern_methods"
7
+
8
+ # Load Rails validators if Rails is present
9
+ if defined?(Rails) || defined?(ActiveModel)
10
+ require_relative "no_regex/rails_validators"
11
+ end
12
+
13
+ module NoRegex
14
+ class Error < StandardError; end
15
+ end
16
+
17
+ # Load aliases after module is defined
18
+ require_relative "no_regex/aliases"
19
+
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: no_regex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Your Name
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rake
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '13.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '13.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rubocop
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.21'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.21'
54
+ description: Replace complex regex patterns with simple, readable methods for string
55
+ validation and manipulation
56
+ email:
57
+ - your.email@example.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - README.md
63
+ - lib/no_regex.rb
64
+ - lib/no_regex/aliases.rb
65
+ - lib/no_regex/numeric_extensions.rb
66
+ - lib/no_regex/pattern_methods.rb
67
+ - lib/no_regex/rails_validators.rb
68
+ - lib/no_regex/string_extensions.rb
69
+ - lib/no_regex/version.rb
70
+ homepage: https://github.com/yourusername/no_regex
71
+ licenses:
72
+ - MIT
73
+ metadata:
74
+ homepage_uri: https://github.com/yourusername/no_regex
75
+ source_code_uri: https://github.com/yourusername/no_regex
76
+ changelog_uri: https://github.com/yourusername/no_regex/blob/main/CHANGELOG.md
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.6.0
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.6.9
92
+ specification_version: 4
93
+ summary: Write Ruby without regex
94
+ test_files: []