cloudapp 2.0.0.beta.5 → 2.0.0.beta.6

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cloudapp (2.0.0.beta.5)
4
+ cloudapp (2.0.0.beta.6)
5
5
  leadlight (~> 0.0.7)
6
+ mime-types (~> 1.19)
6
7
  netrc (~> 0.7.7)
7
8
  typhoeus (~> 0.3.3)
8
9
 
@@ -10,6 +11,7 @@ GEM
10
11
  remote: http://rubygems.org/
11
12
  specs:
12
13
  addressable (2.2.8)
14
+ diff-lcs (1.1.3)
13
15
  fail-fast (1.0.0)
14
16
  faraday (0.8.1)
15
17
  multipart-post (~> 1.1)
@@ -37,6 +39,14 @@ GEM
37
39
  hpricot (>= 0.8.2)
38
40
  mustache (>= 0.7.0)
39
41
  rdiscount (>= 1.5.8)
42
+ rspec (2.12.0)
43
+ rspec-core (~> 2.12.0)
44
+ rspec-expectations (~> 2.12.0)
45
+ rspec-mocks (~> 2.12.0)
46
+ rspec-core (2.12.2)
47
+ rspec-expectations (2.12.1)
48
+ diff-lcs (~> 1.1.3)
49
+ rspec-mocks (2.12.0)
40
50
  typhoeus (0.3.3)
41
51
  mime-types
42
52
 
@@ -47,3 +57,4 @@ DEPENDENCIES
47
57
  cloudapp!
48
58
  rake
49
59
  ronn
60
+ rspec
data/README.md CHANGED
@@ -15,20 +15,38 @@ you're willing to lend a hand, we'd love to officially support it.
15
15
 
16
16
  ``` bash
17
17
  $ gem install cloudapp --pre
18
- $ cloudapp upload screenshot.png
19
18
  $ cloudapp bookmark http://getcloudapp.com
19
+ $ cloudapp upload screenshot.png
20
+ $ cloudapp upload --direct screenshot.png
21
+ ```
22
+
23
+ For a good time, install `gem-man` and read the man page or
24
+ [read it online][man].
25
+
26
+ [man]: http://cloudapp.github.com/cloudapp
27
+
28
+
29
+ ``` bash
30
+ $ gem install gem-man
31
+ $ gem man cloudapp
20
32
  ```
21
33
 
22
34
  ## Commands
23
35
 
24
- ### cloudapp upload
36
+ ### cloudapp upload `<file>`
37
+
38
+ Upload `<file>` and print its link to standard out. Use the `--direct` flag to
39
+ print the file's direct link which is suitable for use in places that expect a
40
+ link to a file like an HTML IMG tag.
25
41
 
26
42
  ``` bash
27
43
  $ cloudapp upload screenshot.png
28
44
  http://cl.ly/abc123
29
45
  ```
30
46
 
31
- ### cloudapp bookmark
47
+ ### cloudapp bookmark `<url>`
48
+
49
+ Bookmark `<url>` and print its link to standard out.
32
50
 
33
51
  ``` bash
34
52
  $ cloudapp bookmark http://getcloudapp.com
@@ -40,29 +58,12 @@ http://cl.ly/abc123
40
58
  A few simple commands to allow scripting and input from other Unix programs
41
59
  would be ideal.
42
60
 
43
- ### Phase: Next
44
-
45
61
  - Share several files: `cloudapp upload *.png`
46
62
  - Bookmark several links: `cloudapp bookmark http://douglasadams.com http://zombo.com`
47
63
  - Handle bookmarks from STDIN: `pbpaste | cloudapp bookmark`
48
- - Handle files from STDIN: `find *.png | cloudapp upload`
49
64
  - Download a drop: `cloudapp download http://cl.ly/abc123`
50
-
51
- ### Phase: Unstoppable
52
-
53
- - Archive and share several files: `cloudapp upload --archive *.png`
54
65
  - Encrypt and share a file: `cloudapp upload --encrypt launch_codes.txt`
55
66
  - Download and decrypt and encrypted drop: `cloudapp download --key=def456 http://cl.ly/abc123`
56
67
 
