module VV::StringMethods

Public Class Methods

included(base) click to toggle source
# File lib/vv/string_methods.rb, line 4
def self.included(base)
  base.instance_eval do
    extend(ClassMethods)
    extend(SharedInstanceAndClassMethods)
    include(SharedInstanceAndClassMethods)

    alias_method :starts_with?, :start_with?
    alias_method :ends_with?,   :end_with?
    alias_method :includes?,    :include?
  end
end

Public Instance Methods

_ensure_pluralize_available!() click to toggle source
# File lib/vv/string_methods.rb, line 466
def _ensure_pluralize_available!
  message = "String does not define pluralize."
  pluralize_available = self.respond_to? :pluralize
  raise NotImplementedError, message unless pluralize_available
end
_ensure_singularize_available!() click to toggle source
# File lib/vv/string_methods.rb, line 472
def _ensure_singularize_available!
  message = "String does not define singularize."
  singularize_available = self.respond_to? :singularize
  raise NotImplementedError, message unless singularize_available
end
_numeral_postfixes() click to toggle source
# File lib/vv/string_methods.rb, line 379
def _numeral_postfixes
  { k: 1000,
    m: 1000_000,
    b: 1000_000_000,
    t: 1000_000_000_000 }.stringify_keys
end
after(string, safe: true) click to toggle source
# File lib/vv/string_methods.rb, line 122
def after(string, safe: true)
  if safe && ! self.starts_with?(string)
    message = "String does not start with #{string}"
    raise RuntimeError, message
  elsif not self.starts_with?(string)
    return self
  end

  self[string.size..-1]
end
cli_print(width: nil, padding: nil, position: nil, hard_wrap: false) click to toggle source
# File lib/vv/string_methods.rb, line 592
def cli_print width: nil,
              padding: nil,
              position: nil,
              hard_wrap: false

  width    ||= 80
  position ||= 0
  padding  ||= 0

  raise NotImplemented if hard_wrap
  raise NotImplemented if self.includes? newline

  pad_length = padding - position
  position += pad_length
  print pad_length.spaces

  unstyled_length = self.unstyled.length
  remaining_length = width - position
  if unstyled_length <= remaining_length
    print self
    position += unstyled_length
    return position
  end

  space_index   = self[0..remaining_length].rindex(" ")
  space_index ||= self.index(" ")

  if space_index
    sub = self[0..space_index]
    print sub
    puts
    position = 0
    start = space_index + 1
    return self[start..-1].cli_print width: width,
                                     padding: padding,
                                     position: position,
                                     hard_wrap: hard_wrap
  else
    print self
    puts
    position = 0
  end

  return position
end
cli_puts(**kwargs) click to toggle source
# File lib/vv/string_methods.rb, line 588
def cli_puts **kwargs
  puts String.get_stdout { self.cli_print( **kwargs ) }
end
eighth() click to toggle source
# File lib/vv/string_methods.rb, line 576
def eighth
  self[7]
end
fifth() click to toggle source
# File lib/vv/string_methods.rb, line 564
def fifth
  self[4]
end
file_join(*args) click to toggle source
# File lib/vv/string_methods.rb, line 274
def file_join *args
  unsafe = args.reject(&:safe_path?)

  return File.join self, *args if unsafe.blank?

  frags = unsafe.first(3).stringify_collection grave: true
  count = unsafe.count

  message = \
  "#{count} unsafe path fragments including: #{frags}"

  fail ArgumentError, message
end
first(limit=1) click to toggle source
# File lib/vv/string_methods.rb, line 542
def first limit=1
  if limit == 0
    ""
  elsif limit >= size
    dup
  else
    to(limit - 1)
  end
end
format!(other) click to toggle source
# File lib/vv/string_methods.rb, line 191
def format!(other)
  mappings = {}
  self.split('#{')[1..-1].map do | token_fragment |
    format_string = token_fragment.split("}").first
    token = format_string.squish

    value = other.instance_variable_get(token).to_s
    wrapped_format_string = '#{' + format_string + "}"
    mappings[wrapped_format_string] = value
  end

  response = self.dup

  mappings.each do |key, value|
    response.gsub! key, value
  end

  response
