Class: Store::Digest::ReadWrapper
- Inherits:
-
Object
- Object
- Store::Digest::ReadWrapper
- Defined in:
- lib/store/digest/readwrapper.rb
Overview
This class is an attempt to normalize input so that it can be #read like an IO handle. Use the class method ReadWrapper.coerce to determine if it's even necessary.
Class Method Summary collapse
-
.coerce(obj, thunk: false) ⇒ ReadWrapper, Object
(also: [])
Attempt to coerce a suitable object or no-op.
-
.quacks?(obj) ⇒ false, true
Test if the object quacks like an IO.
Instance Method Summary collapse
-
#close ⇒ Object
closefor parity with IO. -
#gets(sep = $/, chomp = false) ⇒ String?
getsfor parity with IO. -
#initialize(obj) ⇒ ReadWrapper
constructor
Initialize a wrapper.
-
#read(maxlen = nil, string = nil) ⇒ String?
readfor parity with IO.
Constructor Details
#initialize(obj) ⇒ ReadWrapper
Initialize a wrapper.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/store/digest/readwrapper.rb', line 101 def initialize obj test = obj.respond_to?(:arity) ? obj : obj.respond_to?(:call) ? obj.method(:call) : nil if test raise ArgumentError, 'Callable object is expected to take a write handle as an argument' if test.arity == 0 elsif obj.respond_to?(:each) nil elsif obj.respond_to? :to_s obj = [obj.to_s] else raise ArgumentError, 'Argument must respond to #call(write_fh) or #each or #to_s' end @done = false @mutex = Mutex.new @read, @write = IO.pipe @thread = Thread.new do if obj.respond_to? :call obj.call @write else obj.each { |x| @write << x.to_s.b } end rescue Errno::EPIPE # => e nil # not sure if we do anything here ensure @write.close unless @write.closed? end end |
Class Method Details
.coerce(obj, thunk: false) ⇒ ReadWrapper, Object Also known as: []
Attempt to coerce a suitable object or no-op.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/store/digest/readwrapper.rb', line 65 def self.coerce obj, thunk: false return obj if [self, Store::Digest::Entry].any? { |c| obj.is_a? c } return obj.open('rb') if obj.is_a? Pathname return obj if quacks? obj # no need for this if it can read return StringIO.new(obj) if obj.is_a? String # response bodies /don't do this but other stuff does if obj.respond_to?(:arity) && obj.arity == 0 || obj.respond_to?(:call) && obj.method(:call).arity == 0 # let the thunk through return obj if thunk out = obj.call raise ArgumentError, 'a `call` with no arguments must return an IO-like object' unless quacks? out return out end new obj end |
.quacks?(obj) ⇒ false, true
Test if the object quacks like an IO.
20 21 22 23 24 |
# File 'lib/store/digest/readwrapper.rb', line 20 def self.quacks? obj obj.is_a?(IO) or %i[gets read close].all? do |m| obj.respond_to? m end end |
Instance Method Details
#close ⇒ Object
close for parity with IO
167 168 169 170 |
# File 'lib/store/digest/readwrapper.rb', line 167 def close cleanup nil # close returns nil end |
#gets(sep = $/, chomp = false) ⇒ String?
gets for parity with IO
140 141 142 143 144 145 146 147 |
# File 'lib/store/digest/readwrapper.rb', line 140 def gets sep = $/, chomp = false unless @read.closed? out = @read.gets sep, chomp cleanup if out.nil? out end end |
#read(maxlen = nil, string = nil) ⇒ String?
read for parity with IO
156 157 158 159 160 161 162 163 |
# File 'lib/store/digest/readwrapper.rb', line 156 def read maxlen = nil, string = nil unless @read.closed? out = @read.read maxlen, string cleanup if out.nil? out end end |