57
- ### Phase: World Domination
58
-
59
- While we're dreaming, what could you do if `cloudapp` had a database of all your
60
- drops? Bonus points for a light weight daemon that kept everything in sync at
61
- all times.
62
-
63
- - Find all your screen shots: `cloudapp list /^screen ?shot.*\.png$/`
64
- - Trash all your stale drops: `cloudapp delete --last-viewed="> 1 month ago"`
65
- - See your drop views in real time: `cloudapp --tail`
66
-
67
- There's bound to be a better way to express some of these commands, but you get
68
- the picture.
68
+ There's be a better way to express some of these commands, but you get the
69
+ picture.
data/bin/cloudapp CHANGED
@@ -1,30 +1,47 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'cloudapp/credentials'
4
+ require 'cloudapp/cli/prompt'
4
5
  require 'cloudapp/service'
5
6
 
6
7
  def service
7
- CloudApp::Service.using_token Credentials.token
8
+ CloudApp::Service.using_token token
9
+ end
10
+
11
+ def token
12
+ Credentials.token
13
+ end
14
+
15
+ def valid_token?
16
+ !token.nil? and service.root.authorized?
8
17
  end
9
18
 
10
19
  def error error
11
20
  puts "ERROR: #{error}"
12
- exit 1
21
+ exit 9
13
22
  end
14
23
 
15
- def validate_url url
24
+ def valid_url? url
16
25
  error 'URL missing' if url.nil?
17
26
  error "#{ url } doesn't look like a valid URL" unless url =~ URI.regexp
27
+ true
18
28
  end
19
29
 
20
- def validate_file file
30
+ def valid_file? file
21
31
  error "File doesn't exist" if file.is_a? Errno::ENOENT
22
32
  error 'File missing' if file.nil? or file == STDIN
33
+ not file.closed?
34
+ end
35
+
36
+ def next_file
37
+ ARGF.file rescue $!
23
38
  end
24
39
 
25
40
 
26
- while service.root.unauthorized?
27
- Credentials.new.ask_for_and_save_credentials
41
+ while not valid_token?
42
+ credentials = CloudApp::CLI::Prompt.new.ask_for_credentials
43
+ token = CloudApp::Service.token_for_account *credentials
44
+ Credentials.save_token token
28
45
  end
29
46
 
30
47
  link = ARGV.delete('--direct') || ARGV.delete('-d') ? :embed : :canonical
@@ -32,13 +49,16 @@ link = ARGV.delete('--direct') || ARGV.delete('-d') ? :embed : :canonical
32
49
  case ARGV.shift
33
50
  when 'bookmark'
34
51
  link = :canonical # No such thing as an embed link for a bookmark.
35
- url = ARGV.shift
36
- validate_url url
37
- puts service.bookmark(url).link(link)
52
+ while url = ARGV.shift
53
+ break unless valid_url? url
54
+ puts service.bookmark(url).link(link)
55
+ end
38
56
  when 'upload'
39
- file = ARGF.file rescue $!
40
- validate_file file
41
- puts service.upload(file).link(link)
57
+ while file = next_file
58
+ break unless valid_file? file
59
+ puts service.upload(file).link(link)
60
+ ARGF.skip
61
+ end
42
62
  else
43
63
  puts <<EOS
44
64
  Usage:
data/cloudapp.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'cloudapp'
16
- s.version = '2.0.0.beta.5'
17
- s.date = '2012-12-17'
16
+ s.version = '2.0.0.beta.6'
17
+ s.date = '2012-12-23'
18
18
  s.rubyforge_project = 'cloudapp'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -43,14 +43,16 @@ Gem::Specification.new do |s|
43
43
 
44
44
  ## List your runtime dependencies here. Runtime dependencies are those
45
45
  ## that are needed for an end user to actually USE your code.
46
- s.add_dependency 'netrc', '~> 0.7.7'
47
- s.add_dependency 'leadlight', '~> 0.0.7'
48
- s.add_dependency 'typhoeus', '~> 0.3.3'
46
+ s.add_dependency 'netrc', '~> 0.7.7'
47
+ s.add_dependency 'leadlight', '~> 0.0.7'
48
+ s.add_dependency 'mime-types', '~> 1.19'
49
+ s.add_dependency 'typhoeus', '~> 0.3.3'
49
50
 
50
51
  ## List your development dependencies here. Development dependencies are
51
52
  ## those that are only needed during development
