# 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