Class: IOStreams::Stream
- Inherits:
-
Object
- Object
- IOStreams::Stream
- Defined in:
- lib/io_streams/stream.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#builder ⇒ Object
writeonly
Sets the attribute builder.
-
#io_stream ⇒ Object
readonly
Returns the value of attribute io_stream.
Instance Method Summary collapse
-
#basename(suffix = nil) ⇒ Object
Returns [String] the last component of this path.
-
#copy_from(source, convert: true, mode: nil, **args) ⇒ Object
Copy from another stream, path, file_name or IO instance.
- #copy_to(target, **args) ⇒ Object
-
#dirname ⇒ Object
Returns [String] the directory for this file.
-
#each(mode = :line, **args, &block) ⇒ Object
Iterate over a file / stream returning one line at a time.
-
#extension ⇒ Object
Returns [String] the extension for this file without the last period.
-
#extname ⇒ Object
Returns [String] the extension for this file including the last period.
-
#file_name(file_name = :none) ⇒ Object
Set/get the original file_name.
-
#file_name=(file_name) ⇒ Object
Set the original file_name.
-
#format(format = :none) ⇒ Object
Set/get the tabular format_options.
-
#format=(format) ⇒ Object
Set the tabular format.
-
#format_options(format_options = :none) ⇒ Object
Set/get the tabular format options.
-
#format_options=(format_options) ⇒ Object
Set the tabular format_options.
-
#initialize(io_stream) ⇒ Stream
constructor
A new instance of Stream.
-
#option(stream) ⇒ Object
Set the options for an element within the stream for this file.
-
#option_or_stream(stream) ⇒ 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.
-
#pipeline ⇒ Object
Returns [Hash<Symbol:Hash>] the pipeline of streams with their options that will be applied when the reader or writer is invoked.
-
#read(*args) ⇒ Object
Read an entire file into memory.
-
#reader(mode = :stream, **args) ⇒ Object
Returns a Reader for reading a file / stream.
-
#remove_from_pipeline(stream_name) ⇒ Object
Removes the named stream from the current pipeline.
-
#setting(stream) ⇒ Object
Return the options already set for either a stream or option.
-
#stream(stream) ⇒ Object
Ignore the filename and use only the supplied streams.
-
#write(data) ⇒ Object
Write entire string to file.
-
#writer(mode = :stream, **args) ⇒ Object
Returns a Writer for writing to a file / stream.
Constructor Details
#initialize(io_stream) ⇒ Stream
Returns a new instance of Stream.
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
4 5 6 |
# File 'lib/io_streams/stream.rb', line 4 def builder=(value) @builder = value end |
#io_stream ⇒ Object (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"
262 263 264 265 266 267 |
# File 'lib/io_streams/stream.rb', line 262 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(:encode, encoding: “BINARY”) IOStreams.path(“target_file.pgp”).option(:pgp, passphrase: “hello”).copy_from(source)
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/io_streams/stream.rb', line 181 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
201 202 203 204 |
# File 'lib/io_streams/stream.rb', line 201 def copy_to(target, **args) target = IOStreams.new(target) target.copy_from(self, **args) end |
#dirname ⇒ Object
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 #=> "."
280 281 282 283 |
# File 'lib/io_streams/stream.rb', line 280 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
-
The file name contains .csv
-
Or the embedded_within argument is set
-
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/io_streams/stream.rb', line 93 def each(mode = :line, **args, &block) raise(ArgumentError, "Invalid mode: #{mode.inspect}") if mode == :stream # Deliberately not returning an Enumerator when no block is given. # The stream pipeline manages resources via block scope: every stream is opened with an # `ensure` that closes the file handle, reaps the gpg subprocess, deletes temp files, etc. # A Fiber-backed Enumerator (e.g. `to_enum(__method__, mode, **args)`) would leave that block # suspended; if the caller abandons a partially-consumed enumerator, none of the cleanup runs # until GC collects the Fiber, leaking file descriptors, gpg processes, and temp files. reader(mode, **args) { |stream| stream.each(&block) } end |
#extension ⇒ Object
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"
320 321 322 |
# File 'lib/io_streams/stream.rb', line 320 def extension extname&.sub(/^\./, "") end |
#extname ⇒ Object
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"
300 301 302 303 |
# File 'lib/io_streams/stream.rb', line 300 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
207 208 209 210 211 212 213 214 |
# File 'lib/io_streams/stream.rb', line 207 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
217 218 219 |
# File 'lib/io_streams/stream.rb', line 217 def file_name=(file_name) builder.file_name = file_name end |
#format(format = :none) ⇒ Object
Set/get the tabular format_options
222 223 224 225 226 227 228 229 |
# File 'lib/io_streams/stream.rb', line 222 def format(format = :none) if format == :none builder.format else builder.format = format self end end |
#format=(format) ⇒ Object
Set the tabular format
232 233 234 |
# File 'lib/io_streams/stream.rb', line 232 def format=(format) builder.format = format end |
#format_options(format_options = :none) ⇒ Object
Set/get the tabular format options
237 238 239 240 241 242 243 244 |
# File 'lib/io_streams/stream.rb', line 237 def ( = :none) if == :none builder. else builder. = self end end |
#format_options=(format_options) ⇒ Object
Set the tabular format_options
247 248 249 |
# File 'lib/io_streams/stream.rb', line 247 def () builder. = end |
#option(stream) ⇒ 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, **) builder.option(stream, **) self end |
#option_or_stream(stream) ⇒ 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, **) builder.option_or_stream(stream, **) self end |
#pipeline ⇒ Object
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.
127 128 129 |
# File 'lib/io_streams/stream.rb', line 127 def read(*args) reader { |stream| stream.read(*args) } end |
#reader(mode = :stream, **args) ⇒ Object
Returns a Reader for reading a file / stream
106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/io_streams/stream.rb', line 106 def reader(mode = :stream, **args, &) case mode when :stream stream_reader(&) when :line line_reader(**args, &) when :array row_reader(**args, &) when :hash record_reader(**args, &) 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) ⇒ 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, **) builder.stream(stream, **) 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.
153 154 155 |
# File 'lib/io_streams/stream.rb', line 153 def write(data) writer { |stream| stream.write(data) } end |
#writer(mode = :stream, **args) ⇒ Object
Returns a Writer for writing to a file / stream
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/io_streams/stream.rb', line 132 def writer(mode = :stream, **args, &) case mode when :stream stream_writer(&) when :line line_writer(**args, &) when :array row_writer(**args, &) when :hash record_writer(**args, &) else raise(ArgumentError, "Invalid mode: #{mode.inspect}") end end |