52
53
  s.add_development_dependency 'rake'
53
54
  s.add_development_dependency 'ronn'
55
+ s.add_development_dependency 'rspec'
54
56
 
55
57
  ## Leave this section as-is. It will be automatically generated from the
56
58
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
@@ -66,12 +68,21 @@ Gem::Specification.new do |s|
66
68
  cloudapp.gemspec
67
69
  lib/cloudapp.rb
68
70
  lib/cloudapp/authorized.rb
71
+ lib/cloudapp/cli/prompt.rb
69
72
  lib/cloudapp/collection_json.rb
73
+ lib/cloudapp/collection_json/collection.rb
74
+ lib/cloudapp/collection_json/item.rb
75
+ lib/cloudapp/collection_json/template.rb
70
76
  lib/cloudapp/credentials.rb
71
77
  lib/cloudapp/service.rb
72
78
  man/cloudapp.1
73
79
  man/cloudapp.1.html
74
80
  man/cloudapp.1.ronn
81
+ spec/cloudapp/authorized_spec.rb
82
+ spec/cloudapp/collection_json/collection_spec.rb
83
+ spec/cloudapp/collection_json/item_spec.rb
84
+ spec/cloudapp/collection_json/template_spec.rb
85
+ spec/cloudapp/credentials_spec.rb
75
86
  ]
76
87
  # = MANIFEST =
77
88
 
@@ -0,0 +1,34 @@
1
+ # Lovingly borrowed from the heroku gem:
2
+ # https://github.com/heroku/heroku/blob/master/lib/heroku/auth.rb
3
+ module CloudApp
4
+ module CLI
5
+ class Prompt
6
+ def ask_for_credentials
7
+ puts "Sign into CloudApp."
8
+ print "Email: "
9
+ email = ask
10
+ print "Password (typing will be hidden): "
11
+ password = ask_for_password
12
+ [ email, password ]
13
+ end
14
+
15
+ def ask() $stdin.gets.to_s.strip end
16
+ def ask_for_password
17
+ echo_off
18
+ password = ask
19
+ puts
20
+ echo_on
21
+ return password
22
+ end
23
+
24
+ def echo_on() with_tty { system "stty echo" } end
25
+ def echo_off() with_tty { system "stty -echo" } end
26
+ def with_tty(&block)
27
+ return unless $stdin.isatty
28
+ yield
29
+ rescue
30
+ # fails on windows
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ require 'cloudapp/collection_json/item'
2
+ require 'cloudapp/collection_json/template'
3
+
4
+ module CloudApp
5
+ module CollectionJson
6
+ class Collection < Item
7
+ def initialize representation
8
+ super representation.fetch('collection')
9
+ end
10
+
11
+ def item() items.first end
12
+ def items
13
+ fetch('items', []).map {|item| Item.new(item) }
14
+ end
15
+
16
+ def template
17
+ Template.new(fetch('template'), href)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ require 'delegate'
2
+
3
+ module CloudApp
4
+ module CollectionJson
5
+ class Item < SimpleDelegator
6
+ def href() fetch('href') end
7
+ def rel() fetch('rel') end
8
+
9
+ def links
10
+ fetch('links', []).map {|link| Item.new(link) }
11
+ end
12
+
13
+ def link rel
14
+ links.find {|link| link.rel == rel.to_s }.href
15
+ end
16
+
17
+ def data
18
+ data = {}
19
+ fetch('data').each do |datum|
20
+ data[datum.fetch('name')] = datum.fetch('value')
21
+ end
22
+ data
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require 'cloudapp/collection_json/item'
2
+
3
+ module CloudApp
4
+ module CollectionJson
5
+ class Template < Item
6
+ attr_reader :href
7
+
8
+ def initialize item, href
9
+ @href = href
10
+ super item
11
+ end
12
+
13
+ def fill key, value
14
+ return self unless data.has_key? key
15
+ new_data = fetch('data').map {|datum|
16
+ if datum.fetch('name') == key
17
+ datum = datum.merge('value' => value)
18
+ end
19
+ datum
20
+ }
21
+ new_item = self.merge('data' => new_data)
22
+ Template.new new_item, href
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,7 @@
1
+ require 'cloudapp/collection_json/item'
2
+ require 'cloudapp/collection_json/collection'
3
+ require 'cloudapp/collection_json/template'
4
+
1
5
  module CloudApp
