Module: StringWizard

Defined in:
lib/string_wizard.rb,
lib/string_wizard/version.rb,
lib/string_wizard/validator.rb,
lib/string_wizard/encryption.rb,
lib/string_wizard/transformer.rb,
lib/string_wizard/pattern_matcher.rb

Defined Under Namespace

Modules: Encryption, PatternMatcher, Transformer, Validator Classes: EncryptionError, Error, PatternMatchError

Constant Summary collapse

VERSION =
"0.1.1"

Class Method Summary collapse

Class Method Details

.alternating_case(str) ⇒ Object



37
38
39
40
41
# File 'lib/string_wizard.rb', line 37

def alternating_case(str)
  str.chars.each_with_index.map do |char, index|
    index.even? ? char.upcase : char.downcase
  end.join
end

.analyze(str) ⇒ Object

Advanced string analysis



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/string_wizard.rb', line 48

def analyze(str)
  {
    length: str.length,
    word_count: str.split.size,
    character_frequency: character_frequency(str),
    vowel_count: str.scan(/[aeiouAEIOU]/).size,
    consonant_count: str.scan(/[^aeiouAEIOU\s\W]/).size,
    digit_count: str.scan(/\d/).size,
    special_char_count: str.scan(/[^a-zA-Z0-9\s]/).size,
    entropy: calculate_entropy(str),
    readability_score: calculate_readability(str)
  }
end

.character_frequency(str) ⇒ Object

Memoized character frequency analysis



95
96
97
98
99
100
101
# File 'lib/string_wizard.rb', line 95

def character_frequency(str)
  @memo_cache["frequency_#{str}"] ||= begin
    frequency = Hash.new(0)
    str.each_char { |char| frequency[char] += 1 }
    frequency
  end
end

.clear_cacheObject

Clear memoization cache



104
105
106
# File 'lib/string_wizard.rb', line 104

def clear_cache
  @memo_cache.clear
end

.decrypt(encrypted_str, key, algorithm: 'AES-256-CBC') ⇒ Object



124
125
126
# File 'lib/string_wizard.rb', line 124

def decrypt(encrypted_str, key, algorithm: 'AES-256-CBC')
  Encryption.decrypt(encrypted_str, key, algorithm: algorithm)
end

.encrypt(str, key, algorithm: 'AES-256-CBC') ⇒ Object

Encryption



120
121
122
# File 'lib/string_wizard.rb', line 120

def encrypt(str, key, algorithm: 'AES-256-CBC')
  Encryption.encrypt(str, key, algorithm: algorithm)
end

.hash(str, algorithm: :sha256) ⇒ Object



128
129
130
# File 'lib/string_wizard.rb', line 128

def hash(str, algorithm: :sha256)
  Encryption.hash(str, algorithm: algorithm)
end

.match_pattern(str, pattern) ⇒ Object

Pattern matching



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/string_wizard.rb', line 63

def match_pattern(str, pattern)
  regex = pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern)
  match = regex.match(str)
  return nil unless match

  if match.named_captures.any?
    match.named_captures
  else
    match.captures
  end
end

.palindrome?(str) ⇒ Boolean

Returns:

  • (Boolean)


32
33
34
35
# File 'lib/string_wizard.rb', line 32

def palindrome?(str)
  normalized = str.downcase.gsub(/[^a-z0-9]/, '')
  normalized == normalized.reverse
end

.remove_consonants(str) ⇒ Object



28
29
30
# File 'lib/string_wizard.rb', line 28

def remove_consonants(str)
  str.gsub(/[^aeiouAEIOU\s]/, '')
end

.remove_vowels(str) ⇒ Object



24
25
26
# File 'lib/string_wizard.rb', line 24

def remove_vowels(str)
  str.gsub(/[aeiouAEIOU]/, '')
end

.reverse_words(str) ⇒ Object



43
44
45
# File 'lib/string_wizard.rb', line 43

def reverse_words(str)
  str.split.reverse.join(' ')
end

.secure_compare(str1, str2) ⇒ Object



132
133
134
# File 'lib/string_wizard.rb', line 132

