file_discard 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -13
- data/Rakefile +43 -16
- data/bin/discard +11 -1
- data/lib/file_discard.rb +52 -5
- data/lib/file_discard_version.rb +4 -2
- data/spec/file_discard_spec.rb +24 -1
- metadata +12 -7
- data/.gitignore +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80106d989c491a8d79a5b2f6eca34d4a73a12bd1
|
4
|
+
data.tar.gz: 262dc75d7c97871b948ea70064df0f0021f07dcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4370a3a0c0228c31b4f402224a1d3edf5d1918f4ee5c502ba6983fefc4bd27abf2e9c8c897f27310713229c4e1f1cbeda65ed2e5c127c4d2334f20550cb0bfb
|
7
|
+
data.tar.gz: 1f84dc4c065f51175c48332aacc3976b29a40c0db72f331bc79498ab6ae2dfcf1cb68aa1f1f94caa3ee54d42feabe59c81964e00eff2fda8af8d406141fd84a3
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
FileDiscard is a simple helper to make it easy for applications to move files to the correct trash folder. The location is determined by the platform and what file is being discarded (the latter is important so that files on other volumes/mountpoints are moved in to the appropriate trash folder).
|
2
2
|
|
3
3
|
## Getting Started
|
4
4
|
|
@@ -9,17 +9,17 @@ Part of the `file_discard` gem is an executable that can be used as a drop-in re
|
|
9
9
|
```shell
|
10
10
|
> discard
|
11
11
|
Usage: discard [options] file ...
|
12
|
+
-d, --dir allow empty directories to be discarded
|
13
|
+
-r allow directories to be discarded recursively
|
14
|
+
-R, --recursive allow directories to be discarded recursively
|
12
15
|
-v, --verbose show where files are discarded
|
13
16
|
-h, --help show this message
|
14
17
|
--version show version
|
15
18
|
|
16
19
|
Options ignored to provide compatibility with "rm":
|
17
|
-
-d
|
18
20
|
-f
|
19
21
|
-i
|
20
|
-
-
|
21
|
-
-R
|
22
|
-
-r
|
22
|
+
-I
|
23
23
|
```
|
24
24
|
|
25
25
|
### Using the Library
|
@@ -54,7 +54,7 @@ p.open('w') {|io| io.puts 'four'}
|
|
54
54
|
Pathname.discard 'file4.txt'
|
55
55
|
```
|
56
56
|
|
57
|
-
Another approach is to leave Ruby's [`File`](http://www.ruby-doc.org/core/File.html) and [`Pathname`](http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html) classes alone and work directly with
|
57
|
+
Another approach is to leave Ruby's [`File`](http://www.ruby-doc.org/core/File.html) and [`Pathname`](http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html) classes alone and work directly with FileDiscard:
|
58
58
|
|
59
59
|
```ruby
|
60
60
|
require 'file_discard'
|
@@ -73,7 +73,7 @@ FileDiscard.discard 'file6.txt'
|
|
73
73
|
|
74
74
|
#### More Options
|
75
75
|
|
76
|
-
|
76
|
+
A call to discard can enable a report of the operation that is taking place:
|
77
77
|
|
78
78
|
```ruby
|
79
79
|
require 'file_discard'
|
@@ -94,7 +94,9 @@ Pathname.discard 'file8.txt', verbose:true
|
|
94
94
|
# ===> mv /path/to/file8.txt /Users/brad/.Trash/file8.txt
|
95
95
|
```
|
96
96
|
|
97
|
-
|
97
|
+
Other options can be enabled to allow discarding empty directories (:directory) or directories with items in them (:recursive).
|
98
|
+
|
99
|
+
Also of note is that FileDiscard will not blindly stomp on existing files already present in the trash. Instead, much like OS X's Finder, FileDiscard creates new file names based on the time when a collision occurs:
|
98
100
|
|
99
101
|
```ruby
|
100
102
|
require 'file_discard'
|
@@ -154,16 +156,16 @@ Pathname.new('/path/to/my/home/a/trash/folder').children
|
|
154
156
|
# ===> [#<Pathname:/path/to/my/home/a/trash/folder/myfile.txt>]
|
155
157
|
```
|
156
158
|
|
157
|
-
Each
|
159
|
+
Each FileDiscard::Discarder is expected to provide the following (as passed to FileDiscard::Discarder.new):
|
158
160
|
|
159
|
-
1. `home`: An _absolute_ path to the home directory of the current user.
|
161
|
+
1. `home`: An _absolute_ path to the home directory of the current user. FileDiscard will expand the path, so on systems that support it, special variables can be used (e.g. a tilde (~) will expand to the current user's home directory on OS X and Linux).
|
160
162
|
|
161
163
|
2. `home_trash`: A _relative_ path where the trash is expected from the `home` directory.
|
162
164
|
|
163
165
|
3. `mountpoint_trash_fmt`: A _relative_ path where the trash is expected from any given mountpoint. This string can optionally include a `%s` format specifier which will be replaced by the current user's numeric ID (ie. UID).
|
164
166
|
|
165
|
-
The
|
167
|
+
The FileDiscard::Discarder will rely on comparison between mountpoints (as determined by [`Pathname#mountpoint?`](http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html#method-i-mountpoint-3F)) to decide if the home trash should be used or if a shared trash for another mounted volume should be used. In other words, if the mountpoint of the file being trashed is _not_ the same as the `home` directory's mountpoint, the discarder will use the trash located in the mountpoint associated with the file being discarded using the `mountpoint_trash_fmt` relative result as presented by the discarder.
|
166
168
|
|
167
|
-
If the trash location does not already exist, the
|
169
|
+
If the trash location does not already exist, the FileDiscard::Discarder will not automatically create it. Instead, it will raise a FileDiscard::TrashMissing exception for any discard request that attempts to move a file to a trash that does not exist. It is expected that the caller will ensure the trash directories are present before attempting to discard files or make use of FileDiscard.create_trash_when_missing= to enable automatically creating missing trash folders.
|
168
170
|
|
169
|
-
For a more complex example,
|
171
|
+
For a more complex example, see FileDiscard::LinuxDiscarder.
|
data/Rakefile
CHANGED
@@ -1,57 +1,84 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/clean'
|
4
|
+
require 'rdoc/task'
|
4
5
|
require 'rubygems/package_task'
|
5
6
|
|
6
7
|
task default: :test
|
7
8
|
task spec: :test
|
8
9
|
task build: :package
|
9
10
|
|
10
|
-
PKG_VERSION = '0.1.
|
11
|
+
PKG_VERSION = '0.1.3'
|
11
12
|
NOW = Time.now.utc
|
12
13
|
|
13
14
|
# delay updating the version file unless building the gem or package
|
15
|
+
VER_FN = 'lib/file_discard_version.rb'
|
14
16
|
task :update_version do
|
15
|
-
File.open(
|
17
|
+
File.open(VER_FN,'w') do |f|
|
16
18
|
f.puts <<EOF
|
17
19
|
module FileDiscard
|
20
|
+
# :nodoc:
|
18
21
|
VERSION = '#{PKG_VERSION}'
|
22
|
+
# :nodoc:
|
19
23
|
RELEASE = '#{`git rev-parse --short HEAD`.chomp}:#{NOW.strftime('%Y%m%d%H%M%S')}'
|
20
24
|
end
|
21
25
|
EOF
|
22
26
|
end
|
23
27
|
end
|
24
|
-
|
25
|
-
|
28
|
+
|
29
|
+
if File.exist? VER_FN
|
30
|
+
task package: :update_version
|
31
|
+
task gem: :update_version
|
32
|
+
else
|
33
|
+
Rake::Task[:update_version].execute
|
34
|
+
end
|
26
35
|
|
27
36
|
Rake::TestTask.new do |t|
|
28
37
|
t.pattern = "spec/*_spec.rb"
|
29
38
|
end
|
30
39
|
|
40
|
+
RDOC_EXTRA_FILES = ['README.md','LICENSE']
|
41
|
+
|
42
|
+
RDoc::Task.new :rdoc do |rdoc|
|
43
|
+
rdoc.rdoc_files.include(*RDOC_EXTRA_FILES, 'lib/**/*.rb')
|
44
|
+
rdoc.title = 'FileDiscard'
|
45
|
+
rdoc.main = 'README.md'
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
end
|
48
|
+
|
31
49
|
def list_files
|
32
50
|
if Dir.exist? '.git'
|
33
|
-
`git ls-files -z`.split("\x0")
|
51
|
+
files = `git ls-files -z`.split("\x0")
|
34
52
|
else
|
35
53
|
# e.g. when installed and tasks are run from there...
|
36
|
-
Dir.glob('**/*').select{|e| File.file? e}
|
54
|
+
files = Dir.glob('**/*').select{|e| File.file? e}
|
37
55
|
end
|
56
|
+
files.delete '.gitignore'
|
57
|
+
files
|
38
58
|
end
|
39
59
|
|
40
60
|
spec = Gem::Specification.new do |s|
|
41
61
|
s.name = 'file_discard'
|
42
|
-
s.
|
43
|
-
s.
|
44
|
-
|
45
|
-
s.
|
46
|
-
s.
|
47
|
-
s.
|
62
|
+
s.summary = 'Move files to the trash.'
|
63
|
+
s.description = 'Simple helper to move files to the trash folder.'
|
64
|
+
|
65
|
+
s.authors = ['Brad Robel-Forrest']
|
66
|
+
s.email = 'brad+filediscard@gigglewax.com'
|
67
|
+
s.homepage = 'https://github.com/bradrf/file_discard#readme'
|
68
|
+
s.license = 'MIT'
|
69
|
+
|
70
|
+
s.version = PKG_VERSION
|
71
|
+
s.date = NOW.strftime('%Y-%m-%d')
|
72
|
+
|
73
|
+
s.required_ruby_version = '>= 1.9.0'
|
74
|
+
|
48
75
|
s.files = list_files << 'lib/file_discard_version.rb'
|
49
76
|
s.test_files = s.files.grep(%r{^spec/})
|
50
77
|
s.executables = %w(discard)
|
51
|
-
s.homepage = 'https://github.com/bradrf/file_discard#readme'
|
52
|
-
s.license = 'MIT'
|
53
78
|
|
54
|
-
s.
|
79
|
+
s.has_rdoc = true
|
80
|
+
s.rdoc_options += ['--title','FileDiscard','--main','README.md']
|
81
|
+
s.extra_rdoc_files += RDOC_EXTRA_FILES
|
55
82
|
end
|
56
83
|
|
57
84
|
Gem::PackageTask.new(spec) do |pkg|
|
@@ -64,4 +91,4 @@ task :grip do
|
|
64
91
|
exec 'grip --gfm --context=bradrf/file_discard'
|
65
92
|
end
|
66
93
|
|
67
|
-
CLOBBER.
|
94
|
+
CLOBBER.include 'coverage', VER_FN
|
data/bin/discard
CHANGED
@@ -9,6 +9,16 @@ parser = OptionParser.new do |opts|
|
|
9
9
|
Version = FileDiscard::VERSION
|
10
10
|
Release = FileDiscard::RELEASE
|
11
11
|
|
12
|
+
opts.on('-d', '--dir', 'allow empty directories to be discarded') do |v|
|
13
|
+
options.directory = v
|
14
|
+
end
|
15
|
+
|
16
|
+
[?r,?R].each do |o|
|
17
|
+
opts.on("-#{o}", '--recursive', 'allow directories to be discarded recursively') do |v|
|
18
|
+
options.recursive = v
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
12
22
|
opts.on('-v', '--verbose', 'show where files are discarded') do |v|
|
13
23
|
options.verbose = v
|
14
24
|
end
|
@@ -25,7 +35,7 @@ parser = OptionParser.new do |opts|
|
|
25
35
|
|
26
36
|
opts.separator('')
|
27
37
|
opts.separator('Options ignored to provide compatibility with "rm":')
|
28
|
-
[?
|
38
|
+
[?f,?i,?I].each {|o| opts.on("-#{o}")}
|
29
39
|
|
30
40
|
opts.banner << ' file ...'
|
31
41
|
end
|
data/lib/file_discard.rb
CHANGED
@@ -30,12 +30,15 @@ module FileDiscard
|
|
30
30
|
######################################################################
|
31
31
|
# Module Methods
|
32
32
|
|
33
|
+
# Extend Ruby's +File+ and +Pathname+ classes with Discarder.discard methods.
|
33
34
|
def self.mix_it_in!
|
34
35
|
[File, Pathname].each do |klass|
|
35
36
|
klass.class_eval do
|
37
|
+
# :nodoc:
|
36
38
|
def self.discard(*args)
|
37
39
|
FileDiscard.discarder.discard(*args)
|
38
40
|
end
|
41
|
+
# :nodoc:
|
39
42
|
def discard(options = {})
|
40
43
|
FileDiscard.discarder.discard(self, options)
|
41
44
|
end
|
@@ -44,10 +47,12 @@ module FileDiscard
|
|
44
47
|
self
|
45
48
|
end
|
46
49
|
|
50
|
+
# See Discarder.discard for usage.
|
47
51
|
def self.discard(*args)
|
48
52
|
discarder.discard(*args)
|
49
53
|
end
|
50
54
|
|
55
|
+
# Set the default discarder to use.
|
51
56
|
def self.discarder=(discarder)
|
52
57
|
@@discarder = discarder
|
53
58
|
end
|
@@ -62,11 +67,27 @@ module FileDiscard
|
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
70
|
+
@@create_trash_when_missing = false
|
71
|
+
|
72
|
+
# Enable or disable the automatic creation of trash directories if they do not exist. The default
|
73
|
+
# is to raise a TrashMissing exception).
|
74
|
+
def self.create_trash_when_missing=(value)
|
75
|
+
@@create_trash_when_missing = value
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.create_trash_when_missing
|
79
|
+
@@create_trash_when_missing
|
80
|
+
end
|
81
|
+
|
65
82
|
######################################################################
|
66
83
|
# Discarders
|
67
84
|
|
85
|
+
# Raised when the configured trash directory for a given mountpoint does not exist.
|
86
|
+
class TrashMissing < Errno::ENOENT; end;
|
87
|
+
|
88
|
+
# The core logic for moving files to an appropriate trash directory.
|
68
89
|
class Discarder
|
69
|
-
SPECIAL_DIRS = ['.','..']
|
90
|
+
SPECIAL_DIRS = ['.','..'] # :nodoc:
|
70
91
|
|
71
92
|
def initialize(home, home_trash, mountpoint_trash_fmt)
|
72
93
|
home = pathname_for(home).expand_path
|
@@ -75,13 +96,39 @@ module FileDiscard
|
|
75
96
|
@mountpoint_trash_fmt = mountpoint_trash_fmt
|
76
97
|
end
|
77
98
|
|
78
|
-
|
99
|
+
# Request that +obj+ be moved to the trash.
|
100
|
+
#
|
101
|
+
# +options+ - a hash of any of the following:
|
102
|
+
# * :directory - allow an empty directory to be discarded
|
103
|
+
# * :recursive - allow a directory to be discarded even if not empty
|
104
|
+
# * :verbose - report the move operation
|
105
|
+
#
|
106
|
+
# May raise:
|
107
|
+
# * Errno::EINVAL - +obj+ is "." or ".." which are not allowed to be discarded
|
108
|
+
# * Errno::EISDIR - +obj+ is a directory
|
109
|
+
# * Errno::ENOTEMPTY - +obj+ is a directory with children
|
110
|
+
# * Errno::ENOENT - +obj+ does not exist on the file system
|
111
|
+
# * TrashMissing - the trash directory for the mountpoint associated with +obj+ did not exist
|
112
|
+
#
|
113
|
+
def discard(obj, options = {})
|
79
114
|
pn = pathname_for obj
|
80
|
-
if
|
81
|
-
|
115
|
+
if pn.directory?
|
116
|
+
if SPECIAL_DIRS.include?(pn.basename.to_s)
|
117
|
+
raise Errno::EINVAL.new(SPECIAL_DIRS.join(' and ') << ' may not be removed')
|
118
|
+
end
|
119
|
+
unless options[:recursive]
|
120
|
+
raise Errno::EISDIR.new(pn.to_s) unless options[:directory]
|
121
|
+
raise Errno::ENOTEMPTY.new(pn.to_s) if pn.children.any?
|
122
|
+
end
|
82
123
|
end
|
124
|
+
|
83
125
|
trash = find_trash_for pn
|
84
|
-
|
126
|
+
unless trash.exist?
|
127
|
+
raise TrashMissing.new(trash.to_s) unless FileDiscard.create_trash_when_missing
|
128
|
+
trash.mkpath
|
129
|
+
end
|
130
|
+
|
131
|
+
move_options = options.has_key?(:verbose) ? {verbose: options[:verbose]} : {}
|
85
132
|
move(pn, trash, move_options)
|
86
133
|
end
|
87
134
|
|
data/lib/file_discard_version.rb
CHANGED
data/spec/file_discard_spec.rb
CHANGED
@@ -24,6 +24,7 @@ describe FileDiscard do
|
|
24
24
|
|
25
25
|
@discarder = FileDiscard::OsxDiscarder.new(@home)
|
26
26
|
FileDiscard.discarder = @discarder
|
27
|
+
FileDiscard.create_trash_when_missing = false
|
27
28
|
end
|
28
29
|
|
29
30
|
after do
|
@@ -49,7 +50,13 @@ describe FileDiscard do
|
|
49
50
|
|
50
51
|
it 'should fail without trash' do
|
51
52
|
f = File.new(@base.join('file.txt').to_s, 'w')
|
52
|
-
->{ f.discard }.must_raise
|
53
|
+
->{ f.discard }.must_raise FileDiscard::TrashMissing
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should support creating missing trash' do
|
57
|
+
FileDiscard.create_trash_when_missing = true
|
58
|
+
f = File.new(@base.join('file.txt').to_s, 'w')
|
59
|
+
f.discard
|
53
60
|
end
|
54
61
|
|
55
62
|
describe 'with trash in the home' do
|
@@ -62,6 +69,22 @@ describe FileDiscard do
|
|
62
69
|
@trash.children(false).collect(&:to_s).sort
|
63
70
|
end
|
64
71
|
|
72
|
+
it 'should conditionally allow removal of empty directories' do
|
73
|
+
d = @base.join('foozy')
|
74
|
+
d.mkdir
|
75
|
+
->{ FileDiscard.discard(d) }.must_raise Errno::EISDIR
|
76
|
+
FileDiscard.discard(d, directory: true)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should conditionally allow removal of non-empty directories' do
|
80
|
+
d = @base.join('foozy')
|
81
|
+
d.mkdir
|
82
|
+
f = d.join('stuff.txt')
|
83
|
+
f.open('w') {|io| io.puts 'stuff'}
|
84
|
+
->{ FileDiscard.discard(d, directory: true) }.must_raise Errno::ENOTEMPTY
|
85
|
+
FileDiscard.discard(d, recursive: true)
|
86
|
+
end
|
87
|
+
|
65
88
|
it 'should discard a file' do
|
66
89
|
f = File.new(@base.join('file.txt').to_s, 'w')
|
67
90
|
f.discard
|
metadata
CHANGED
@@ -1,23 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: file_discard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brad Robel-Forrest
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Simple helper to move files to the trash folder
|
13
|
+
description: Simple helper to move files to the trash folder.
|
14
14
|
email: brad+filediscard@gigglewax.com
|
15
15
|
executables:
|
16
16
|
- discard
|
17
17
|
extensions: []
|
18
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
19
|
+
- README.md
|
20
|
+
- LICENSE
|
19
21
|
files:
|
20
|
-
- ".gitignore"
|
21
22
|
- LICENSE
|
22
23
|
- README.md
|
23
24
|
- Rakefile
|
@@ -30,7 +31,11 @@ licenses:
|
|
30
31
|
- MIT
|
31
32
|
metadata: {}
|
32
33
|
post_install_message:
|
33
|
-
rdoc_options:
|
34
|
+
rdoc_options:
|
35
|
+
- "--title"
|
36
|
+
- FileDiscard
|
37
|
+
- "--main"
|
38
|
+
- README.md
|
34
39
|
require_paths:
|
35
40
|
- lib
|
36
41
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -48,6 +53,6 @@ rubyforge_project:
|
|
48
53
|
rubygems_version: 2.2.2
|
49
54
|
signing_key:
|
50
55
|
specification_version: 4
|
51
|
-
summary: Move files to the trash
|
56
|
+
summary: Move files to the trash.
|
52
57
|
test_files:
|
53
58
|
- spec/file_discard_spec.rb
|