down 4.2.1 → 4.3.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: 16efde61a43b30f68aa001eb0f06bdc8403d2e7c
4
- data.tar.gz: 0e56e5adc2bb0bc0387f7198af7b0063ab577aef
3
+ metadata.gz: 4fe68b913e3b94078cfc74c7599ef57cab7d4ac2
4
+ data.tar.gz: f2cc86395be9ee08f188bd40d90cac2b9ae0ab59
5
5
  SHA512:
6
- metadata.gz: b2f9108523aea427699de88ffc65f8e6d114d75850317f07bce6c3c7019e7f5add1b52ee660e57c109b526d1a8ea42f81c0944564c17ba6f6b18d537f51f4a69
7
- data.tar.gz: 535dbb6812caba261e692ec713bf25df4aa57ec97027a1b74474aef060b2c9c182267a0d8008210e760d66826e7c978b898efdf4dc0d66355507c39755d84944
6
+ metadata.gz: 6a28ee64408befa22c4fb0eb51a5863daaa83555bb4dc5a72c3ee536cb32a2aaa0781cf163284144cdf42c179fdf0f3530bf5c5e804b18e6ff2dea2ab3e48fb6
7
+ data.tar.gz: 45d8928e426182b463dee00daa5956e0a828a547e672b7e611cf135e333da696aa19fdf7f29eff45ce46580918c48c1720c1f5727d4d8bf01e534b2aa4d9f093
@@ -1,3 +1,13 @@
1
+ ## 4.3.0 (2018-03-11)
2
+
3
+ * Accept CLI arguments as a list of symbols in `Down::Wget#download` (@janko-m)
4
+
5
+ * Avoid potential URL parsing errors in `Down::Http::DownloadedFile#filename_from_url` (@janko-m)
6
+
7
+ * Make memory usage of `Down::Wget#download` constant (@janko-m)
8
+
9
+ * Add `:destination` option to `Down.download` for specifying download destination (@janko-m)
10
+
1
11
  ## 4.2.1 (2018-01-29)
2
12
 
3
13
  * Reduce memory allocation in `Down::ChunkedIO` by 10x when buffer string is used (@janko-m)
data/README.md CHANGED
@@ -41,7 +41,7 @@ Down allows you to pass a `:max_size` option:
41
41
 
42
42
  ```rb
43
43
  Down.download("http://example.com/image.jpg", max_size: 5 * 1024 * 1024) # 5 MB
44
- # raises Down::TooLarge
44
+ # !~> Down::TooLarge
45
45
  ```
46
46
 
47
47
  What is the advantage over simply checking size after downloading? Well, Down
@@ -49,6 +49,17 @@ terminates the download very early, as soon as it gets the `Content-Length`
49
49
  header. And if the `Content-Length` header is missing, Down will terminate the
50
50
  download as soon as the downloaded content surpasses the maximum size.
51
51
 
52
+ ### Destination
53
+
54
+ By default the remote file will be downloaded into a temporary location and
55
+ returned as a `Tempfile`. If you would like the file to be downloaded to a
56
+ specific location on disk, you can specify the `:destination` option:
57
+
58
+ ```rb
59
+ Down.download("http://example.com/image.jpg", destination: "/path/to/destination")
60
+ #=> nil
61
+ ```
62
+
52
63
  ### Basic authentication
53
64
 
54
65
  `Down.download` and `Down.open` will automatically detect and apply HTTP basic
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
6
6
 
7
7
  spec.required_ruby_version = ">= 2.1"
8
8
 
9
- spec.summary = "Robust streaming downloads using net/http."
9
+ spec.summary = "Robust streaming downloads using Net::HTTP, HTTP.rb or wget."
10
10
  spec.homepage = "https://github.com/janko-m/down"
11
11
  spec.authors = ["Janko Marohnić"]
12
12
  spec.email = ["janko.marohnic@gmail.com"]
@@ -4,6 +4,8 @@ require "down/version"
4
4
  require "down/chunked_io"
5
5
  require "down/errors"
6
6
 
7
+ require "fileutils"
8
+
7
9
  module Down
8
10
  class Backend
9
11
  def self.download(*args, &block)
@@ -13,5 +15,17 @@ module Down
13
15
  def self.open(*args, &block)
14
16
  new.open(*args, &block)
15
17
  end
18
+
19
+ private
20
+
21
+ def download_result(tempfile, destination)
22
+ if destination
23
+ tempfile.close
24
+ FileUtils.mv tempfile.path, destination
25
+ nil
26
+ else
27
+ tempfile
28
+ end
29
+ end
16
30
  end
17
31
  end
@@ -276,8 +276,8 @@ module Down
276
276
 
277
277
  # Creates a Fiber wrapper around the underlying enumerator. The advantage
278
278
  # of using a Fiber here is that we can terminate the chunk retrieval, in a
279
- # way that executes any cleanup code that the enumerator carries. At the
280
- # end of iteration the :on_close callback is executed if one was specified.
279
+ # way that executes any cleanup code that the enumerator potentially
280
+ # carries. At the end of iteration the :on_close callback is executed.
281
281
  def chunks_fiber
282
282
  @chunks_fiber ||= Fiber.new do
283
283
  begin
@@ -19,7 +19,7 @@ module Down
19
19
  @options = { headers: { "User-Agent" => "Down/#{Down::VERSION}" }, follow: { max_hops: 2 } }.merge(options)
20
20
  end
21
21
 
22
- def download(url, max_size: nil, progress_proc: nil, content_length_proc: nil, **options, &block)
22
+ def download(url, max_size: nil, progress_proc: nil, content_length_proc: nil, destination: nil, **options, &block)
23
23
  io = open(url, **options, rewindable: false, &block)
24
24
 
25
25
  content_length_proc.call(io.size) if content_length_proc && io.size
@@ -32,7 +32,9 @@ module Down
32
32
  tempfile = Tempfile.new(["down-http", extname], binmode: true)
33
33
 
34
34
  until io.eof?
35
- tempfile.write(io.readpartial(nil, buffer ||= String.new))
35
+ chunk = io.readpartial(nil, buffer ||= String.new)
36
+
37
+ tempfile.write(chunk)
36
38
 
37
39
  progress_proc.call(tempfile.size) if progress_proc
38
40
 
@@ -47,7 +49,7 @@ module Down
47
49
  tempfile.url = io.data[:response].uri.to_s
48
50
  tempfile.headers = io.data[:headers]
49
51
 
50
- tempfile
52
+ download_result(tempfile, destination)
51
53
  rescue
52
54
  tempfile.close! if tempfile
53
55
  raise
@@ -152,7 +154,7 @@ module Down
152
154
  private
153
155
 
154
156
  def content_type_header
155
- ::HTTP::ContentType.parse(headers["Content-Type"])
157
+ HTTP::ContentType.parse(headers["Content-Type"])
156
158
  end
157
159
 
158
160
  def filename_from_content_disposition
@@ -163,7 +165,7 @@ module Down
163
165
  end
164
166
 
165
167
  def filename_from_url
166
- path = URI(url).path
168
+ path = HTTP::URI.parse(url).path
167
169
  filename = path.split("/").last
168
170
  CGI.unescape(filename) if filename
169
171
  end
@@ -22,6 +22,7 @@ module Down
22
22
  max_redirects = options.delete(:max_redirects)
23
23
  progress_proc = options.delete(:progress_proc)
24
24
  content_length_proc = options.delete(:content_length_proc)
25
+ destination = options.delete(:destination)
25
26
 
26
27
  open_uri_options = {
27
28
  content_length_proc: proc { |size|
@@ -70,7 +71,7 @@ module Down
70
71
  OpenURI::Meta.init tempfile, open_uri_file # add back open-uri methods
71
72
  tempfile.extend Down::NetHttp::DownloadedFile
72
73
 
73
- tempfile
74
+ download_result(tempfile, destination)
74
75
  end
75
76
 
76
77
  def open(url, options = {})
@@ -1,5 +1,5 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Down
4
- VERSION = "4.2.1"
4
+ VERSION = "4.3.0"
5
5
  end
@@ -19,8 +19,8 @@ module Down
19
19
  @arguments = [max_redirect: 2, user_agent: "Down/#{Down::VERSION}"] + arguments
20
20
  end
21
21
 
22
- def download(url, *args, max_size: nil, content_length_proc: nil, progress_proc: nil, **options)
23
- io = open(url, **options, rewindable: false)
22
+ def download(url, *args, max_size: nil, content_length_proc: nil, progress_proc: nil, destination: nil, **options)
23
+ io = open(url, *args, **options, rewindable: false)
24
24
 
25
25
  content_length_proc.call(io.size) if content_length_proc && io.size
26
26
 
@@ -32,7 +32,9 @@ module Down
32
32
  tempfile = Tempfile.new(["down-wget", extname], binmode: true)
33
33
 
34
34
  until io.eof?
35
- tempfile.write(io.readpartial)
35
+ chunk = io.readpartial(nil, buffer ||= String.new)
36
+
37
+ tempfile.write(chunk)
36
38
 
37
39
  progress_proc.call(tempfile.size) if progress_proc
38
40
 
@@ -47,7 +49,7 @@ module Down
47
49
  tempfile.url = url
48
50
  tempfile.headers = io.data[:headers]
49
51
 
50
- tempfile
52
+ download_result(tempfile, destination)
51
53
  rescue
52
54
  tempfile.close! if tempfile
53
55
  raise
@@ -105,10 +107,12 @@ module Down
105
107
  command = %W[wget --no-verbose --save-headers -O -]
106
108
 
107
109
  options = @arguments.grep(Hash).inject({}, :merge).merge(options)
108
- args = @arguments.grep(Symbol) + args
110
+ args = @arguments.grep(->(o){!o.is_a?(Hash)}) + args
109
111
 
110
112
  (args + options.to_a).each do |option, value|
111
- if option.length == 1
113
+ if option.is_a?(String)
114
+ command << option
115
+ elsif option.length == 1
112
116
  command << "-#{option}"
113
117
  else
114
118
  command << "--#{option.to_s.gsub("_", "-")}"
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: 4.2.1
4
+ version: 4.3.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: 2018-01-29 00:00:00.000000000 Z
11
+ date: 2018-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -150,5 +150,5 @@ rubyforge_project:
150
150
  rubygems_version: 2.6.11
151
151
  signing_key:
152
152
  specification_version: 4
153
- summary: Robust streaming downloads using net/http.
153
+ summary: Robust streaming downloads using Net::HTTP, HTTP.rb or wget.
154
154
  test_files: []