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"


249
250
251
252
253
254
# File 'lib/io_streams/stream.rb', line 249

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)



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/io_streams/stream.rb', line 168

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



188
189
190
191
# File 'lib/io_streams/stream.rb', line 188

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


267
268
269
270
# File 'lib/io_streams/stream.rb', line 267

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)


85
86
87
88
89
90
# File 'lib/io_streams/stream.rb', line 85

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"


307
308
309
# File 'lib/io_streams/stream.rb', line 307

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"


287
288
289
290
# File 'lib/io_streams/stream.rb', line 287

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



194
195
196
197
198
199
200
201
# File 'lib/io_streams/stream.rb', line 194

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



204
205
206
# File 'lib/io_streams/stream.rb', line 204

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

#format(format = :none) ⇒ Object

Set/get the tabular format_options



209
210
211
212
213
214
215
216
# File 'lib/io_streams/stream.rb', line 209

def format(format = :none)
  if format == :none
    builder.format
  else
    builder.format = format
    self
  end
end

#format=(format) ⇒ Object

Set the tabular format



219
220
221
# File 'lib/io_streams/stream.rb', line 219

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

#format_options(format_options = :none) ⇒ Object

Set/get the tabular format options



224
225
226
227
228
229
230
231
# File 'lib/io_streams/stream.rb', line 224

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



234
235
236
# File 'lib/io_streams/stream.rb', line 234

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.



114
115
116
# File 'lib/io_streams/stream.rb', line 114

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

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

Returns a Reader for reading a file / stream



93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/io_streams/stream.rb', line 93

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

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



140
141
142
# File 'lib/io_streams/stream.rb', line 140

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

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

Returns a Writer for writing to a file / stream



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/io_streams/stream.rb', line 119

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