2
6
  module CollectionJson
3
7
  Tint = Leadlight::Tint.new 'collection+json', status: [ :success, 401 ] do
@@ -7,6 +11,7 @@ module CloudApp
7
11
 
8
12
  module Representation
9
13
  extend Forwardable
14
+ def_delegators :collection, :template, :item
10
15
 
11
16
  def self.extended representation
12
17
  Collection.new(representation).links.each do |link|
@@ -21,66 +26,6 @@ module CloudApp
21
26
  def collection
22
27
  Collection.new(self)
23
28
  end
24
-
25
- def_delegators :collection, :template, :item
26
-
27
- class Item < SimpleDelegator
28
- def links
29
- fetch('links', []).map {|link| Item.new(link) }
30
- end
31
-
32
- def link rel
33
- links.find {|link| link.rel == rel.to_s }.href
34
- end
35
-
36
- def href() fetch('href') end
37
- def rel() fetch('rel') end
38
- def data
39
- data = {}
40
- fetch('data').each do |datum|
41
- data[datum.fetch('name')] = datum.fetch('value')
42
- end
43
- data
44
- end
45
- end
46
-
47
- class Collection < Item
48
- def initialize representation
49
- super representation.fetch('collection')
50
- end
51
-
52
- def template() Template.new(fetch('template'), href) end
53
- def items
54
- fetch('items').map {|item| Item.new(item) }
55
- end
56
-
57
- def item
58
- items.first
59
- end
60
- end
61
-
62
- class Template < Item
63
- attr_reader :href
64
-
65
- def initialize item, href
66
- @href = href
67
- super item
68
- end
69
-
70
- def enctype() fetch('enctype') end
71
-
72
- def fill key, value
73
- return self unless data.has_key?(key)
74
- new_data = fetch('data').map {|datum|
75
- if datum.fetch('name') == key
76
- datum = datum.merge 'value' => value
77
- end
78
- datum
79
- }
80
- new_item = self.merge('data' => new_data)
81
- Template.new new_item, href
82
- end
83
- end
84
29
  end
85
30
  end
86
31
  end
@@ -1,115 +1,33 @@
1
- # Taken from the heroku gem.
2
- # https://github.com/heroku/heroku/blob/master/lib/heroku/auth.rb
3
1
  require 'netrc'
4
2
 
5
3
  class Credentials
6
- def self.token
7
- new.credentials.last
8
- end
4
+ attr_reader :netrc
9
5
 
10
- def netrc_path
11
- default = Netrc.default_path
12
- encrypted = default + ".gpg"
13
- if File.exists?(encrypted)
14
- encrypted
15
- else
16
- default
17
- end
6
+ def initialize netrc
7
+ @netrc = netrc
18
8
  end
19
9
 
20
- def netrc
21
- @netrc ||= begin
22
- File.exists?(netrc_path) && Netrc.read(netrc_path)
23
- rescue => error
24
- if error.message =~ /^Permission bits for/
25
- perm = File.stat(netrc_path).mode & 0777
26
- abort("Permissions #{perm} for '#{netrc_path}' are too open. You should run `chmod 0600 #{netrc_path}` so that your credentials are NOT accessible by others.")
27
- else
28
- raise error
29
- end
30
- end
10
+ def self.token netrc = Netrc.read
11
+ new(netrc).token
31
12
  end
32
13
 
33
- def credentials=(credentials) @credentials = credentials end
34
- def credentials()
35
- (@credentials ||= read_credentials) || ask_for_and_save_credentials
14
+ def self.save_token token, netrc = Netrc.read
15
+ new(netrc).save_token token
36
16
  end
37
17
 
38
- def read_credentials
39
- # TODO: convert legacy credentials to netrc
40
- # if File.exists?(legacy_credentials_path)
41
- # @api, @client = nil
42
- # @credentials = File.read(legacy_credentials_path).split("\n")
43
- # write_credentials
44
- # FileUtils.rm_f(legacy_credentials_path)
45
- # end
46
-
47
- # read netrc credentials if they exist
48
- self.credentials = netrc['api.getcloudapp.com'] if netrc
18
+ def token
19
+ credentials.last
49
20
  end
50
21
 
