# module GxG::Support::Library::TranscodingIO

### Public Instance Methods

bytes(&block)
Alias for: each_byte
chars(&block)
Alias for: each_char
codepoints(&block)
Alias for: each_codepoint
each(separator=$/, limit=nil,&block)
Alias for: each_line
each_byte(&block) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 668
    def each_byte(&block)
      if block.respond_to?(:call)
        if self.closed_read?
          raise IOError, "not open for reading"
        else
          until self.eof?()
            data = self.getbyte()
            if data
              block.call(data)
            end
            pause
          end
          #
          self
        end
      else
        # Note: when each_byte alias is called, will be cosmetic off, but will work.
        self.to_enum(:each_byte)
      end
    end

Also aliased as: bytes
each_char(&block) click to toggle source
Calls superclass method

    # File lib/gxg/gxg_transcode.rb, line 647
    def each_char(&block)
      if block.respond_to?(:call)
        if self.closed_read?
          raise IOError, "not open for reading"
        else
          #
          # Note: this approach burns another 20 or 40 bytes (depending on arch-bits) for extra cooperative Enumerator encapsulation,
          # but avoids stack-too-deep errors..
          super().to_enum.each do |the_character|
            block.call(self.transcode_to_internal(the_character))
          end
          #
          self
        end
      else
        # Note: when each_char alias is called, will be cosmetic off, but will work.
        self.to_enum(:each_char)
      end
    end

Also aliased as: chars
each_codepoint(&block) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 712
    def each_codepoint(&block)
      if block.respond_to?(:call)
        if self.closed_read?
          raise IOError, "not open for reading"
        else
          # transcodes at the character level prior to codepoint passage to the block.
          self.each_char do |the_character|
            block.call(the_character.codepoints.first)
          end
          #
          self
        end
      else
        # Note: when each_codepoint alias is called, will be cosmetic off, but will work.
        self.to_enum(:each_codepoint)
      end
    end

Also aliased as: codepoints
each_line(separator=$/, limit=nil,&block) click to toggle source
Calls superclass method

    # File lib/gxg/gxg_transcode.rb, line 731
    def each_line(separator=$/, limit=nil,&block)
      # should not do an *args param capture for interface behavior compatibility.
      # use of limit and separator appear exclusive in this method.
      if separator.is_a?(Numeric)
        limit = separator.to_i
        separator = nil
      end
      # if transcoding is set, overwrite default separator according to translation flag settings.
      if (self.internal_encoding() && self.internal_encoding() != self.external_encoding)
        if separator == $/
          #Note : line separator supplied as method parameter will be applied to the transcoded string, not the StringIO data itself.
          separator = self.newline_used(:internal)
        end
      end
      #
      if limit
        limit = limit.to_i
        unless limit > 0
          # Note: a work-around : irb FREAKS entire system when you call readlines with limit equal to 0 (memleak: IO lock up)
          limit = 1
        end
        args = [(separator),(limit)]
      else
        args = [(separator)]
      end
      #
      if block.respond_to?(:call)
        if self.closed_read?
          raise IOError, "not open for reading"
        else
          # Note: this approach burns another 20 or 40 bytes (depending on arch-bits) for extra cooperative Enumerator encapsulation,
          # but avoids stack-too-deep errors..
          super(*args) do |the_line|
            block.call(self.transcode_to_internal(the_line))
            pause
          end
          #
          self
        end
      else
        # Note: when each_line alias is called, will be cosmetic off, but will work.
        self.to_enum(:each_line,*args)
      end
    end

Also aliased as: each, lines
each_transcoded_byte(&block) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 690
    def each_transcoded_byte(&block)
      if block.respond_to?(:call)
        if self.closed_read?
          raise IOError, "not open for reading"
        else
          # transcodes at the character level prior to byte passage to the block.
          self.each_char do |the_character|
            # the_character is pre-transcoded by each_char where appropriate.
            the_character.to_enum(:bytes).each do |the_byte|
              block.call(the_byte)
            end
          end
          #
          self
        end
      else
        # Note: when each_transcoded_byte alias is called, will be cosmetic off, but will work.
        self.to_enum(:each_transcoded_byte)
      end
    end

Also aliased as: transcoded_bytes
external_conversion() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 377
    def external_conversion()
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      @conversion_options[:external].clone
    end

external_conversion=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 384
    def external_conversion=(*args)
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      @conversion_options[:external] = self.prepare_conversion_options(*args)
      @conversion_options[:external].clone
    end

