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
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)
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