string_wizard 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: 77a377b78f738c3a61b4b851407971dca945528bf2b6107e741219c91ff126c4
4
+ data.tar.gz: 6bb673e6a74c0996fe1f5432bd36c7315f3960ac2139f4d6b113c920e028bd6f
5
+ SHA512:
6
+ metadata.gz: aef54bddf1d3424e24d9901dedbe651325c12dcaffd53fb2d86d2b2cb8af48e68303d6152364459258c12565c081079864c54cb10abf8212f5ab4979717d0659
7
+ data.tar.gz: 8dd77cf902dc0f192904c8558eb27cfe5bbd5c34465f637b1feb6839d06d02f324334d8b285cf65650f749659d0e04fccb47265dee2b4f6e3eaf36684e5b15cb
@@ -0,0 +1,156 @@
1
+ class String
2
+ # Returns a string with the first letter of each word capitalized
3
+ def titleize
4
+ StringEnhancer.titleize(self)
5
+ end
6
+
7
+ # Returns a string with all vowels removed
8
+ def remove_vowels
9
+ StringEnhancer.remove_vowels(self)
10
+ end
11
+
12
+ # Returns a string with all consonants removed
13
+ def remove_consonants
14
+ StringEnhancer.remove_consonants(self)
15
+ end
16
+
17
+ # Returns true if the string is a palindrome
18
+ def palindrome?
19
+ StringEnhancer.palindrome?(self)
20
+ end
21
+
22
+ # Returns a string with alternating case
23
+ def alternating_case
24
+ StringEnhancer.alternating_case(self)
25
+ end
26
+
27
+ # Returns a string with words in reverse order
28
+ def reverse_words
29
+ StringEnhancer.reverse_words(self)
30
+ end
31
+
32
+ # Advanced string analysis
33
+ def analyze
34
+ StringEnhancer.analyze(self)
35
+ end
36
+
37
+ # Pattern matching
38
+ def match_pattern(pattern)
39
+ StringEnhancer.match_pattern(self, pattern)
40
+ end
41
+
42
+ def matches_pattern?(pattern_name)
43
+ StringEnhancer::PatternMatcher.match_pattern(self, pattern_name)
44
+ end
45
+
46
+ def extract_patterns
47
+ StringEnhancer::PatternMatcher.extract_patterns(self)
48
+ end
49
+
50
+ def validate_format(pattern_name)
51
+ StringEnhancer::PatternMatcher.validate_format(self, pattern_name)
52
+ end
53
+
54
+ def sanitize(pattern_name)
55
+ StringEnhancer::PatternMatcher.sanitize(self, pattern_name)
56
+ end
57
+
58
+ # String transformation chain
59
+ def transform
60
+ StringEnhancer::Transformer.transform(self)
61
+ end
62
+
63
+ # String similarity
64
+ def similarity(other)
65
+ StringEnhancer.similarity(self, other)
66
+ end
67
+
68
+ # Parallel processing
69
+ def self.process_batch(strings, batch_size: 100, &block)
70
+ StringEnhancer.process_batch(strings, batch_size: batch_size, &block)
71
+ end
72
+
73
+ def self.analyze_batch(strings, batch_size: 100)
74
+ StringEnhancer.analyze_batch(strings, batch_size: batch_size)
75
+ end
76
+
77
+ def self.transform_batch(strings, transformations, batch_size: 100)
78
+ StringEnhancer.transform_batch(strings, transformations, batch_size: batch_size)
79
+ end
80
+
81
+ def self.similarity_matrix(strings, batch_size: 100)
82
+ StringEnhancer.similarity_matrix(strings, batch_size: batch_size)
83
+ end
84
+
85
+ # Encryption
86
+ def encrypt(key, algorithm: 'AES-256-CBC')
87
+ StringEnhancer.encrypt(self, key, algorithm: algorithm)
88
+ end
89
+
90
+ def self.decrypt(encrypted_str, key, algorithm: 'AES-256-CBC')
91
+ StringEnhancer.decrypt(encrypted_str, key, algorithm: algorithm)
92
+ end
93
+
94
+ def hash(algorithm: :sha256)
95
+ StringEnhancer.hash(self, algorithm: algorithm)
96
+ end
97
+
98
+ def secure_compare(other)
99
+ StringEnhancer.secure_compare(self, other)
100
+ end
101
+
102
+ # Fuzzy matching
103
+ def fuzzy_match(candidates, threshold: 0.8)
104
+ StringEnhancer.fuzzy_match(self, candidates, threshold: threshold)
105
+ end
106
+
107
+ def best_match(candidates, threshold: 0.8)
108
+ StringEnhancer.best_match(self, candidates, threshold: threshold)
109
+ end
110
+
111
+ # Validation methods
112
+ def valid_email?
113
+ StringEnhancer.valid_email?(self)
114
+ end
115
+
116
+ def valid_url?
117
+ StringEnhancer.valid_url?(self)
118
+ end
119
+
120
+ def valid_phone?
121
+ StringEnhancer.valid_phone?(self)
122
+ end
123
+
124
+ def valid_date?(format: '%Y-%m-%d')
125
+ StringEnhancer.valid_date?(self, format: format)
126
+ end
127
+
128
+ def valid_time?
129
+ StringEnhancer.valid_time?(self)
130
+ end
131
+
132
+ def valid_ip?
133
+ StringEnhancer.valid_ip?(self)
134
+ end
135
+
136
+ def valid_credit_card?
137
+ StringEnhancer.valid_credit_card?(self)
138
+ end
139
+
140
+ def valid_hex_color?
141
+ StringEnhancer.valid_hex_color?(self)
142
+ end
143
+
144
+ def valid_json?
145
+ StringEnhancer.valid_json?(self)
146
+ end
147
+
148
+ def valid_xml?
149
+ StringEnhancer.valid_xml?(self)
150
+ end
151
+
152
+ # Clear memoization cache
153
+ def self.clear_cache
154
+ StringEnhancer.clear_cache
155
+ end
156
+ end
@@ -0,0 +1,67 @@
1
+ module StringEnhancer
2
+ module Encryption
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ class << self
7
+ def encrypt(str, key, algorithm: 'AES-256-CBC')
8
+ cipher = OpenSSL::Cipher.new(algorithm)
9
+ cipher.encrypt
10
+ cipher.key = Digest::SHA256.digest(key)
11
+ iv = cipher.random_iv
12
+
13
+ encrypted = cipher.update(str) + cipher.final
14
+ Base64.strict_encode64(iv + encrypted)
15
+ end
16
+
17
+ def decrypt(encrypted_str, key, algorithm: 'AES-256-CBC')
18
+ decoded = Base64.strict_decode64(encrypted_str)
19
+ cipher = OpenSSL::Cipher.new(algorithm)
20
+ cipher.decrypt
21
+ cipher.key = Digest::SHA256.digest(key)
22
+
23
+ iv = decoded[0...cipher.iv_len]
24
+ encrypted = decoded[cipher.iv_len..-1]
25
+
26
+ cipher.iv = iv
27
+ cipher.update(encrypted) + cipher.final
28
+ end
29
+
30
+ def hash(str, algorithm: :sha256)
31
+ case algorithm
32
+ when :sha256
33
+ Digest::SHA256.hexdigest(str)
34
+ when :sha512
35
+ Digest::SHA512.hexdigest(str)
36
+ when :md5
37
+ Digest::MD5.hexdigest(str)
38
+ else
39
+ raise Error, "Unsupported hash algorithm: #{algorithm}"
40
+ end
41
+ end
42
+
43
+ def secure_compare(str1, str2)
44
+ return false unless str1.bytesize == str2.bytesize
45
+
46
+ result = 0
47
+ str1.bytes.zip(str2.bytes) do |b1, b2|
48
+ result |= b1 ^ b2
49
+ end
50
+ result.zero?
51
+ end
52
+
53
+ def generate_salt(length = 16)
54
+ OpenSSL::Random.random_bytes(length)
55
+ end
56
+
57
+ def pbkdf2(str, salt, iterations: 10000, key_length: 32)
58
+ OpenSSL::PKCS5.pbkdf2_hmac_sha1(
59
+ str,
60
+ salt,
61
+ iterations,
62
+ key_length
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,41 @@
1
+ module StringEnhancer
2
+ module PatternMatcher
3
+ # Predefined patterns for common use cases
4
+ PATTERNS = {
5
+ email: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i,
6
+ url: %r{\Ahttps?://[^\s/$.?#].[^\s]*\z},
7
+ phone: /\A\+?[\d\s\-()]{10,}\z/,
8
+ date: /\A\d{4}-\d{2}-\d{2}\z/,
9
+ time: /\A([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?\z/,
10
+ ip_address: /\A(\d{1,3}\.){3}\d{1,3}\z/,
11
+ credit_card: /\A\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\z/,
12
+ hex_color: /\A#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})\z/
13
+ }.freeze
14
+
15
+ def self.match_pattern(str, pattern_name)
16
+ pattern = PATTERNS[pattern_name.to_sym]
17
+ raise PatternMatchError, "Unknown pattern: #{pattern_name}" unless pattern
18
+
19
+ pattern.match?(str)
20
+ end
21
+
22
+ def self.extract_patterns(str)
23
+ matches = {}
24
+ PATTERNS.each do |name, pattern|
25
+ matches[name] = str.scan(pattern)
26
+ end
27
+ matches
28
+ end
29
+
30
+ def self.validate_format(str, pattern_name)
31
+ match_pattern(str, pattern_name)
32
+ end
33
+
34
+ def self.sanitize(str, pattern_name)
35
+ pattern = PATTERNS[pattern_name.to_sym]
36
+ raise PatternMatchError, "Unknown pattern: #{pattern_name}" unless pattern
37
+
38
+ str.gsub(pattern, '')
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,76 @@
1
+ module StringEnhancer
2
+ module Transformer
3
+ class Chain
4
+ def initialize(str)
5
+ @str = str
6
+ @transformations = []
7
+ end
8
+
9
+ def titleize
10
+ @transformations << :titleize
11
+ self
12
+ end
13
+
14
+ def upcase
15
+ @transformations << :upcase
16
+ self
17
+ end
18
+
19
+ def downcase
20
+ @transformations << :downcase
21
+ self
22
+ end
23
+
24
+ def reverse
25
+ @transformations << :reverse
26
+ self
27
+ end
28
+
29
+ def strip
30
+ @transformations << :strip
31
+ self
32
+ end
33
+
34
+ def remove_vowels
35
+ @transformations << :remove_vowels
36
+ self
37
+ end
38
+
39
+ def remove_consonants
40
+ @transformations << :remove_consonants
41
+ self
42
+ end
43
+
44
+ def alternating_case
45
+ @transformations << :alternating_case
46
+ self
47
+ end
48
+
49
+ def reverse_words
50
+ @transformations << :reverse_words
51
+ self
52
+ end
53
+
54
+ def custom(&block)
55
+ @transformations << block
56
+ self
57
+ end
58
+
59
+ def apply
60
+ result = @str.dup
61
+ @transformations.each do |transformation|
62
+ if transformation.is_a?(Proc)
63
+ result = transformation.call(result)
64
+ else
65
+ result = StringEnhancer.transform(result, transformation)
66
+ end
67
+ end
68
+ result
69
+ end
70
+ end
71
+
72
+ def self.transform(str)
73
+ Chain.new(str)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,45 @@
1
+ module StringEnhancer
2
+ module Validator
3
+ class << self
4
+ def valid_email?(str)
5
+ str.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
6
+ end
7
+
8
+ def valid_url?(str)
9
+ str.match?(%r{\Ahttps?://[^\s/$.?#].[^\s]*\z})
10
+ end
11
+
12
+ def valid_phone?(str)
13
+ str.match?(/\A\+?[\d\s\-()]{10,}\z/)
14
+ end
15
+
16
+ def valid_date?(str, format: '%Y-%m-%d')
17
+ Date.strptime(str, format) rescue false
18
+ end
19
+
20
+ def valid_time?(str)
21
+ str.match?(/\A([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?\z/)
22
+ end
23
+
24
+ def valid_ip?(str)
25
+ str.match?(/\A(\d{1,3}\.){3}\d{1,3}\z/)
26
+ end
27
+
28
+ def valid_credit_card?(str)
29
+ str.match?(/\A\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\z/)
30
+ end
31
+
32
+ def valid_hex_color?(str)
33
+ str.match?(/\A#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})\z/)
34
+ end
35
+
36
+ def valid_json?(str)
37
+ JSON.parse(str) rescue false
38
+ end
39
+
40
+ def valid_xml?(str)
41
+ Nokogiri::XML(str) rescue false
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module StringEnhancer
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,3 @@
1
+ module StringWizard
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,261 @@
1
+ require "string_wizard/version"
2
+ require "string_wizard/core_ext"
3
+ require "string_wizard/pattern_matcher"
4
+ require "string_wizard/transformer"
5
+ require "string_wizard/validator"
6
+ require "json"
7
+ require "nokogiri"
8
+ require "date"
9
+
10
+ module StringWizard
11
+ class Error < StandardError; end
12
+ class PatternMatchError < Error; end
13
+ class EncryptionError < Error; end
14
+
15
+ # Memoization cache for expensive operations
16
+ @memo_cache = {}
17
+
18
+ class << self
19
+ # Basic string operations
20
+ def titleize(str)
21
+ str.split.map(&:capitalize).join(' ')
22
+ end
23
+
24
+ def remove_vowels(str)
25
+ str.gsub(/[aeiouAEIOU]/, '')
26
+ end
27
+
28
+ def remove_consonants(str)
29
+ str.gsub(/[^aeiouAEIOU\s]/, '')
30
+ end
31
+
32
+ def palindrome?(str)
33
+ normalized = str.downcase.gsub(/[^a-z0-9]/, '')
34
+ normalized == normalized.reverse
35
+ end
36
+
37
+ def alternating_case(str)
38
+ str.chars.each_with_index.map do |char, index|
39
+ index.even? ? char.upcase : char.downcase
40
+ end.join
41
+ end
42
+
43
+ def reverse_words(str)
44
+ str.split.reverse.join(' ')
45
+ end
46
+
47
+ # Advanced string analysis
48
+ def analyze(str)
49
+ {
50
+ length: str.length,
51
+ word_count: str.split.size,
52
+ character_frequency: character_frequency(str),
53
+ vowel_count: str.scan(/[aeiouAEIOU]/).size,
54
+ consonant_count: str.scan(/[^aeiouAEIOU\s\W]/).size,
55
+ digit_count: str.scan(/\d/).size,
56
+ special_char_count: str.scan(/[^a-zA-Z0-9\s]/).size,
57
+ entropy: calculate_entropy(str),
58
+ readability_score: calculate_readability(str)
59
+ }
60
+ end
61
+
62
+ # Pattern matching
63
+ def match_pattern(str, pattern)
64
+ regex = pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern)
65
+ match = regex.match(str)
66
+ return nil unless match
67
+
68
+ if match.named_captures.any?
69
+ match.named_captures
70
+ else
71
+ match.captures
72
+ end
73
+ end
74
+
75
+ # String transformation chain
76
+ def transform(str, *transformations)
77
+ transformations.inject(str) do |result, transformation|
78
+ case transformation
79
+ when :titleize then titleize(result)
80
+ when :upcase then result.upcase
81
+ when :downcase then result.downcase
82
+ when :reverse then result.reverse
83
+ when :strip then result.strip
84
+ when :remove_vowels then remove_vowels(result)
85
+ when :remove_consonants then remove_consonants(result)
86
+ when :alternating_case then alternating_case(result)
87
+ when :reverse_words then reverse_words(result)
88
+ else
89
+ raise Error, "Unknown transformation: #{transformation}"
90
+ end
91
+ end
92
+ end
93
+
94
+ # Memoized character frequency analysis
95
+ def character_frequency(str)
96
+ @memo_cache["frequency_#{str}"] ||= begin
97
+ frequency = Hash.new(0)
98
+ str.each_char { |char| frequency[char] += 1 }
99
+ frequency
100
+ end
101
+ end
102
+
103
+ # Clear memoization cache
104
+ def clear_cache
105
+ @memo_cache.clear
106
+ end
107
+
108
+ # String similarity methods
109
+ def similarity(str1, str2)
110
+ return 1.0 if str1 == str2
111
+ return 0.0 if str1.empty? || str2.empty?
112
+
113
+ # Calculate Levenshtein distance
114
+ distance = levenshtein_distance(str1, str2)
115
+ max_length = [str1.length, str2.length].max
116
+ 1.0 - (distance.to_f / max_length)
117
+ end
118
+
119
+ # Encryption
120
+ def encrypt(str, key, algorithm: 'AES-256-CBC')
121
+ Encryption.encrypt(str, key, algorithm: algorithm)
122
+ end
123
+
124
+ def decrypt(encrypted_str, key, algorithm: 'AES-256-CBC')
125
+ Encryption.decrypt(encrypted_str, key, algorithm: algorithm)
126
+ end
127
+
128
+ def hash(str, algorithm: :sha256)
129
+ Encryption.hash(str, algorithm: algorithm)
130
+ end
131
+
132
+ def secure_compare(str1, str2)
133
+ Encryption.secure_compare(str1, str2)
134
+ end
135
+
136
+ # String validation
137
+ def valid_email?(str)
138
+ str.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
139
+ end
140
+
141
+ def valid_url?(str)
142
+ str.match?(/\Ahttps?:\/\/[\w\-]+(\.[\w\-]+)+[\/#?]?.*\z/i)
143
+ end
144
+
145
+ def valid_phone?(str)
146
+ str.match?(/\A\+?[\d\s\-()]+\z/)
147
+ end
148
+
149
+ def valid_date?(str, format: '%Y-%m-%d')
150
+ Date.strptime(str, format)
151
+ true
152
+ rescue Date::Error
153
+ false
154
+ end
155
+
156
+ def valid_time?(str)
157
+ str.match?(/\A([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?\z/)
158
+ end
159
+
160
+ def valid_ip?(str)
161
+ str.match?(/\A(\d{1,3}\.){3}\d{1,3}\z/) &&
162
+ str.split('.').all? { |octet| octet.to_i.between?(0, 255) }
163
+ end
164
+
165
+ def valid_credit_card?(str)
166
+ # Remove all non-digit characters
167
+ digits = str.gsub(/\D/, '').chars.map(&:to_i)
168
+ return false if digits.empty?
169
+
170
+ # Luhn algorithm
171
+ sum = 0
172
+ digits.reverse.each_with_index do |digit, index|
173
+ if index.odd?
174
+ doubled = digit * 2
175
+ sum += doubled > 9 ? doubled - 9 : doubled
176
+ else
177
+ sum += digit
178
+ end
179
+ end
180
+
181
+ (sum % 10).zero?
182
+ end
183
+
184
+ def valid_hex_color?(str)
185
+ str.match?(/\A#[0-9A-Fa-f]{6}\z/)
186
+ end
187
+
188
+ def valid_json?(str)
189
+ JSON.parse(str)
190
+ true
191
+ rescue JSON::ParserError
192
+ false
193
+ end
194
+
195
+ def valid_xml?(str)
196
+ Nokogiri::XML(str) { |config| config.strict }
197
+ true
198
+ rescue Nokogiri::XML::SyntaxError
199
+ false
200
+ end
201
+
202
+ private
203
+
204
+ # Levenshtein distance calculation
205
+ def levenshtein_distance(str1, str2)
206
+ m = str1.length
207
+ n = str2.length
208
+ return m if n == 0
209
+ return n if m == 0
210
+
211
+ d = Array.new(m + 1) { Array.new(n + 1) }
212
+
213
+ (0..m).each { |i| d[i][0] = i }
214
+ (0..n).each { |j| d[0][j] = j }
215
+
216
+ (1..m).each do |i|
217
+ (1..n).each do |j|
218
+ cost = str1[i - 1] == str2[j - 1] ? 0 : 1
219
+ d[i][j] = [
220
+ d[i - 1][j] + 1, # deletion
221
+ d[i][j - 1] + 1, # insertion
222
+ d[i - 1][j - 1] + cost # substitution
223
+ ].min
224
+ end
225
+ end
226
+
227
+ d[m][n]
228
+ end
229
+
230
+ # Calculate string entropy
231
+ def calculate_entropy(str)
232
+ return 0.0 if str.empty?
233
+
234
+ frequency = character_frequency(str)
235
+ length = str.length.to_f
236
+
237
+ -frequency.values.sum do |count|
238
+ probability = count / length
239
+ probability * Math.log2(probability)
240
+ end
241
+ end
242
+
243
+ # Calculate readability score
244
+ def calculate_readability(str)
245
+ words = str.split
246
+ sentences = str.split(/[.!?]+/)
247
+ syllables = words.sum { |word| count_syllables(word) }
248
+
249
+ return 0.0 if words.empty? || sentences.empty?
250
+
251
+ # Flesch-Kincaid Grade Level
252
+ (0.39 * (words.size / sentences.size.to_f)) +
253
+ (11.8 * (syllables / words.size.to_f)) - 15.59
254
+ end
255
+
256
+ # Count syllables in a word
257
+ def count_syllables(word)
258
+ word.downcase.gsub(/[^a-z]/, '').scan(/[aeiouy]+/).size
259
+ end
260
+ end
261
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: string_wizard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hassan Tahir
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.10'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: date
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description: Provides a wizard's toolkit of string manipulation methods that aren't
98
+ available in Ruby's standard library
99
+ email:
100
+ - hassantahirjaura@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - lib/string_enhancer/core_ext.rb
106
+ - lib/string_enhancer/encryption.rb
107
+ - lib/string_enhancer/pattern_matcher.rb
108
+ - lib/string_enhancer/transformer.rb
109
+ - lib/string_enhancer/validator.rb
110
+ - lib/string_enhancer/version.rb
111
+ - lib/string_wizard.rb
112
+ - lib/string_wizard/version.rb
113
+ homepage: https://github.com/hassantahir176/string_wizard
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: 2.6.0
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubygems_version: 3.5.22
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: A magical collection of string manipulation and validation methods
136
+ test_files: []