51
- def write_credentials
52
- FileUtils.mkdir_p(File.dirname(netrc_path))
53
- FileUtils.touch(netrc_path)
54
- FileUtils.chmod(0600, netrc_path)
55
- netrc['api.getcloudapp.com'] = credentials
22
+ def save_token token
23
+ return if token.nil? or token =~ /^\s*$/
24
+ netrc['api.getcloudapp.com'] = [ 'api@getcloudapp.com', token ]
56
25
  netrc.save
57
26
  end
58
27
 
59
- def delete_credentials
60
- # TODO: delete legacy credentials
61
- # if File.exists?(legacy_credentials_path)
62
- # FileUtils.rm_f(legacy_credentials_path)
63
- # end
64
- if netrc
65
- netrc.delete('api.getcloudapp.com')
66
- netrc.save
67
- end
68
- self.credentials = nil
69
- end
70
-
71
- def ask_for_and_save_credentials
72
- self.credentials = ask_for_credentials
73
- write_credentials
74
- credentials
75
- end
76
-
77
- def ask_for_credentials
78
- puts "Enter your CloudApp credentials."
79
-
80
- print "Email: "
81
- email = ask
82
-
83
- print "Password (typing will be hidden): "
84
- password = ask_for_password
85
-
86
- # TODO: Remove this dependency on Service.
87
- token = CloudApp::Service.token_for_account email, password
88
- unless token
89
- puts "Incorrect email or password."
90
- puts
91
- delete_credentials
92
- return ask_for_credentials
93
- end
94
-
95
- [ email, token ]
96
- end
97
-
98
- def ask() $stdin.gets.to_s.strip end
99
- def ask_for_password
100
- echo_off
101
- password = ask
102
- puts
103
- echo_on
104
- return password
105
- end
28
+ private
106
29
 
107
- def echo_on() with_tty { system "stty echo" } end
108
- def echo_off() with_tty { system "stty -echo" } end
109
- def with_tty(&block)
110
- return unless $stdin.isatty
111
- yield
112
- rescue
113
- # fails on windows
30
+ def credentials
31
+ Array netrc['api.getcloudapp.com']
114
32
  end
115
33
  end
@@ -1,12 +1,13 @@
1
1
  require 'leadlight'
2
2
  require 'cloudapp/authorized'
3
3
  require 'cloudapp/collection_json'
4
+ require 'mime/types'
4
5
  require 'uri'
5
6
 
6
7
  module CloudApp
7
8
  class Service
8
9
  Leadlight.build_service self do
9
- url 'http://api.getcloudapp.com'
10
+ url 'https://api.getcloudapp.com'
10
11
  tints << CloudApp::CollectionJson::Tint
11
12
  tints << CloudApp::Authorized::Tint
12
13
 
@@ -70,7 +71,7 @@ module CloudApp
70
71
 
71
72
  def upload_file(path, template)
72
73
  file = File.open path
73
- file_io = Faraday::UploadIO.new file, 'image/png' # TODO: Use correct mime type
74
+ file_io = Faraday::UploadIO.new file, mime_type_for(path)
74
75
  template = template.fill('file', file_io)
75
76
  uri = Addressable::URI.parse template.href
76
77
 
@@ -87,5 +88,10 @@ module CloudApp
87
88
  end
88
89
  end
89
90
  end
91
+
92
+ def mime_type_for path
93
+ MIME::Types.type_for(File.basename(path)).first ||
94
+ 'application/octet-stream'
95
+ end
90
96
  end
91
97
  end
data/lib/cloudapp.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CloudApp
2
- VERSION = '2.0.0.beta.5'
2
+ VERSION = '2.0.0.beta.6'
3
3
  end
data/man/cloudapp.1 CHANGED
@@ -19,7 +19,7 @@ Upload a file or share a bookmark with CloudApp\. The drop\'s share link will be
19
19
  .
20
20
  .TP
21
21
  \fB\-d\fR, \fB\-\-direct\fR
22
- Print the drop\'s direct link after creation\. The direct link is suitable for use in places that expect a link to a file content like an HTML IMG tag\.
22
+ Print the drop\'s direct link after creation\. The direct link is suitable for use in places that expect a link to a file like an HTML IMG tag\.
23
23
  .
24
24
  .SH "EXIT STATUS"
