dropbox 0.0.2 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/
2
+ .DS_Store
3
+ *.gem
data/README.markdown ADDED
@@ -0,0 +1,10 @@
1
+ DropBox
2
+ =======
3
+
4
+ A simple Ruby API for DropBox
5
+
6
+ Usage
7
+ -----
8
+
9
+ d = DropBox.new("you@email.com","password!")
10
+ p d.list("/")
data/Rakefile CHANGED
@@ -1,22 +1,35 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
+ require 'spec/rake/spectask'
3
4
 
4
5
  begin
5
6
  require 'jeweler'
6
7
  Jeweler::Tasks.new do |gem|
7
8
  gem.name = "dropbox"
8
- gem.summary = %Q{A simple Ruby API for DropBox }
9
- gem.description = <<-DESC
10
- A simple Ruby API for DropBox
11
- DESC
12
- gem.email = ""
13
- gem.homepage = ""
14
- gem.authors = []
15
- gem.files = FileList["[A-Z]*", "{lib}/**/*"]
16
-
17
- gem.add_dependency("nokogiri")
18
- gem.add_dependency("mechanize")
9
+ open("VERSION") do |f|
10
+ gem.version = f.read
11
+ end
12
+ gem.summary = %Q{A Simple DropBox API in Ruby}
13
+ gem.description = %Q{A Simple DropBox API in Ruby}
14
+ gem.email = "tys@tvg.ca"
15
+ gem.homepage = "http://github.com/tvongaza/DropBox"
16
+ gem.authors = ["Tys von Gaza","JP Hastings-Spital","Chris Searle","Nicholas A. Evans"]
17
+ gem.add_development_dependency "Shoulda"
18
+ gem.add_dependency "mechanize"
19
+ gem.add_dependency "nokogiri"
20
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
21
  end
22
+ Jeweler::GemcutterTasks.new
20
23
  rescue LoadError
21
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
24
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
+ end
26
+
27
+ desc "Run all examples"
28
+ Spec::Rake::SpecTask.new('examples') do |t|
29
+ t.spec_files = FileList['examples/**/*.rb']
30
+ t.libs << 'lib'
31
+ t.spec_opts = %w[-c -fs]
32
+ t.ruby_opts = %w[-rubygems]
22
33
  end
