class IOStreams::Stream

Attributes

builder[W]
io_stream[R]

Public Class Methods

new(io_stream) click to toggle source
# File lib/io_streams/stream.rb, line 6
def initialize(io_stream)
  raise(ArgumentError, "io_stream cannot be nil") if io_stream.nil?
  raise(ArgumentError, "io_stream must not be a string: #{io_stream.inspect}") if io_stream.is_a?(String)

  @io_stream = io_stream
  @builder   = nil
end

Public Instance Methods

basename(suffix = nil) click to toggle source

Returns [String] the last component of this path. Returns `nil` if no `file_name` was set.

Parameters:

suffix: [String]
  When supplied the `suffix` is removed from the file_name before being returned.
  Use `.*` to remove any extension.

IOStreams.path("/home/gumby/work/ruby.rb").basename         #=> "ruby.rb"
IOStreams.path("/home/gumby/work/ruby.rb").basename(".rb")  #=> "ruby"
IOStreams.path("/home/gumby/work/ruby.rb").basename(".*")   #=> "ruby"
# File lib/io_streams/stream.rb, line 257
def basename(suffix = nil)
  file_name = builder.file_name
  return unless file_name

  suffix.nil? ? ::File.basename(file_name) : ::File.basename(file_name, suffix)
end
copy_from(source, convert: true, mode: nil, **args) click to toggle source

Copy from another stream, path, file_name or IO instance.

Parameters:

stream [IOStreams::Path|String<file_name>|IO]
  The stream to read from.

:convert [true|false]
  Whether to apply the stream conversions during the copy.
  Default: true

:mode [:line, :array, :hash]
  When convert is `true` then use this mode to convert the contents of the file.

Examples:

# Copy and convert streams based on file extensions IOStreams.path(“target_file.json”).copy_from(“source_file_name.csv.gz”)

# Copy “as-is” without any automated stream conversions IOStreams.path(“target_file.json”).copy_from(“source_file_name.csv.gz”, convert: false)

# Advanced copy with custom stream conversions on source and target. source = IOStreams.path(“source_file”).stream(encoding: “BINARY”) IOStreams.path(“target_file.pgp”).option(:pgp, passphrase: “hello”).copy_from(source)

# File lib/io_streams/stream.rb, line 176
def copy_from(source, convert: true, mode: nil, **args)
  if convert
    stream = IOStreams.new(source)
    if mode
      writer(mode, **args) do |target|
        stream.each(mode) { |row| target << row }
      end
    else
      writer(**args) do |target|
        stream.reader { |src| IO.copy_stream(src, target) }
      end
    end
  else
    stream = source.is_a?(Stream) ? source.dup : IOStreams.new(source)
    dup.stream(:none).writer do |target|
      stream.stream(:none).reader { |src| IO.copy_stream(src, target) }
    end
  end
end
copy_to(target, **args) click to toggle source
# File lib/io_streams/stream.rb, line 196
def copy_to(target, **args)
  target = IOStreams.new(target)
  target.copy_from(self, **args)
end
dirname() click to toggle source

Returns [String] the directory for this file. Returns `nil` if no `file_name` was set.

If `path` does not include a directory name the “.” is returned.

IOStreams.path("test.rb").dirname         #=> "."
IOStreams.path("a/b/d/test.rb").dirname   #=> "a/b/d"
IOStreams.path(".a/b/d/test.rb").dirname  #=> ".a/b/d"
IOStreams.path("foo.").dirname            #=> "."
IOStreams.path("test").dirname            #=> "."
IOStreams.path(".profile").dirname        #=> "."
# File lib/io_streams/stream.rb, line 275
def dirname
  file_name = builder.file_name
  ::File.dirname(file_name) if file_name
end
each(mode = :line, **args, &block) click to toggle source

Iterate over a file / stream returning one line at a time.

Example: Read a line at a time

IOStreams.path("file.txt").each(:line) do |line|
  puts line
end

Example: Read a line at a time with custom options

IOStreams.path("file.csv").each(:line, embedded_within: '"') do |line|
  puts line
end

Example: Read a row at a time

IOStreams.path("file.csv").each(:array) do |array|
  p array
end

Example: Read a record at a time

IOStreams.path("file.csv").each(:hash) do |hash|
  p hash
end

Notes:

  • Embedded lines (within double quotes) will be skipped if

    1. The file name contains .csv

    2. Or the embedded_within argument is set

# File lib/io_streams/stream.rb, line 93
def each(mode = :line, **args, &block)
  raise(ArgumentError, "Invalid mode: #{mode.inspect}") if mode == :stream

  #    return enum_for __method__ unless block_given?
  reader(mode, **args) { |stream| stream.each(&block) }
end
extension() click to toggle source

Returns [String] the extension for this file without the last period. Returns `nil` if no `file_name` was set.

If `path` is a dotfile, or starts with a period, then the starting dot is not considered part of the extension.

An empty string will also be returned when the period is the last character in the `path`.

