Class: String

Inherits:
Object
  • Object
show all
Defined in:
lib/extension/string.rb

Overview

Reopen the core ruby String class and add the below methods to it.

Case Sensitivity rules for [ALL] the below methods that are added to the core Ruby string class.

For case insensitive behaviour make sure you downcase both the string object and the parameter strings (or strings within other parameter objects, like arrays and hashes).

Instance Method Summary collapse

Instance Method Details

#block_decode_decrypt(crypt_key) ⇒ Object

First apply a base64 (block mode) decode to this string and then use the parameter symmetric decryption key to decrypt the result. The output is then returned within a new string.

Examples:

cipher_text  = "Hello crypt world".decrypt_block_encode "ABC123XYZ"
original_txt = cipher_text.block_decode_decrypt "ABC123XYZ"
puts original_txt # "Hello crypt world"

Parameters:

  • crypt_key (String)

    a strong long decryption key that is used to decrypt this string after the Base64 block decoding has been applied.



55
56
57
58
# File 'lib/extension/string.rb', line 55

def block_decode_decrypt crypt_key
  the_ciphertxt = Base64.decode64( self )
  return SafeDb::ToolBelt::Blowfish.decryptor( the_ciphertxt, crypt_key )
end

#concat_lengthString

Find the length of this string and return a string that is the concatenated union of this string and its integer length. If this string is empty a string of length one ie “0” will be returned.

Returns:

  • (String)

    Return this string with a cheeky integer tagged onto the end that represents the (pre-concat) length of the string.



195
196
197
# File 'lib/extension/string.rb', line 195

def concat_length
  return self + "#{self.length}"
end

#decrypt(encrypt_key) ⇒ Object

– Decrypt this string with the parameter encryption/decryption key and return the decrypted text as a new string. –

encrypt_key  => the key the input string was encrypted with

– –



532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
# File 'lib/extension/string.rb', line 532

def decrypt encrypt_key

## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting
## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting
## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting
## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting

###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key
###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key
###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key

  cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').decrypt
  cipher.key = Digest::SHA1.hexdigest encrypt_key
  uncrypted = [self].pack("H*").unpack("C*").pack("c*")
  decrypted_text = cipher.update(uncrypted) + cipher.final

  return decrypted_text

end

#do_flattenString

Flatten (lower) a camel cased string and add periods to denote separation where the capital letters used to be.

Example behaviour is illustrated

  • in => ObjectOriented

  • out => object.oriented

Even when a capital letter does not lead lowercase characters the behaviour should resemble this.

  • in => SuperX

  • out => super.x

And if every letter is uppercase, each one represents its own section like this.

  • in => BEAST

  • out => b.e.a.s.t

Flatten Class Names

If the string comes in as a class name we can expect it to contain colons like the below examples.

This::That
::That
This::That::TheOther

So we find the last index of a colon and then continue as per the above with flattening the string.

Returns:

  • (String)

    a flatten (period separated) version of this camel cased string



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/extension/string.rb', line 297

def do_flatten

  to_flatten_str = self

  last_colon_index = to_flatten_str.rindex ":"
  ends_with_colon = to_flatten_str[-1].eql? ":"
  unless ( last_colon_index.nil? || ends_with_colon )
    to_flatten_str = to_flatten_str[ (last_colon_index+1) .. -1 ]
  end

  snapped_str = ""
  to_flatten_str.each_char do |this_char|
    is_lower = "#{this_char}".is_all_lowercase?
    snapped_str += "." unless is_lower || snapped_str.empty?
    snapped_str += this_char.downcase
  end

  return snapped_str

end

#encrypt(decrypt_key) ⇒ Object

– Encrypt this string with the parameter encryption/decryption key and return the encrypted text as a new string. –

decrypt_key  => the key that will decrypt the output string

– –



499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
# File 'lib/extension/string.rb', line 499

def encrypt decrypt_key

## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting
## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting
## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting
## ----> Write a RE-CRYPT method that goes through a folder - decrypting and recrypting

###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key
###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key
###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key
###### ON Linux improve by changing to OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
###### ON Linux improve by changing to Digest::SHA2.hexdigest decrypt_key

  cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').encrypt
  cipher.key = Digest::SHA1.hexdigest decrypt_key
  crypted = cipher.update(self) + cipher.final
  encrypted_text = crypted.unpack('H*')[0].upcase

  return encrypted_text

