class String

Alteration to <string> class

Public Class Methods

transcode_options(destination_encoding, source_encoding, options={}) click to toggle source

:macos text handling notes: hints.macworld.com/article.php?story=20060825071728278 Also, research UTF8_MAC <-> UTF8_HFS <-> UTF8 normalization conversions.

# File lib/gxg/gxg_augmented.rb, line 1850
def self.transcode_options(destination_encoding, source_encoding, options={})
  # TODO: ::String::transcode_options : complete transcoding back-end supports.
  # select a default encoding_option set given the two encodings, then merge options over that and return.  Explore Hash deep-merge ideas.
  #
  new_options = {}
  # fallback set/method or replace char
  if options[:fallback]
    # Note: I *confirmed* (thanks VGoff) that :invalid/:undef/:replace and :fallback are exclusive - So maybe this is really an optimized :fallback thing?
    #    Sets the replacement string by the given object for undefined character. The object should be a Hash, a Proc, a Method,
    #    or an object which has [] method. Its key is an undefined character encoded in the source encoding of current transcoder.
    #    Its value can be any encoding until it can be converted into the destination encoding of the transcoder.
    if (options[:fallback].is_any?(::Hash, ::Struct, ::Proc, ::Method) || options[:fallback].respond_to?(:[]))
      # if :fallback will not process an Array as mentioned above ... remove :[] respond_to? condition.
      new_options[:fallback] = options[:fallback].dup
    end
  else
    #
    if options[:invalid] == :replace
      #    If the value is :replace, encode replaces invalid byte sequences in str with the replacement character. The default is to
      #    raise the Encoding::InvalidByteSequenceError exception
      new_options[:invalid] = :replace
    end
    #
    if options[:undef] == :replace
      #    If the value is :replace, encode replaces characters which are undefined in the destination encoding with the replacement character.
      #    The default is to raise the Encoding::UndefinedConversionError.
      new_options[:undef] = :replace
    end
    #
    if options[:replace]
      #    Sets the replacement string to the given value. The default replacement string is “uFFFD” for Unicode encoding forms, and “?” otherwise.
      new_options[:replace] = options[:replace].dup
    end
    #
  end
  # xml
  if options[:xml]
    #    The value must be :text or :attr. If the value is :text encode replaces undefined characters with their (upper-case hexadecimal) numeric character
    #    references. ‘&’, ‘<’, and ‘>’ are converted to “&amp;”, “&lt;”, and “&gt;”, respectively. If the value is :attr, encode also quotes the replacement
    #    result (using ‘“’), and replaces ‘”’ with “&quot;”.
    if [:text, :attr].include?(options[:xml])
      new_options[:xml] = options[:xml].dup
    end
  end
  #
  if options[:universal_newline]
    #    Replaces CRLF (“rn”) and CR (“r”) with LF (“n”) if value is true.
    unless (new_options[:cr_newline] || new_options[:crlf_newline])
      if options[:universal_newline] == true
        new_options[:universal_newline] = true
      end
    end
  else
    if options[:crlf_newline]
      #    Replaces LF (“n”) with CRLF (“rn”) if value is true.
      unless (new_options[:cr_newline] || new_options[:universal_newline])
        if options[:crlf_newline] == true
          new_options[:crlf_newline] = true
        end
      end
    else
      if options[:cr_newline]
        #    Replaces LF (“n”) with CR (“r”) if value is true.
        unless (new_options[:crlf_newline] || new_options[:universal_newline])
          if options[:cr_newline] == true
            new_options[:cr_newline] = true
          end
        end
      else
        # default
      end
    end
  end
  #
  default_options = {}
  # find the default conversion options given the destination and source encodings
  # then ...
  new_options
  # deep-merge new_options into a provided default_options
  # then return default_options
  # default_options
end

Public Instance Methods

base64?() click to toggle source

Base64 Stuff:

# File lib/gxg/gxg_augmented.rb, line 2932
def base64?()
  # RFC 4648
  # SOMEDAY: use regex based detection, current is open to some bugs.
  # See: http://ruby.about.com/od/advancedruby/ss/Base64-In-Ruby.htm
  # See: http://www.perlmonks.org/?node_id=775820
  # See: http://mattfaus.com/blog/2007/02/14/base64-regular-expression/
  # See: http://stackoverflow.com/questions/475074/regex-to-parse-or-validate-base64-data
  # Regex Testing: http://www.myregexp.com/signedJar.html
  # For now:
  begin
    # Review : So, for a work-around - keep adding exclusion tests to this conditional set as you discover them.
    if (self.size > 0) && (not ["html","form","page","head","body"].include?(self.downcase))
      # Review : *almost perfect* - words like 'html' 'form' 'page' get mangled because this regex senses they are base64 when they are not! (consult regex expert for remedy)
      if self.match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/)
        true
      else
        false
      end
    else
      false
    end
  rescue Exception => the_error
    false
  end
