# module GxG::Support::Library::Transcoding

### Public Instance Methods

convert_to_string(the_object=nil,encoding=::Encoding.default_external,conversion_options={}) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 214
    def convert_to_string(the_object=nil,encoding=::Encoding.default_external,conversion_options={})
      # return the supplied string, or supported object string data, or UTF_8 codepoint, un-transcoded
      # encoding is used for when a byte value integer is passed to know what encoding to set.
      the_string = ""
      the_string.force_encoding(encoding || ::Encoding.default_external)
      if the_object
        if the_object.is_a?(::Array)
          dataset = the_object.flatten
        else
          dataset = [(the_object)]
        end
        dataset.to_enum(:each).each do |object|
          buffer = ""
          if object.is_a?(::String)
            # find the string content of these classes and pass them for transcoding: Numeric, String, ::IO via gets, ::StringIO via gets, ::GxG::ByteArray
            buffer = object.dup
          else
            if object.is_any?(::IO, ::StringIO)
              # Note: what issues arise when the_object is in binary mode?  Also, how does this scale to very large things or files?
              buffer = object.gets().to_s
            end
            if object.is_any?(::GxG::ByteArray)
              buffer = object.to_s
            end
            if object.is_a?(::Numeric)
              if object.to_i >= 0
                data = ""
                if (0xFFFFFFFF && object.to_i) > 255
                  # interprets as unicode code point
                  data.force_encoding(::Encoding::UTF_8)
                else
                  # interprets as a char value in its own encoding, no transcoding needed.
                  data.force_encoding(encoding || ::Encoding.default_external)
                end
                buffer = (data << object.to_i)
                data = nil
              else
                # signed integers not supported for char values or codepoints at this time.
              end
            end
          end
          #
          if buffer.size > 0
            if (buffer.encoding == (encoding || ::Encoding.default_external) && ! self.binmode?())
              the_string << buffer
            else
              # ::String::transcode_options((encoding || ::Encoding.default_external),buffer.encoding, (conversion_options || {}))
              if self.binmode?()
                buffer.to_enum(:chars).each do |the_char|
                  the_char.to_enum(:bytes).each do |the_byte|
                    the_string << the_byte
                  end
                end
              else
                nl_op = self.newline_option_used(conversion_options)
                options = {}
                if nl_op
                  options[(nl_op)] = true
                end
                #
                the_string << buffer.transcode!((encoding || ::Encoding.default_external),options)
              end
            end
          end
          #
        end
      end
      #
      the_string
    end

field_separator_used(io_channel=:external) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 162
    def field_separator_used(io_channel=:external)
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      unless self.instance_variable_defined?(:@internal_field_separator)
        @internal_field_separator = nil
      end
      unless self.instance_variable_defined?(:@external_field_separator)
        @external_field_separator = nil
      end
      field_separator = ""
      if io_channel == :internal
        field_separator.force_encoding((@internal_encoding || self.external_encoding))
        field_separator << (@internal_field_separator || ($,).to_s)
      else
        io_channel = :external
        field_separator.force_encoding(self.external_encoding)
        field_separator << (@external_field_separator || ($,).to_s)
      end
      if field_separator.size > 0
        field_separator
      else
        nil
      end
    end

newline_option_used(io_channel=:external) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 103
    def newline_option_used(io_channel=:external)
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      # determine the correct new_line trancoding option used
      if io_channel.is_a?(::Hash)
        options = io_channel
      else
        options = (@conversion_options[(io_channel.to_sym)] || {})
      end
      if options[:cr_newline]
        :cr_newline
      else
        if options[:crlf_newline]
          :crlf_newline
        else
          if options[:universal_newline]
            :universal_newline
          else
            # use nil if none specified
            nil
          end
        end
      end
      #
    end

newline_used(io_channel=:external) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 130
    def newline_used(io_channel=:external)
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      newline = ""
      if io_channel == :internal
        newline.force_encoding((@internal_encoding || self.external_encoding))
      else
        io_channel = :external
        newline.force_encoding(self.external_encoding)
      end
      # determine the correct new_line_separator
      if @conversion_options[(io_channel)][:cr_newline]
        newline << "\r"
      else
        if @conversion_options[(io_channel)][:crlf_newline]
          newline << "\r\n"
        else
          if @conversion_options[(io_channel)][:universal_newline]
            newline << "\n"
          else
            # use global default if none specified
            newline << $/
          end
        end
      end
      newline
    end

prepare_conversion_options(options={}) click to toggle source