end

#encrypt_block_encode(crypt_key) ⇒ Object

Encrypt this string with the parameter symmetric encryption/decryption key and then return the Base64 (block mode) encoded result.

Examples:

cipher_text  = "Hello crypt world".encrypt_block_encode "ABC123XYZ"
original_txt = cipher_text.block_decode_decrypt "ABC123XYZ"
puts original_txt # "Hello crypt world"

Parameters:

  • crypt_key (String)

    a strong long encryption key that is used to encrypt this string before applying the Base64 block encoding.



36
37
38
39
# File 'lib/extension/string.rb', line 36

def encrypt_block_encode crypt_key
  encrypted_text = SafeDb::ToolBelt::Blowfish.encryptor( self, crypt_key )
  return Base64.encode64( encrypted_text )
end

#encrypt_url_encode(crypt_key) ⇒ Object

Encrypt this string with the parameter symmetric encryption/decryption key and then return the Base64 (url safe mode) encoded result.

The output will be a single line and differs from the block mode with

  • underscores printed instead of forward slash characters

  • hyphens printed instead of plus characters

  • no (blocked) carriage return or new line characters

Note however that sometimes one or more equals characters will be printed at the end of the string by way of padding. In places like environment variables that are sensitive to the equals character this can be replaced by an @ symbol.

Examples:

cipher_text  = "Hello @:==:@ world".encrypt_url_encode "ABC123XYZ"
original_txt = cipher_text.url_decode_decrypt "ABC123XYZ"
puts original_txt # "Hello @:==:@ world"

Parameters:

  • crypt_key (String)

    a strong long encryption key that is used to encrypt this string before applying the Base64 ul safe encoding.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/extension/string.rb', line 84

def encrypt_url_encode crypt_key

  ## ################################################
  ## ################################################
  ## ################################################
  ## ################################################
  ## https://www.di-mgt.com.au/cryptokeys.html
  ## ################################################
  ## ################################################
  ## ################################################
  ## ################################################
  ## ################################################

  log.info(x){ "Encrypt Length => [ #{self.length} ]" }
  log.info(x){ "The Key Length => [ #{crypt_key.length} ]" }
  log.info(x){ "Encrypt String => [ #{self} ]" }
  log.info(x){ "Encryption Key => [ #{crypt_key} ]" }

  encrypted_text = SafeDb::ToolBelt::Blowfish.encryptor( self, crypt_key )

  log.info(x){ "Encrypt Result => [ #{encrypted_text} ]" }
  log.info(x){ "Encrypted Text => [ #{Base64.urlsafe_encode64(encrypted_text)} ]" }

  return Base64.urlsafe_encode64(encrypted_text)

end

#from_hexString

From hex converts this (assumed) hexadecimal string back into its normal string form and returns the result leaving this string unchanged.

Returns:

  • (String)

    string that matches the hexadecimal representation



257
258
259
260
261
# File 'lib/extension/string.rb', line 257

def from_hex

  return [self].pack("H*")

end

#has_wrapped?(little_str, prefix, postfix) ⇒ Boolean

– Return true if the [little string] within this string object is both –

a] topped by the parameter prefix AND
b] tailed by the parameter postfix


In the below example [true] is returned


This [String] => "Hey [<-secrets->] are juicy."
little string => "secrets"
topped string => "[<-"
tailed string => "->]"

– Why true? Because the little string “secret” is (wrapped) topped by “[<-” and tailed by “->]” –


Assumptions | Constraints | Boundaries


- all matches are [case sensitive]
- this string must contain little_str
- one strike and its true
    (if little string appears more than once)
    so => "all secrets, most [<-secrets->] r juicy"
       => true as long as (at least) one is wrapped

– –

Returns:

  • (Boolean)


403
404
405
406
407
# File 'lib/extension/string.rb', line 403

def has_wrapped? little_str, prefix, postfix

  return self.include?( prefix + little_str + postfix )

end

#hr_pathString

Overtly long file paths (eg in logs) can hamper readability so this human readable filepath converter counters the problem by returning (only) the 2 immediate ancestors of the filepath.

So this method returns the name of the grandparent folder then parent folder and then the most significant file (or folder) name.

When this is not possible due to the filepath being colisively near the filesystem’s root, it returns the parameter name.