25
25
  cloudapp may return one of several error codes if it encouters problems\.
@@ -31,7 +31,7 @@ cloudapp may return one of several error codes if it encouters problems\.
31
31
  \fB1\fR File exceeds the limits of the account\'s plan
32
32
  .
33
33
  .IP "\(bu" 4
34
- \fB9\fR Something horrible has happened
34
+ \fB9\fR Some horrible, unexpected thing has happened
35
35
  .
36
36
  .IP "" 0
37
37
  .
data/man/cloudapp.1.html CHANGED
@@ -94,7 +94,7 @@ printed to standard output. Account credentials are stored in <code>~/.netrc</co
94
94
 
95
95
  <dl>
96
96
  <dt><code>-d</code>, <code>--direct</code></dt><dd>Print the drop's direct link after creation. The direct link is suitable for
97
- use in places that expect a link to a file content like an HTML IMG tag.</dd>
97
+ use in places that expect a link to a file like an HTML IMG tag.</dd>
98
98
  </dl>
99
99
 
100
100
 
@@ -105,7 +105,7 @@ use in places that expect a link to a file content like an HTML IMG tag.</dd>
105
105
  <ul>
106
106
  <li><code>0</code> Success</li>
107
107
  <li><code>1</code> File exceeds the limits of the account's plan</li>
108
- <li><code>9</code> Something horrible has happened</li>
108
+ <li><code>9</code> Some horrible, unexpected thing has happened</li>
109
109
  </ul>
110
110
 
111
111
 
data/man/cloudapp.1.ronn CHANGED
@@ -15,7 +15,7 @@ printed to standard output. Account credentials are stored in `~/.netrc`.
15
15
 
16
16
  - `-d`, `--direct`:
17
17
  Print the drop's direct link after creation. The direct link is suitable for
18
- use in places that expect a link to a file content like an HTML IMG tag.
18
+ use in places that expect a link to a file like an HTML IMG tag.
19
19
 
20
20
  ## EXIT STATUS
21
21
 
@@ -23,7 +23,7 @@ cloudapp may return one of several error codes if it encouters problems.
23
23
 
24
24
  - `0` Success
25
25
  - `1` File exceeds the limits of the account's plan
26
- - `9` Something horrible has happened
26
+ - `9` Some horrible, unexpected thing has happened
27
27
 
28
28
  ## FILES
29
29
 
