maid 0.10.0.pre.alpha.2 → 0.10.0.pre.alpha.3

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
  SHA256:
3
- metadata.gz: d8d0fa40b9069dd973a12021c729407e1f98719ea96e8ede17aff4426cd8d9eb
4
- data.tar.gz: ed334d76e2cdc9ba723e600a6f371efab241ea24c080e7009425dee9a99d52f4
3
+ metadata.gz: 0be19c0367daaad7154c2649987ff99d97702a964ca2c6af5331fd876da16d7a
4
+ data.tar.gz: cb3598e65e48db7529b0584c041eb3f87fdbf66b57030d83f2ac981251de74a3
5
5
  SHA512:
6
- metadata.gz: 4be4e2a2771566d670b9b7a5d5966c334e3ca58c7c204dab7182654821b47b6076dc2ceb0e880de1a2e6966f110fee7422d289ffa058c9ba6861287afd2f60be
7
- data.tar.gz: 124d6e7f02282b4772b4a849acfad62efdc3277c08ea0696cd32b57672e199104bf314e53b609c47960e026b2073f4aba55d441de5061600fa9f499f9e90ceae
6
+ metadata.gz: d887908840f3369f2250226d888563444431f95cd662a50cdaddde49b0883bfb82958788516e9dc56d5329a8eefbdf470c761c1645d004cba2193c050bab60c2
7
+ data.tar.gz: a6349bb2e1d6e1b7dbd8358c7cf7e5f1955f2ae873d5b3286212c955e3ae11bb3ab743f3291f25c633bbda571caa0f0e90364a151f150789c2c8020698ab84ab
@@ -39,7 +39,7 @@ jobs:
39
39
  # Uncomment for pre-releases, see
40
40
  # https://github.com/maid/maid/wiki/Release-Process
41
41
  prerelease: true
42
- release-as: v0.10.0-alpha.2
42
+ release-as: v0.10.0-alpha.3
43
43
  - name: Set up Ruby
44
44
  uses: ruby/setup-ruby@v1
45
45
  with:
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.10.0-alpha.2"
2
+ ".": "0.10.0-alpha.3"
3
3
  }
data/.rubocop_todo.yml CHANGED
@@ -66,7 +66,7 @@ Metrics/MethodLength:
66
66
  # Offense count: 4
67
67
  # Configuration parameters: CountComments, CountAsOne.
68
68
  Metrics/ModuleLength:
69
- Max: 711
69
+ Max: 753
70
70
 
71
71
  # Offense count: 2
72
72
  # Configuration parameters: AllowedMethods, AllowedPatterns.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.0-alpha.3](https://github.com/maid/maid/compare/v0.10.0-alpha.2...v0.10.0-alpha.3) (2023-04-04)
