down 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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