end
fourth() click to toggle source
# File lib/vv/string_methods.rb, line 560
def fourth
  self[3]
end
from(position) click to toggle source
# File lib/vv/string_methods.rb, line 462
def from position
  self[position..-1]
end
hex?() click to toggle source
# File lib/vv/string_methods.rb, line 288
def hex?
  return false if self.blank?
  match_non_hex_digits = /\H/
  !self[match_non_hex_digits]
end
insta() click to toggle source
# File lib/vv/string_methods.rb, line 440
def insta
  return self if self.starts_with?("@")
  "@#{self}"
end
insta_sym() click to toggle source
# File lib/vv/string_methods.rb, line 445
def insta_sym
  self.insta.to_sym
end
is_directory_path?() click to toggle source
# File lib/vv/string_methods.rb, line 266
def is_directory_path?
  File.directory? self
end
is_file_path?() click to toggle source
# File lib/vv/string_methods.rb, line 270
def is_file_path?
  File.file? self
end
last(limit = 1) click to toggle source
# File lib/vv/string_methods.rb, line 532
def last(limit = 1)
  if limit == 0
    ""
  elsif limit >= size
    self.dup
  else
    self.from(-limit)
  end
end
matches_glob(pattern) click to toggle source
# File lib/vv/string_methods.rb, line 211
def matches_glob pattern
  File.fnmatch(pattern, self)
end
ninth() click to toggle source
# File lib/vv/string_methods.rb, line 580
def ninth
  self[8]
end
number?() click to toggle source
# File lib/vv/string_methods.rb, line 294
def number?
  return false if self.blank?
  self.gsub(/[^0-9]/, '') == self
end
parse(notation: :json) click to toggle source
# File lib/vv/string_methods.rb, line 324
def parse notation: :json
  message = "Only JSON support at this time."
  fail NotImplementedError, message unless notation == :json

  ::JSON.parse self
end
parse_json() click to toggle source
# File lib/vv/string_methods.rb, line 331
def parse_json
  self.parse notation: :json
end
plural?(coward: true) click to toggle source
# File lib/vv/string_methods.rb, line 478
def plural?(coward: true)
  self._ensure_pluralize_available!
  self._ensure_singularize_available!

  plural = self == self.pluralize
  return plural if !coward || !plural

  non_ambiguous = self.pluralize != self.singularize

  message = \
  "String is ambiguously plural. Cowardly exiting."
  raise RuntimeError, message unless non_ambiguous

  true
end
pop() click to toggle source
# File lib/vv/string_methods.rb, line 117
def pop
  self.slice!(-1)
end
Also aliased as: pop!
pop!()
Alias for: pop
query() click to toggle source
# File lib/vv/string_methods.rb, line 510
def query
  string_fragments = self.split("#")[0].split("?")
  message = "Query string contains multiple question marks"

  fail message if string_fragments.count > 2
  substring = string_fragments[-1]
  response = {}

  substring.split("&").each do |key_value_pair|
    key, value = key_value_pair.split(String.equals_sign)
    if key.ends_with? "[]"
      _key = key[0..-3]
      response[_key] ||= Array.new
      response[_key] << value
    else
      response[key] = value
    end
  end

  response
end
readable_number?() click to toggle source
# File lib/vv/string_methods.rb, line 299
def readable_number?
  self.readable_to_i
  true
rescue StandardError => e
  return false if e.message == "String is not a number"
  raise
end
readable_to_i() click to toggle source
# File lib/vv/string_methods.rb, line 366
def readable_to_i
  return self.to_i if self.number?

  valid_postfix = self._numeral_postfixes.include? self.last
  valid_body    = self[0...-1].number?
  valid = valid_body && valid_postfix

  message = "String is not a number"
  raise StandardError, message unless valid

  self[0...-1].to_i * self._numeral_postfixes[self.last]