end
byte_at(*args) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2733
def byte_at(*args)
  # Random-access indexed byte value retrieval. Returns a Integer or nil.
  # why?  This is to pluck a single byte value out of a string as if it were merely a string of bytes. 1.8.7 used to provide a [] method for this purpose.
  if args[0].is_a?(Numeric)
    args[0] = args[0].to_i
  else
    raise ArgumentError.new("The parameter needs to be a Numeric, you provided #{args[0].inspect}")
  end
  if self.bytesize > 0
    if self.encoding == ::Encoding::ASCII_8BIT
      self[(args[0])].ord
    else
      self.slice_bytes(args[0])[0].ord
    end
  else
    nil
  end
end
bytes_at(*args) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2752
def bytes_at(*args)
  # Returns GxG::ByteArray
  unless args.size > 0
    args = [(0..-1)]
  end
  GxG::ByteArray.new(1,self.slice_bytes(*args))
end
camel_case?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2278
def camel_case?()
  # self.match(/([A-Z][a-z]+[A-Z][a-zA-Z]+)/)
  if self.match(/[A-Z]([A-Z0-9]*[a-z][a-z0-9]*[A-Z]|[a-z0-9]*[A-Z][A-Z0-9]*[a-z])[A-Za-z0-9]*/)      
    true
  else
    false
  end
end
decode64() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2967
def decode64()
  # RFC 4648
  if self.base64?()
    ::Base64::strict_decode64(self)
  else
    self
  end
end
decode64!() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2984
def decode64!()
  data = self.decode64()
  if data != self
    self.replace(data)
  end
  self
end
decrypt(withkey="") click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3029
def decrypt(withkey="")
  #
  if withkey.to_s.size > 0
    the_encoding = self.encoding()
    keybytes = ::GxG::ByteArray.new(withkey.to_s)
    container = ::GxG::ByteArray.new(self)
    #
    container.each_index do |index|
      the_value = container[(index)]
      #
      keybytes.each do |the_byte|
        [127,63,31,15,7,3,1,0].each do |the_bit|
          if the_byte > the_bit
            the_value -= 1
            if the_value < 0
              the_value = 255
            end
          else
            the_value += 1
            if the_value > 255
              the_value = 0
            end
          end
        end
      end
      #
      container[(index)] = the_value
    end
    #
    result = container.to_s
    result.force_encoding(the_encoding)
    result
  else
    self.dup
  end