Examples:

A really long input like
=> /home/joe/project/degrees/math/2020
is reduced to
=> degrees/math/2020

Returns:

  • (String)

    the segmented 3 most significant path name elements.



156
157
158
159
160
161
162
163
164
165
166
# File 'lib/extension/string.rb', line 156

def hr_path

  object_name   = File.basename self
  parent_folder = File.dirname  self
  parent_name   = File.basename parent_folder
  granny_folder = File.dirname  parent_folder
  granny_name   = File.basename granny_folder

  return [granny_name,parent_name,object_name].join("/")

end

#in_between(this_delimiter, that_delimiter) ⇒ String

Get the text [in between] this and that delimiter [exclusively]. Exclusively means the returned text [does not] include either of the matched delimiters (although an unmatched instance of [this] delimiter may appear in the in-between text).

### Multiple Delimiters

When multiple delimiters exist, the text returned is in between the

  • first occurrence of [this] delimiter AND the

  • 1st occurrence of [that] delimiter [AFTER] the 1st delimiter

Instances of [that] delimiter occurring before [this] are ignored. The text could contain [this] delimiter instances but is guaranteed not to contain a [that] delimiter.

  • any nil (or empties) exist in the input parameters

  • this delimiter does not appear in the in_string

  • that delimiter does not appear after [this] one

Parameters:

  • this_delimiter (String)

    begin delimiter (not included in returned string)

  • that_delimiter (String)

    end delimiter (not included in returned string)

Returns:

  • (String)

    the text in between (excluding) the two parameter delimiters

Raises:

  • (ArgumentError)


226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/extension/string.rb', line 226

def in_between this_delimiter, that_delimiter

  raise ArgumentError, "This string is NIL or empty." if self.nil? || self.empty?
  raise ArgumentError, "Begin delimiter is NIL or empty." if this_delimiter.nil? || this_delimiter.empty?
  raise ArgumentError, "End delimiter is NIL or empty." if that_delimiter.nil? || that_delimiter.empty?
  
  scanner_1 = StringScanner.new self
  scanner_1.scan_until /#{this_delimiter}/
  scanner_2 = StringScanner.new scanner_1.post_match
  scanner_2.scan_until /#{that_delimiter}/

  in_between_text = scanner_2.pre_match.strip
  return in_between_text

end

#includes_all?(word_array) ⇒ Boolean

The parameter is a list of character sequences and TRUE is returned if EVERY ONE of the character sequences is always found nestled somewhere within this string. The matching is case-sensitive.

The parameter array can be [empty] but not nil. And the harboured character sequences can neither be nil nor empty.

Parameters:

  • word_array (Array)

    array of string words for the inclusivity test

Returns:

  • (Boolean)

    true if EVERY ONE of the char sequences appear somewhere in this string

Raises:

  • (ArgumentError)


448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/extension/string.rb', line 448

def includes_all? word_array

  raise ArgumentError, "This string is NIL" if self.nil?
  raise ArgumentError, "The parameter word array is NIL" if word_array.nil?

  word_array.each do |word|

    raise ArgumentError, "The word array #{word_array} contains a nil value." if word.nil?
    return false unless self.include? word

  end

  return true

end

#includes_any?(word_array) ⇒ Boolean

The parameter is a list of character sequences and TRUE is returned if any one of the character sequences can be found nestled somewhere within this string. The matching is case-sensitive.

The parameter array can be [empty] but not nil. And the harboured character sequences can neither be nil nor empty.

Parameters:

  • word_array (Array)

    array of string words for the inclusivity test

Returns:

  • (Boolean)

    true if string includes ANY one of the character sequences in array

Raises:

  • (ArgumentError)


475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/extension/string.rb', line 475

def includes_any? word_array

  raise ArgumentError, "This string is NIL" if self.nil?
  raise ArgumentError, "The parameter word array is NIL" if word_array.nil?

  word_array.each do |word|

    raise ArgumentError, "The word array #{word_array} contains a nil value." if word.nil?
    return true if self.include? word

  end

  return false

end

#is_all_lowercase?Boolean

Return true if every character in this string is lowercase. Note that if this string is empty this method returns true.

Returns:

  • (Boolean)

    true if every alpha character in this string is lowercase



324
325
326
# File 'lib/extension/string.rb', line 324