end
safe_dir_path?(allow_hidden: false, allow_absolute: true) click to toggle source
# File lib/vv/string_methods.rb, line 252
def safe_dir_path? allow_hidden: false,
                   allow_absolute: true
  separator = File::SEPARATOR

  unsafe   = false
  unsafe ||= self.starts_with?(separator) unless allow_absolute
  unsafe ||= self.after(separator, safe: false)
               .split(separator).map do |fragment|
    fragment.safe_filename? allow_hidden: allow_hidden
  end.map(&:!).any?

  ! unsafe
end
safe_filename?( allow_hidden: false ) click to toggle source
# File lib/vv/string_methods.rb, line 228
def safe_filename?( allow_hidden: false )
  unsafe   = self.blank?

  unsafe ||= self.starts_with?(period) unless allow_hidden
  unsafe ||= self.starts_with? dash

  unsafe ||= self.end_with? period
  unsafe ||= self.end_with? dash

  unsafe ||= self =~ self.safe_filename_characters.to_regex_filter

  ! unsafe
end
safe_path?( allow_hidden: false, allow_absolute: false ) click to toggle source
# File lib/vv/string_methods.rb, line 242
def safe_path?( allow_hidden: false, allow_absolute: false )
  safe = self.safe_dir_path? allow_hidden: allow_hidden,
                             allow_absolute: allow_absolute

  unsafe   = ( ! safe )
  unsafe ||= self.ends_with? File::SEPARATOR

  ! unsafe
end
second() click to toggle source
# File lib/vv/string_methods.rb, line 552
def second
  self[1]
end
setter() click to toggle source
# File lib/vv/string_methods.rb, line 449
def setter
  return self if self.ends_with?(String.equals_sign)
  "#{self}="
end
setter_sym() click to toggle source
# File lib/vv/string_methods.rb, line 454
def setter_sym
  self.setter.to_sym
end
seventh() click to toggle source
# File lib/vv/string_methods.rb, line 572
def seventh
  self[6]
end
shift() click to toggle source

Instance methods start

# File lib/vv/string_methods.rb, line 112
def shift
  self.slice!(0)
end
Also aliased as: shift!
shift!()
Alias for: shift
singular?(coward: true) click to toggle source
# File lib/vv/string_methods.rb, line 494
def singular?(coward: true)
  self._ensure_pluralize_available!
  self._ensure_singularize_available!

  singular = self == self.singularize
  return singular if !coward || !singular

  non_ambiguous = self.pluralize != self.singularize

  message = \
  "String is ambiguously singular. Cowardly exiting."
  raise RuntimeError, message unless non_ambiguous

  true
end
sixth() click to toggle source
# File lib/vv/string_methods.rb, line 568
def sixth
  self[5]
end
split_english(ignore_newlines: false) click to toggle source
# File lib/vv/string_methods.rb, line 168
def split_english ignore_newlines: false

  options = [ ", ",
              ", and ",
              ", or ",
              " and ",
              " or "]
  self.split_via(options,
                 ignore_newlines: ignore_newlines)
    .map(&:strip)
end
split_via(*arguments, ignore_newlines: false) click to toggle source
# File lib/vv/string_methods.rb, line 141
def split_via *arguments, ignore_newlines: false
  newlines_encountered = self.include? String.newline
  newlines_ok   = ( not newlines_encountered )
  newlines_ok ||= ignore_newlines

  message  = "Newlines encountered, but disallowed. "
  message += \
  "Set `ignore_newlines` to true to treat as spaces."

  fail message unless newlines_ok

  args = arguments.flatten.sort_by(&:length).reverse

  response = [self.gsub(String.newline, String.space)]

  args.map do |arg|

    response.map! do |fragment|
      fragment.split arg
    end

    response.flatten!
  end

  response
end
squish() click to toggle source
# File lib/vv/string_methods.rb, line 187
def squish
  self.dup.squish!
end
squish!() click to toggle source
# File lib/vv/string_methods.rb, line 180
def squish!
  self.gsub!(/\A[[:space:]]+/, "")
  self.gsub!(/[[:space:]]+\z/, "")
  self.gsub!(/[[:space:]]+/, " ")
  self