end
each_byte(&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2818
def each_byte(&block)
  enumerator = self.to_enum(:bytes)
  if block.respond_to?(:call)
    enumerator.each do |item|
      block.call(item)
    end
    self
  else
    enumerator
  end
end
each_byte_with_index(offset=0,&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2830
def each_byte_with_index(offset=0,&block)
  # Thanks to Hanmac from IRC :)
  enumerator = self.to_enum(:bytes).with_index(offset)
  if block.respond_to?(:call)
    enumerator.each do |item,index|
      block.call(item,index)
    end
    self
  else
    enumerator
  end
end
each_char(&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2793
def each_char(&block)
  enumerator = self.to_enum(:chars)
  if block.respond_to?(:call)
    enumerator.each do |item|
      block.call(item)
    end
    self
  else
    enumerator
  end
end
each_char_with_index(offset=0,&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2805
def each_char_with_index(offset=0,&block)
  # Thanks to Hanmac from IRC :)
  enumerator = self.to_enum(:chars).with_index(offset)
  if block.respond_to?(:call)
    enumerator.each do |item,index|
      block.call(item,index)
    end
    self
  else
    enumerator
  end
end
each_codepoint(&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2843
def each_codepoint(&block)
  # String.codepoint will not return a GxG::Enumerator (non-blocking), so I'm providing these methods.
  enumerator = self.to_enum(:codepoints)
  if block.respond_to?(:call)
    enumerator.each do |item|
      block.call(item)
    end
    self
  else
    enumerator
  end
end
each_codepoint_with_index(offset=0,&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2856
def each_codepoint_with_index(offset=0,&block)
  enumerator = self.to_enum(:codepoints).with_index(offset)
  if block.respond_to?(:call)
    enumerator.each do |item,index|
      block.call(item,index)
    end
    self
  else
    enumerator
  end
end
each_line(separator=$/,&block) click to toggle source

Note: documentation: recommend use of these methods and NOT those which they call to ensure cooperative event processing. LATER: String: look into c code : is there a way to pluck a char off a string w/o using chars,bytes,codepoints,lines ? This would afford an opportunity to override chars,bytes,codepoints and lines so that cooperative event processing was truly and invisibly supported. This would be slower than the c code, but would let you load up gems w/o overriding another author's code to make it cooperative. (i.e. facets, etc)

# File lib/gxg/gxg_augmented.rb, line 2769
def each_line(separator=$/,&block)
  enumerator = self.lines(separator).to_enum
  if block.respond_to?(:call)
    enumerator.each do |item|
      block.call(item)
    end
    self
  else
    enumerator
  end
end
each_line_with_index(separator=$/,offset=0,&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2781
def each_line_with_index(separator=$/,offset=0,&block)
  enumerator = self.lines(separator).to_enum.with_index(offset)
  if block.respond_to?(:call)
    enumerator.each do |item,index|
      block.call(item,index)
    end
    self
  else
    enumerator
  end
end
encode64() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2958
def encode64()
  # RFC 4648
  if self.base64?()
    self
  else
    ::Base64::strict_encode64(self)
  end
end
encode64!() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2976
def encode64!()
  data = self.encode64()
  if data != self
    self.replace(data)
  end
  self
end
encrypt(withkey="") click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2992
def encrypt(withkey="")
  #
  if withkey.to_s.size > 0
    the_encoding = self.encoding()
    keybytes = ::GxG::ByteArray.new(withkey.to_s)
    container = ::GxG::ByteArray.new(self)
    #
    container.each_index do |index|
      the_value = container[(index)]
      #
      keybytes.each do |the_byte|
        [127,63,31,15,7,3,1,0].each do |the_bit|
          if the_byte > the_bit
            the_value += 1
            if the_value > 255
              the_value = 0
            end
          else
            the_value -= 1
            if the_value < 0
              the_value = 255
            end
          end
        end
      end
      #
      container[(index)] = the_value
    end
    #
    result = container.to_s
    result.force_encoding(the_encoding)
    result
  else
    self.dup
  end
end
from_json(symbolize_names = true) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2896
def from_json(symbolize_names = true)
  if self.json?
    the_object = ::JSON::parse(self,{:symbolize_names => symbolize_names})
    if the_object.is_any?(::Hash, ::Array)
      the_object.process! do |value, selector, container|
        if value.is_a?(::String)
          item = value.numeric_values()
          if item.is_a?(::Hash)
            if item[:integer]
              item = item[:integer]
              container[(selector)] = item
            else
              if item[:float]
                item = item[:float]
                container[(selector)] = item
              end
            end
          else
            if (value.valid_datetime? || value.valid_datetime_nolocale?)
              container[(selector)] = ::DateTime::parse(value)
            end
          end
          #
          if value[0..6] == "binary:" && value[7..-1].base64?
            container[(selector)] = GxG::ByteArray.new(value[7..-1].decode64)
          end
        end
        nil
      end
      #
    end
  else
    self
  end
end
html?() click to toggle source

def from_xml(options={})

#
unless options[:no_test] == true
  unless self.xml?()
    raise Exception, "String is NOT formatted as XML."
  end
end
result = nil
visit = Proc.new do |the_node=nil, accumulator=[]|
  node_stack = []
  if the_node
    node_stack.push(the_node)
    while (node_stack.size > 0) do
      a_node = node_stack.pop()
      # process(a_node)
      if a_node.is_a?(::Oga::XML::Text)
        accumulator << a_node.text()
      end
      if a_node.is_any?(::Oga::XML::Element, ::Oga::XML::Document)
        record = {:name => "document_root", :attributes => {}, :parent => nil, :object => nil, :path => "/", :assembled => false}
        if a_node.respond_to?(:name)
          record[:name] = a_node.name()
        end
        if a_node.respond_to?(:attributes)
          a_node.attributes.each do |the_attr|
            record[:attributes][(the_attr.name.to_s.to_sym)] = the_attr.value
          end
        end
        if a_node.respond_to?(:parent)
          record[:parent] = a_node.parent()
        else
          record[:parent] = a_node
        end
        record[:object] = a_node
        unless a_node.is_a?(::Oga::XML::Document)
          # set accumulator path
          #
        end
        accumulator << record
      end
      if a_node.children.size > 0
        a_node.children.each do |entry|
          node_stack.push(entry)
        end
      end
    end
  end
  accumulator
end
#
begin
  if options[:sax] == true
    database = visit.call(::Oga::sax_parse_xml(self.transcode({:replace => "."},::Encoding::UTF_8)),[])
  else
    database = visit.call(::Oga::parse_xml(self.transcode({:replace => "."},::Encoding::UTF_8)),[])
  end
  link_db = []
  accumulator = []
  # Build link_db
  database.each do |the_node|
    if the_node.is_a?(::Hash)
      node_record = {}
      as_key = the_node[:name].to_s.to_sym
      if the_node[:object].is_a?(::Oga::XML::Document)
        node_record[(as_key)] = {:attributes => (the_node[:attributes]), :text => "", :children => []}
      else
        node_record[(as_key)] = {:attributes => (the_node[:attributes]), :text => (the_node[:object].text), :children => []}
      end
      link_record = {:desendents => [], :accumulator => (node_record[(as_key)][:children])}
      #
      database.each do |a_node|
        if a_node.is_a?(::Hash)
          if a_node[:parent].object_id == the_node[:object].object_id
            link_record[:desendents] << a_node[:object]
          end
        end
      end
      link_db << link_record
      if the_node[:parent].is_a?(::Oga::XML::Document)
        accumulator << node_record
      end
    else
      accumulator << the_node
    end
  end
  #
  while (link_db.size > 0) do
    entry = link_db.shift
    if entry.is_a?(::Hash)
      entry[:desendents].each do |node|
        unless node.is_a?(::Oga::XML::Document)
          if node.is_a?(::Oga::XML::Text)
            node_record = node.text
          else
            if node.is_a?(::Oga::XML::Comment)
              node_record = {:comment => node.text}
            else
              node_record = {}
              as_key = node.name.to_s.to_sym
              node_record[(as_key)] = {:attributes => {}, :text => (node.text), :children => []}
              node.attributes.each do |the_attr|
                node_record[(as_key)][:attributes][(the_attr.name.to_s.to_sym)] = the_attr.value
              end
              link_record = {:desendents => [], :accumulator => (node_record[(as_key)][:children])}
              node.children.each do |node_descendent|
                link_record[:desendents] << node_descendent
              end
              if link_record[:desendents].size > 0
                link_db.push(link_record)
              end
            end
          end
          #
          entry[:accumulator] << node_record
        end
      end
      #
    end
  end
  #
  result = accumulator
rescue Exception => the_error
end
#
result

end

def from_xml_simple()

if self.xml?
  the_hash = ::XmlSimple.xml_in(self)
  if the_hash.is_a?(::Hash)
    the_hash.symbolize_keys
    the_hash.process! do |value, selector, container|
      if value.is_a?(::String)
        item = value.numeric_values()
        if item.is_a?(::Hash)
          if item[:integer]
            item = item[:integer]
            container[(selector)] = item
          else
            if item[:float]
              item = item[:float]
              container[(selector)] = item
            end
          end
        else
          # Cast all time elements to ISO-8601
          if (value.valid_time? || value.valid_date? || value.valid_datetime? || value.valid_datetime_nolocale?)
            container[(selector)] = ::DateTime::parse(value.to_s)
          end
        end
      end
      nil
    end
  end
  the_hash
else
  nil
end

end

# File lib/gxg/gxg_augmented.rb, line 2482
def html?()
  declaration_test = (self.include?('<!DOCTYPE HTML') || self.include?('<!DOCTYPE html') || self.include?('<!DOCTYPE xhtml'))
  parse_test = false
  if declaration_test
    begin
      mime = self.mime_type()
      if mime.is_a?(::Hash)
        if ["html", "xhtml", "xhtml+xml"].include?(mime[:subtype])
          parse_test = true
        end
      end
    rescue Exception => the_error
    end
  end
  (declaration_test && parse_test)
end
json?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2892
def json?()
  self.json_1?() || self.json_2?()
end
json_1?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2884
def json_1?()
  self.slice(0,1) == '{'
end
json_2?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2888
def json_2?()
  (self.json_1?() && (self.match('"apiVersion"\s?:\s?"2.0"') || false))
end
mime_type() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2295
def mime_type()
  result = nil
  raw = ::MimeMagic.by_magic(::StringIO.new(self.clone))
  if raw
    result = {:type => (raw.type), :mediatype => (raw.mediatype), :subtype => (raw.subtype)}
  end
  result
end
numeric_values(categories=:any,delimiter="\t",locale=:en_US, numeric_base=10) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2108
def numeric_values(categories=:any,delimiter="\t",locale=:en_US, numeric_base=10)
  results = []
  prepared = []
  # SOMEDAY: <string>.numeric_values: formulate regex patterns per locale and numeric_base
  quanta_pattern = /[a-zA-Z]*/
  # proposed: /^-{0,1}\d*\.{0,1}\d+$/
  # /^[-+]{0,1}\d*\.{0,1}\d+$/
  # old: /[0-9.,]*/
  numerical_pattern = /[-+0-9.,]*/
  self.to_enum(:each_line).each do |row_text|
    # ?? allow empty lines ??  I'm just not sure if I really *want* to attempt to preserve the structure that much.
    row_prep = []
    row_text.split(delimiter).to_enum.each do |column_text|
      if column_text.size > 0
        column_entry = {:text => column_text, :denomination => nil, :multiplier => nil}
        column_text.scan(quanta_pattern).to_enum.each do |quanta|
          if quanta.size > 0
            #
            interpretation = ::GxG::Units::interpret_units({:text => quanta,:categories => categories,:locale => locale, :base => numeric_base})
            #
            if interpretation[:error]
              raise interpretation[:error]
            else
              # SOMEDAY: <string>.numeric_values: a bit more discernment here than just the first interpretation.
              interpretation = interpretation[:result]
              if interpretation[0].is_a?(Hash)
                if interpretation[0][:quantum].is_a?(Hash)
                  denomination = interpretation[0][:quantum].keys[0]
                  multiplier = interpretation[0][:quantum][(denomination)]
                  column_entry = {:text => column_text, :denomination => denomination, :multiplier => multiplier}
                  if interpretation[0][:attributes].is_a?(Hash)
                    column_entry[:attributes] = interpretation[0][:attributes]
                  end
                  break
                end
              end
            end
            #
          end
          #
        end
        #
        row_prep << column_entry
        #
      else
        row_prep << nil
      end
    end
    prepared << row_prep
    #
  end
  # process prepared array
  prepared.to_enum.each do |row|
    results << row.to_enum.map do |column|
      result = nil
      if column.is_a?(Hash)
        column[:text].scan(numerical_pattern).to_enum.each do |text|
          text.gsub!(",","")
          if text.size > 0
            denomination = column[:denomination]
            multiplier = column[:multiplier]
            if text.include?(".")
              # Note: defaults *assume* base-10 numbers
              unless denomination
                denomination = :float
              end
              unless multiplier
                multiplier = 1.0
              end
              result = {}
              result[(denomination)] = text.to_f * multiplier.to_f
            else
              # Note: defaults *assume* base-10 numbers
              unless denomination
                denomination = :integer
              end
              unless multiplier
                multiplier = 1
              end
              result = {}
              result[(denomination)] = text.to_i * multiplier.to_i
            end
            if column[:attributes].is_a?(Hash)
              result.merge(column[:attributes])
            end
            break
          end
        end
      end
      result
    end
  end
  # unless it is a multi-line, or multi-column result, pass only the found denomination/value Hash.
  if results.size == 1
    # single row
    results = results[0]
    if results.size == 1
      # single column
      results = results[0]
    end
  end
  #
  results
end
serialized?() click to toggle source

Encoding format detection and handling: Serialized, JSON & binhex(base64)

# File lib/gxg/gxg_augmented.rb, line 2868
def serialized?()
  if ((self[0..7].to_s == "marshal:" || self[0..9].to_s == "structure:") && (self[8..-1].to_s.base64?() || self[10..-1].to_s.base64?()))
    true
  else
    false
  end
end
slice_bytes(*args) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2641
def slice_bytes(*args)
  # Return an ASCII_8BIT encoded sub-string
  result = nil
  the_range = nil
  if args[0].is_a?(Numeric)
    args[0] = args[0].to_i
    if args[0] < 0
      args[0] = self.bytesize + args[0]
    end
    the_range = ((args[0])..(args[0]))
    if args[1].is_a?(Numeric)
      args[1] = args[1].to_i
      if args[1] < 1
        raise ArgumentError.new("Second parameter needs to be a Numeric greater than 0, you provided #{args[1].inspect}")
      else
        the_range = ((args[0])..(args[0] + (args[1] - 1)))
      end
    end
  else
    if args[0].is_a?(Range)
      if args[0].first < 0
        args[1] = self.bytesize + args[0].first
      else
        args[1] = args[0].first
      end
      if args[0].last < 0
        args[2] = self.bytesize + args[0].last
      else
        args[2] = args[0].last
      end
      if args[1] <= args[2]
        the_range = ((args[1])..(args[2]))
      else
        the_range = ((args[2])..(args[1]))
      end
    else
      raise ArgumentError.new("First parameter needs to be a Numeric or a Range, you provided #{args[0].inspect}")
    end
  end
  #
  if the_range
    result = ""
    result.force_encoding(::Encoding::ASCII_8BIT)
    #
    if self.encoding == ::Encoding::ASCII_8BIT
      if self.bytesize > 0
        if the_range.min != the_range.max
          result << self.slice(the_range)
        else
          result << self[(the_range.min)]
        end
      end
    else
      # based upon memory-load and processing-load of Ruby Engine, select space-vs-speed or speed-vs-space techniques.
      if (GxG::Engine::memory_load_high?() && (self.to_enum(:bytes).heap_used() < self.heap_used()))
        # trade off speed for space considerations
        # long-way 'round
        position = 0
        index = 0
        #
        self.to_enum(:bytes).each do |the_byte|
          if the_range.include?(position)
            if the_range.min == the_range.max
              result << the_byte.chr
              break
            else
              result[(index)] = the_byte.chr
            end
            index += 1
          end
          position += 1
        end
        #
      else
        # trade off space for speed considerations
        if self.bytesize > 0
          raw_text = self.clone
          raw_text.force_encoding(::Encoding::ASCII_8BIT)
          if the_range.min != the_range.max
            result << raw_text.slice(the_range)
          else
            result << raw_text[(the_range.min)]
          end
        end
        #
      end
    end
    #
  end
  result
end
split_camelcase() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2287
def split_camelcase()
  if self.camel_case?()
    self.split(/(?=[A-Z])/)
  else
    self
  end
end
to_uri() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2637
def to_uri()
  ::URI::parse(self)
end
transcode(*args) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 1933
def transcode(*args)
  destination_encoding = nil
  conversion_options = nil
  if args.size > 0
    if args[0].is_a?(::Hash)
      conversion_options = args[0]
      if args[1].is_a?(::Encoding)
        destination_encoding = args[1]
      else
        destination_encoding = ::Encoding.default_external
      end
    else
      #
      if args[0].is_a?(::Encoding)
        destination_encoding = args[0]
        if args[1].is_a?(::Hash)
          conversion_options = args[1]
        else
          conversion_options = {}
        end
      end
    end
    args = nil
  end
  #
  unless destination_encoding.is_a?(::Encoding)
    raise ArgumentError, "You must provide a valid Encoding, instead you provided #{destination_encoding.class}"
  end
  unless conversion_options.is_a?(::Hash)
    raise ArgumentError, "You must provide a Hash for conversion options, instead you provided #{conversion_options.class}"
  end
  in_options = {}
  out_options = {}
  #
  if (conversion_options[:invalid] || conversion_options[:undef] || conversion_options[:replace])
    # Note: I *confirmed* (thanks VGoff) that :invalid/:undef/:replace and :fallback are exclusive.
    #
    # If the value is :replace, encode replaces invalid byte sequences in str with the replacement character. The default is to
    #    raise the Encoding::InvalidByteSequenceError exception
    if conversion_options[:invalid] == :replace
      in_options[:invalid] = :replace
      out_options[:invalid] = :replace
    end
    #    If the value is :replace, encode replaces characters which are undefined in the destination encoding with the replacement character.
    #    The default is to raise the Encoding::UndefinedConversionError.
    if conversion_options[:undef] == :replace
      in_options[:undef] = :replace
      out_options[:undef] = :replace
    end
    #
    #    Sets the replacement string to the given value. The default replacement string is “uFFFD” for Unicode encoding forms, and “?” otherwise.
    if conversion_options[:replace].is_a?(::String)
      in_options[:replace] = conversion_options[:replace]
      out_options[:replace] = conversion_options[:replace]
    end
    #
  else
    #    Sets the replacement string by the given object for undefined character. The object should be a Hash, a Proc, a Method,
    #    or an object which has [] method. Its key is an undefined character encoded in the source encoding of current transcoder.
    #    Its value can be any encoding until it can be converted into the destination encoding of the transcoder.
    if (conversion_options[:fallback].is_any?(::Hash, ::Struct, ::Proc, ::Method) || conversion_options[:fallback].respond_to?(:[]))
      # if :fallback will not process an Array as mentioned above ... remove :[] respond_to? condition.
      if conversion_options[:fallback].is_any?(::Proc, ::Method)
        # TODO: study arguments and output expected, and construct one in and one out proc as wrapper.
        # FIX: Odd Bug : MRI 1.9.3 will attempt to convert a Proc into a Hash directly and raise exception, instead of calling the proc.
        # Also, when a method is supplied: it does call it, but passes no data and I don't think even collects a response.  (wtf?) what is the point then??
        # So ... as a work around (FORNOW) I will simply construct a Hash and use that resultant Hash as fallback.
        # LATER: I think I'd like to add the above comparison to simply check for a .respond_to?(:call) on action objects.
        in_fallback = {}
        out_fallback = {}
        self.each_char do |the_char|
          dst_defined_char = conversion_options[:fallback].call(the_char).to_s.chars.first
          if (dst_defined_char.size > 0 && the_char != dst_defined_char)
            utf_bridge = the_char.encode(::Encoding::UTF_8)
            in_fallback[(the_char)] = utf_bridge
            out_fallback[(utf_bridge)] = dst_defined_char
          end
        end
        in_options[:fallback] = in_fallback
        out_options[:fallback] = out_fallback
      else
        if conversion_options[:fallback].is_any?(::Hash, ::Struct)
          #
          in_fallback = {}
          out_fallback = {}
          #
          conversion_options[:fallback].to_enum(:each_pair).each do |src_undefined_char,dst_defined_char|
            utf_bridge = src_undefined_char.encode(::Encoding::UTF_8)
            in_fallback[(src_undefined_char)] = utf_bridge
            out_fallback[(utf_bridge)] = dst_defined_char
          end
          #
          in_options[:fallback] = in_fallback
          out_options[:fallback] = out_fallback
        else
          if (conversion_options[:fallback].respond_to?(:[]) && conversion_options[:fallback].respond_to?(:to_a))
            in_fallback = {}
            out_fallback = {}
            the_data = conversion_options[:fallback].to_a.flatten
            the_size = the_data.size
            if (the_size.even? && the_size > 0)
              (0..(the_size)).step(2) do |index|
                src_undefined_char = the_data[(index)]
                dst_defined_char = the_data[(index + 1)]
                utf_bridge = src_undefined_char.encode(::Encoding::UTF_8)
                in_fallback[(src_undefined_char)] = utf_bridge
                out_fallback[(utf_bridge)] = dst_defined_char
              end
            else
              # raise error?  this really requires matched pairs of things
            end
            in_options[:fallback] = in_fallback
            out_options[:fallback] = out_fallback
          end
        end
      end
    end
  end
  #
  #    The value must be :text or :attr. If the value is :text encode replaces undefined characters with their (upper-case hexadecimal) numeric character
  #    references. ‘&’, ‘<’, and ‘>’ are converted to “&amp;”, “&lt;”, and “&gt;”, respectively. If the value is :attr, encode also quotes the replacement
  #    result (using ‘“’), and replaces ‘”’ with “&quot;”.
  if [:text, :attr].include?(conversion_options[:xml])
    in_options[:xml] = conversion_options[:xml]
    out_options[:xml] = conversion_options[:xml]
  end
  #
  #    Replaces LF (“n”) with CR (“r”) if value is true.
  unless (conversion_options[:crlf_newline] || conversion_options[:universal_newline])
    if conversion_options[:cr_newline] == true
      in_options[:cr_newline] = true
      out_options[:cr_newline] = true
    end
  end
  #
  #    Replaces LF (“n”) with CRLF (“rn”) if value is true.
  unless (conversion_options[:cr_newline] || conversion_options[:universal_newline])
    if conversion_options[:crlf_newline] == true
      in_options[:crlf_newline] = true
      out_options[:crlf_newline] = true
    end
  end
  #
  #    Replaces CRLF (“rn”) and CR (“r”) with LF (“n”) if value is true.
  unless (conversion_options[:cr_newline] || conversion_options[:crlf_newline])
    if conversion_options[:universal_newline] == true
      in_options[:universal_newline] = true
      out_options[:universal_newline] = true
    end
  end
  # ###
  # the_string = self.encode(::Encoding::UTF_8,self.external_encoding,in_options)
  # the_string.encode!(destination_encoding,::Encoding::UTF_8,out_options)
  # --or--
  if self.encoding == ::Encoding::UTF_8
    the_string = self.dup
  else
    the_string = self.encode(::Encoding::UTF_8,self.encoding,in_options)
  end
  if destination_encoding != ::Encoding::UTF_8
    the_string.encode!(destination_encoding,::Encoding::UTF_8,out_options)
  end
  #
  the_string
end
transcode!(*args) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2099
def transcode!(*args)
  data = self.transcode(*args)
  if data.is_a?(::String)
    self.force_encoding(data.encoding)
    self.replace(data)
  end
  self
end
unpack_bytes(format_template_string="") click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2760
def unpack_bytes(format_template_string="")
  # See : http://ruby-doc.org/core-1.9.3/String.html#method-i-byteslice#This%20table%20summarizes
  GxG::ByteArray.new(self.unpack(format_template_string))
end
unserialize() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2876
def unserialize()
  if self.serialized?()
    ::GxG::reconstitute(self)
  else
    self
  end
end
valid_date?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2227
def valid_date?()
  # Match for Date pattern
  if (/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/.match(self))
    true
  else
    false
  end
end
valid_datetime?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2236
def valid_datetime?()
  # Match for ISO 8601 pattern
  if (/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9][+-][0-9][0-9]:[0-9][0-9]/.match(self))
    true
  else
    false
  end
end
valid_datetime_nolocale?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2245
def valid_datetime_nolocale?()
  # Match for not-so-much ISO 8601-ish pattern
  if (/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]/.match(self))
    true
  else
    false
  end
end
valid_jid?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2262
def valid_jid?()
  # From Blather: /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/
  # From xmpp4r: /^(?:([^@\/<>\'\"]+)@)?([^@\/<>\'\"]+)(?:\/([^<>\'\"]*))?$/
  # Note: for now - using the one from Blather
  if /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/.match(self)
    true
  else
    false
  end
  # if /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/.match(self)
  #   true
  # else
  #   false
  # end
end
valid_path?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2254
def valid_path?()
  if (/.*(?:\\|\/)(.+)$/.match(self) || (self.split(" ").size == 1 || self.split("/").size > 1 || self == "/"))
    true
  else
    false
  end
end
valid_time?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2213
def valid_time?()
  # Parse for Time class
  instance = nil
  begin
    instance = ::Chronic::parse(self)
  rescue Exception
  end
  if instance.is_a?(::Time)
    true
  else
    false
  end
end
valid_uri?() click to toggle source

def from_html(options={})

#
unless options[:no_test] == true
  unless self.html?()
    raise Exception, "String is NOT formatted as HTML."
  end
end
result = nil
visit = Proc.new do |the_node=nil, accumulator=[]|
  node_stack = []
  if the_node
    node_stack.push(the_node)
    while (node_stack.size > 0) do
      a_node = node_stack.pop()
      # process(a_node)
      if a_node.is_a?(::Oga::XML::Text)
        accumulator << a_node.text()
      end
      if a_node.is_any?(::Oga::XML::Element, ::Oga::XML::Document)
        record = {:name => "document_root", :attributes => {}, :parent => nil, :object => nil, :path => "/", :assembled => false}
        if a_node.respond_to?(:name)
          record[:name] = a_node.name()
        end
        if a_node.respond_to?(:attributes)
          a_node.attributes.each do |the_attr|
            record[:attributes][(the_attr.name.to_s.to_sym)] = the_attr.value
          end
        end
        if a_node.respond_to?(:parent)
          record[:parent] = a_node.parent()
        else
          record[:parent] = a_node
        end
        record[:object] = a_node
        unless a_node.is_a?(::Oga::XML::Document)
          # set accumulator path
          #
        end
        accumulator << record
      end
      if a_node.children.size > 0
        a_node.children.each do |entry|
          node_stack.push(entry)
        end
      end
    end
  end
  accumulator
end
#
begin
  if options[:sax] == true
    database = visit.call(::Oga::sax_parse_html(self.transcode({:replace => "."},::Encoding::UTF_8)),[])
  else
    database = visit.call(::Oga::parse_html(self.transcode({:replace => "."},::Encoding::UTF_8)),[])
  end
  link_db = []
  accumulator = []
  # Build link_db
  database.each do |the_node|
    if the_node.is_a?(::Hash)
      node_record = {}
      as_key = the_node[:name].to_s.to_sym
      if the_node[:object].is_a?(::Oga::XML::Document)
        node_record[(as_key)] = {:attributes => (the_node[:attributes]), :text => "", :children => []}
      else
        node_record[(as_key)] = {:attributes => (the_node[:attributes]), :text => (the_node[:object].text), :children => []}
      end
      link_record = {:desendents => [], :accumulator => (node_record[(as_key)][:children])}
      #
      database.each do |a_node|
        if a_node.is_a?(::Hash)
          if a_node[:parent].object_id == the_node[:object].object_id
            link_record[:desendents] << a_node[:object]
          end
        end
      end
      link_db << link_record
      if the_node[:parent].is_a?(::Oga::XML::Document)
        accumulator << node_record
      end
    else
      accumulator << the_node
    end
  end
  #
  while (link_db.size > 0) do
    entry = link_db.shift
    if entry.is_a?(::Hash)
      entry[:desendents].each do |node|
        unless node.is_a?(::Oga::XML::Document)
          if node.is_a?(::Oga::XML::Text)
            node_record = node.text
          else
            if node.is_a?(::Oga::XML::Comment)
              node_record = {:comment => node.text}
            else
              node_record = {}
              as_key = node.name.to_s.to_sym
              node_record[(as_key)] = {:attributes => {}, :text => (node.text), :children => []}
              node.attributes.each do |the_attr|
                node_record[(as_key)][:attributes][(the_attr.name.to_s.to_sym)] = the_attr.value
              end
              link_record = {:desendents => [], :accumulator => (node_record[(as_key)][:children])}
              node.children.each do |node_descendent|
                link_record[:desendents] << node_descendent
              end
              if link_record[:desendents].size > 0
                link_db.push(link_record)
              end
            end
          end
          #
          entry[:accumulator] << node_record
        end
      end
      #
    end
  end
  #
  result = accumulator
rescue Exception => the_error
end
#
result

end

# File lib/gxg/gxg_augmented.rb, line 2626
def valid_uri?()
  result = false
  begin
    if ::URI::parse(self).is_a?(::URI::Generic)
      result = true
    end
  rescue Exception
  end
  result
end
xml?() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 2304
def xml?()
  declaration_test = self.include?("<?xml version=")
  parse_test = false
  if declaration_test
    begin
      mime = self.mime_type()
      if mime.is_a?(::Hash)
        if mime[:subtype] == "xml" || mime[:subtype] = "xhtml+xml"
          parse_test = true
        end
      end
    rescue Exception => the_error
    end
  end
  (declaration_test && parse_test)
end