IOStreams.path("test.rb").extension         #=> "rb"
IOStreams.path("a/b/d/test.rb").extension   #=> "rb"
IOStreams.path(".a/b/d/test.rb").extension  #=> "rb"
IOStreams.path("foo.").extension            #=> ""
IOStreams.path("test").extension            #=> ""
IOStreams.path(".profile").extension        #=> ""
IOStreams.path(".profile.sh").extension     #=> "sh"
# File lib/io_streams/stream.rb, line 315
def extension
  extname&.sub(/^\./, "")
end
extname() click to toggle source

Returns [String] the extension for this file including the last period. Returns `nil` if no `file_name` was set.

If `path` is a dotfile, or starts with a period, then the starting dot is not considered part of the extension.

An empty string will also be returned when the period is the last character in the `path`.

IOStreams.path("test.rb").extname         #=> ".rb"
IOStreams.path("a/b/d/test.rb").extname   #=> ".rb"
IOStreams.path(".a/b/d/test.rb").extname  #=> ".rb"
IOStreams.path("foo.").extname            #=> ""
IOStreams.path("test").extname            #=> ""
IOStreams.path(".profile").extname        #=> ""
IOStreams.path(".profile.sh").extname     #=> ".sh"
# File lib/io_streams/stream.rb, line 295
def extname
  file_name = builder.file_name
  ::File.extname(file_name) if file_name
end
file_name(file_name = :none) click to toggle source

Set/get the original file_name

# File lib/io_streams/stream.rb, line 202
def file_name(file_name = :none)
  if file_name == :none
    builder.file_name
  else
    builder.file_name = file_name
    self
  end
end
file_name=(file_name) click to toggle source

Set the original file_name

# File lib/io_streams/stream.rb, line 212
def file_name=(file_name)
  builder.file_name = file_name
end
format(format = :none) click to toggle source

Set/get the tabular format_options

# File lib/io_streams/stream.rb, line 217
def format(format = :none)
  if format == :none
    builder.format
  else
    builder.format = format
    self
  end
end
format=(format) click to toggle source

Set the tabular format

# File lib/io_streams/stream.rb, line 227
def format=(format)
  builder.format = format
end
format_options(format_options = :none) click to toggle source

Set/get the tabular format options

# File lib/io_streams/stream.rb, line 232
def format_options(format_options = :none)
  if format_options == :none
    builder.format_options
  else
    builder.format_options = format_options
    self
  end
end
format_options=(format_options) click to toggle source

Set the tabular format_options

# File lib/io_streams/stream.rb, line 242
def format_options=(format_options)
  builder.format_options = format_options
end
option(stream, **options) click to toggle source

Set the options for an element within the stream for this file. If the relevant stream is not found for this file it is ignored. For example, if the file does not have a pgp extension then the pgp option is not relevant.

IOStreams.path(“keep_safe.pgp”).option(:pgp, passphrase: “receiver_passphrase”).read

# In this case the file is not pgp so the `passphrase` option is ignored. IOStreams.path(“keep_safe.enc”).option(:pgp, passphrase: “receiver_passphrase”).read

IOStreams.path(output_file_name).option(:pgp, passphrase: “receiver_passphrase”).read

# File lib/io_streams/stream.rb, line 36
def option(stream, **options)
  builder.option(stream, **options)
  self
end
option_or_stream(stream, **options) click to toggle source

Adds the options for the specified stream as an option, but if streams have already been added it is instead added as a stream.

# File lib/io_streams/stream.rb, line 43
def option_or_stream(stream, **options)
  builder.option_or_stream(stream, **options)
  self
end
pipeline() click to toggle source

Returns [Hash<Symbol:Hash>] the pipeline of streams with their options that will be applied when the reader or writer is invoked.

# File lib/io_streams/stream.rb, line 55
def pipeline
  builder.pipeline
end
read(*args) click to toggle source

Read an entire file into memory.

Notes:

  • Use with caution since large files can cause a denial of service since this method will load the entire file into memory.

  • Recommend using instead `#reader` to read a block into memory at a time.

# File lib/io_streams/stream.rb, line 122
def read(*args)
  reader { |stream| stream.read(*args) }
end
reader(mode = :stream, **args, &block) click to toggle source

Returns a Reader for reading a file / stream

# File lib/io_streams/stream.rb, line 101
def reader(mode = :stream, **args, &block)
  case mode
  when :stream
    stream_reader(&block)
  when :line
    line_reader(**args, &block)
  when :array
    row_reader(**args, &block)
  when :hash
    record_reader(**args, &block)
  else
    raise(ArgumentError, "Invalid mode: #{mode.inspect}")
  end
end
remove_from_pipeline(stream_name) click to toggle source

Removes the named stream from the current pipeline. If the stream pipeline has not yet been built it will be built from the file_name if present. Note: Any options must be set before calling this method.

# File lib/io_streams/stream.rb, line 62
def remove_from_pipeline(stream_name)
  builder.remove_from_pipeline(stream_name)
  self
end
setting(stream) click to toggle source

Return the options already set for either a stream or option.

# File lib/io_streams/stream.rb, line 49
def setting(stream)
  builder.setting(stream)
end
stream(stream, **options) click to toggle source

Ignore the filename and use only the supplied streams.

See option to set an option for one of the streams included based on the file name extensions.

Example:

IOStreams.path(“tempfile2527”).stream(:zip).stream(:pgp, passphrase: “receiver_passphrase”).read

# File lib/io_streams/stream.rb, line 21
def stream(stream, **options)
  builder.stream(stream, **options)
  self
end
write(data) click to toggle source

Write entire string to file.

Notes:

  • Use with caution since preparing large amounts of data in memory can cause a denial of service since all the data for the file needs to be resident in memory before writing.

  • Recommend using instead `#writer` to write a block of memory at a time.

# File lib/io_streams/stream.rb, line 148
def write(data)
  writer { |stream| stream.write(data) }
end
writer(mode = :stream, **args, &block) click to toggle source

Returns a Writer for writing to a file / stream

# File lib/io_streams/stream.rb, line 127
def writer(mode = :stream, **args, &block)
  case mode
  when :stream
    stream_writer(&block)
  when :line
    line_writer(**args, &block)
  when :array
    row_writer(**args, &block)
  when :hash
    record_writer(**args, &block)
  else
    raise(ArgumentError, "Invalid mode: #{mode.inspect}")
  end
end

Private Instance Methods

builder() click to toggle source
# File lib/io_streams/stream.rb, line 321
def builder
  @builder ||= IOStreams::Builder.new
end
line_reader(embedded_within: nil, **args) { |reader(io, original_file_name: file_name, embedded_within: embedded_within, **args)| ... } click to toggle source
# File lib/io_streams/stream.rb, line 329
def line_reader(embedded_within: nil, **args)
  embedded_within = '"' if embedded_within.nil? && builder.file_name&.include?(".csv")

  stream_reader do |io|
    yield IOStreams::Line::Reader.new(io,
                                      original_file_name: builder.file_name,
                                      embedded_within:    embedded_within,
                                      **args)
  end
end
line_writer(**args, &block) click to toggle source
# File lib/io_streams/stream.rb, line 370
def line_writer(**args, &block)
  return block.call(io_stream) if io_stream&.is_a?(IOStreams::Line::Writer)

  writer do |io|
    IOStreams::Line::Writer.stream(io, original_file_name: builder.file_name, **args, &block)
  end
end
record_reader(delimiter: nil, embedded_within: nil, **args) { |reader( io, original_file_name: file_name, format: format, format_options: format_options, **args| ... } click to toggle source

Iterate over a file / stream returning each line as a hash, one at a time.

# File lib/io_streams/stream.rb, line 354
def record_reader(delimiter: nil, embedded_within: nil, **args)
  line_reader(delimiter: delimiter, embedded_within: embedded_within) do |io|
    yield IOStreams::Record::Reader.new(
      io,
      original_file_name: builder.file_name,
      format:             builder.format,
      format_options:     builder.format_options,
      **args
    )
  end
end
record_writer(delimiter: $/, **args, &block) click to toggle source
# File lib/io_streams/stream.rb, line 393
def record_writer(delimiter: $/, **args, &block)
  return block.call(io_stream) if io_stream&.is_a?(IOStreams::Record::Writer)

  line_writer(delimiter: delimiter) do |io|
    IOStreams::Record::Writer.stream(
      io,
      original_file_name: builder.file_name,
      format:             builder.format,
      format_options:     builder.format_options,
      **args,
      &block
    )
  end
end
row_reader(delimiter: nil, embedded_within: nil, **args) { |reader( io, original_file_name: file_name, format: format, format_options: format_options, **args| ... } click to toggle source

Iterate over a file / stream returning each line as an array, one at a time.

# File lib/io_streams/stream.rb, line 341
def row_reader(delimiter: nil, embedded_within: nil, **args)
  line_reader(delimiter: delimiter, embedded_within: embedded_within) do |io|
    yield IOStreams::Row::Reader.new(
      io,
      original_file_name: builder.file_name,
      format:             builder.format,
      format_options:     builder.format_options,
      **args
    )
  end
end
row_writer(delimiter: $/, **args, &block) click to toggle source
# File lib/io_streams/stream.rb, line 378
def row_writer(delimiter: $/, **args, &block)
  return block.call(io_stream) if io_stream&.is_a?(IOStreams::Row::Writer)

  line_writer(delimiter: delimiter) do |io|
    IOStreams::Row::Writer.stream(
      io,
      original_file_name: builder.file_name,
      format:             builder.format,
      format_options:     builder.format_options,
      **args,
      &block
    )
  end
end
stream_reader(&block) click to toggle source
# File lib/io_streams/stream.rb, line 325
def stream_reader(&block)
  builder.reader(io_stream, &block)
end
stream_writer(&block) click to toggle source
# File lib/io_streams/stream.rb, line 366
def stream_writer(&block)
  builder.writer(io_stream, &block)
end