34
+
35
+ task :default => :examples
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.5
@@ -0,0 +1,98 @@
1
+ require 'spec'
2
+ require 'dropbox'
3
+
4
+ %w[DROPBOX_EMAIL DROPBOX_PASSWORD].each do |var|
5
+ raise "Need to set #{var} to run the specs." unless ENV[var]
6
+ end
7
+ ENV["DROPBOX_FOLDER_NAMESPACE"] ||= "dropboxrb/specroot"
8
+
9
+ describe DropBox do
10
+ before :all do
11
+ # TODO: check for existance of DROPBOX_FOLDER_NAMESPACE
12
+ # TODO: ensure the folder starts out empty
13
+ @connection = connection
14
+ end
15
+
16
+ def connection
17
+ DropBox.new(ENV["DROPBOX_EMAIL"],
18
+ ENV["DROPBOX_PASSWORD"],
19
+ ENV["DROPBOX_FOLDER_NAMESPACE"])
20
+ end
21
+
22
+ def dirent_for(name)
23
+ @connection.list.find {|f| f["name"] == name }
24
+ end
25
+
26
+ context "uploading a file" do
27
+ before :all do
28
+ @file = Tempfile.new("dbrb")
29
+ @contents = <<-EOF
30
+ This is a temp file used by the dropbox.rb specs.
31
+ foo
32
+ bar
33
+ baz
34
+ EOF
35
+ @file.print @contents
36
+ @file.flush
37
+ @basename = File.basename(@file.path)
38
+ @connection.create(@file.path)
39
+ end
40
+ after :all do
41
+ # TODO: fix the bugs that force us to reset the connection.before deleting the file
42
+ @connection.login
43
+ @connection.destroy @basename
44
+ @file.close!
45
+ end
46
+
47
+ it "should be listed at the toplevel" do
48
+ @connection.list.map {|f| f["name"] }.should include(@basename)
49
+ end
50
+
51
+ it "should be listed as not a directory" do
52
+ dirent_for(@basename)["directory"].should be_false
53
+ end
54
+
55
+ it "should have a path relative to the folder namespace (containing query params)" do
56
+ dirent_for(@basename)["path"].should match(%r{^/#{@basename}\?w=.*$})
57
+ end
58
+
59
+ it "should be retrievable" do
60
+ path = dirent_for(@basename)["path"]
61
+ @connection.get(path).should == @contents
62
+ end
63
+
64
+ end
65
+
66
+ context "creating a directory at the toplevel" do
67
+ before { @connection.create_directory("spec_create_dir") }
68
+ after { @connection.destroy("spec_create_dir") }
69
+
70
+ it "should be listed at the toplevel" do
71
+ @connection.list.map {|f| f["name"] }.should include("spec_create_dir")
72
+ end
73
+
74
+ it "should be listed as a directory" do
75
+ dirent_for("spec_create_dir")["directory"].should be_true
76
+ end
77
+
78
+ it "should have a path relative to the folder namespace" do
79
+ dirent_for("spec_create_dir")["path"].should == "/spec_create_dir"
80
+ end
81
+
82
+ it "should contain only a link to the parent directory" do
83
+ list = @connection.list("spec_create_dir")
84
+ list.should have(1).item
85
+ dir = list.first
86
+ dir["name"].should == "Parent folder"
87
+ dir["directory"].should be_true
88
+ dir["path"].should == ""
89
+ end
90
+
91
+ end
92
+
93
+ #context "renaming a file"
94
+ #context "deleting a file"
95
+
96
+ end
97
+
98
+ #describe DropBox, "folder namespace"
data/lib/dropbox.rb CHANGED
@@ -1 +1,14 @@
1
- require 'dropbox/dropbox'
1
+ require 'dropbox/dropbox'
2
+
3
+ ## Should I include this?
4
+ require 'delegate'
5
+
6
+ # Allows percentages to be inspected and stringified in human
7
+ # form "33.3%", but kept in a float format for mathmatics
8
+ class Percentage < DelegateClass(Float)
9
+ def to_s(decimalplaces = 0)
10
+ (((self * 10**(decimalplaces+2)).round)/10**decimalplaces).to_s+"%"
11
+ end
12
+ alias :inspect :to_s
13
+ end
14
+
@@ -1,8 +1,7 @@
1
- require 'rubygems'
2
1
  require 'nokogiri'
3
2
  require 'mechanize'
4
3
 
5
- WWW::Mechanize.html_parser = Nokogiri::HTML
4
+ Mechanize.html_parser = Nokogiri::HTML
6
5
 
7
6
  # TODO: Tests (mock out expected DropBox output)
8
7
  # TODO: Directory object, File object
@@ -13,35 +12,12 @@ class DropBox
13
12
  def initialize(email, password, folder_namespace = "")
14
13
  @email = email
15
14
  @password = password
16
- @agent = WWW::Mechanize.new
15
+ @agent = Mechanize.new
17
16
  @folder_namespace = folder_namespace.gsub(/^\//,"")
18
17
  @logged_in = false
19
18
  end
20
19
 
21
- def login
22
- page = @agent.get('https://www.dropbox.com/login')
23
- login_form = page.forms.detect { |f| f.action == "/login" }
24
- login_form.login_email = @email
25
- login_form.login_password = @password
26
-
27
- home_page = @agent.submit(login_form)
28
- # todo check if we are logged in! (ie search for email and "Log out"
29
- @logged_in = true
30
- @token = home_page.at('//script[contains(text(), "TOKEN")]').content.match("TOKEN: '(.*)',$")[1]
31
-
32
- # check if we have our namespace
33
-
34
- home_page
35
- end
36
-
37
- def login_filter
38
- login unless @logged_in
39
- end
40
-
41
- def list(path = "/")
42
- index(path)
43
- end
44
-
20
+ # Lists all the files and folders in a given directory
45
21
  def index(path = "/")
46
22
  login_filter
47
23
  path = namespace_path(path)
@@ -58,9 +34,14 @@ class DropBox
58
34
  if match_data = details['url'].match(/^\/browse_plain(.*)$/)
59
35
  details['directory'] = true
60
36
  details['path'] = normalize_namespace(match_data[1])
61
- else
37
+ elsif match_data = details['url'].match(%r{^https?://[^/]*/get(.*)$})
62
38
  details['directory'] = false
63
- details['path'] = normalize_namespace(details['url'][33..-1])
39
+ details['path'] = normalize_namespace(match_data[1])
40
+ elsif match_data = details['url'].match(%r{^https?://[^/]*/u/\d*/(.*)$})
41
+ details['directory'] = false
42
+ details['path'] = "Public/#{match_data[1]}"
43
+ else
44
+ raise "could not parse path from Dropbox URL: #{details['url'] }"
64
45
  end
65
46
 
66
47
  details
@@ -69,6 +50,9 @@ class DropBox
69
50
  return listing
70
51
  end
71
52
 
53
+ alias :list :index
54
+
55
+ # Lists the full history for a file on DropBox
72
56
  def list_history(path)
73
57
  login_filter
74
58
 
@@ -91,11 +75,8 @@ class DropBox
91
75
 
92
76
  return listing
93
77
  end
94
-
95
- def get(path)
96
- show(path)
97
- end
98
78
 
79
+ # Downloads the specified file from DropBox
99
80
  def show(path)
100
81
  # change to before filter
101
82
  login_filter
@@ -105,15 +86,18 @@ class DropBox
105
86
  #https://dl-web.dropbox.com/get/testing.txt?w=0ff80d5d&sjid=125987568
106
87
  @agent.get("https://dl-web.dropbox.com/get/#{path}").content
107
88
  end
108
-
89
+
90
+ alias :get :show
91
+
92
+ # Creates a directory
109
93
  def create_directory(new_path, destination = "/" )
110
94
  # change to before filter
111
95
  login unless @logged_in
112
96
  destination = namespace_path(destination)
113
- @agent.post("/cmd/new#{destination}",{"to_path"=>new_path, "folder"=>"yes", "t" => @token })
114
- # check status code
97
+ @agent.post("/cmd/new#{destination}",{"to_path"=>new_path, "folder"=>"yes", "t" => @token }).code == "200"
115
98
  end
116
99
 
100
+ # Uploads a file to DropBox under the given filename
117
101
  def create(file, destination = "/")
118
102
  # change to before filter
119
103
  if @logged_in
@@ -122,39 +106,44 @@ class DropBox
122
106
  home_page = login
123
107
  end
124
108
 
125
- destination = namespace_path(destination)
126
-
127
109
  upload_form = home_page.forms.detect{ |f| f.action == "https://dl-web.dropbox.com/upload" }
128
- upload_form.dest = "/#{@folder_namespace}/#{destination}"
110
+ upload_form.dest = namespace_path(destination)
129
111
  upload_form.file_uploads.first.file_name = file if file
130
112
 
131
- @agent.submit(upload_form)
132
- end
133
-
134
- def update(file, destination = "/")
135
- create(file, destination)
113
+ @agent.submit(upload_form).code == "200"
136
114
  end
137
115
 
116
+ alias :update :create
117
+
118
+ # Renames a file or folder in the DropBox
138
119
  def rename(file, destination)
139
120
  login_filter
140
121
  file = namespace_path(file)
141
122
  destination = namespace_path(destination)
142
- @agent.post("/cmd/rename#{file}", {"to_path"=> destination, "t" => @token })
123
+ @agent.post("/cmd/rename#{file}", {"to_path"=> destination, "t" => @token }).code == "200"
143
124
  end
144
125
 
126
+ # Deletes a file/folder from the DropBox (accepts string path or an array of string paths)
145
127
  def destroy(paths)
146
128
  login_filter
147
129
  paths = [paths].flatten
148
130
  paths = paths.collect { |path| namespace_path(path) }
149
- @agent.post("/cmd/delete", {"files"=> paths, "t" => @token })
131
+ @agent.post("/cmd/delete", {"files"=> paths, "t" => @token }).code == "200"
150
132
  end
151
133
 
134
+ # Permanently deletes a file from the DropBox (no history!) accepts arrays, as #destroy does
152
135
  def purge(paths)
153
136
  login_filter
154
137
  paths = [paths].flatten
155
138
  paths = paths.collect { |path| namespace_path(path) }
156
- @agent.post("/cmd/purge", {"files"=> paths, "t" => @token })
139
+ @agent.post("/cmd/purge", {"files"=> paths, "t" => @token }).code == "200"
157
140
  end
141
+
142
+ # Will give a hash of the amount of space left on the DropBox, the amound used, the calculated amount free (all as a 1 d.p. rounded GB value) and the percentage used (scraped)
143
+ def usage_stats
144
+ login_filter
145
+ @agent.get("/account").at('#usage-percent').content.scan(/(\d+(?:\.\d+)?)%\ used\ \((\d+(?:\.\d+)?)([MG])B of (\d+(?:\.\d+)?)GB\)/).collect{|d| {:used => d[1].to_f * ((d[2] == "M") ? 1024 : 1), :total => d[3].to_f, :free => (d[3].to_f - d[1].to_f * ((d[2] == "M") ? 1024 : 1)), :percent => Percentage.new(d[0].to_f/100)} }[0]
146
+ end
158
147
 
159
148
  private
160
149
  def namespace_path(path)
@@ -171,4 +160,27 @@ class DropBox
171
160
  file.gsub(/^\/#{@folder_namespace}/,"")
172
161
  end
173
162
 
174
- end
163
+ def login
164
+ page = @agent.get('https://www.dropbox.com/login')
165
+ login_form = page.forms.detect { |f| f.action == "/login" }
166
+ login_form.login_email = @email
167
+ login_form.login_password = @password
168
+
169
+ home_page = @agent.submit(login_form)
170
+ # todo check if we are logged in! (ie search for email and "Log out"
171
+ @logged_in = true
172
+ @token = home_page.at('//script[contains(text(), "TOKEN")]').content.match("TOKEN: '(.*)',$")[1]
173
+
174
+ # check if we have our namespace
175
+
176
+ home_page
177
+ end
178
+
179
+ def login_filter
180
+ login unless @logged_in
181
+ end
182
+ end
183
+
184
+ # this file doesn't use the standard ruby indent settings, so the following
185
+ # modeline will make sure that the whitespace stays consistent.
186
+ # vim:noexpandtab tabstop=4 shiftwidth=4
metadata CHANGED
@@ -1,55 +1,79 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dropbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 5
9
+ version: 0.0.5
5
10
  platform: ruby
6
- authors: []
7
-
11
+ authors:
12
+ - Tys von Gaza
13
+ - JP Hastings-Spital
14
+ - Chris Searle
15
+ - Nicholas A. Evans
8
16
  autorequire:
9
17
  bindir: bin
10
18
  cert_chain: []
11
19
 
12
- date: 2010-01-06 00:00:00 +01:00
20
+ date: 2010-03-04 00:00:00 -07:00
13
21
  default_executable:
14
22
  dependencies:
15
23
  - !ruby/object:Gem::Dependency
16
- name: nokogiri
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
24
+ name: Shoulda
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
20
27
  requirements:
21
28
  - - ">="
22
29
  - !ruby/object:Gem::Version
30
+ segments:
31
+ - 0
23
32
  version: "0"
24
- version:
33
+ type: :development
34
+ version_requirements: *id001
25
35
  - !ruby/object:Gem::Dependency
26
36
  name: mechanize
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ version: "0"
27
45
  type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: nokogiri
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
30
51
  requirements:
31
52
  - - ">="
32
53
  - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
33
56
  version: "0"
34
- version:
35
- description: |
36
- A simple Ruby API for DropBox
37
-
38
- email: ""
57
+ type: :runtime
58
+ version_requirements: *id003
59
+ description: A Simple DropBox API in Ruby
60
+ email: tys@tvg.ca
39
61
  executables: []
40
62
 
41
63
  extensions: []
42
64
 
43
65
  extra_rdoc_files:
44
- - README
66
+ - README.markdown
45
67
  files:
46
- - README
68
+ - .gitignore
69
+ - README.markdown
47
70
  - Rakefile
48
71
  - VERSION
72
+ - examples/dropbox_spec.rb
49
73
  - lib/dropbox.rb
50
74
  - lib/dropbox/dropbox.rb
51
75
  has_rdoc: true
52
- homepage: ""
76
+ homepage: http://github.com/tvongaza/DropBox
53
77
  licenses: []
54
78
 
55
79
  post_install_message:
@@ -61,20 +85,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
61
85
  requirements:
62
86
  - - ">="
63
87
  - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
64
90
  version: "0"
65
- version:
66
91
  required_rubygems_version: !ruby/object:Gem::Requirement
67
92
  requirements:
68
93
  - - ">="
69
94
  - !ruby/object:Gem::Version
95
+ segments:
96
+ - 0
70
97
  version: "0"
71
- version:
72
98
  requirements: []
73
99
 
74
100
  rubyforge_project:
75
- rubygems_version: 1.3.5
101
+ rubygems_version: 1.3.6
76
102
  signing_key:
77
103
  specification_version: 3
78
- summary: A simple Ruby API for DropBox
79
- test_files: []
80
-
104
+ summary: A Simple DropBox API in Ruby
105
+ test_files:
106
+ - examples/dropbox_spec.rb
data/README DELETED
@@ -1,3 +0,0 @@
1
- A simple Ruby API for DropBox
2
-
3
- Install with: gem install dropbox (using gemcutter as source)