droxi 0.0.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7475e5467fb8a2cce45ca783361e37dcfe2f2361
4
- data.tar.gz: 71a443989f3ef75df19997850f865fef2bac27fe
3
+ metadata.gz: ed8c5f6d9c0df8aff83fc755d298fda9dda25adf
4
+ data.tar.gz: f882a46c0a98a0f4f69cb88f3610fc403abc23e3
5
5
  SHA512:
6
- metadata.gz: 20b0e20d19722a326203d48a5b5232203c88ebeecb809c94e084ebb223de4c97a756de512959e667d6dca5224e71ef82d587f1870d215fc75b795a16ff9edff3
7
- data.tar.gz: 09afb109d29dd70c2d77add8a3557a9442f58cb02deda624731022bf4eb73ad500e9d2ebe2876bf7115b7a690fd16d74e144f8e7f58801e27c187523b6191c9e
6
+ metadata.gz: c5cbb62624375b1515ff9e7de15167ead211bb535dd427a87954c3a585865e5d25ba90236a0f717c4a491b307d6bbb01fdd430dbee3c4edfaf43e8c49a30b3da
7
+ data.tar.gz: 4c9b4bc88008c441cb8f7284be5c90470b147233f134dceb035e9dc681e3ce303168220ecfdea5deb27f2bac94fad43109aeb52b3da18d23bafa730ba8b5580d
data/droxi.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'droxi'
3
- s.version = '0.0.4'
4
- s.date = '2014-06-03'
3
+ s.version = '0.0.5'
4
+ s.date = '2014-06-04'
5
5
  s.summary = 'ftp-like command-line interface to Dropbox'
6
6
  s.description = "A command-line Dropbox interface inspired by GNU \
7
7
  coreutils, GNU ftp, and lftp. Features include smart tab \
@@ -59,12 +59,14 @@ module Commands
59
59
 
60
60
  private
61
61
 
62
+ # Return +true+ if the given number of arguments is acceptable for the
63
+ # command, +false+ otherwise.
62
64
  def num_args_ok?(num_args)
63
65
  args = @usage.split.drop(1)
64
66
  min_args = args.reject { |arg| arg.start_with?('[') }.length
65
67
  if args.empty?
66
68
  max_args = 0
67
- elsif args.last.end_with?('...')
69
+ elsif args.any? { |arg| arg.end_with?('...') }
68
70
  max_args = num_args
69
71
  else
70
72
  max_args = args.length
@@ -96,6 +98,18 @@ module Commands
96
98
  end
97
99
  )
98
100
 
101
+ # Copy remote files.
102
+ CP = Command.new(
103
+ 'cp REMOTE_FILE... REMOTE_FILE',
104
+ "When given two arguments, copies the remote file or folder at the first \
105
+ path to the second path. When given more than two arguments or when the \
106
+ final argument is a directory, copies each remote file or folder into \
107
+ that directory.",
108
+ lambda do |client, state, args, output|
109
+ cp_mv(client, state, args, output, 'cp', :file_copy)
110
+ end
111
+ )
112
+
99
113
  # Terminate the session.
100
114
  EXIT = Command.new(
101
115
  'exit',
@@ -132,14 +146,12 @@ module Commands
132
146
  if path.is_a?(GlobError)
133
147
  output.call("get: #{path}: No such file or directory")
134
148
  else
135
- begin
149
+ try_and_handle(DropboxError, output) do
136
150
  contents = client.get_file(path)
137
151
  File.open(File.basename(path), 'wb') do |file|
138
152
  file.write(contents)
139
153
  end
140
154
  output.call("#{File.basename(path)} <- #{path}")
141
- rescue DropboxError => error
142
- output.call(error.to_s)
143
155
  end
144
156
  end
145
157
  end
@@ -240,11 +252,9 @@ module Commands
240
252
  if path.is_a?(GlobError)
241
253
  output.call("media: #{path}: No such file or directory")
242
254
  else
243
- begin
255
+ try_and_handle(DropboxError, output) do
244
256
  url = client.media(path)['url']
245
257
  output.call("#{File.basename(path)} -> #{url}")
246
- rescue DropboxError => error
247
- output.call(error.to_s)
248
258
  end
249
259
  end
250
260
  end
@@ -257,16 +267,26 @@ module Commands
257
267
  "Create remote directories.",
258
268
  lambda do |client, state, args, output|
259
269
  args.each do |arg|
260
- begin
270
+ try_and_handle(DropboxError, output) do
261
271
  path = state.resolve_path(arg)
262
272
  state.cache[path] = client.file_create_folder(path)
263
- rescue DropboxError => error
264
- output.call(error.to_s)
265
273
  end
266
274
  end
267
275
  end
268
276
  )
269
277
 
278
+ # Move/rename remote files.
279
+ MV = Command.new(
280
+ 'mv REMOTE_FILE... REMOTE_FILE',
281
+ "When given two arguments, moves the remote file or folder at the first \
282
+ path to the second path. When given more than two arguments or when the \
283
+ final argument is a directory, moves each remote file or folder into \
284
+ that directory.",
285
+ lambda do |client, state, args, output|
286
+ cp_mv(client, state, args, output, 'mv', :file_move)
287
+ end
288
+ )
289
+
270
290
  # Upload a local file.
271
291
  PUT = Command.new(
272
292
  'put LOCAL_FILE [REMOTE_FILE]',
@@ -283,14 +303,12 @@ module Commands
283
303
  end
284
304
  to_path = state.resolve_path(to_path)
285
305
 
286
- begin
306
+ try_and_handle(Exception, output) do
287
307
  File.open(File.expand_path(from_path), 'rb') do |file|
288
308
  data = client.put_file(to_path, file)
289
309
  state.cache[data['path']] = data
290
310
  output.call("#{from_path} -> #{data['path']}")
291
311
  end
292
- rescue Exception => error
293
- output.call(error.to_s)
294
312
  end
295
313
  end
296
314
  )
@@ -304,14 +322,13 @@ module Commands
304
322
  if path.is_a?(GlobError)
305
323
  output.call("rm: #{path}: No such file or directory")
306
324
  else
307
- begin
325
+ try_and_handle(DropboxError, output) do
308
326
  client.file_delete(path)
309
- state.cache.delete(path)
310
- rescue DropboxError => error
311
- output.call(error.to_s)
327
+ state.cache_remove(path)
312
328
  end
313
329
  end
314
330
  end
331
+ check_pwd(state)
315
332
  end
316
333
  )
317
334
 
@@ -327,11 +344,9 @@ module Commands
327
344
  if path.is_a?(GlobError)
328
345
  output.call("share: #{path}: No such file or directory")
329
346
  else
330
- begin
347
+ try_and_handle(DropboxError, output) do
331
348
  url = client.shares(path)['url']
332
349
  output.call("#{File.basename(path)} -> #{url}")
333
- rescue DropboxError => error
334
- output.call(error.to_s)
335
350
  end
336
351
  end
337
352
  end
@@ -356,6 +371,16 @@ module Commands
356
371
 
357
372
  private
358
373
 
374
+ # Attempt to run the associated block, handling the given type of +Exception+
375
+ # by passing its +String+ representation to an output +Proc+.
376
+ def self.try_and_handle(exception_class, output)
377
+ yield
378
+ rescue exception_class => error
379
+ output.call(error.to_s)
380
+ end
381
+
382
+ # Run a command with the given name, or print an error message if usage is
383
+ # incorrect or no such command exists.
359
384
  def self.try_command(command_name, args, client, state)
360
385
  if NAMES.include?(command_name)
361
386
  begin
@@ -369,6 +394,8 @@ module Commands
369
394
  end
370
395
  end
371
396
 
397
+ # Split a +String+ into tokens, allowing for backslash-escaped spaces, and
398
+ # return the resulting +Array+.
372
399
  def self.tokenize(string)
373
400
  string.split.reduce([]) do |list, token|
374
401
  list << if !list.empty? && list.last.end_with?('\\')
@@ -379,6 +406,7 @@ module Commands
379
406
  end
380
407
  end
381
408
 
409
+ # Return a +String+ of information about a remote file for ls -l.
382
410
  def self.long_info(state, path, name)
383
411
  meta = state.metadata(state.resolve_path(path), false)
384
412
  is_dir = meta['is_dir'] ? 'd' : '-'
@@ -388,6 +416,8 @@ module Commands
388
416
  "#{is_dir} #{size} #{mtime.strftime(format_str)} #{name}"
389
417
  end
390
418
 
419
+ # Yield lines of output for the ls command executed on the given file paths
420
+ # and names.
391
421
  def self.list(state, paths, names, long)
392
422
  if long
393
423
  paths.zip(names).each { |path, name| yield long_info(state, path, name) }
@@ -396,6 +426,7 @@ module Commands
396
426
  end
397
427
  end
398
428
 
429
+ # Run a command in the system shell and yield lines of output.
399
430
  def self.shell(cmd)
400
431
  IO.popen(cmd) do |pipe|
401
432
  pipe.each_line { |line| yield line.chomp if block_given? }
@@ -405,4 +436,54 @@ module Commands
405
436
  yield error.to_s if block_given?
406
437
  end
407
438
 
439
+ # Return an +Array+ of paths from an +Array+ of globs, passing error messages
440
+ # to the output +Proc+ for non-matches.
441
+ def self.expand(state, paths, preserve_root, output, cmd_name)
442
+ state.expand_patterns(paths, true).map do |item|
443
+ if item.is_a?(GlobError)
444
+ output.call("#{cmd_name}: #{item}: no such file or directory")
445
+ nil
446
+ else
447
+ item
448
+ end
449
+ end.compact
450
+ end
451
+
452
+ # Copies or moves the file at +source+ to +dest+ and passes a description of
453
+ # the operation to the output +Proc+.
454
+ def self.copy_move(method, source, dest, client, state, output)
455
+ from_path, to_path = [source, dest].map { |p| state.resolve_path(p) }
456
+ try_and_handle(DropboxError, output) do
457
+ metadata = client.send(method, from_path, to_path)
458
+ state.cache_remove(from_path) if method == :file_move
459
+ state.cache_add(metadata)
460
+ output.call("#{source} -> #{dest}")
461
+ end
462
+ end
463
+
464
+ # Execute a 'mv' or 'cp' operation depending on arguments given.
465
+ def self.cp_mv(client, state, args, output, cmd, method)
466
+ sources = expand(state, args.take(args.length - 1), true, output, cmd)
467
+ dest = state.resolve_path(args.last)
468
+
469
+ if sources.length == 1 && !state.directory?(dest)
470
+ copy_move(method, sources[0], args.last, client, state, output)
471
+ else
472
+ if state.metadata(dest)
473
+ sources.each do |source|
474
+ to_path = args.last.chomp('/') + '/' + File.basename(source)
475
+ copy_move(method, source, to_path, client, state, output)
476
+ end
477
+ else
478
+ output.call("#{cmd}: #{args.last}: no such directory")
479
+ end
480
+ end
481
+ end
482
+
483
+ # If the remote working directory does not exist, move up the directory
484
+ # tree until at a real location.
485
+ def self.check_pwd(state)
486
+ state.pwd = File.dirname(state.pwd) until state.metadata(state.pwd)
487
+ end
488
+
408
489
  end
@@ -11,7 +11,7 @@ module Complete
11
11
  end
12
12
  end
13
13
 
14
- # Returns an +Array+ of potential local tab-completions for a +String+.
14
+ # Return an +Array+ of potential local tab-completions for a +String+.
15
15
  def self.local(string)
16
16
  dir = local_search_path(string)
17
17
  name = string.end_with?('/') ? '' : File.basename(string)
@@ -24,7 +24,7 @@ module Complete
24
24
  end
25
25
  end
26
26
 
27
- # Returns an +Array+ of potential local tab-completions for a +String+,
27
+ # Return an +Array+ of potential local tab-completions for a +String+,
28
28
  # including only directories.
29
29
  def self.local_dir(string)
30
30
  local(string).select { |result| result.end_with?('/') }
@@ -42,7 +42,7 @@ module Complete
42
42
  strip_filename(collapse(path))
43
43
  end
44
44
 
45
- # Returns an +Array+ of potential remote tab-completions for a +String+.
45
+ # Return an +Array+ of potential remote tab-completions for a +String+.
46
46
  def self.remote(string, state)
47
47
  dir = remote_search_path(string, state)
48
48
  name = string.end_with?('/') ? '' : File.basename(string)
@@ -57,7 +57,7 @@ module Complete
57
57
  end
58
58
  end
59
59
 
60
- # Returns an +Array+ of potential remote tab-completions for a +String+,
60
+ # Return an +Array+ of potential remote tab-completions for a +String+,
61
61
  # including only directories.
62
62
  def self.remote_dir(string, state)
63
63
  remote(string, state).select { |result| result.end_with?('/') }
@@ -65,6 +65,7 @@ module Complete
65
65
 
66
66
  private
67
67
 
68
+ # Return the name of the directory indicated by a path.
68
69
  def self.strip_filename(path)
69
70
  if path != '/'
