down 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29dd2b9e7c612e2be576964dc0b35203d4e6b038
4
- data.tar.gz: 3f9146bd292d11b4bcd82b196b8c59a4125cff2d
3
+ metadata.gz: 813656418d3c378ea8a8731355e5b46f830cbb9e
4
+ data.tar.gz: 73e7e5125c7b4a2912672f63512fc822bddb552d
5
5
  SHA512:
6
- metadata.gz: 5dba71a205bb2f2e0353774e8801cf8692e1c0e5605bdb62810f9bd1ea16bc0076e8d17f2edaa7986ad019675a723c91b693bd8c8f9f19a8637f6aa2630ad040
7
- data.tar.gz: d1d810b2defabd1a460dcd614e65d578b9c27f2ac6008efb5fd3d56c3a080cb12d721a4196383b9eb1349c7939cce9ff07716692a6c803f13eb095d136fd9aa4
6
+ metadata.gz: f6a6427ffec868c38a689f0d992af7d6187234cfbdd9c63c94ebeb9192174880742eb58c2f7a7d4faed90c86b9a731a369dbadaa5fc37280cb8ef41b64dbeb90
7
+ data.tar.gz: 615d0c7c046727e07bc0e67b82906d7f5ca508fde7eb6b1f38b9ff6f3db787ab0eea4c055acc4584651a669aca38714a8a41f1320064e10c8ed0f559ebfce52f
data/README.md CHANGED
@@ -285,7 +285,7 @@ Down::NetHttp.open("http://example.com/image.jpg", {"Authorization" => "..."})
285
285
  ### HTTP.rb
286
286
 
287
287
  ```rb
288
- gem "down", "~> 3.0"
288
+ gem "down", ">= 3.0"
289
289
  gem "http", "~> 2.1"
290
290
  ```