@@ -0,0 +1,19 @@
1
+ require 'cloudapp/authorized'
2
+
3
+ describe CloudApp::Authorized::Representation do
4
+ let(:representation) { stub :representation, __response__: response }
5
+ let(:response) { stub :response, status: status }
6
+ subject { representation.extend described_class }
7
+
8
+ context 'an unauthorized response' do
9
+ let(:status) { 401 }
10
+ it { should be_unauthorized }
11
+ it { should_not be_authorized }
12
+ end
13
+
14
+ context 'a success response' do
15
+ let(:status) { 200 }
16
+ it { should_not be_unauthorized }
17
+ it { should be_authorized }
18
+ end
19
+ end
@@ -0,0 +1,69 @@
1
+ require 'cloudapp/collection_json/collection'
2
+
3
+ describe CloudApp::CollectionJson::Collection do
4
+ let(:collection) { described_class.new(data) }
5
+ subject { collection }
6
+
7
+ describe 'the collection item' do
8
+ let(:data) {{ 'collection' => { 'href' => 'http://href.com' }}}
9
+ its(:href) { should eq 'http://href.com' }
10
+ end
11
+
12
+ describe '#items' do
13
+ let(:data) {{
14
+ 'collection' => {
15
+ 'items' => [
16
+ { 'href' => 'http://one.com' },
17
+ { 'href' => 'http://two.com' } ]}
18
+ }}
19
+ subject { collection.items }
20
+
21
+ it { should be_an Array }
22
+ it { should have(2).items }
23
+
24
+ it 'returns an array of Items' do
25
+ subject.each do |item|
26
+ item.should be_an CloudApp::CollectionJson::Item
27
+ end
28
+
29
+ item = subject.first
30
+ item.href.should eq 'http://one.com'
31
+ end
32
+
33
+ context 'with no items' do
34
+ let(:data) {{ 'collection' => {} }}
35
+ it { should be_empty }
36
+ end
37
+ end
38
+
39
+ describe '#item' do
40
+ let(:data) {{
41
+ 'collection' => {
42
+ 'items' => [
43
+ { 'href' => 'http://one.com' },
44
+ { 'href' => 'http://two.com' } ]}}}
45
+ subject { collection.item }
46
+
47
+ it { should eq collection.items.first }
48
+
49
+ context 'with no items' do
50
+ let(:data) {{ 'collection' => {} }}
51
+ it { should be_nil }
52
+ end
53
+ end
54
+
55
+ describe '#template' do
56
+ let(:data) {{
57
+ 'collection' => {
58
+ 'href' => 'http://href.com',
59
+ 'template' => {
60
+ 'data' => [
61
+ { 'name' => 'first_name', 'value' => '' },
62
+ { 'name' => 'last_name', 'value' => '' } ]}}}}
63
+ subject { collection.template }
64
+
65
+ it { should be_an CloudApp::CollectionJson::Template }
66
+ its(:href) { should eq 'http://href.com' }
67
+ its(:data) { should eq 'first_name' => '', 'last_name' => '' }
68
+ end
69
+ end
@@ -0,0 +1,55 @@
1
+ require 'cloudapp/collection_json/item'
2
+
3
+ describe CloudApp::CollectionJson::Item do
4
+ subject { described_class.new(data) }
5
+
6
+ describe '#href' do
7
+ let(:data) {{ 'href' => 'http://getcloudapp.com' }}
8
+ its(:href) { should eq 'http://getcloudapp.com' }
9
+ end
10
+
11
+ describe '#rel' do
12
+ let(:data) {{ 'rel' => 'relation' }}
13
+ its(:rel) { should eq 'relation' }
14
+ end
15
+
16
+ describe '#links' do
17
+ subject { described_class.new(data).links }
18
+ let(:data) {{ 'links' => [
19
+ { 'rel' => 'self', 'href' => 'http://self.com' },
20
+ { 'rel' => 'next', 'href' => 'http://next.com' }] }}
21
+
22
+ it { should be_an Array }
23
+ it { should have(2).items }
24
+
25
+ it 'returns an array of Items' do
26
+ subject.each do |item|
27
+ item.should be_a described_class
28
+ end
29
+
30
+ item = subject.first
31
+ item.rel.should eq 'self'
32
+ item.href.should eq 'http://self.com'
33
+ end
34
+
35
+ context 'with no links' do
36
+ let(:data) { {} }
37
+ it { should be_empty }
38
+ end
39
+ end
40
+
41
+ describe '#link' do
42
+ subject { described_class.new(data).link('next') }
43
+ let(:data) {{ 'links' => [
44
+ { 'rel' => 'self', 'href' => 'http://self.com' },
45
+ { 'rel' => 'next', 'href' => 'http://next.com' }] }}
46
+
47
+ it { should eq 'http://next.com' }
48
+ end
49
+
50
+ describe '#data' do
51
+ let(:data) {{ 'data' => [{ 'name' => 'first_name', 'value' => 'Arthur' },
52
+ { 'name' => 'last_name', 'value' => 'Dent' }] }}
53
+ its(:data) { should eq 'first_name' => 'Arthur', 'last_name' => 'Dent' }
54
+ end
55
+ end
@@ -0,0 +1,35 @@
1
+ require 'cloudapp/collection_json/template'
2
+
3
+ describe CloudApp::CollectionJson::Template do
4
+ let(:template) { described_class.new(data, 'http://href.com') }
5
+ subject { template }
6
+
7
+ describe 'the template item' do
8
+ let(:data) {{ 'data' => [
9
+ { 'name' => 'first_name', 'value' => '' },
10
+ { 'name' => 'last_name', 'value' => '' } ]}}
11
+
12
+ its(:href) { should eq 'http://href.com' }
13
+ its(:data) { should eq 'first_name' => '', 'last_name' => '' }
14
+ end
15
+
16
+ describe '#fill' do
17
+ let(:data) {{ 'data' => [
18
+ { 'name' => 'first_name', 'value' => '' },
19
+ { 'name' => 'last_name', 'value' => '' } ]}}
20
+ subject { template.fill('first_name', 'Arthur') }
21
+
22
+ it { should be_a described_class }
23
+ it { should_not eq template }
24
+
25
+ it 'fills the datum' do
26
+ subject.data.fetch('first_name').should eq 'Arthur'
27
+ end
28
+
29
+ context 'a nonexistent key' do
30
+ it 'does nothing' do
31
+ subject.fill('bad', 'value').should eq subject
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,61 @@
1
+ require 'cloudapp/credentials'
2
+
3
+ describe Credentials do
4
+ describe '.token' do
5
+ let(:netrc) { stub :netrc, :[] => %w( arthur@dent.com towel ) }
6
+ subject { Credentials.token(netrc) }
7
+ it { should eq 'towel' }
8
+ end
9
+
10
+ describe '#token' do
11
+ let(:netrc) { stub :netrc, :[] => %w( arthur@dent.com towel ) }
12
+ subject { Credentials.new(netrc).token }
13
+
14
+ it { should eq 'towel' }
15
+
16
+ it 'fetches token from netrc' do
17
+ netrc.should_receive(:[]).with('api.getcloudapp.com').once
18
+ subject
19
+ end
20
+
21
+ context 'without saved token' do
22
+ let(:netrc) { stub :netrc, :[] => nil }
23
+ it { should be_nil }
24
+ end
25
+ end
26
+
27
+ describe '.save_token' do
28
+ let(:netrc) { stub :netrc, :[]= => nil }
29
+
30
+ it 'saves the token' do
31
+ netrc.should_receive(:save).once.ordered
32
+ Credentials.save_token 'new token', netrc
33
+ end
34
+ end
35
+
36
+ describe '#save_token' do
37
+ let(:netrc) { stub :netrc }
38
+ subject { Credentials.new(netrc) }
39
+
40
+ it 'saves the token' do
41
+ credentials = [ 'api@getcloudapp.com', 'new token' ]
42
+ netrc.should_receive(:[]=).with('api.getcloudapp.com', credentials)
43
+ .once.ordered
44
+ netrc.should_receive(:save).once.ordered
45
+ subject.save_token 'new token'
46
+ end
47
+
48
+ it 'ignores a nil token' do
49
+ netrc.should_not_receive(:[]=)
50
+ netrc.should_not_receive(:save)
51
+ subject.save_token nil
52
+ end
53
+
54
+ it 'ignores an empty token' do
55
+ netrc.should_not_receive(:[]=)
56
+ netrc.should_not_receive(:save)
57
+ subject.save_token ''
58
+ subject.save_token ' '
59
+ end
60
+ end
61
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudapp
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta.5
4
+ version: 2.0.0.beta.6
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-17 00:00:00.000000000 Z
12
+ date: 2012-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: netrc
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: 0.0.7
46
+ - !ruby/object:Gem::Dependency
47
+ name: mime-types
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.19'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.19'
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: typhoeus
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -91,6 +107,22 @@ dependencies:
91
107
  - - ! '>='