external_field_separator() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 408
    def external_field_separator()
      unless self.instance_variable_defined?(:@external_field_separator)
        @external_field_separator = nil
      end
      @external_field_separator.dup
    end

external_field_separator=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 415
    def external_field_separator=(*args)
      unless self.instance_variable_defined?(:@external_field_separator)
        @external_field_separator = nil
      end
      if args[0].is_a?(::String)
        @external_field_separator = args[0]
      else
        case args[0]
        when :globalcopy
          @external_field_separator = ($,).dup
        when :global
          @external_field_separator = $,
        end
      end
    end

external_newline() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 392
    def external_newline()
      self.newline_option_used(:external)
    end

external_newline=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 396
    def external_newline=(*args)
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      if [:cr_newline, :crlf_newline, :universal_newline].include?(args[0])
        @conversion_options[:external].delete(:cr_newline)
        @conversion_options[:external].delete(:crlf_newline)
        @conversion_options[:external].delete(:universal_newline)
        @conversion_options[:external][(args[0])] = true
      end
    end

external_record_separator() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 431
    def external_record_separator()
      unless self.instance_variable_defined?(:@external_record_separator)
        @external_record_separator = nil
      end
      @external_record_separator.dup
    end

external_record_separator=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 438
    def external_record_separator=(*args)
      unless self.instance_variable_defined?(:@external_record_separator)
        @external_record_separator = nil
      end
      if args[0].is_a?(::String)
        @external_record_separator = args[0]
      else
        case args[0]
        when :globalcopy
          @external_record_separator = ($\).dup
        when :global
          @external_record_separator = $\
        end
      end
    end

getbyte() click to toggle source
Calls superclass method

    # File lib/gxg/gxg_transcode.rb, line 586
    def getbyte()
      # regarding getbyte : I don't see any practical way to do auto-transcoding ... leaving that one alone for now.
      super()
    end

getbytes() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 591
    def getbytes()
      result = GxG::ByteArray.new
      until self.eof?()
        data = self.getbyte()
        if data
          result << data
        end
        pause
      end
      result
    end

getc() click to toggle source
Calls superclass method

    # File lib/gxg/gxg_transcode.rb, line 603
    def getc()
      data = super()
      if data.is_a?(::String)
        data = self.transcode_to_internal(data)
      end
      data
    end

gets(*args) click to toggle source
Calls superclass method

    # File lib/gxg/gxg_transcode.rb, line 566
    def gets(*args)
      # Reads the next “line” from the I/O stream; lines are separated by sep. A separator of nil reads the entire contents,
      # and a zero-length separator reads the input a paragraph at a time (two successive newlines in the input separate paragraphs).
      # The stream must be opened for reading or an IOError will be raised. The line read in will be returned and also assigned to $_.
      # Returns nil if called at end of file. If the first argument is an integer, or optional second argument is given, the returning string
      # would not be longer than the given value in bytes.
      if self.closed_read?
        raise IOError, "not open for reading"
      else
        data = super(*args)
        if data.is_a?(::String)
          data = self.transcode_to_internal(data)
          $_ = data.dup
          data
        else
          nil
        end
      end
    end

internal_conversion() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 489
    def internal_conversion()
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      @conversion_options[:internal].clone
    end

internal_conversion=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 496
    def internal_conversion=(*args)
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      @conversion_options[:internal] = self.prepare_conversion_options(*args)
      @conversion_options[:internal].clone
    end

internal_encoding() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 454
    def internal_encoding()
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      @internal_encoding
    end

internal_encoding=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 461
    def internal_encoding=(*args)
      unless self.instance_variable_defined?(:@internal_encoding)
        @internal_encoding = nil
      end
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      unless self.binmode?()
        if args[0].is_any?(::Encoding, ::NilClass)
          if args[0].is_a?(::Encoding)
            @internal_encoding = args[0]
            # preserve newline settings
            nl_op = self.newline_option_used(:internal)
            options = {}
            if nl_op
              options[(nl_op)] = true
            end
            @conversion_options[:internal] = ::String::transcoding_options(@internal_encoding,self.external_encoding,options)
          else
            @internal_encoding = nil
            @conversion_options[:internal] = {}
          end
        else
          raise ArgumentError, "Expected an Encoding or NilClass, you provided #{args[0].class}"
        end
      end
    end

internal_field_separator() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 520
    def internal_field_separator()
      unless self.instance_variable_defined?(:@internal_field_separator)
        @internal_field_separator = nil
      end
      @internal_field_separator.dup
    end