end
style(*args) click to toggle source
# File lib/vv/string_methods.rb, line 397
def style *args
  color = bold = underline = italic = nil

  args.flatten!
  args.map! { |arg| arg.to_sym }

  args.each do |arg|
    if Color.known_color? arg
      if color.present?
        raise "Color already set"
      else
        color = Color.new arg
      end
    elsif arg == :bold
      bold = Bold.new
    elsif arg == :underline
      underline = Underline.new
    elsif ( arg == :italic ) or ( arg == :italics )
      italic = Italic.new
    else
      raise NotImplemented
    end
  end

  reset = Format.reset_code
  response = self.chomp(reset) + reset

  response.prepend italic.code    if italic
  response.prepend underline.code if underline
  response.prepend bold.code      if bold

  if color
    start  = response.index color.start_code
    if start
      finish = response[start..-1].index("m") + start
      response.slice! start..finish
    end
    response.prepend color.code
  end

  response
end
tenth() click to toggle source
# File lib/vv/string_methods.rb, line 584
def tenth
  self[9]
end
third() click to toggle source
# File lib/vv/string_methods.rb, line 556
def third
  self[2]
end
to(position) click to toggle source
# File lib/vv/string_methods.rb, line 458
def to position
  self[0..position]
end
to_boolean() click to toggle source
# File lib/vv/string_methods.rb, line 307
def to_boolean
  _true = self == "true"
  return true if _true

  _false = self == "false"
  return false if _false

  message = %w[ Unable to cast supplied string to boolean,
                only `"true"` and `"false"` can be coerced into
                boolean. ].spaced
  raise RuntimeError, message
end
to_h(parse: :json, symbolize_keys: false) click to toggle source
# File lib/vv/string_methods.rb, line 347
def to_h parse: :json, symbolize_keys: false
  message = "Only JSON support at this time."
  fail NotImplementedError, message unless parse == :json

  response = self.parse_json

  response.symbolize_keys! if symbolize_keys

  return response if response.to_h == response

  message = \
  "Parse string was #{response.class}, instead of Hash."
  fail message
end
to_i!() click to toggle source
# File lib/vv/string_methods.rb, line 362
def to_i!
  Integer(self)
end
to_regex() click to toggle source
# File lib/vv/string_methods.rb, line 215
def to_regex
  Regexp.new self
end
to_regex_filter() click to toggle source
# File lib/vv/string_methods.rb, line 219
def to_regex_filter
  regex_string = '[^' + self + ']'
  regex_string.to_regex
end
to_regexp_filter() click to toggle source
# File lib/vv/string_methods.rb, line 224
def to_regexp_filter
  self.to_regex_filter
end
to_time() click to toggle source
# File lib/vv/string_methods.rb, line 335
def to_time
  message = "Incorrect time string formatting `#{self}`, " + \
            "must be of the form `2020-02-20T11:22:33.4567Z`"

  fail message unless self.ends_with? "Z"
  fail message unless self.split(String.dash).count == 3
  fail message unless self.split(String.colon).count == 3
  fail message unless self[10] == "T"

  Time.parse self
end
unstyle() click to toggle source
# File lib/vv/string_methods.rb, line 386
def unstyle
  self.gsub( /\e\[+\d+m/, empty_string )
    .gsub( /\e\[((\d+)+\;)+\d+m/, empty_string )
end
Also aliased as: unstyled
unstyle!() click to toggle source
# File lib/vv/string_methods.rb, line 392
def unstyle!
  self.gsub!( /\e\[+\d+m/,          empty_string )
  self.gsub!( /\e\[((\d+)+\;)+\dm/, empty_string )
end
unstyled()
Alias for: unstyle
vv_json() click to toggle source
# File lib/vv/string_methods.rb, line 320
def vv_json
  VV::JSON.generate self
end
with_ending(string) click to toggle source
# File lib/vv/string_methods.rb, line 133
def with_ending(string)
  self.chomp(string) + string
end
with_newline() click to toggle source
# File lib/vv/string_methods.rb, line 137
def with_newline
  self.with_ending newline
end