Instance Methods

    # File lib/gxg/gxg_transcode.rb, line 8
    def prepare_conversion_options(options={})
      # obsoleted by ::String::transcode_options
      unless options.is_a?(::Hash)
        raise ArgumentError, "You must pass conversion options parameter as a Hash"
      end
      #
      new_options = {}
      #
      valid_options = [:invalid,:undef,:replace,:fallback,:xml,:cr_newline,:crlf_newline,:universal_newline]
      #
      for the_option_key in valid_options
        #
        if options[(the_option_key)]
          # Note Source: http://ruby-doc.org/core-1.9.3/String.html#method-i-encode
          if the_option_key == :fallback
            #    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.
            unless new_options[:replace]
              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]
              end
            end
          end
          #
          if the_option_key == :invalid
            #    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
            unless new_options[:fallback]
              if options[:invalid] == :replace
                new_options[:invalid] = :replace
              end
            end
          end
          #
          if (the_option_key == :undef)
            #    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.
            unless new_options[:fallback]
              if options[:undef] == :replace
                new_options[:undef] = :replace
              end
            end
          end
          if (the_option_key == :replace)
            #    Sets the replacement string to the given value. The default replacement string is “uFFFD” for Unicode encoding forms, and “?” otherwise.
            unless new_options[:fallback]
              if options[:replace].is_a?(::String)
                new_options[:replace] = options[:replace]
              end
            end
          end
          if the_option_key == :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]
            end
          end
          if the_option_key == :cr_newline
            #    Replaces LF (“n”) with CR (“r”) if value is true.
            unless (new_options[:crlf_newline] || new_options[:universal_newline])
              if options[(the_option_key)] == true
                new_options[(the_option_key)] = true
              end
            end
          end
          #
          if the_option_key == :crlf_newline
            #    Replaces LF (“n”) with CRLF (“rn”) if value is true.
            unless (new_options[:cr_newline] || new_options[:universal_newline])
              if options[(the_option_key)] == true
                new_options[(the_option_key)] = true
              end
            end
          end
          #
          if the_option_key == :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[(the_option_key)] == true
                new_options[(the_option_key)] = true
              end
            end
          end
          #
        end
        #
        pause
      end
      new_options
    end

record_separator_used(io_channel=:external) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 188
    def record_separator_used(io_channel=:external)
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      unless self.instance_variable_defined?(:@internal_record_separator)
        @internal_record_separator = nil
      end
      unless self.instance_variable_defined?(:@external_record_separator)
        @external_record_separator = nil
      end
      record_separator = ""
      if io_channel == :internal
        record_separator.force_encoding((@internal_encoding || self.external_encoding))
        record_separator << (@internal_record_separator || ($\).to_s)
      else
        io_channel = :external
        record_separator.force_encoding(self.external_encoding)
        record_separator << (@external_record_separator || ($\).to_s)
      end
      if record_separator.size > 0
        record_separator
      else
        nil
      end
    end

transcode_to_external(the_string="") click to toggle source

TODO: GxG::StringIO : transcoding methods : tie into conversion-options-set-selector supports (dst-encoding,src-encoding). `Hash` deep-merge method needed.

    # File lib/gxg/gxg_transcode.rb, line 287
    def transcode_to_external(the_string="")
      # return the supplied string, or supported object string data, or UTF_8 codepoint, transcoded
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      #
      unless the_string.is_a?(::String)
        # External conversion options will have to be dynamically generated upon transcode_to_external as *any* encoding is possible, not just internal_encoding
        the_string = self.convert_to_string(the_string,self.external_encoding,@conversion_options[:external])
      end
      if the_string.size > 0
        if self.binmode?()
          the_string.force_encoding(::Encoding::ASCII_8BIT)
        else
          if (the_string.encoding != self.external_encoding)
            if the_string.encoding == @internal_encoding
              options = ::String::transcode_options(self.external_encoding,the_string.encoding,@conversion_options[:external])
            else
              # External conversion options will have to be dynamically generated upon transcode_to_external as *any* encoding is possible, not just internal_encoding
              nl_op = self.newline_option_used(:external)
              options = {}
              if nl_op
                options[(nl_op)] = true
              end
              options = ::String::transcode_options(self.external_encoding,the_string.encoding,options)
            end
            the_string.transcode!(self.external_encoding,options)
          end
        end
      end
      #
      the_string
    end

transcode_to_internal(the_string="") click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 324
    def transcode_to_internal(the_string="")
      # return the supplied string, or supported object string data, or UTF_8 codepoint, transcoded
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      #
      if (@internal_encoding && ! self.binmode?())
        unless the_string.is_a?(::String)
          the_string = self.convert_to_string(the_string,@internal_encoding,@conversion_options[:internal])
        end
        if the_string.size > 0
          if @internal_encoding == ::Encoding::ASCII_8BIT
            # for cases where the external encoding is anything but binary, but the internal is set to BINARY.
            # instead of actually transcoding something char by char into binary - just sets the encoding and filters for newline settings.
            #
            the_string.force_encoding(::Encoding::ASCII_8BIT)
            nl_op = self.newline_option_used(:internal)
            options = {}
            if nl_op
              options[(nl_op)] = true
            end
            the_string = the_string.encode(::Encoding::ASCII_8BIT,::Encoding::ASCII_8BIT,options)
          else
            if (the_string.encoding != @internal_encoding)
              if the_string.encoding == self.external_encoding
                options = ::String::transcode_options(@internal_encoding,the_string.encoding,@conversion_options[:internal])
              else
                nl_op = self.newline_option_used(:internal)
                options = {}
                if nl_op
                  options[(nl_op)] = true
                end
                options = ::String::transcode_options(@internal_encoding,the_string.encoding,options)
              end
              the_string.transcode!(@internal_encoding,options)
            end
          end
        end
      else
        the_string = self.transcode_to_external(the_string)
      end
      #
      the_string
    end