def is_all_lowercase?
  return self.downcase.eql? self
end

#log_linesObject

Log the string which is expected to be delineated.

If the string originated from a file it will be logged
line by line. If no line delineation the string will be
dumped just as a blob.

The INFO log level is used to log the lines - if this is not

appropriate create a (level) parameterized log lines method.


563
564
565
566
567
568
569
570
# File 'lib/extension/string.rb', line 563

def log_lines

  self.each_line do |line|
    clean_line = line.chomp.gsub("\\n","")
    log.info(x) { line } if clean_line.length > 0
  end

end

#sandwich_substr(to_wrap_str, prefix, postfix) ⇒ Object

Sandwich the first occurrence of a substring in this string with the specified pre and postfix.

This string contains the little string and an IN-PLACE change is performed with the first occurrence of the little string being prefixed and postfixed with the 2 parameter strings.

Example of sandwiching [wrapping]

  • String

    > “Hey secrets are juicy.”

  • To_Wrap

    > “secrets”

  • Prefix

    > “[<-”

  • Postfix

    > “->]”

[String]  => "Hey [<-secrets->] are juicy."

This string IS changed in place.



428
429
430
431
432
433
434
435
# File 'lib/extension/string.rb', line 428

def sandwich_substr to_wrap_str, prefix, postfix

  occurs_index = self.downcase.index to_wrap_str.downcase
  self.insert occurs_index, prefix
  shifted_index = occurs_index + prefix.length + to_wrap_str.length
  self.insert shifted_index, postfix

end

#to_alphanumericString

Return a new string matching this one with every non alpha-numeric character removed. This string is left unchanged.

Spaces, hyphens, underscores, periods are all removed. The only characters left standing belong to a set of 62 and are

  • a to z

  • A to Z

  • 0 to 9

Returns:

  • (String)

    Remove any character that is not alphanumeric, a to z, A to Z and 0 to 9 and return a new string leaving this one unchanged.



182
183
184
# File 'lib/extension/string.rb', line 182

def to_alphanumeric
  return self.delete("^A-Za-z0-9")
end

#to_hexString

To hex converts this string to hexadecimal form and returns the result leaving this string unchanged.

Returns:

  • (String)

    hexadecimal representation of this string



246
247
248
249
250
# File 'lib/extension/string.rb', line 246

def to_hex

  return self.unpack("H*").first

end

#un_flattenString

Flatten (lower) a camel cased string and add periods to denote separation where the capital letters used to be. The inverse operation to [ do_flatten ] which resurrects this (expected) period separated string changing it back to a camel (mountain) cased string.

Example behaviour is illustrated

  • in => object.oriented

  • out => ObjectOriented

Even when a single character exists to the right of the period the behaviour should resemble this.

  • in => super.x

  • out => SuperX

And if every letter is period separated

  • in => b.e.a.s.t

  • out => BEAST

Returns:

  • (String)

    camel cased version of this flattened (period separated) string



354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/extension/string.rb', line 354

def un_flatten

  segment_array = self.strip.split "."
  resurrected_arr = Array.new

  segment_array.each do |seg_word|
    resurrected_arr.push seg_word.capitalize
  end

  undone_str = resurrected_arr.join
  log.info(x){ "unflattening => [#{self}] and resurrecting to => [#{undone_str}]" }

  return undone_str

end

#url_decode_decrypt(crypt_key) ⇒ Object

First apply a base64 (url safe mode) decode to this string and then use the parameter symmetric decryption key to decrypt the result. The output is then returned within a new string.

The input must will be a single line and differs from the block mode with

  • underscores printed instead of forward slash characters

  • hyphens printed instead of plus characters

  • no (blocked) carriage return or new line characters

Examples:

cipher_text  = "Hello @:==:@ world".encrypt_url_encode "ABC123XYZ"
original_txt = cipher_text.url_decode_decrypt "ABC123XYZ"
puts original_txt # "Hello @:==:@ world"

Parameters:

  • crypt_key (String)

    a strong long decryption key that is used to decrypt this string after the Base64 url safe decoding has been applied.



131
132
133
134
# File 'lib/extension/string.rb', line 131

def url_decode_decrypt crypt_key
  the_ciphertxt = Base64.urlsafe_decode64( self )
  return SafeDb::ToolBelt::Blowfish.decryptor( the_ciphertxt, crypt_key )
end