92
108
  - !ruby/object:Gem::Version
93
109
  version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
94
126
  description: Experience all the pleasures of sharing with CloudApp now in your terminal.
95
127
  email: larry@marburger.cc
96
128
  executables:
@@ -109,12 +141,21 @@ files:
109
141
  - cloudapp.gemspec
110
142
  - lib/cloudapp.rb
111
143
  - lib/cloudapp/authorized.rb
144
+ - lib/cloudapp/cli/prompt.rb
112
145
  - lib/cloudapp/collection_json.rb
146
+ - lib/cloudapp/collection_json/collection.rb
147
+ - lib/cloudapp/collection_json/item.rb
148
+ - lib/cloudapp/collection_json/template.rb
113
149
  - lib/cloudapp/credentials.rb
114
150
  - lib/cloudapp/service.rb
115
151
  - man/cloudapp.1
116
152
  - man/cloudapp.1.html
117
153
  - man/cloudapp.1.ronn
154
+ - spec/cloudapp/authorized_spec.rb
155
+ - spec/cloudapp/collection_json/collection_spec.rb
156
+ - spec/cloudapp/collection_json/item_spec.rb
157
+ - spec/cloudapp/collection_json/template_spec.rb
158
+ - spec/cloudapp/credentials_spec.rb
118
159
  homepage: https://github.com/cloudapp/cloudapp
119
160
  licenses: []
120
161
  post_install_message: