dropbox 0.0.2 → 0.0.5
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/.gitignore +3 -0
- data/README.markdown +10 -0
- data/Rakefile +25 -12
- data/VERSION +1 -1
- data/examples/dropbox_spec.rb +98 -0
- data/lib/dropbox.rb +14 -1
- data/lib/dropbox/dropbox.rb +60 -48
- metadata +51 -25
- data/README +0 -3
data/.gitignore
ADDED
data/README.markdown
ADDED
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
gem.
|
13
|
-
gem.
|
14
|
-
gem.
|
15
|
-
gem.
|
16
|
-
|
17
|
-
gem.add_dependency
|
18
|
-
gem.add_dependency
|
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
|
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.
|
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
|
+
|
data/lib/dropbox/dropbox.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'nokogiri'
|
3
2
|
require 'mechanize'
|
4
3
|
|
5
|
-
|
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 =
|
15
|
+
@agent = Mechanize.new
|
17
16
|
@folder_namespace = folder_namespace.gsub(/^\//,"")
|
18
17
|
@logged_in = false
|
19
18
|
end
|
20
19
|
|
21
|
-
|
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
|
-
|
37
|
+
elsif match_data = details['url'].match(%r{^https?://[^/]*/get(.*)$})
|
62
38
|
details['directory'] = false
|
63
|
-
details['path'] = normalize_namespace(
|
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 =
|
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
|
-
|
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
|
-
|
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-
|
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:
|
17
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
-
|
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.
|
101
|
+
rubygems_version: 1.3.6
|
76
102
|
signing_key:
|
77
103
|
specification_version: 3
|
78
|
-
summary: A
|
79
|
-
test_files:
|
80
|
-
|
104
|
+
summary: A Simple DropBox API in Ruby
|
105
|
+
test_files:
|
106
|
+
- examples/dropbox_spec.rb
|
data/README
DELETED