internal_field_separator=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 527
    def internal_field_separator=(*args)
      unless self.instance_variable_defined?(:@internal_field_separator)
        @internal_field_separator = nil
      end
      if args[0].is_a?(::String)
        @internal_field_separator = args[0]
      else
        case args[0]
        when :globalcopy
          @internal_field_separator = ($,).dup
        when :global
          @internal_field_separator = $,
        end
      end
    end

internal_newline() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 504
    def internal_newline()
      self.newline_option_used(:internal)
    end

internal_newline=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 508
    def internal_newline=(*args)
      unless self.instance_variable_defined?(:@conversion_options)
        @conversion_options = {:internal => {}, :external => {}}
      end
      if [:cr_newline, :crlf_newline, :universal_newline].include?(args[0])
        @conversion_options[:internal].delete(:cr_newline)
        @conversion_options[:internal].delete(:crlf_newline)
        @conversion_options[:internal].delete(:universal_newline)
        @conversion_options[:internal][(args[0])] = true
      end
    end

internal_record_separator() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 543
    def internal_record_separator()
      unless self.instance_variable_defined?(:@internal_record_separator)
        @internal_record_separator = nil
      end
      @internal_record_separator.dup
    end

internal_record_separator=(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 550
    def internal_record_separator=(*args)
      unless self.instance_variable_defined?(:@internal_record_separator)
        @internal_record_separator = nil
      end
      if args[0].is_a?(::String)
        @internal_record_separator = args[0]
      else
        case args[0]
        when :globalcopy
          @internal_record_separator = ($\).dup
        when :global
          @internal_record_separator = $\
        end
      end
    end

lines(separator=$/, limit=nil,&block)
Alias for: each_line
print(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 877
    def print(*args)
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        fieldseparator = self.field_separator_used(:external)
        recordseparator = self.record_separator_used(:external)
        args = args.flatten
        if args.size > 0
          data = ""
          data.force_encoding(self.external_encoding)
          args.to_enum(:each_with_index) do |element,index|
            if element.is_any?(::String, ::Numeric, ::IO, ::StringIO, ::GxG::ByteArray)
              args[(index)] = self.transcode_to_external(element)
            else
              args[(index)] = self.transcode_to_external(element.to_s)
            end
          end
          args.to_enum(:each_with_index).each do |element,index|
            data << element
            unless index == (args.size - 1)
              if fieldseparator
                data << fieldseparator
              end
            end
          end
          if recordseparator
            data << recordseparator
          end
          if data.size > 0
            self.write(data)
          end
        end
      end
      #
      nil
    end

printf(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 848
    def printf(*args)
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        formatting = ""
        args = args.flatten
        if args[0].is_a?(::String)
          formatting = args.delete_at(0)
        end
        args.to_enum(:each_with_index) do |element,index|
          if element.is_any?(::String, ::Numeric, ::IO, ::StringIO, ::GxG::ByteArray)
            args[(index)] = self.transcode_to_external(element)
          else
            args[(index)] = self.transcode_to_external(element.inspect)
          end
        end
        data = ""
        data.force_encoding(self.external_encoding)
        data << formatting.%(*args)
        #
        if data.size > 0
          self.write(data)
        end
        #
      end
      #
      nil
    end

put_codepoint(the_object=nil)
Alias for: putc
putc(the_object=nil) click to toggle source

`Transcoding` 'write' methods:

    # File lib/gxg/gxg_transcode.rb, line 792
    def putc(the_object=nil)
      # make multi-byte safe version of putc for StringIO. (alternate3)
      # unlike stock putc : multi-byte char safe, can accept arrays of objects : where this will read the first char available on each object and write it.
      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.chars.first
          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.getc.to_s
            end
            if object.is_any?(::GxG::ByteArray)
              buffer = object.to_s.chars.first
            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(self.external_encoding)
                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 == (self.external_encoding)
              self.write(buffer.chars.first)
            else
              self.write(self.transcode_to_external(buffer).chars.first)
            end
          end
          #
        end
      end
      #
      nil
    end

Also aliased as: put_codepoint, putwc
puts(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 914
    def puts(*args)
      # Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any
      # that do not already end with a newline sequence. If called with an array argument, writes each element on a new line.
      # If called without arguments, outputs a single record separator.
      #  ###
      # determine the correct new_line_separator
      newline = self.newline_used(:external)
      #
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        args = args.flatten
        if args.size > 0
          args.to_enum(:each_with_index) do |element,index|
            if element.is_any?(::String, ::Numeric, ::IO, ::StringIO, ::GxG::ByteArray)
              args[(index)] = self.transcode_to_external(element)
            else
              args[(index)] = self.transcode_to_external(element.to_s)
            end
          end
          #
          data = ""
          data.force_encoding(self.external_encoding)
          args.to_enum.each do |element|
            if newline.size > 0
              # sense if newline is already present, add if not
              if element.size >= newline.size
                if element.slice((newline.size * -1)..-1) == newline
                  data << element
                else
                  data << element
                  data << newline
                end
              else
                data << element
                data << newline
              end
            else
              data << element
            end
          end
          if data.size > 0
            self.write(data)
          end
          #
        else
          self.write(newline)
        end
      end
      #
      nil
    end

putwc(the_object=nil)
Alias for: putc
readbyte() click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 611
    def readbyte()
      if self.closed_read?
        raise IOError, "not open for reading"
      else
        if self.eof?
          raise EOFError, "end of stream reached"
        else
          self.getbyte()
        end
      end
    end

readchar(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 623
    def readchar(*args)
      if self.closed_read?
        raise IOError, "not open for reading"
      else
        if self.eof?
          raise EOFError, "end of stream reached"
        else
          self.transcode_to_internal(self.read(1))
        end
      end
    end

readline(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 635
    def readline(*args)
      if self.closed_read?
        raise IOError, "not open for reading"
      else
        if self.eof?
          raise EOFError, "end of stream reached"
        else
          self.gets(*args)
        end
      end
    end

readlines(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 778
    def readlines(*args)
      # Reads all of the lines in ios, and returns them in anArray. Lines are separated by the optional sep.
      # If sep is nil, the rest of the stream is returned as a single record. If the first argument is an integer,
      # or optional second argument is given, the returning string would not be longer than the given value in bytes.
      # The stream must be opened for reading or an IOError will be raised.
      if self.closed_read?
        raise IOError, "not open for reading"
      else
        data = []
        self.each_line(*args) { |the_line|  data << the_line }
        data
      end
    end

transcoded_bytes(&block)
Alias for: each_transcoded_byte
unget_transcoded_byte(the_byte=nil)
Alias for: ungetbyte
unget_transcoded_bytes(*args)
Alias for: ungetbytes
ungetbyte(the_byte=nil) click to toggle source
Calls superclass method

    # File lib/gxg/gxg_transcode.rb, line 967
    def ungetbyte(the_byte=nil)
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        #
        if the_byte.is_a?(::Numeric)
          if (0..255).include?(the_byte.to_i)
            super(the_byte.to_i)
          else
            self.ungetbytes(the_byte)
          end
        else
          self.ungetbytes(the_byte)
        end
        #
      end
      nil
    end

Also aliased as: unget_transcoded_byte
ungetbytes(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 987
    def ungetbytes(*args)
      # unget the string content of these classes and pre-pend them to the StringIO: Numeric, String, ::IO via gets, ::StringIO via gets, ::GxG::ByteArray
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        args = args.flatten
        args.to_enum.each do |the_object|
          #
          the_string = self.transcode_to_external(the_object)
          if the_string.size > 0
            the_string.reverse.each_char do |the_character|
              bytes = []
              the_character.each_byte do |the_byte_value|
                bytes.unshift(the_byte_value)
              end
              bytes.to_enum.each do |the_byte_value|
                self.ungetbyte(the_byte_value)
              end
            end
          end
          #
        end
      end
      nil
    end

Also aliased as: unget_transcoded_bytes
ungetc(the_character="") click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 1014
    def ungetc(the_character="")
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        unless the_character.is_a?(::String)
          the_character = the_character.to_s.chars.first
        end
        if the_character.size > 1
          the_character = the_character.chars.first
        end
        self.ungetbytes(the_character)
      end
      nil
    end

ungets(*args) click to toggle source

    # File lib/gxg/gxg_transcode.rb, line 1029
    def ungets(*args)
      # unget the string content of these classes and pre-pend them to the StringIO: Numeric, String, ::IO via gets, ::StringIO via gets, ::GxG::ByteArray
      if self.closed_write?
        raise IOError, "not open for writing"
      else
        args = args.flatten
        args.to_enum.each do |the_object|
          #
          the_string = self.transcode_to_external(the_object)
          if the_string.size > 0
            the_string.reverse.to_enum(:each_char).each do |the_character|
              self.ungetc(the_character)
            end
          end
          #
        end
      end
      nil
    end