291
291
  ```rb
@@ -7,38 +7,37 @@ module Down
7
7
  class ChunkedIO
8
8
  attr_accessor :size, :data, :encoding
9
9
 
10
- def initialize(chunks:, size: nil, on_close: ->{}, data: {}, rewindable: true, encoding: Encoding::BINARY)
11
- @chunks = chunks
12
- @size = size
13
- @on_close = on_close
14
- @data = data
15
- @encoding = find_encoding(encoding)
16
-
17
- @buffer = String.new("").force_encoding(@encoding)
18
- @tempfile = Tempfile.new("down-chunked_io", binmode: true) if rewindable
10
+ def initialize(chunks:, size: nil, on_close: nil, data: {}, rewindable: true, encoding: nil)
11
+ @chunks = chunks
12
+ @size = size
13
+ @on_close = on_close
14
+ @data = data
15
+ @encoding = find_encoding(encoding || Encoding::BINARY)
16
+ @rewindable = rewindable
17
+ @buffer = nil
19
18
 
20
19
  retrieve_chunk
21
20
  end
22
21
 
23
22
  def each_chunk
24
- raise IOError, "closed stream" if @closed
23
+ raise IOError, "closed stream" if closed?
25
24
 
26
25
  return enum_for(__method__) if !block_given?
27
26
  yield retrieve_chunk until chunks_depleted?
28
27
  end
29
28
 
30
29
  def read(length = nil, outbuf = nil)
31
- raise IOError, "closed stream" if @closed
30
+ raise IOError, "closed stream" if closed?
32
31
 
33
32
  outbuf = outbuf.to_s.replace("").force_encoding(@encoding)
34
33
 
35
- if @tempfile && !@tempfile.eof?
36
- @tempfile.read(length, outbuf)
34
+ if cache && !cache.eof?
35
+ cache.read(length, outbuf)
37
36
  outbuf.force_encoding(@encoding)
38
37
  end
39
38
 
40
- until outbuf.bytesize == length || chunks_depleted?
41
- @buffer << retrieve_chunk if @buffer.empty?
39
+ until outbuf.bytesize == length || (@buffer.nil? && chunks_depleted?)
40
+ @buffer = retrieve_chunk if @buffer.nil?
42
41
 
43
42
  buffered_data = if length && length - outbuf.bytesize < @buffer.bytesize
44
43
  @buffer.byteslice(0, length - outbuf.bytesize)
@@ -46,45 +45,87 @@ module Down
46
45
  @buffer
47
46
  end
48
47
 
49
- @tempfile.write(buffered_data) if @tempfile
50
-
51
48
  outbuf << buffered_data
52
49
 
50
+ cache.write(buffered_data) if cache
51
+
53
52
  if buffered_data.bytesize < @buffer.bytesize
54
- @buffer.replace @buffer.byteslice(buffered_data.bytesize..-1)
53
+ @buffer = @buffer.byteslice(buffered_data.bytesize..-1)
55
54
  else
56
- @buffer.clear
55
+ @buffer = nil
57
56
  end
58
57
  end
59
58
 
60
- outbuf unless length && outbuf.empty?
59
+ outbuf unless outbuf.empty? && length
60
+ end
61
+
62
+ def readpartial(maxlen = nil, outbuf = nil)
63
+ raise IOError, "closed stream" if closed?
64
+
65
+ available_length = 0
66
+ available_length += cache.size - cache.pos if cache
67
+ available_length += @buffer.bytesize if @buffer
68
+
69
+ if available_length > 0
70
+ read([available_length, *maxlen].min, outbuf)
71
+ elsif !chunks_depleted?
72
+ read([@next_chunk.bytesize, *maxlen].min, outbuf)
73
+ else
74
+ outbuf.replace("").force_encoding(@encoding) if outbuf
75
+ raise EOFError, "end of file reached"
76
+ end
61
77
  end
62
78
 
63
79
  def eof?
64
- raise IOError, "closed stream" if @closed
80
+ raise IOError, "closed stream" if closed?
65
81
 
66
- return false if @tempfile && !@tempfile.eof?
67
- @buffer.empty? && chunks_depleted?
82
+ return false if cache && !cache.eof?
83
+ @buffer.nil? && chunks_depleted?
68
84
  end
69
85
 
70
86
  def rewind
71
- raise IOError, "closed stream" if @closed
72
- raise IOError, "this Down::ChunkedIO is not rewindable" if !@tempfile
87
+ raise IOError, "closed stream" if closed?
88
+ raise IOError, "this Down::ChunkedIO is not rewindable" if cache.nil?
73
89
 
74
- @tempfile.rewind
90
+ cache.rewind
75
91
  end
76
92
 
77
93
  def close
78
94
  return if @closed
79
95
 
80
96
  chunks_fiber.resume(:terminate) if chunks_fiber.alive?
81
- @buffer.clear
82
- @tempfile.close! if @tempfile
97
+ @buffer = nil
98
+ cache.close! if cache
83
99
  @closed = true
84
100
  end
85
101
 
102
+ def closed?
103
+ !!@closed
104
+ end
105
+
106
+ def rewindable?
107
+ @rewindable
108
+ end
109
+
110
+ def inspect
111
+ string = String.new
112
+ string << "#<Down::ChunkedIO"
113
+ string << " chunks=#{@chunks.inspect}"
114
+ string << " size=#{size.inspect}"
115
+ string << " encoding=#{encoding.inspect}"
116
+ string << " data=#{data.inspect}"
117
+ string << " on_close=#{@on_close.inspect}"
118
+ string << " rewindable=#{@rewindable.inspect}"
119
+ string << " (closed)" if closed?
120
+ string << ">"
121
+ end
122
+
86
123
  private
87
124
 
125
+ def cache
126
+ @cache ||= Tempfile.new("down-chunked_io", binmode: true) if @rewindable
127
+ end
128
+
88
129
  def retrieve_chunk
89
130
  chunk = @next_chunk
90
131
  @next_chunk = chunks_fiber.resume
@@ -103,7 +144,7 @@ module Down
103
144
  break if action == :terminate
104
145
  end
105
146
  ensure
106
- @on_close.call
147
+ @on_close.call if @on_close
107
148
  end
108
149
  end
109
150
  end
@@ -62,9 +62,7 @@ module Down
62
62
  io.close if io
63
63
  end
64
64
 
65
- def open(url, **options, &block)
66
- rewindable = options.delete(:rewindable)
67
-
65
+ def open(url, rewindable: true, **options, &block)
68
66
  begin
69
67
  response = get(url, **options, &block)
70
68
  response_error!(response) if !response.status.success?
@@ -72,16 +70,14 @@ module Down
72
70
  request_error!(exception)
73
71
  end
74
72
 
75
- down_options = {
76
- chunks: response.body.enum_for(:each),
77
- size: response.content_length,
78
- data: { status: response.code, headers: response.headers.to_h, response: response },
79
- }
80
- down_options[:encoding] = response.content_type.charset if response.content_type.charset
81
- down_options[:on_close] = -> { response.connection.close } unless client.persistent?
82
- down_options[:rewindable] = rewindable if rewindable != nil
83
-
84
- Down::ChunkedIO.new(down_options)
73
+ Down::ChunkedIO.new(
74
+ chunks: response.body.enum_for(:each),
75
+ size: response.content_length,
76
+ encoding: response.content_type.charset,
77
+ rewindable: rewindable,
78
+ on_close: (-> { response.connection.close } unless client.persistent?),
79
+ data: { status: response.code, headers: response.headers.to_h, response: response },
80
+ )
85
81
  end
86
82
 
87
83
  def get(url, **options, &block)
@@ -180,23 +180,21 @@ module Down
180
180
  request_error!(exception)
181
181
  end
182
182
 
183
- down_params = {
184
- chunks: response.enum_for(:read_body),
185
- size: response["Content-Length"] && response["Content-Length"].to_i,
186
- on_close: -> { request.resume }, # close HTTP connnection
183
+ Down::ChunkedIO.new(
184
+ chunks: response.enum_for(:read_body),
185
+ size: response["Content-Length"] && response["Content-Length"].to_i,
186
+ encoding: response.type_params["charset"],
187
+ rewindable: options.fetch(:rewindable, true),
188
+ on_close: -> { request.resume }, # close HTTP connnection
187
189
  data: {
188
- status: response.code.to_i,
189
- headers: response.each_header.inject({}) { |headers, (downcased_name, value)|
190
- name = downcased_name.split("-").map(&:capitalize).join("-")
191
- headers.merge!(name => value)
192
- },
190
+ status: response.code.to_i,
191
+ headers: response.each_header.inject({}) { |headers, (downcased_name, value)|
192
+ name = downcased_name.split("-").map(&:capitalize).join("-")
193
+ headers.merge!(name => value)
194
+ },
193
195
  response: response,
194
- }
195
- }
196
- down_params[:rewindable] = options[:rewindable] if options.key?(:rewindable)
197
- down_params[:encoding] = response.type_params["charset"] if response.type_params["charset"]
198
-
199
- Down::ChunkedIO.new(down_params)
196
+ },
197
+ )
200
198
  end
201
199
 
202
200
  def copy_to_tempfile(basename, io)
@@ -1,3 +1,3 @@
1
1
  module Down
2
- VERSION = "3.1.0"
2
+ VERSION = "3.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: down
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-16 00:00:00.000000000 Z
11
+ date: 2017-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest