cloudapp 1.0.2 → 1.1.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.
data/man/cloudapp.1.html CHANGED
@@ -86,7 +86,8 @@
86
86
  <p><code>cloudapp</code> [<code>--format</code>=<var>format</var>] <var>command</var> [<var>args</var>]<br />
87
87
  <code>cloudapp list</code> [<code>--count</code>=<var>count</var>]<br />
88
88
  <code>cloudapp bookmark</code> [<code>--private</code>] [<code>--public</code>] <var>url</var> [<var>url</var>...]<br />
89
- <code>cloudapp upload</code> [<code>--private</code>] [<code>--public</code>] <var>file</var> [<var>file</var>...]</p>
89
+ <code>cloudapp upload</code> [<code>--private</code>] [<code>--public</code>] <var>file</var> [<var>file</var>...]<br />
90
+ <code>cloudapp download</code> [<code>--output</code>=<var>file</var>] <var>url</var></p>
90
91
 
91
92
  <h2 id="DESCRIPTION">DESCRIPTION</h2>
92
93
 
@@ -105,8 +106,9 @@ output to a terminal and <strong>csv</strong> when output is piped to another pr
105
106
  <h2 id="COMMANDS">COMMANDS</h2>
106
107
 
107
108
  <dl>
108
- <dt><code>list</code> [<code>--count</code>=<var>count</var>]</dt><dd><p>List the most recent <var>count</var> drops. The default is to list <strong>20</strong> drops.</p></dd>
109
109
  <dt><code>bookmark</code> [<code>--private</code>] [<code>--public</code>] [<var>url</var>...]</dt><dd><p>Create a new bookmark to each <var>url</var> and print each link.</p></dd>
110
+ <dt><code>download</code> [<code>--output</code>=<var>file</var>] <var>url</var></dt><dd><p>Download the file at <var>url</var> to the current directory or to <var>file</var> if present.</p></dd>
111
+ <dt><code>list</code> [<code>--count</code>=<var>count</var>]</dt><dd><p>List the most recent <var>count</var> drops. The default is to list <strong>20</strong> drops.</p></dd>
110
112
  <dt><code>upload</code> [<code>--private</code>] [<code>--public</code>] <var>file</var> [<var>file</var>...]</dt><dd><p>Upload each <var>file</var> and print each link.</p></dd>
111
113
  </dl>
112
114
 
@@ -114,9 +116,11 @@ output to a terminal and <strong>csv</strong> when output is piped to another pr
114
116
  <h2 id="COMMAND-OPTIONS">COMMAND OPTIONS</h2>
115
117
 
116
118
  <dl>
119
+ <dt><code>-n</code> <var>count</var>, <code>--count</code>=<var>count</var></dt><dd><p>Display <var>count</var> drops. (Default: <strong>20</strong>)</p></dd>
120
+ <dt><code>-o</code> <var>file</var>, <code>--output</code>=<var>file</var></dt><dd><p>Download file as <var>file</var>. (Default: current directory using the remote file's
121
+ name)</p></dd>
117
122
  <dt><code>--private</code></dt><dd><p>Use a private (long) link when creating a new drop.</p></dd>
118
123
  <dt><code>--public</code></dt><dd><p>Use a public (short) link when creating a new drop.</p></dd>
119
- <dt><code>-n</code> <var>count</var>, <code>--count</code>=<var>count</var></dt><dd><p>Display <var>count</var> drops. (Default: <strong>20</strong>)</p></dd>
120
124
  </dl>
121
125
 
122
126
 
@@ -161,13 +165,13 @@ Cover.jpeg,http://cl.ly/1x20...,1
161
165
  Chapter 1.md,http://cl.ly/3U3d...,7
162
166
  </code></pre>
163
167
 
164
- <p>Share a new bookmark to "http://douglasadams.com":</p>
168
+ <p>Share a new bookmark to <strong>http://douglasadams.com</strong>:</p>
165
169
 
166
170
  <pre><code>$ cloudapp bookmark http://douglasadams.com
167
171
  Bookmarking http://douglasadams.com... http://cl.ly/1y0j403g3D0c0X1G0R3m
168
172
  </code></pre>
169
173
 
170
- <p>Share the file "screenshot.png":</p>
174
+ <p>Share the file <strong>screenshot.png</strong>:</p>
171
175
 
172
176
  <pre><code>$ cloudapp upload screenshot.png
173
177
  Uploading screenshot.png... http://cl.ly/040u2o3X1w0z1z3n2T04
@@ -185,6 +189,18 @@ $ cloudapp upload screenshot.png | pbcopy
185
189
  http://cl.ly/1y0j403g3D0c0X1G0R3m
186
190
  </code></pre>
187
191
 
192
+ <p>Download a drop to the current direcctory:</p>
193
+
194
+ <pre><code>$ cloudapp download http://cl.ly/040u2o3X1w0z1z3n2T04
195
+ Downloading screenshot.png... done
196
+ </code></pre>
197
+
198
+ <p>Download a drop to another path:</p>
199
+
200
+ <pre><code>$ cloudapp download --output=/Users/Larry/image.png http://cl.ly/040u2o3X1w0z1z3n2T04
201
+ Downloading screenshot.png to /Users/Larry... done
202
+ </code></pre>
203
+
188
204
  <h2 id="LICENSE">LICENSE</h2>
189
205
 
190
206
  <p><code>cloudapp</code> is distributed under the <a href="https://github.com/cloudapp/cloudapp/blob/master/MIT-LICENSE">MIT license</a>.</p>
data/man/cloudapp.1.ronn CHANGED
@@ -6,7 +6,8 @@ cloudapp(1) -- All the pleasures of CloudApp now at your terminal
6
6
  `cloudapp` [`--format`=<format>] <command> [<args>]<br>
7
7
  `cloudapp list` [`--count`=<count>]<br>
8
8
  `cloudapp bookmark` [`--private`] [`--public`] <url> [<url>...]<br>
9
- `cloudapp upload` [`--private`] [`--public`] <file> [<file>...]
9
+ `cloudapp upload` [`--private`] [`--public`] <file> [<file>...]<br>
10
+ `cloudapp download` [`--output`=<file>] <url>
10
11
 
11
12
  ## DESCRIPTION
12
13
 
@@ -22,26 +23,33 @@ terminal and other times it's the only tool available.
22
23
 
23
24
  ## COMMANDS
24
25
 
25
- * `list` [`--count`=<count>]:
26
- List the most recent <count> drops. The default is to list **20** drops.
27
-
28
26
  * `bookmark` [`--private`] [`--public`] [<url>...]:
29
27
  Create a new bookmark to each <url> and print each link.
30
28
 
29
+ * `download` [`--output`=<file>] <url>:
30
+ Download the file at <url> to the current directory or to <file> if present.
31
+
32
+ * `list` [`--count`=<count>]:
33
+ List the most recent <count> drops. The default is to list **20** drops.
34
+
31
35
  * `upload` [`--private`] [`--public`] <file> [<file>...]:
32
36
  Upload each <file> and print each link.
33
37
 
34
38
  ## COMMAND OPTIONS
35
39
 
40
+ * `-n` <count>, `--count`=<count>:
41
+ Display <count> drops. (Default: **20**)
42
+
43
+ * `-o` <file>, `--output`=<file>:
44
+ Download file as <file>. (Default: current directory using the remote file's
45
+ name)
46
+
36
47
  * `--private`:
37
48
  Use a private (long) link when creating a new drop.
38
49
 
39
50
  * `--public`:
40
51
  Use a public (short) link when creating a new drop.
41
52
 
42
- * `-n` <count>, `--count`=<count>:
43
- Display <count> drops. (Default: **20**)
44
-
45
53
  ## REQUIREMENTS
46
54
 
47
55
  `cloudapp` requires Ruby 1.9.2 or greater.
@@ -80,12 +88,12 @@ List newest 5 drops in CSV format:
80
88
  Cover.jpeg,http://cl.ly/1x20...,1
81
89
  Chapter 1.md,http://cl.ly/3U3d...,7
82
90
 
83
- Share a new bookmark to "http://douglasadams.com":
91
+ Share a new bookmark to **http://douglasadams.com**:
84
92
 
85
93
  $ cloudapp bookmark http://douglasadams.com
86
94
  Bookmarking http://douglasadams.com... http://cl.ly/1y0j403g3D0c0X1G0R3m
87
95
 
88
- Share the file "screenshot.png":
96
+ Share the file **screenshot.png**:
89
97
 
90
98
  $ cloudapp upload screenshot.png
91
99
  Uploading screenshot.png... http://cl.ly/040u2o3X1w0z1z3n2T04
@@ -100,6 +108,16 @@ Share a new bookmark and output only the URL:
100
108
  $ cloudapp --format=csv bookmark http://douglasadams.com
101
109
  http://cl.ly/1y0j403g3D0c0X1G0R3m
102
110
 
111
+ Download a drop to the current direcctory:
112
+
113
+ $ cloudapp download http://cl.ly/040u2o3X1w0z1z3n2T04
114
+ Downloading screenshot.png... done
115
+
116
+ Download a drop to another path:
117
+
118
+ $ cloudapp download --output=/Users/Larry/image.png http://cl.ly/040u2o3X1w0z1z3n2T04
119
+ Downloading screenshot.png to /Users/Larry... done
120
+
103
121
 
104
122
  ## LICENSE
105
123
 
@@ -0,0 +1,116 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://cl.ly/C23W/drop_presenter.rb
6
+ body: ''
7
+ headers:
8
+ Accept:
9
+ - application/json
10
+ response:
11
+ status:
12
+ code: 302
13
+ message: Moved Temporarily
14
+ headers:
15
+ Server:
16
+ - nginx
17
+ Date:
18
+ - Fri, 17 Feb 2012 01:43:07 GMT
19
+ Content-Type:
20
+ - text/html;charset=utf-8
21
+ Connection:
22
+ - keep-alive
23
+ Vary:
24
+ - Accept
25
+ Cache-Control:
26
+ - public, max-age=900
27
+ Location:
28
+ - http://api.cld.me/C23W/drop_presenter.rb
29
+ X-Content-Digest:
30
+ - da39a3ee5e6b4b0d3255bfef95601890afd80709
31
+ X-Rack-Cache:
32
+ - stale, invalid, store
33
+ Content-Length:
34
+ - '0'
35
+ X-Varnish:
36
+ - '1852427632'
37
+ Age:
38
+ - '0'
39
+ Via:
40
+ - 1.1 varnish
41
+ body: ''
42
+ http_version:
43
+ recorded_at: Fri, 17 Feb 2012 01:43:07 GMT
44
+ - request:
45
+ method: get
46
+ uri: http://api.cld.me/C23W/drop_presenter.rb
47
+ body: ''
48
+ headers:
49
+ Accept:
50
+ - application/json
51
+ response:
52
+ status:
53
+ code: 302
54
+ message: Moved Temporarily
55
+ headers:
56
+ Cache-Control:
57
+ - no-cache
58
+ Content-Type:
59
+ - text/html; charset=utf-8
60
+ Location:
61
+ - http://f.cl.ly/items/152S3l2X1y3P2M262D3V/drop_presenter.rb
62
+ Server:
63
+ - thin 1.3.1 codename Triple Espresso
64
+ X-Runtime:
65
+ - '0.025914'
66
+ X-Ua-Compatible:
67
+ - IE=Edge,chrome=1
68
+ Transfer-Encoding:
69
+ - chunked
70
+ Connection:
71
+ - keep-alive
72
+ body: <html><body>You are being <a href="http://f.cl.ly/items/152S3l2X1y3P2M262D3V/drop_presenter.rb">redirected</a>.</body></html>
73
+ http_version:
74
+ recorded_at: Fri, 17 Feb 2012 01:44:07 GMT
75
+ - request:
76
+ method: get
77
+ uri: http://f.cl.ly/items/152S3l2X1y3P2M262D3V/drop_presenter.rb
78
+ body: ''
79
+ headers:
80
+ Accept:
81
+ - application/json
82
+ response:
83
+ status:
84
+ code: 200
85
+ message: OK
86
+ headers:
87
+ X-Amz-Id-2:
88
+ - iyFXxRKOKM5CYt1f7jI9bN8btGeacX2VeXxCIMNL2/AQNzPEH7pAIUjQ9A4Q/TYC
89
+ X-Amz-Request-Id:
90
+ - 9092E1275FD0C3F5
91
+ Date:
92
+ - Fri, 17 Feb 2012 01:44:09 GMT
93
+ Last-Modified:
94
+ - Tue, 22 Nov 2011 19:40:51 GMT
95
+ Etag:
96
+ - ! '"f24a305d5a90516f0b0877b93158ee0a"'
97
+ Accept-Ranges:
98
+ - bytes
99
+ Content-Type:
100
+ - application/ruby
101
+ Content-Length:
102
+ - '610'
103
+ Server:
104
+ - AmazonS3
105
+ body: ! "require 'delegate'\nrequire 'yajl'\n\nclass DropPresenter < SimpleDelegator\n
106
+ \ def initialize(drop, template)\n @template = template\n\n super drop\n
107
+ \ end\n\n def render_html\n if bookmark?\n @template.redirect_to_api\n
108
+ \ else\n @template.erb template_name, locals: { drop: self, body_id:
109
+ body_id }\n end\n end\n\n def render_json\n Yajl::Encoder.encode data\n
110
+ \ end\n\nprivate\n\n def template_name\n if image?\n :image\n elsif
111
+ text?\n :text\n else\n :other\n end\n end\n\n def body_id\n
112
+ \ if image?\n 'image'\n elsif text?\n 'text'\n else\n 'other'\n
113
+ \ end\n end\n\nend\n"
114
+ http_version:
115
+ recorded_at: Fri, 17 Feb 2012 01:44:08 GMT
116
+ recorded_with: VCR 2.0.0.rc1
@@ -0,0 +1,81 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://cl.ly/C23W
6
+ body: ''
7
+ headers:
8
+ Accept:
9
+ - application/json
10
+ response:
11
+ status:
12
+ code: 200
13
+ message: OK
14
+ headers:
15
+ Server:
16
+ - nginx
17
+ Date:
18
+ - Thu, 16 Feb 2012 20:19:27 GMT
19
+ Content-Type:
20
+ - application/json;charset=utf-8
21
+ Connection:
22
+ - keep-alive
23
+ Vary:
24
+ - Accept
25
+ X-Rack-Cache:
26
+ - miss
27
+ Content-Length:
28
+ - '627'
29
+ X-Varnish:
30
+ - '587912818'
31
+ Age:
32
+ - '0'
33
+ Via:
34
+ - 1.1 varnish
35
+ body: ! '{"created_at":"2011-11-22T19:40:50Z","deleted_at":null,"id":12142483,"item_type":"text","name":"drop_presenter.rb","private":false,"redirect_url":null,"remote_url":"http://f.cl.ly/items/152S3l2X1y3P2M262D3V/drop_presenter.rb","source":"Cloud/1.5.3b1
36
+ CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (MacBookPro5%2C5)","updated_at":"2012-02-16T20:09:52Z","view_counter":90,"href":"http://my.cl.ly/items/12142483","url":"http://cl.ly/C23W","content_url":"http://cl.ly/C23W/drop_presenter.rb","icon":"http://assets.my.cld.me/images/item-types/text.png","subscribed":true,"download_url":"http://api.cld.me/C23W/download/drop_presenter.rb"}'
37
+ http_version:
38
+ recorded_at: Thu, 16 Feb 2012 20:19:27 GMT
39
+ - request:
40
+ method: get
41
+ uri: http://cl.ly/nonexistent
42
+ body: ''
43
+ headers:
44
+ Accept:
45
+ - application/json
46
+ response:
47
+ status:
48
+ code: 404
49
+ message: Not Found
50
+ headers:
51
+ Server:
52
+ - nginx
53
+ Date:
54
+ - Thu, 16 Feb 2012 20:26:01 GMT
55
+ Content-Type:
56
+ - text/html;charset=utf-8
57
+ Connection:
58
+ - keep-alive
59
+ Vary:
60
+ - Accept
61
+ X-Rack-Cache:
62
+ - miss
63
+ Content-Length:
64
+ - '621'
65
+ X-Varnish:
66
+ - '2047120769'
67
+ Age:
68
+ - '0'
69
+ Via:
70
+ - 1.1 varnish
71
+ body: ! "<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n\n <title>CloudApp
72
+ &mdash; Not Found</title>\n\n <link href='/favicon.ico' rel='shortcut icon'
73
+ />\n <link href=\"/stylesheets/error.css\" rel=\"stylesheet\" type=\"text/css\"
74
+ />\n\n <!--[if lt IE 9]>\n <script src=\"//html5shim.googlecode.com/svn/trunk/html5.js\"></script>\n
75
+ \ <![endif]-->\n </head>\n\n <body>\n <div class=\"wrapper\">\n <h1>Cloud<em>App</em></h1>\n\n
76
+ \ <h2>Sorry, no drops live here.</h2>\n\n <p>\n Perhaps the
77
+ link you clicked was broken or the owner of this drop has\n deleted it.\n
78
+ \ </p>\n </div>\n </body>\n</html>\n"
79
+ http_version:
80
+ recorded_at: Thu, 16 Feb 2012 20:26:01 GMT
81
+ recorded_with: VCR 2.0.0.rc1
@@ -255,7 +255,7 @@ http_interactions:
255
255
  recorded_at: Wed, 15 Feb 2012 14:39:02 GMT
256
256
  - request:
257
257
  method: get
258
- uri: https://my.cl.ly/items/s3?bucket=f.cl.ly&etag=%22567d2d49d2d30e2db956d680a4d03f25%22&key=items/2B0E373Z1J2U1u071E28/favicon.ico&item%5Bprivate%5D=false
258
+ uri: https://my.cl.ly/items/s3?bucket=f.cl.ly&etag=%22567d2d49d2d30e2db956d680a4d03f25%22&item%5Bprivate%5D=false&key=items/2B0E373Z1J2U1u071E28/favicon.ico
259
259
  body: ''
260
260
  headers:
261
261
  Authorization:
@@ -0,0 +1,59 @@
1
+ require 'helper'
2
+ require 'tempfile'
3
+
4
+ require 'cloudapp/config'
5
+
6
+ describe CloudApp::Config do
7
+ let(:config) { {} }
8
+ let(:content) { YAML.dump(config) }
9
+ let(:path) { config_file.path }
10
+ let(:config_file) {
11
+ Tempfile.new('cloudapprc', '.').tap do |file|
12
+ file << content
13
+ file.close
14
+ end
15
+ }
16
+
17
+ describe '#new' do
18
+ subject { CloudApp::Config.new path }
19
+
20
+ describe 'an existing config file' do
21
+ let(:config) {{ token: 'token' }}
22
+
23
+ it 'reads the content' do
24
+ subject.token.should eq(config[:token])
25
+ end
26
+
27
+ it 'updates a key' do
28
+ new_token = 'new token'
29
+ subject.token = new_token
30
+ expected = YAML.dump token: new_token
31
+
32
+ content = File.open(path) {|file| file.read }
33
+ content.should eq(expected)
34
+ end
35
+
36
+ it 'clears a key' do
37
+ subject.token = nil
38
+ expected = YAML.dump({})
39
+
40
+ content = File.open(path) {|file| file.read }
41
+ content.should eq(expected)
42
+ end
43
+ end
44
+
45
+ describe 'an empty config file' do
46
+ it 'returns nil' do
47
+ subject.token.should be_nil
48
+ end
49
+ end
50
+
51
+ describe 'a nonexistent config file' do
52
+ let(:path) { 'nonexistent' }
53
+
54
+ it 'returns nil' do
55
+ subject.token.should be_nil
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,21 @@
1
+ require 'helper'
2
+ require 'support/vcr_rspec'
3
+
4
+ require 'cloudapp/drop_content'
5
+
6
+ describe CloudApp::DropContent do
7
+ describe '.download' do
8
+ let(:content_url) { 'http://cl.ly/C23W/drop_presenter.rb' }
9
+ let(:drop) { stub :drop, content_url: content_url }
10
+ subject {
11
+ VCR.use_cassette('DropContent/download') {
12
+ CloudApp::DropContent.download drop
13
+ }
14
+ }
15
+
16
+ it 'downloads content' do
17
+ expected = "require 'delegate'"
18
+ subject[0...expected.size].should == expected
19
+ end
20
+ end
21
+ end
@@ -11,10 +11,10 @@ describe CloudApp::DropPresenter do
11
11
  let(:io) { StringIO.new }
12
12
 
13
13
  describe 'a single line' do
14
- subject do
14
+ subject {
15
15
  CloudApp::DropPresenter.print(options, &action)
16
16
  io.tap(&:rewind).readlines
17
- end
17
+ }
18
18
 
19
19
  describe 'with no format' do
20
20
  let(:options) {{ on: io, waiting: waiting }}
@@ -47,16 +47,16 @@ describe CloudApp::DropPresenter do
47
47
 
48
48
  describe 'a table of data' do
49
49
  let(:columns) {{ name: 'Name', url: 'Link' }}
50
- let(:result) do
50
+ let(:result) {
51
51
  [ stub(:result1, name: 'Stub 1', url: 'http://stub1.com'),
52
52
  stub(:result2, name: 'Stub 2', url: 'http://stub2.com') ]
53
- end
53
+ }
54
54
  let(:options) {{ on: io, format: format, columns: columns }}
55
55
 
56
- subject do
56
+ subject {
57
57
  CloudApp::DropPresenter.print(options, &action)
58
58
  io.tap(&:rewind).readlines
59
- end
59
+ }
60
60
 
61
61
  describe 'pretty format' do
62
62
  let(:format) { :pretty }
@@ -91,5 +91,30 @@ describe CloudApp::DropPresenter do
91
91
  end
92
92
  end
93
93
  end
94
+
95
+ describe 'providing multiple formats' do
96
+ let(:result) {{ pretty: 'pretty', csv: 'csv' }}
97
+ subject {
98
+ CloudApp::DropPresenter.print(options, &action)
99
+ io.tap(&:rewind).readlines
100
+ }
101
+
102
+ describe 'pretty format' do
103
+ let(:options) {{ on: io, format: :pretty }}
104
+
105
+ it 'pretty prints' do
106
+ subject.first.should eq("pretty\n")
107
+ end
108
+ end
109
+
110
+ describe 'csv format' do
111
+ let(:options) {{ on: io, format: :csv }}
112
+
113
+ it 'prints csv' do
114
+ subject.first.should eq("csv\n")
115
+ end
116
+ end
117
+
118
+ end
94
119
  end
95
120
  end
@@ -1,10 +1,10 @@
1
1
  require 'helper'
2
+ require 'support/fakefs_rspec'
2
3
  require 'support/vcr_rspec'
3
4
 
4
5
  require 'cloudapp/drop_service'
5
6
 
6
7
  describe CloudApp::DropService do
7
-
8
8
  let(:token) { '8762f6679f8d001016b2' }
9
9
 
10
10
  describe '.using_token' do
@@ -29,6 +29,160 @@ describe CloudApp::DropService do
29
29
  end
30
30
  end
31
31
 
32
+ describe '#drop' do
33
+ let(:service) { CloudApp::DropService.new }
34
+
35
+ describe 'retrieving a drop' do
36
+ let(:url) { 'http://cl.ly/C23W' }
37
+ subject {
38
+ VCR.use_cassette('DropService/drop',
39
+ match_requests_on: [:method, :uri, :body, :headers]) {
40
+ service.drop url
41
+ }
42
+ }
43
+
44
+ it 'returns the drop' do
45
+ subject.should be_a(CloudApp::Drop)
46
+ end
47
+
48
+ it 'parses the response' do
49
+ subject.id.should == 12142483
50
+ end
51
+ end
52
+
53
+ describe 'retrieving a nonexistent drop' do
54
+ let(:url) { 'http://cl.ly/nonexistent' }
55
+ subject {
56
+ VCR.use_cassette('DropService/drop',
57
+ match_requests_on: [:method, :uri, :body, :headers]) {
58
+ service.drop url
59
+ }
60
+ }
61
+
62
+ it 'returns nil' do
63
+ subject.should be_nil
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#download_drop', :fakefs do
69
+ let(:service) { CloudApp::DropService.new }
70
+ let(:url) { 'http://cl.ly/C23W' }
71
+ let(:options) { {} }
72
+ let(:content) { 'content' }
73
+ let(:content_url) { 'http://cl.ly/C23W/drop_presenter.rb' }
74
+ let(:drop) { stub :drop, content: content,
75
+ content_url: content_url,
76
+ has_content?: true }
77
+
78
+ before do
79
+ CloudApp::DropContent.stub download: content
80
+ service.stub drop: drop
81
+ end
82
+
83
+ it 'fetches the drop' do
84
+ CloudApp::DropContent.should_receive(:download).with(drop)
85
+ service.download_drop url, options
86
+ end
87
+
88
+ it 'returns the content' do
89
+ service.download_drop(url, options).should eq(content)
90
+ end
91
+
92
+ it 'saves the file to the current directory using the remote filename' do
93
+ service.download_drop url, options
94
+ downloaded = File.open('drop_presenter.rb') {|f| f.read }
95
+
96
+ downloaded.should eq(content)
97
+ end
98
+
99
+ describe 'to a path' do
100
+ let(:options) {{ to: '/tmp/file.txt' }}
101
+
102
+ it 'saves the file to the given path' do
103
+ service.download_drop url, options
104
+ File.exist?(options[:to]).should be_true
105
+ end
106
+ end
107
+
108
+ describe 'to an existing file' do
109
+ let(:options) {{ to: '/tmp/file.txt' }}
110
+ before do
111
+ Dir.mkdir '/tmp'
112
+ File.open(options[:to], 'w', 0600) {|file| file << 'existing' }
113
+ end
114
+
115
+ it 'overwrites the file' do
116
+ service.download_drop url, options
117
+ downloaded = File.open(options[:to]) {|f| f.read }
118
+
119
+ downloaded.should eq(content)
120
+ end
121
+ end
122
+
123
+ describe 'an unexpanded path' do
124
+ let(:options) {{ to: '~/file.txt' }}
125
+ before do
126
+ FileUtils.mkdir_p File.expand_path('~')
127
+ end
128
+
129
+ it 'saves the file to the expanded directory' do
130
+ service.download_drop url, options
131
+ saved_path = File.expand_path(options[:to])
132
+
133
+ File.exist?(saved_path).should be_true
134
+ end
135
+ end
136
+
137
+ describe 'to an existing directory' do
138
+ let(:options) {{ to: '/tmp' }}
139
+ before do
140
+ Dir.mkdir '/tmp'
141
+ end
142
+
143
+ it 'raises an exception' do
144
+ -> { service.download_drop url, options }.
145
+ should raise_exception(Errno::EISDIR)
146
+ end
147
+ end
148
+
149
+ describe 'a bookmark' do
150
+ let(:drop) { stub :drop, has_content?: false }
151
+
152
+ it 'raises an exception' do
153
+ -> { service.download_drop url, options }.
154
+ should raise_exception(CloudApp::DropService::NO_CONTENT)
155
+ end
156
+
157
+ it "doesn't save a file" do
158
+ FakeFS::FileSystem.files.should be_empty
159
+ end
160
+ end
161
+
162
+ describe 'a file with URL-encoded name' do
163
+ let(:content_url) { 'http://cl.ly/C23W/screen%20shot.png' }
164
+
165
+ it 'decodes the filename' do
166
+ service.download_drop url, options
167
+
168
+ File.exist?('screen shot.png').should be_true
169
+ end
170
+ end
171
+
172
+ describe 'a nonexistent drop' do
173
+ let(:drop) { nil }
174
+
175
+ it 'raises an exception' do
176
+ -> { service.download_drop url, options }.
177
+ should raise_exception(CloudApp::DropService::NO_CONTENT)
178
+ end
179
+
180
+ it "doesn't save a file" do
181
+ FakeFS::FileSystem.files.should be_empty
182
+ end
183
+ end
184
+ end
185
+
32
186
  describe '#drops' do
33
187
  let(:service) { CloudApp::DropService.using_token token }
34
188