70
71
  path.end_with?('/') ? path.sub(/\/$/, '') : File.dirname(path)
@@ -73,10 +74,13 @@ module Complete
73
74
  end
74
75
  end
75
76
 
77
+ # Return a version of a path with .. and . resolved to appropriate
78
+ # directories.
76
79
  def self.collapse(path)
77
- nil while path.sub!(/[^\/]+\/\.\.\//, '/')
78
- nil while path.sub!('./', '')
79
- path
80
+ new_path = path.dup
81
+ nil while new_path.sub!(/[^\/]+\/\.\.\//, '/')
82
+ nil while new_path.sub!('./', '')
83
+ new_path
80
84
  end
81
85
 
82
86
  end
@@ -38,6 +38,7 @@ class Settings
38
38
  FileUtils.mkdir_p(File.dirname(CONFIG_FILE_PATH))
39
39
  File.open(CONFIG_FILE_PATH, 'w') do |file|
40
40
  @@settings.each_pair { |k, v| file.write("#{k}=#{v}\n") }
41
+ file.chmod(0600)
41
42
  end
42
43
  end
43
44
  nil
@@ -45,11 +46,15 @@ class Settings
45
46
 
46
47
  private
47
48
 
49
+ # Print a warning for an invalid setting and return an empty +Hash+ (the
50
+ # result of an invalid setting).
48
51
  def Settings.warn_invalid(line)
49
52
  warn "invalid setting: #{line}"
50
53
  {}
51
54
  end
52
55
 
56
+ # Parse a line of the rc file and return a +Hash+ containing the resulting
57
+ # setting data.
53
58
  def Settings.parse(line)
54
59
  if /^(.+?)=(.+)$/ =~ line
55
60
  key, value = $1.to_sym, $2
@@ -63,6 +68,7 @@ class Settings
63
68
  end
64
69
  end
65
70
 
71
+ # Read and parse the rc file.
66
72
  def Settings.read
67
73
  if File.exists?(CONFIG_FILE_PATH)
68
74
  File.open(CONFIG_FILE_PATH) do |file|
data/lib/droxi/state.rb CHANGED
@@ -33,6 +33,28 @@ class State
33
33
  @local_oldpwd = Dir.pwd
34
34
  end
35
35
 
36
+ # Adds a metadata +Hash+ and its contents to the metadata cache.
37
+ def cache_add(metadata)
38
+ @cache[metadata['path']] = metadata
39
+ if metadata.include?('contents')
40
+ metadata['contents'].each { |content| cache_add(content) }
41
+ end
42
+ end
43
+
44
+ # Removes a path from the metadata cache.
45
+ def cache_remove(path)
46
+ if directory?(path) && @cache[path].include?('contents')
47
+ @cache[path]['contents'].each { |item| cache_remove(item['path']) }
48
+ end
49
+
50
+ @cache.delete(path)
51
+
52
+ dir = File.dirname(path)
53
+ if @cache.include?(dir) && @cache[dir].include?('contents')
54
+ @cache[dir]['contents'].delete_if { |item| item['path'] == path }
55
+ end
56
+ end
57
+
36
58
  # Return a +Hash+ of the Dropbox metadata for a file, or +nil+ if the file
37
59
  # does not exist.
38
60
  def metadata(path, require_contents=true)
@@ -42,15 +64,18 @@ class State
42
64
  partial_path = '/' + tokens.take(i).join('/')
43
65
  unless have_all_info_for(partial_path, require_contents)
44
66
  begin
45
- data = @cache[partial_path] = @client.metadata(partial_path)
67
+ data = @client.metadata(partial_path)
68
+ if !data['is_deleted']
69
+ @cache[partial_path] = data
70
+ if data.include?('contents')
71
+ data['contents'].each do |datum|
72
+ @cache[datum['path']] = datum
73
+ end
74
+ end
75
+ end
46
76
  rescue DropboxError
47
77
  return nil
48
78
  end
49
- if data.include?('contents')
50
- data['contents'].each do |datum|
51
- @cache[datum['path']] = datum
52
- end
53
- end
54
79
  end
55
80
  end
56
81
 
@@ -122,6 +147,8 @@ class State
122
147
 
123
148
  private
124
149
 
150
+ # Return an +Array+ of file paths matching a glob pattern, or a GlobError if
151
+ # no files were matched.
125
152
  def get_matches(pattern, path, preserve_root)
126
153
  dir = File.dirname(path)
127
154
  matches = contents(dir).select { |entry| File.fnmatch(path, entry) }
@@ -135,6 +162,7 @@ class State
135
162
  end
136
163
  end
137
164
 
165
+ # Return +true+ if the path's information is cached, +false+ otherwise.
138
166
  def have_all_info_for(path, require_contents=true)
139
167
  @cache.include?(path) && (
140
168
  !require_contents ||
data/lib/droxi/text.rb CHANGED
@@ -33,6 +33,7 @@ module Text
33
33
 
34
34
  private
35
35
 
36
+ # Return the width of the terminal in columns.
36
37
  def self.get_columns
37
38
  require 'readline'
38
39
  begin
@@ -43,6 +44,7 @@ module Text
43
44
  end
44
45
  end
45
46
 
47
+ # Return an +Array+ of lines of the given items formatted as a table.
46
48
  def self.format_table(items, item_width, items_per_line, num_lines)
47
49
  num_lines.times.map do |i|
48
50
  items[i * items_per_line, items_per_line].map do |item|
@@ -51,6 +53,7 @@ module Text
51
53
  end
52
54
  end
53
55
 
56
+ # Return a wrapped line of output from the start of the given text.
54
57
  def self.get_wrap_segment(text, columns)
55
58
  segment, sep, text = text.partition(' ')
56
59
  while !text.empty? && segment.length < columns
data/lib/droxi.rb CHANGED
@@ -28,8 +28,7 @@ module Droxi
28
28
 
29
29
  private
30
30
 
31
- # Attempt to authorize the user for app usage. Return +true+ if
32
- # authorization was successful, +false+ otherwise.
31
+ # Attempt to authorize the user for app usage.
33
32
  def self.authorize
34
33
  app_key = '5sufyfrvtro9zp7'
35
34
  app_secret = 'h99ihzv86jyypho'
@@ -46,8 +45,8 @@ module Droxi
46
45
  end
47
46
  end
48
47
 
49
- # Get the access token for the user, requesting authorization if no token
50
- # exists.
48
+ # Return the access token for the user, requesting authorization if no saved
49
+ # token exists.
51
50
  def self.get_access_token
52
51
  authorize() until Settings.include?(:access_token)
53
52
  Settings[:access_token]
@@ -55,7 +54,7 @@ module Droxi
55
54
 
56
55
  # Return a prompt message reflecting the current state of the application.
57
56
  def self.prompt(info, state)
58
- "droxi #{info['email']}:#{state.pwd}> "
57
+ "\rdroxi #{info['email']}:#{state.pwd}> "
59
58
  end
60
59
 
61
60
  # Run the client in interactive mode.
@@ -66,10 +65,11 @@ module Droxi
66
65
  init_readline(state)
67
66
  with_interrupt_handling { do_interaction_loop(client, state, info) }
68
67
 
69
- # Set pwd so that the oldpwd setting is saved to pwd
68
+ # Set pwd before exiting so that the oldpwd setting is saved to pwd
70
69
  state.pwd = '/'
71
70
  end
72
71
 
72
+ # Set up the Readline library's completion capabilities.
73
73
  def self.init_readline(state)
74
74
  Readline.completion_proc = proc do |word|
75
75
  words = Readline.line_buffer.split
@@ -103,12 +103,16 @@ module Droxi
103
103
  end
104
104
  end
105
105
 
106
+ # Run the associated block, handling Interrupt errors by printing a blank
107
+ # line.
106
108
  def self.with_interrupt_handling
107
109
  yield
108
110
  rescue Interrupt
109
111
  puts
110
112
  end
111
113
 
114
+ # Run the main loop of the program, getting user input and executing it as a
115
+ # command until an getting input fails or an exit is requested.
112
116
  def self.do_interaction_loop(client, state, info)
113
117
  while !state.exit_requested &&
114
118
  line = Readline.readline(prompt(info, state), true)
@@ -117,6 +121,8 @@ module Droxi
117
121
  puts if !line
118
122
  end
119
123
 
124
+ # Instruct the user to enter an authorization code and return the code. If
125
+ # the user gives EOF, exit the program.
120
126
  def self.get_auth_code(url)
121
127
  puts '1. Go to: ' + url
122
128
  puts '2. Click "Allow" (you might have to log in first)'
@@ -90,6 +90,38 @@ describe Commands do
90
90
  end
91
91
  end
92
92
 
93
+ describe 'when executing the cp command' do
94
+ before do
95
+ state.pwd = '/testing'
96
+ end
97
+
98
+ after do
99
+ Commands::RM.exec(client, state, '*')
100
+ end
101
+
102
+ it 'must copy source to dest when given 2 args and last arg is non-dir' do
103
+ Commands::MKDIR.exec(client, state, 'source')
104
+ Commands::CP.exec(client, state, 'source', 'dest')
105
+ ['source', 'dest'].all? do |dir|
106
+ client.metadata("/testing/#{dir}")
107
+ end.must_equal true
108
+ end
109
+
110
+ it 'must copy source into dest when given 2 args and last arg is dir' do
111
+ Commands::MKDIR.exec(client, state, 'source', 'dest')
112
+ Commands::CP.exec(client, state, 'source', 'dest')
113
+ client.metadata('/testing/dest/source').wont_equal nil
114
+ end
115
+
116
+ it 'must copy sources into dest when given 3 or more args' do
117
+ Commands::MKDIR.exec(client, state, 'source1', 'source2', 'dest')
118
+ Commands::CP.exec(client, state, 'source1', 'source2', 'dest')
119
+ ['source2', 'source2'].all? do |dir|
120
+ client.metadata("/testing/dest/#{dir}")
121
+ end.must_equal true
122
+ end
123
+ end
124
+
93
125
  describe 'when executing the forget command' do
94
126
  it 'must clear entire cache when given no arguments' do
95
127
  Commands::LS.exec(client, state, '/')
@@ -206,6 +238,39 @@ describe Commands do
206
238
  end
207
239
  end
208
240
 
241
+ describe 'when executing the mv command' do
242
+ before do
243
+ state.pwd = '/testing'
244
+ end
245
+
246
+ after do
247
+ Commands::RM.exec(client, state, '*')
248
+ end
249
+
250
+ it 'must move source to dest when given 2 args and last arg is non-dir' do
251
+ Commands::MKDIR.exec(client, state, 'source')
252
+ Commands::MV.exec(client, state, 'source', 'dest')
253
+ client.metadata('/testing/source')['is_deleted'].must_equal true
254
+ client.metadata('/testing/dest').wont_equal nil
255
+ end
256
+
257
+ it 'must move source into dest when given 2 args and last arg is dir' do
258
+ Commands::MKDIR.exec(client, state, 'source', 'dest')
259
+ Commands::MV.exec(client, state, 'source', 'dest')
260
+ client.metadata('/testing/source')['is_deleted'].must_equal true
261
+ client.metadata('/testing/dest/source').wont_equal nil
262
+ end
263
+
264
+ it 'must move sources into dest when given 3 or more args' do
265
+ Commands::MKDIR.exec(client, state, 'source1', 'source2', 'dest')
266
+ Commands::MV.exec(client, state, 'source1', 'source2', 'dest')
267
+ ['source2', 'source2'].all? do |dir|
268
+ client.metadata("/testing/#{dir}")['is_deleted'].must_equal true
269
+ client.metadata("/testing/dest/#{dir}")
270
+ end.must_equal true
271
+ end
272
+ end
273
+
209
274
  describe 'when executing the put command' do
210
275
  it 'must put a file of the same name when given 1 arg' do
211
276
  state.pwd = '/testing'
@@ -239,10 +304,17 @@ describe Commands do
239
304
 
240
305
  describe 'when executing the rm command' do
241
306
  it 'must remove the remote file when given args' do
242
- # FIXME: This test fails and I don't know why
243
- #Commands::MKDIR.exec(client, state, '/testing/test')
244
- #Commands::RM.exec(client, state, '/testing/test')
245
- #client.metadata('/testing/test')['is_deleted'].must_equal true
307
+ Commands::MKDIR.exec(client, state, '/testing/test')
308
+ Commands::RM.exec(client, state, '/testing/test')
309
+ client.metadata('/testing/test')['is_deleted'].must_equal true
310
+ end
311
+
312
+ it 'must change pwd to existing dir if the current one is removed' do
313
+ Commands::MKDIR.exec(client, state, '/testing/one')
314
+ Commands::MKDIR.exec(client, state, '/testing/one/two')
315
+ Commands::CD.exec(client, state, '/testing/one/two')
316
+ Commands::RM.exec(client, state, '..')
317
+ state.pwd.must_equal('/testing')
246
318
  end
247
319
  end
248
320
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: droxi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
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-03 00:00:00.000000000 Z
11
+ date: 2014-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dropbox-sdk