droxi 0.0.0 → 0.0.1

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: c42bb596852aacff40852b70646a1a74c49930ff
4
- data.tar.gz: a1cae76af97bc5064f2ee567035d5a50c6e768c9
3
+ metadata.gz: 9e5303c28f4ee1e364769a554be98314b4c3c953
4
+ data.tar.gz: 5170d5affcbf11282c0a2c8e305c0c553ca961b6
5
5
  SHA512:
6
- metadata.gz: 1a4b91bca5b16d9bc98b3ab37fde5e5404ec86eb8ffc0f28426657a6555882efa34849b020c410205665044a4e2abe34bce85928e011d5d13b4417a2debe2486
7
- data.tar.gz: b5fa9257afa11b305124d823efa38dc32c3c8fffc577a094ce6f0b249bccdce1d89f8f95cf4e28114da916a074782c94a96503be0b84d8ec4449c44fe42436b5
6
+ metadata.gz: 335e2e4caa00193fb73a0f912ac819ba23b677ba42bb0185de8a143fc7fdb98bf9c5d51724df7ef7da4bd238b231e052f13b686ea17c52f0da4960a947aef294
7
+ data.tar.gz: ea91d29b4b67e3384f3605bb884f4ea07edb828bf6fac7e3c084d6e7320af748c9af878f378330dfd5b81cec1a92c4bd0f0a8f07113be46a61f65f6f4751d040
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2014 Brandon Mulcahy
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ droxi
2
+ =====
3
+
4
+ ftp-like command-line [Dropbox](https://www.dropbox.com/home) interface in
5
+ [Ruby](https://www.ruby-lang.org/en/)
6
+
7
+ installation
8
+ ------------
9
+
10
+ gem install droxi
11
+
12
+ features
13
+ --------
14
+
15
+ - interface inspired by
16
+ [GNU coreutils](http://www.gnu.org/software/coreutils/),
17
+ [GNU ftp](http://www.gnu.org/software/inetutils/), and
18
+ [lftp](http://lftp.yar.ru/)
19
+ - context-sensitive tab completion and path globbing
20
+ - upload, download, and share files
21
+ - man page and interactive help
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ task :default => :test
2
+
3
+ desc 'run unit tests'
4
+ task :test do
5
+ sh 'ruby spec/all.rb'
6
+ end
7
+
8
+ desc 'run program'
9
+ task :run do
10
+ require_relative 'lib/droxi'
11
+ Droxi.run
12
+ end
13
+
14
+ desc 'install gem'
15
+ task :gem do
16
+ sh 'rm *.gem'
17
+ sh 'gem build droxi.gemspec'
18
+ sh 'gem install ./droxi-*.gem'
19
+ end
20
+
21
+ desc 'install man page (must have root permissions)'
22
+ task :man do
23
+ gemspec = IO.read('droxi.gemspec')
24
+
25
+ def date(gemspec)
26
+ require 'time'
27
+ Time.parse(/\d{4}-\d{2}-\d{2}/.match(gemspec)[0]).strftime('%B %Y')
28
+ end
29
+
30
+ def commands
31
+ require_relative 'lib/droxi/commands'
32
+ Commands::NAMES.sort.map do |name|
33
+ cmd = Commands.const_get(name.upcase.to_sym)
34
+ ".TP\n#{cmd.usage}\n#{cmd.description}\n"
35
+ end.join.strip
36
+ end
37
+
38
+ contents = IO.read('droxi.1.template').
39
+ sub('{date}', date(gemspec)).
40
+ sub('{version}', /\d+\.\d+\.\d+/.match(gemspec)[0]).
41
+ sub('{commands}', commands)
42
+
43
+ Dir.mkdir('build') unless Dir.exists?('build')
44
+ IO.write('build/droxi.1', contents)
45
+
46
+ prefix = ENV['PREFIX'] || ENV['prefix'] || '/usr/local'
47
+ install_path = "#{prefix}/share/man/man1"
48
+
49
+ require 'fileutils'
50
+ begin
51
+ FileUtils.mkdir_p(install_path)
52
+ FileUtils.cp('build/droxi.1', install_path)
53
+ rescue
54
+ puts 'Failed to install man page. This target must be run as root.'
55
+ end
56
+ end
data/droxi.1.template ADDED
@@ -0,0 +1,9 @@
1
+ .TH DROXI 1 "{date}" "droxi {version}"
2
+ .SH NAME
3
+ droxi \- ftp-like command-line interface to Dropbox
4
+ .SH SYNOPSIS
5
+ droxi
6
+ .SH COMMANDS
7
+ {commands}
8
+ .SH AUTHOR
9
+ Written by Brandon Mulcahy (brandon@jangler.info).
data/droxi.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'droxi'
3
+ s.version = '0.0.1'
4
+ s.date = '2014-06-02'
5
+ s.summary = 'ftp-like command-line interface to Dropbox'
6
+ s.description = "a command-line Dropbox interface inspired by GNU \
7
+ coreutils, GNU ftp, and lftp. features smart tab \
8
+ completion, globbing, and interactive help.".squeeze(' ')
9
+ s.authors = ['Brandon Mulcahy']
10
+ s.email = 'brandon@jangler.info'
11
+ s.files = `git ls-files`.split
12
+ s.homepage = 'https://github.com/jangler/droxi'
13
+ s.license = 'MIT'
14
+
15
+ s.executables << 'droxi'
16
+ s.add_runtime_dependency 'dropbox-sdk', '~> 1.6', '>= 1.6.1'
17
+ s.required_ruby_version = '>= 2.0.0'
18
+ end
data/lib/droxi.rb CHANGED
@@ -19,7 +19,13 @@ module Droxi
19
19
  puts '2. Click "Allow" (you might have to log in first)'
20
20
  puts '3. Copy the authorization code'
21
21
  print 'Enter the authorization code here: '
22
- code = gets.strip
22
+ code = $stdin.gets
23
+ if code
24
+ code.strip!
25
+ else
26
+ puts
27
+ exit
28
+ end
23
29
 
24
30
  # This will fail if the user gave us an invalid authorization code
25
31
  begin
@@ -128,10 +134,11 @@ module Droxi
128
134
  end
129
135
 
130
136
  begin
131
- while line = Readline.readline(prompt(info, state), true)
137
+ while !state.exit_requested &&
138
+ line = Readline.readline(prompt(info, state), true)
132
139
  Commands.exec(line.chomp, client, state)
133
140
  end
134
- puts
141
+ puts if !line
135
142
  rescue Interrupt
136
143
  puts
137
144
  end
@@ -25,7 +25,9 @@ module Commands
25
25
  def num_args_ok?(num_args)
26
26
  args = @usage.split.drop(1)
27
27
  min_args = args.reject { |arg| arg.start_with?('[') }.length
28
- if args.last.end_with?('...')
28
+ if args.empty?
29
+ max_args = 0
30
+ elsif args.last.end_with?('...')
29
31
  max_args = num_args
30
32
  else
31
33
  max_args = args.length
@@ -62,6 +64,14 @@ module Commands
62
64
  end
63
65
  )
64
66
 
67
+ EXIT = Command.new(
68
+ 'exit',
69
+ "Exit the program.",
70
+ lambda do |client, state, args, output|
71
+ state.exit_requested = true
72
+ end
73
+ )
74
+
65
75
  GET = Command.new(
66
76
  'get REMOTE_FILE...',
67
77
  "Download each specified remote file to a file of the same name in the \
@@ -220,9 +230,10 @@ module Commands
220
230
 
221
231
  SHARE = Command.new(
222
232
  'share REMOTE_FILE...',
223
- "Get URLs to share remote files. Shareable links created on Dropbox are \
224
- time-limited, but don't require any authentication, so they can be given \
225
- out freely. The time limit should allow at least a day of shareability.",
233
+ "Create Dropbox links to publicly share remote files. The links are \
234
+ shortened and direct to 'preview' pages of the files. Links created by \
235
+ this method are set to expire far enough in the future so that \
236
+ expiration is effectively not an issue.",
226
237
  lambda do |client, state, args, output|
227
238
  state.expand_patterns(client, args).each do |path|
228
239
  begin
data/lib/droxi/state.rb CHANGED
@@ -2,13 +2,14 @@ require_relative 'settings'
2
2
 
3
3
  class State
4
4
  attr_reader :oldpwd, :pwd, :cache
5
- attr_accessor :local_oldpwd
5
+ attr_accessor :local_oldpwd, :exit_requested
6
6
 
7
7
  def initialize
8
8
  @pwd = '/'
9
9
  @oldpwd = Settings[:oldpwd] || '/'
10
10
  @local_oldpwd = Dir.pwd
11
11
  @cache = {}
12
+ @exit_requested = false
12
13
  end
13
14
 
14
15
  def have_all_info_for(path)
data/spec/all.rb ADDED
@@ -0,0 +1,4 @@
1
+ # Run all spec tests
2
+ Dir.glob('spec/*_spec.rb').each do |spec|
3
+ require_relative File.basename(spec, '.rb')
4
+ end
@@ -0,0 +1,206 @@
1
+ require 'dropbox_sdk'
2
+ require 'minitest/autorun'
3
+
4
+ require_relative '../lib/droxi/commands'
5
+ require_relative '../lib/droxi/settings'
6
+ require_relative '../lib/droxi/state'
7
+
8
+ def ignore(error_class)
9
+ begin
10
+ yield
11
+ rescue error_class
12
+ end
13
+ end
14
+
15
+ def put_temp_file(client, state)
16
+ `echo hello > #{TEMP_FILENAME}`
17
+ open(TEMP_FILENAME, 'rb') do |file|
18
+ Commands::PUT.exec(client, state, TEMP_FILENAME,
19
+ "/#{TEST_FOLDER}/#{TEMP_FILENAME}")
20
+ end
21
+ `rm #{TEMP_FILENAME}`
22
+ end
23
+
24
+ def delete_temp_file(client, state)
25
+ Commands::RM.exec(client, state, "/#{TEST_FOLDER}/#{TEMP_FILENAME}")
26
+ end
27
+
28
+ def get_output(cmd, client, state, *args)
29
+ lines = []
30
+ Commands.const_get(cmd).exec(client, state, *args) { |line| lines << line }
31
+ lines
32
+ end
33
+
34
+ describe Commands do
35
+ original_dir = Dir.pwd
36
+
37
+ client = DropboxClient.new(Settings[:access_token])
38
+ state = State.new
39
+
40
+ TEMP_FILENAME = 'test.txt'
41
+ TEMP_FOLDER = 'test'
42
+ TEST_FOLDER = 'testing'
43
+
44
+ ignore(DropboxError) { client.file_delete("/#{TEST_FOLDER}") }
45
+ ignore(DropboxError) { client.file_create_folder("/#{TEST_FOLDER}") }
46
+
47
+ describe 'when executing a shell command' do
48
+ it 'must yield the output' do
49
+ lines = []
50
+ Commands.shell('echo testing') { |line| lines << line }
51
+ lines.must_equal(['testing'])
52
+ end
53
+ end
54
+
55
+ describe 'when executing the cd command' do
56
+ it 'must change to the root directory when given no args' do
57
+ state.pwd = '/testing'
58
+ Commands::CD.exec(client, state)
59
+ state.pwd.must_equal '/'
60
+ end
61
+
62
+ it 'must change to the previous directory when given -' do
63
+ state.pwd = '/testing'
64
+ state.pwd = '/'
65
+ Commands::CD.exec(client, state, '-')
66
+ state.pwd.must_equal '/testing'
67
+ end
68
+
69
+ it 'must change to the stated directory when given 1 arg' do
70
+ state.pwd = '/'
71
+ Commands::CD.exec(client, state, '/testing')
72
+ state.pwd.must_equal '/testing'
73
+ end
74
+
75
+ it 'must set previous directory correctly' do
76
+ state.pwd = '/testing'
77
+ state.pwd = '/'
78
+ Commands::CD.exec(client, state, '/testing')
79
+ state.oldpwd.must_equal '/'
80
+ end
81
+
82
+ it 'must not change to a bogus directory' do
83
+ state.pwd = '/'
84
+ Commands::CD.exec(client, state, '/bogus_dir')
85
+ state.pwd.must_equal '/'
86
+ end
87
+ end
88
+
89
+ describe 'when executing the get command' do
90
+ it 'must get a file of the same name when given args' do
91
+ Dir.chdir(original_dir)
92
+ put_temp_file(client, state)
93
+ Commands::GET.exec(client, state, '/testing/test.txt')
94
+ delete_temp_file(client, state)
95
+ `ls test.txt`.chomp.must_equal 'test.txt'
96
+ `rm test.txt`
97
+ end
98
+ end
99
+
100
+ describe 'when executing the lcd command' do
101
+ it 'must change to home directory when given no args' do
102
+ Dir.chdir(original_dir)
103
+ Commands::LCD.exec(client, state)
104
+ Dir.pwd.must_equal File.expand_path('~')
105
+ end
106
+
107
+ it 'must change to specific directory when specified' do
108
+ Dir.chdir(original_dir)
109
+ Commands::LCD.exec(client, state, '/home')
110
+ Dir.pwd.must_equal File.expand_path('/home')
111
+ end
112
+
113
+ it 'must set oldpwd correctly' do
114
+ Dir.chdir(original_dir)
115
+ oldpwd = Dir.pwd
116
+ Commands::LCD.exec(client, state, '/')
117
+ state.local_oldpwd.must_equal oldpwd
118
+ end
119
+
120
+ it 'must change to previous directory when given -' do
121
+ Dir.chdir(original_dir)
122
+ oldpwd = Dir.pwd
123
+ Commands::LCD.exec(client, state, '/')
124
+ Commands::LCD.exec(client, state, '-')
125
+ Dir.pwd.must_equal oldpwd
126
+ end
127
+
128
+ it 'must fail if given bogus directory name' do
129
+ Dir.chdir(original_dir)
130
+ pwd = Dir.pwd
131
+ oldpwd = state.local_oldpwd
132
+ Commands::LCD.exec(client, state, '/bogus_dir')
133
+ Dir.pwd.must_equal pwd
134
+ state.local_oldpwd.must_equal oldpwd
135
+ end
136
+ end
137
+
138
+ describe 'when executing the ls command' do
139
+ it 'must list the working directory contents when given no args' do
140
+ Commands::MKDIR.exec(client, state, '/testing/test')
141
+ state.pwd = '/testing'
142
+ lines = []
143
+ Commands::LS.exec(client, state) { |line| lines << line }
144
+ lines.must_equal(['test '])
145
+ Commands::RM.exec(client, state, '/testing/test')
146
+ end
147
+
148
+ it 'must list the stated directory contents when given args' do
149
+ state.pwd = '/'
150
+ Commands::MKDIR.exec(client, state, '/testing/test')
151
+ lines = []
152
+ Commands::LS.exec(client, state, '/testing') { |line| lines << line }
153
+ lines.must_equal(['test '])
154
+ Commands::RM.exec(client, state, '/testing/test')
155
+ end
156
+ end
157
+
158
+ describe 'when executing the mkdir command' do
159
+ it 'must create a directory when given args' do
160
+ Commands::MKDIR.exec(client, state, '/testing/test')
161
+ client.metadata('/testing/test')['is_deleted'].wont_equal true
162
+ Commands::RM.exec(client, state, '/testing/test')
163
+ end
164
+ end
165
+
166
+ describe 'when executing the put command' do
167
+ it 'must put a file of the same name when given 1 arg' do
168
+ Dir.chdir(original_dir)
169
+ state.pwd = '/testing'
170
+ `echo hello > test.txt`
171
+ Commands::PUT.exec(client, state, 'test.txt')
172
+ `rm test.txt`
173
+ client.metadata('/testing/test.txt')['is_deleted'].wont_equal true
174
+ Commands::RM.exec(client, state, '/testing/test.txt')
175
+ end
176
+
177
+ it 'must put a file with the stated name when given 2 args' do
178
+ Dir.chdir(original_dir)
179
+ state.pwd = '/testing'
180
+ `echo hello > test.txt`
181
+ Commands::PUT.exec(client, state, 'test.txt', 'dest.txt')
182
+ `rm test.txt`
183
+ client.metadata('/testing/dest.txt')['is_deleted'].wont_equal true
184
+ Commands::RM.exec(client, state, '/testing/dest.txt')
185
+ end
186
+ end
187
+
188
+ describe 'when executing the share command' do
189
+ it 'must yield URL when given file path' do
190
+ put_temp_file(client, state)
191
+ to_path = "/#{TEST_FOLDER}/#{TEMP_FILENAME}"
192
+ lines = get_output(:SHARE, client, state, to_path)
193
+ delete_temp_file(client, state)
194
+ lines.length.must_equal 1
195
+ /https:\/\/.+\..+\//.match(lines[0]).wont_equal nil
196
+ end
197
+ end
198
+
199
+ describe 'when executing the rm command' do
200
+ it 'must remove the remote file when given args' do
201
+ Commands::MKDIR.exec(client, state, '/testing/test')
202
+ Commands::RM.exec(client, state, '/testing/test')
203
+ client.metadata('/testing/test')['is_deleted'].must_equal true
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,56 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../lib/droxi/settings'
4
+
5
+ describe Settings do
6
+ KEY, VALUE = :test_key, :test_value
7
+
8
+ describe 'when attempting access with a bogus key' do
9
+ it 'must return nil' do
10
+ Settings.delete(KEY)
11
+ Settings[KEY].must_equal nil
12
+ end
13
+ end
14
+
15
+ describe 'when attempting access with a valid key' do
16
+ it 'must return the associated value' do
17
+ Settings[KEY] = VALUE
18
+ Settings[KEY].must_equal VALUE
19
+ end
20
+ end
21
+
22
+ describe 'when assigning a value to a key' do
23
+ it 'must assign the value to the key and return the value' do
24
+ Settings.delete(KEY)
25
+ (Settings[KEY] = VALUE).must_equal VALUE
26
+ Settings[KEY].must_equal VALUE
27
+ end
28
+ end
29
+
30
+ describe 'when deleting a bogus key' do
31
+ it 'must return nil' do
32
+ Settings.delete(KEY)
33
+ Settings.delete(KEY).must_equal nil
34
+ end
35
+ end
36
+
37
+ describe 'when deleting a valid key' do
38
+ it 'must delete the key and return the associated value' do
39
+ Settings[KEY] = VALUE
40
+ Settings.delete(KEY).must_equal VALUE
41
+ Settings[KEY].must_equal nil
42
+ end
43
+ end
44
+
45
+ describe 'when checking inclusion of a key' do
46
+ it 'must return true for valid keys' do
47
+ Settings[KEY] = VALUE
48
+ Settings.include?(KEY).must_equal true
49
+ end
50
+
51
+ it 'must return false for bogus keys' do
52
+ Settings.delete(KEY)
53
+ Settings.include?(KEY).must_equal false
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,51 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../lib/droxi/state'
4
+ require_relative '../lib/droxi/settings'
5
+
6
+ describe State do
7
+ describe 'when initializing' do
8
+ it 'must set pwd to root' do
9
+ State.new.pwd.must_equal '/'
10
+ end
11
+
12
+ it 'must set oldpwd to saved oldpwd' do
13
+ if Settings.include?(:oldpwd)
14
+ State.new.oldpwd.must_equal Settings[:oldpwd]
15
+ end
16
+ end
17
+ end
18
+
19
+ describe 'when setting pwd' do
20
+ it 'must change pwd and set oldpwd to previous pwd' do
21
+ state = State.new
22
+ state.pwd = '/testing'
23
+ state.pwd.must_equal '/testing'
24
+ state.pwd = '/'
25
+ state.oldpwd.must_equal '/testing'
26
+ end
27
+ end
28
+
29
+ describe 'when resolving path' do
30
+ state = State.new
31
+
32
+ it 'must resolve root to itself' do
33
+ state.resolve_path('/').must_equal '/'
34
+ end
35
+
36
+ it 'must resolve qualified path to itself' do
37
+ state.pwd = '/alpha'
38
+ state.resolve_path('/beta').must_equal '/beta'
39
+ end
40
+
41
+ it 'must resolve unqualified path to relative path' do
42
+ state.pwd = '/alpha'
43
+ state.resolve_path('beta').must_equal '/alpha/beta'
44
+ end
45
+
46
+ it 'must resolve .. to upper directory' do
47
+ state.pwd = '/alpha/beta/gamma'
48
+ state.resolve_path('../..').must_equal '/alpha'
49
+ end
50
+ end
51
+ end
metadata CHANGED
@@ -1,41 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: droxi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Mulcahy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-01 00:00:00.000000000 Z
11
+ date: 2014-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: dropbox_sdk
14
+ name: dropbox-sdk
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
17
20
  - - ">="
18
21
  - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
22
+ version: 1.6.1
23
+ type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
24
30
  - - ">="
25
31
  - !ruby/object:Gem::Version
26
- version: '0'
27
- description: ftp-like command-line interface to Dropbox
32
+ version: 1.6.1
33
+ description: a command-line Dropbox interface inspired by GNU coreutils, GNU ftp,
34
+ and lftp. features smart tab completion, globbing, and interactive help.
28
35
  email: brandon@jangler.info
29
36
  executables:
30
37
  - droxi
31
38
  extensions: []
32
39
  extra_rdoc_files: []
33
40
  files:
41
+ - LICENSE
42
+ - README.md
43
+ - Rakefile
34
44
  - bin/droxi
45
+ - droxi.1.template
46
+ - droxi.gemspec
35
47
  - lib/droxi.rb
36
48
  - lib/droxi/commands.rb
37
49
  - lib/droxi/settings.rb
38
50
  - lib/droxi/state.rb
51
+ - spec/all.rb
52
+ - spec/commands_spec.rb
53
+ - spec/settings_spec.rb
54
+ - spec/state_spec.rb
39
55
  homepage: https://github.com/jangler/droxi
40
56
  licenses:
41
57
  - MIT
@@ -48,7 +64,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
48
64
  requirements:
49
65
  - - ">="
50
66
  - !ruby/object:Gem::Version
51
- version: '0'
67
+ version: 2.0.0
52
68
  required_rubygems_version: !ruby/object:Gem::Requirement
53
69
  requirements:
54
70
  - - ">="
@@ -59,5 +75,5 @@ rubyforge_project:
59
75
  rubygems_version: 2.2.2
60
76
  signing_key:
61
77
  specification_version: 4
62
- summary: droxi
78
+ summary: ftp-like command-line interface to Dropbox
63
79
  test_files: []