Class: IOStreams::Stream

Inherits:
Object
  • Object
show all
Defined in:
lib/io_streams/stream.rb

Direct Known Subclasses

Path

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io_stream) ⇒ Stream

Returns a new instance of Stream.

Raises:

  • (ArgumentError)


6
7
8
9
10
11
12
# 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

Instance Attribute Details

#builder=(value) ⇒ Object

Sets the attribute builder

Parameters:

  • value

    the value to set the attribute builder to.



4
5
6
# File 'lib/io_streams/stream.rb', line 4

def builder=(value)
  @builder = value
end

#io_streamObject (readonly)

Returns the value of attribute io_stream.



3
4
5
# File 'lib/io_streams/stream.rb', line 3

def io_stream
  @io_stream
end

Instance Method Details

#basename(suffix = nil) ⇒ Object

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"


257
258
259
260
261
262
# 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) ⇒ Object

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)



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# 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) ⇒ Object



196
197
198
199
# File 'lib/io_streams/stream.rb', line 196

def copy_to(target, **args)
  target = IOStreams.new(target)
  target.copy_from(self, **args)
end

#dirnameObject

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        #=> "."


275
276
277
278
# 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) ⇒ Object

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

Raises:

  • (ArgumentError)


93
94
95
96
97
98
# 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

#extensionObject

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"


315
316
317
# File 'lib/io_streams/stream.rb', line 315

def extension
  extname&.sub(/^\./, "")
end

#extnameObject

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"


295
296
297
298
# 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) ⇒ Object

Set/get the original file_name



202
203
204
205
206
207
208
209
# 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) ⇒ Object

Set the original file_name



212
213
214
# File 'lib/io_streams/stream.rb', line 212

def file_name=(file_name)
  builder.file_name = file_name
end

#format(format = :none) ⇒ Object

Set/get the tabular format_options



217
218
219
220
221
222
223
224
# 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) ⇒ Object

Set the tabular format



227
228
229
# File 'lib/io_streams/stream.rb', line 227

def format=(format)
  builder.format = format
end

#format_options(format_options = :none) ⇒ Object

Set/get the tabular format options



232
233
234
235
236
237
238
239
# 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) ⇒ Object

Set the tabular format_options



242
243
244
# File 'lib/io_streams/stream.rb', line 242

def format_options=(format_options)
  builder.format_options = format_options
end

#option(stream, **options) ⇒ Object

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



36
37
38
39
# File 'lib/io_streams/stream.rb', line 36

def option(stream, **options)
  builder.option(stream, **options)
  self
end

#option_or_stream(stream, **options) ⇒ Object

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



43
44
45
46
# File 'lib/io_streams/stream.rb', line 43

def option_or_stream(stream, **options)
  builder.option_or_stream(stream, **options)
  self
end

#pipelineObject

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



55
56
57
# File 'lib/io_streams/stream.rb', line 55

def pipeline
  builder.pipeline
end

#read(*args) ⇒ Object

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.



122
123
124
# File 'lib/io_streams/stream.rb', line 122

def read(*args)
  reader { |stream| stream.read(*args) }
end

#reader(mode = :stream, **args, &block) ⇒ Object

Returns a Reader for reading a file / stream



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 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) ⇒ Object

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.



62
63
64
65
# File 'lib/io_streams/stream.rb', line 62

def remove_from_pipeline(stream_name)
  builder.remove_from_pipeline(stream_name)
  self
end

#setting(stream) ⇒ Object

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



49
50
51
# File 'lib/io_streams/stream.rb', line 49

def setting(stream)
  builder.setting(stream)
end

#stream(stream, **options) ⇒ Object

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



21
22
23
24
# File 'lib/io_streams/stream.rb', line 21

def stream(stream, **options)
  builder.stream(stream, **options)
  self
end

#write(data) ⇒ Object

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.



148
149
150
# File 'lib/io_streams/stream.rb', line 148

def write(data)
  writer { |stream| stream.write(data) }
end

#writer(mode = :stream, **args, &block) ⇒ Object

Returns a Writer for writing to a file / stream



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# 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