4
+
5
+
6
+ ### Features
7
+
8
+ * **maid:** improve `#watch` error message ([#287](https://github.com/maid/maid/issues/287)) ([0894cd6](https://github.com/maid/maid/commit/0894cd69665d5d9fe775b6b3df5a247f22f217d6))
9
+ * **tools:** add option to disable clobbering destination for `#move` ([#284](https://github.com/maid/maid/issues/284)) ([979413f](https://github.com/maid/maid/commit/979413fe284b61b43b33ba2169e72ed23043bcca))
10
+
3
11
  ## [0.10.0-alpha.2](https://github.com/maid/maid/compare/v0.10.0-alpha.1...v0.10.0-alpha.2) (2023-03-28)
4
12
 
5
13
 
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ require 'bundler'
2
2
  require 'rake'
3
3
  require 'rspec/core/rake_task'
4
4
  require 'yard'
5
+ require 'rake/notes/rake_task'
5
6
 
6
7
  task default: :spec
7
8
 
data/lib/maid/maid.rb CHANGED
@@ -88,6 +88,15 @@ class Maid::Maid
88
88
  end
89
89
 
90
90
  def watch(path, options = {}, &block)
91
+ full_path = File.expand_path(path)
92
+
93
+ unless File.directory?(full_path)
94
+ message = "#{full_path} cannot be a file and it must exist in order to watch it"
95
+
96
+ warn(message)
97
+ raise message
98
+ end
99
+
91
100
  @watches << ::Maid::Watch.new(self, path, options, &block)
92
101
  end
93
102
 
@@ -140,7 +149,7 @@ class Maid::Maid
140
149
  def default_trash_path
141
150
  # TODO: Refactor module declaration so this can be `Platform`
142
151
  if Maid::Platform.linux?
143
- # See the [FreeDesktop.org Trash specification](http://www.ramendik.ru/docs/trashspec.html)
152
+ # See the [FreeDesktop.org Trash specification](https://archive.is/cXir4)
144
153
  path = "#{XDG['DATA_HOME']}/Trash/files"
145
154
  elsif Maid::Platform.osx?
146
155
  path = File.expand_path('~/.Trash')
data/lib/maid/tools.rb CHANGED
@@ -24,33 +24,50 @@ module Maid::Tools
24
24
  # For showing deprecation notices
25
25
  include Deprecated
26
26
 
27
- # Move `sources` to a `destination` directory.
27
+ # Moves `sources` file(s) to a `destination` directory.
28
28
  #
29
29
  # Movement is only allowed to directories that already exist. If your
30
30
  # intention is to rename, see the `rename` method.
31
31
  #
32
- # ## Examples
33
- #
34
- # Single path:
35
- #
36
- # move('~/Downloads/foo.zip', '~/Archive/Software/Mac OS X/')
37
- #
38
- # Multiple paths:
39
- #
40
- # move(['~/Downloads/foo.zip', '~/Downloads/bar.zip'], '~/Archive/Software/Mac OS X/')
41
- # move(dir('~/Downloads/*.zip'), '~/Archive/Software/Mac OS X/')
42
- def move(sources, destination)
43
- expanded_destination = expand(destination)
44
-
45
- if File.directory?(expanded_destination)
32
+ # @example Single source file
33
+ # move('~/Downloads/foo.zip', '~/Archive/Software/Mac OS X/')
34
+ #
35
+ # @example Multiple source files
36
+ # move(['~/Downloads/foo.zip', '~/Downloads/bar.zip'],
37
+ # '~/Archive/Software/Mac OS X/')
38
+ # move(dir('~/Downloads/*.zip'), '~/Archive/Software/Mac OS X/')
39
+ #
40
+ # @example Overwrite destination file if it already exists
41
+ # move('~/Downloads/foo.zip', '~/Archive/Software/Mac OS X/')
42
+ # move('~/Downloads/foo.zip', '~/Archive/Software/Mac OS X/', clobber:
43
+ # true)
44
+ #
45
+ # @example Skip file if it already exists at destination
46
+ # move('~/Downloads/foo.zip', '~/Archive/Software/Mac OS X/', clobber:
47
+ # false)
48
+ #
49
+ # @param sources [String, Array<String>] the paths to the source files to
50
+ # move
51
+ # @param destination_dir [String] path of the directory where to move
52
+ # `sources` to
53
+ # @param [Hash] kwargs the arguments to modify behaviour
54
+ # @option kwargs [Boolean] :clobber (true) `true` to overwrite destination
55
+ # file if it exists, `false` to skip moving file if it exists
56
+ def move(sources, destination_dir, clobber: true)
57
+ expanded_destination_dir = expand(destination_dir)
58
+
59
+ if File.directory?(expanded_destination_dir)
46
60
  expand_all(sources).each do |source|
47
- log("move #{sh_escape(source)} #{sh_escape(expanded_destination)}")
48
- FileUtils.mv(source, expanded_destination, **@file_options)
61
+ log("move #{sh_escape(source)} #{sh_escape(expanded_destination_dir)}")
62
+
63
+ unless skip_move?(source, expanded_destination_dir, clobber)
64
+ FileUtils.mv(source, expanded_destination_dir, **@file_options)
65
+ end
49
66
  end
50
67
  else
51
68
  # Unix `mv` warns about the target not being a directory with multiple sources. Maid checks the same.
52
- warn("skipping move because #{sh_escape(expanded_destination)} is not a" \
53
- "directory (use 'mkdir' to create first, or use 'rename')")
69
+ warn("skipping move because #{sh_escape(expanded_destination_dir)} " \
70
+ "is not a directory (use 'mkdir' to create first, or use 'rename')")
54
71
  end
55
72
  end
56
73
 
@@ -1006,4 +1023,29 @@ module Maid::Tools
1006
1023
  []
1007
1024
  end
1008
1025
  end
1026
+
1027
+ # Predicate to tell whether the file should be skipped when moving.
1028
+ # @param source_path [String] the path to the source file
1029
+ # @param destination_dir [String] the path to the destination directory
1030
+ # @param clobber [Boolean] `true` to overwrite existing destination file,
1031
+ # `false` otherwise
1032
+ # @return [Boolean] whether to skip the move
1033
+ def skip_move?(source_path, destination_dir, clobber)
1034
+ destination_path = File.join(destination_dir, File.basename(source_path))
1035
+
1036
+ # if the destination file doesn't exist, we can move.
1037
+ return false unless File.exist?(destination_path)
1038
+
1039
+ log("#{destination_path} already exists")
1040
+
1041
+ # figure out whether to overwrite the existing destination file.
1042
+ if clobber
1043
+ log("clobbering enabled, moving #{File.basename(source_path)} anyway")
1044
+
1045
+ return false
1046
+ end
1047
+ log("clobbering disabled, skipping move for #{File.basename(source_path)}")
1048
+
1049
+ true
1050
+ end
1009
1051
  end
data/lib/maid/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Maid
4
- VERSION = '0.10.0-alpha.2'
4
+ VERSION = '0.10.0-alpha.3'
5
5
  SUMMARY = 'Be lazy. Let Maid clean up after you, based on rules you define. ' \
6
6
  'Think of it as "Hazel for hackers".'
7
7
  end
data/maid.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ['Benjamin Oakes', 'Coaxial']
9
9
  s.email = ['hello@benjaminoakes.com', 'c+rubygems@64b.it']
10
- s.license = 'GPLv2'
10
+ s.license = 'GPL-2.0'
11
11
  s.homepage = 'http://github.com/maid/maid'
12
12
  s.summary = Maid::SUMMARY
13
13
  s.description = s.summary
@@ -53,6 +53,7 @@ Gem::Specification.new do |s|
53
53
  s.add_development_dependency('guard-rubocop')
54
54
  s.add_development_dependency('pry-byebug')
55
55
  s.add_development_dependency('rake', '~> 13.0.6')
56
+ s.add_development_dependency('rake-notes')
56
57
  s.add_development_dependency('redcarpet', '~> 3.6.0') # Soft dependency of `yard`
57
58
  s.add_development_dependency('rspec', '~> 3.12.0')
58
59
  s.add_development_dependency('rubocop')
@@ -1,12 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Maid
4
- describe Maid do
4
+ describe Maid, fakefs: true do
5
5
  let(:logger) { instance_spy('Logger') }
6
6
 
7
7
  before do
8
8
  allow(Logger).to receive(:new).and_return(logger)
9
- allow(FileUtils).to receive(:mkdir_p)
10
9
  end
11
10
 
12
11
  describe '.new' do
@@ -33,8 +32,11 @@ module Maid
33
32
  end
34
33
 
35
34
  it 'makes the log directory in case it does not exist' do
36
- expect(FileUtils).to receive(:mkdir_p).with('/home/username/log')
35
+ expect(File.exist?('/home/username/log')).to be false
36
+
37
37
  Maid.new(log_device: '/home/username/log/maid.log')
38
+
39
+ expect(File.exist?('/home/username/log')).to be true
38
40
  end
39
41
 
40
42
  it 'takes a logger object during intialization' do
@@ -58,8 +60,9 @@ module Maid
58
60
 
59
61
  it 'set the trash to the correct default path' do
60
62
  trash_path = "#{@home}/.local/share/Trash/files/"
61
- expect(FileUtils).to receive(:mkdir_p).with(trash_path).once
63
+
62
64
  maid = Maid.new
65
+
63
66
  expect(maid.trash_path).to eq(trash_path)
64
67
  end
65
68
  end
@@ -71,7 +74,7 @@ module Maid
71
74
 
72
75
  it 'sets the trash to the correct default path' do
73
76
  trash_path = "#{@home}/.Trash/"
74
- expect(FileUtils).to receive(:mkdir_p).with(trash_path).once
77
+
75
78
  maid = Maid.new
76
79
  expect(maid.trash_path).to eq(trash_path)
77
80
  end
@@ -86,8 +89,9 @@ module Maid
86
89
 
87
90
  it 'sets the trash to the given path, if provided' do
88
91
  trash_path = '/home/username/tmp/my_trash/'
89
- expect(FileUtils).to receive(:mkdir_p).with(trash_path).once
92
+
90
93
  maid = Maid.new(trash_path: trash_path)
94
+
91
95
  expect(maid.trash_path).not_to be_nil
92
96
  expect(maid.trash_path).to eq(trash_path)
93
97
  end
@@ -198,6 +202,7 @@ module Maid
198
202
  before do
199
203
  allow(Listen).to receive(:to)
200
204
  allow(Listen).to receive(:start)
205
+ FileUtils.mkdir_p('watch_dir')
201
206
  @maid = Maid.new
202
207
  end
203
208
 
@@ -215,6 +220,8 @@ module Maid
215
220
  # FIXME: Example is too long, shouldn't need the rubocop::disable
216
221
  it 'accepts a hash of options and passes them to Listen' do # rubocop:disable RSpec/ExampleLength
217
222
  hash = { some: :options }
223
+ FileUtils.mkdir_p('some_dir')
224
+
218
225
  @maid.watch('some_dir', hash) do
219
226
  rule 'test' do
220
227
  end
@@ -232,9 +239,29 @@ module Maid
232
239
 
233
240
  @maid.watches.last.run
234
241
  end
242
+
243
+ context('with a non-existent directory') do
244
+ let(:maid) { Maid.new }
245
+
246
+ it 'raises with an intelligible message' do
247
+ expect { maid.watch('/doesnt_exist/') }.to raise_error(/file.*exist/)
248
+ end
249
+
250
+ it 'logs an intelligible message' do
251
+ begin
252
+ maid.watch('/doesnt_exist')
253
+ # Suppressing the exception is fine, because we just want to test
254
+ # that the message is logged when it throws and the test above
255
+ # checks that the exception is raised.
256
+ rescue StandardError # rubocop:disable Lint/SuppressedException
257
+ end
258
+
259
+ expect(logger).to have_received(:warn).with(/file.*exist/)
260
+ end
261
+ end
235
262
  end
236
263
 
237
- describe '#repeat' do
264
+ describe '#repeat', fake_zoneinfo: true do
238
265
  before do
239
266
  @maid = Maid.new
240
267
  end
@@ -73,6 +73,59 @@ module Maid
73
73
  @maid.move([@src_file, another_file], @dst_dir)
74
74
  end
75
75
  end
76
+
77
+ context 'when the destination file already exists' do
78
+ let(:src_file) { '/tmp/src/test_file' }
79
+ let(:dst_dir) { '/tmp/dest/' }
80
+ let(:dst_file) { File.join(dst_dir, File.basename(src_file)) }
81
+ let(:maid) { Maid.new(logger: @logger) }
82
+
83
+ before do
84
+ FileUtils.mkdir_p(File.dirname(src_file))
85
+ FileUtils.mkdir_p(dst_dir)
86
+ FileUtils.touch(src_file)
87
+ FileUtils.touch(dst_file)
88
+ end
89
+
90
+ after do
91
+ FileUtils.rm_rf([src_file, dst_file])
92
+ end
93
+
94
+ context 'by default' do
95
+ let!(:original_mtime) { File.stat(dst_file).mtime }
96
+
97
+ before do
98
+ maid.move(src_file, dst_dir)
99
+ end
100
+
101
+ it 'logs an info message' do
102
+ expect(@logger).to have_received(:info).with(/already/)
103
+ expect(@logger).to have_received(:info).with(/anyway/)
104
+ expect(@logger).not_to have_received(:info).with(/skipping/)
105
+ end
106
+
107
+ it 'overwrites destination' do
108
+ expect(File.stat(dst_file).mtime).not_to eq(original_mtime)
109
+ end
110
+ end
111
+
112
+ context 'when clobber: false' do
113
+ let!(:original_mtime) { File.stat(dst_file).mtime }
114
+
115
+ before do
116
+ maid.move(src_file, dst_dir, clobber: false)
117
+ end
118
+
119
+ it 'logs an info message' do
120
+ expect(@logger).not_to have_received(:info).with(/anyway/)
121
+ expect(@logger).to have_received(:info).with(/skipping/)
122
+ end
123
+
124
+ it "doesn't overwrite the destination file" do
125
+ expect(File.stat(dst_file).mtime).to eq(original_mtime)
126
+ end
127
+ end
128
+ end
76
129
  end
77
130
 
78
131
  describe '#rename' do
data/spec/spec_helper.rb CHANGED
@@ -25,6 +25,39 @@ RSpec.configure do |config|
25
25
  end
26
26
  config.include(FakeFS::SpecHelpers, fakefs: true)
27
27
  config.raise_errors_for_deprecations!
28
+
29
+ config.filter_run focus: true
30
+ config.run_all_when_everything_filtered = true
31
+
32
+ # NOTE: If a test fails because ENOENT /usr/share/zoneinfo/Africa/Abidjan,
33
+ # add `fake_zoneinfo: true` to the describe:
34
+ # `describe(MyClass, fake_zoneinfo: true do`
35
+ config.before(:context, fake_zoneinfo: true) do
36
+ # Rufus needs zoneinfo data to run, but when using FakeFS,
37
+ # /usr/share/zoneinfo doesn't exist on the FakeFS.
38
+ # On Linux, we just have to FakeFS::FileSystem.clone the directory and it
39
+ # just works.
40
+ # OSX is, of course, special. /usr/share/zoneinfo is a symlink on that
41
+ # platform, and `.clone` doesn't seem to be following symlinks. Instead, we
42
+ # have to copy the zoneinfo data to a temporary directory on the live
43
+ # filesystem, enable the FakeFS, clone that temporary directory, create
44
+ # /usr/share/zoneinfo onto the FakeFS, and finally copy the files into it.
45
+ # This way, they're available in the FakeFS where Rufus can find them.
46
+ include FakeFS::SpecHelpers
47
+ FakeFS.activate!
48
+
49
+ if Maid::Platform.osx?
50
+ FakeFS.deactivate!
51
+ FileUtils.mkdir_p('/tmp/')
52
+ FileUtils.cp_r('/usr/share/zoneinfo/', '/tmp/')
53
+ FakeFS.activate!
54
+ FakeFS::FileSystem.clone('/tmp/zoneinfo/')
55
+ FileUtils.mkdir_p('/usr/share/')
56
+ FileUtils.cp_r('/tmp/zoneinfo/', '/usr/share/')
57
+ end
58
+
59
+ FakeFS::FileSystem.clone('/usr/share/zoneinfo') if Maid::Platform.linux?
60
+ end
28
61
  end
29
62
 
30
63
  RSpec::Matchers.define :have_deprecated_method do |expected|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0.pre.alpha.2
4
+ version: 0.10.0.pre.alpha.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Oakes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-31 00:00:00.000000000 Z
12
+ date: 2023-04-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: deprecated
@@ -295,6 +295,20 @@ dependencies:
295
295
  - - "~>"
296
296
  - !ruby/object:Gem::Version
297
297
  version: 13.0.6
298
+ - !ruby/object:Gem::Dependency
299
+ name: rake-notes
300
+ requirement: !ruby/object:Gem::Requirement
301
+ requirements:
302
+ - - ">="
303
+ - !ruby/object:Gem::Version
304
+ version: '0'
305
+ type: :development
306
+ prerelease: false
307
+ version_requirements: !ruby/object:Gem::Requirement
308
+ requirements:
309
+ - - ">="
310
+ - !ruby/object:Gem::Version
311
+ version: '0'
298
312
  - !ruby/object:Gem::Dependency
299
313
  name: redcarpet
300
314
  requirement: !ruby/object:Gem::Requirement
@@ -518,7 +532,7 @@ files:
518
532
  - spec/spec_helper.rb
519
533
  homepage: http://github.com/maid/maid
520
534
  licenses:
521
- - GPLv2
535
+ - GPL-2.0
522
536
  metadata:
523
537
  bug_tracker_uri: https://github.com/maid/maid/issues
524
538
  changelog_uri: https://github.com/maid/maid/blob/master/CHANGELOG.md
@@ -542,7 +556,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
542
556
  - !ruby/object:Gem::Version
543
557
  version: 1.3.1
544
558
  requirements: []
545
- rubygems_version: 3.3.26
559
+ rubygems_version: 3.4.6
546
560
  signing_key:
547
561
  specification_version: 4
548
562
  summary: Be lazy. Let Maid clean up after you, based on rules you define. Think of