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"


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

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

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)



165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/io_streams/stream.rb', line 165

def copy_from(source, convert: true)
  if convert
    stream = IOStreams.new(source)
    writer do |target|
      stream.reader { |src| IO.copy_stream(src, target) }
    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, convert: true) ⇒ Object



179
180
181
182
# File 'lib/io_streams/stream.rb', line 179

def copy_to(target, convert: true)
  target = IOStreams.path(target) unless target.is_a?(Stream)
  target.copy_from(self, convert: convert)
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        #=> "."


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

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"


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

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"


248
249
250
251
# File 'lib/io_streams/stream.rb', line 248

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



185
186
187
188
189
190
191
192
# File 'lib/io_streams/stream.rb', line 185

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/get the original file_name



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

def file_name=(file_name)
  builder.file_name = file_name
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’).reader(&: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’).reader(&:read)

IOStreams.path(output_file_name).option(:pgp, passphrase: ‘receiver_passphrase’).reader(&: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’).reader(&: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