def secure_compare(str1, str2)
  Encryption.secure_compare(str1, str2)
end

.similarity(str1, str2) ⇒ Object

String similarity methods



109
110
111
112
113
114
115
116
117
# File 'lib/string_wizard.rb', line 109

def similarity(str1, str2)
  return 1.0 if str1 == str2
  return 0.0 if str1.empty? || str2.empty?

  # Calculate Levenshtein distance
  distance = levenshtein_distance(str1, str2)
  max_length = [str1.length, str2.length].max
  1.0 - (distance.to_f / max_length)
end

.titleize(str) ⇒ Object

Basic string operations



20
21
22
# File 'lib/string_wizard.rb', line 20

def titleize(str)
  str.split.map(&:capitalize).join(' ')
end

.transform(str, *transformations) ⇒ Object

String transformation chain



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/string_wizard.rb', line 76

def transform(str, *transformations)
  transformations.inject(str) do |result, transformation|
    case transformation
    when :titleize then titleize(result)
    when :upcase then result.upcase
    when :downcase then result.downcase
    when :reverse then result.reverse
    when :strip then result.strip
    when :remove_vowels then remove_vowels(result)
    when :remove_consonants then remove_consonants(result)
    when :alternating_case then alternating_case(result)
    when :reverse_words then reverse_words(result)
    else
      raise Error, "Unknown transformation: #{transformation}"
    end
  end
end

.valid_credit_card?(str) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/string_wizard.rb', line 165

def valid_credit_card?(str)
  # Remove all non-digit characters
  digits = str.gsub(/\D/, '').chars.map(&:to_i)
  return false if digits.empty?

  # Luhn algorithm
  sum = 0
  digits.reverse.each_with_index do |digit, index|
    if index.odd?
      doubled = digit * 2
      sum += doubled > 9 ? doubled - 9 : doubled
    else
      sum += digit
    end
  end

  (sum % 10).zero?
end

.valid_date?(str, format: '%Y-%m-%d') ⇒ Boolean

Returns:

  • (Boolean)


149
150
151
152
153
154
# File 'lib/string_wizard.rb', line 149

def valid_date?(str, format: '%Y-%m-%d')
  Date.strptime(str, format)
  true
rescue Date::Error
  false
end

.valid_email?(str) ⇒ Boolean

String validation

Returns:

  • (Boolean)


137
138
139
# File 'lib/string_wizard.rb', line 137

def valid_email?(str)
  str.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
end

.valid_hex_color?(str) ⇒ Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/string_wizard.rb', line 184

def valid_hex_color?(str)
  str.match?(/\A#[0-9A-Fa-f]{6}\z/)
end

.valid_ip?(str) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
163
# File 'lib/string_wizard.rb', line 160

def valid_ip?(str)
  str.match?(/\A(\d{1,3}\.){3}\d{1,3}\z/) &&
    str.split('.').all? { |octet| octet.to_i.between?(0, 255) }
end

.valid_json?(str) ⇒ Boolean

Returns:

  • (Boolean)


188
189
190
191
192
193
# File 'lib/string_wizard.rb', line 188

def valid_json?(str)
  JSON.parse(str)
  true
rescue JSON::ParserError
  false
end

.valid_phone?(str) ⇒ Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/string_wizard.rb', line 145

def valid_phone?(str)
  str.match?(/\A\+?[\d\s\-()]+\z/)
end

.valid_time?(str) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/string_wizard.rb', line 156

def valid_time?(str)
  str.match?(/\A([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?\z/)
end

.valid_url?(str) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/string_wizard.rb', line 141

def valid_url?(str)
  str.match?(/\Ahttps?:\/\/[\w\-]+(\.[\w\-]+)+[\/#?]?.*\z/i)
end

.valid_xml?(str) ⇒ Boolean

Returns:

  • (Boolean)


195
196
197
198
199
200
# File 'lib/string_wizard.rb', line 195

def valid_xml?(str)
  Nokogiri::XML(str) { |config| config.strict }
  true
rescue Nokogiri::XML::SyntaxError
  false
end