directory_monitor 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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +10 -0
- data/bin/watch +16 -0
- data/directory_monitor.gemspec +26 -0
- data/lib/directory_monitor.rb +3 -0
- data/lib/directory_monitor/directory_monitor.rb +87 -0
- data/lib/directory_monitor/options.rb +58 -0
- data/lib/directory_monitor/version.rb +3 -0
- data/test/directory_monitor_tc.rb +182 -0
- data/test/options_tc.rb +74 -0
- data/test/test_helper.rb +8 -0
- data/test/watch_tc.rb +55 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 08b4bc2deea1a908ad8b79db41709a00fc19390c
|
4
|
+
data.tar.gz: 6bfa3afa6899ef873e3941dbd8328ff438e0c813
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 437a78ad4f72ceed502f37a4874c14a23580c89595f7b9af6879094b278885ff50acd36b01244d3475b292f979066cb692deb5b55fec347e8a9685b2a6a94736
|
7
|
+
data.tar.gz: 28ffbb06717d84e29350e8747e7ed9457f2e0f71aef400d81c30c1182faf8c2293a5d90add5f7d4703762bf849e60505a066cc16b227926fb513c90d4eafcf1e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 David A. Love
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# DirectoryMonitor
|
2
|
+
|
3
|
+
The DirectoryMonitor is a very simple utility class used to watch for file
|
4
|
+
modifications in a directory tree. In addition to the DirectoryMonitor class,
|
5
|
+
this gem also includes an executable, `watch`, which is a command line wrapper
|
6
|
+
for invoking the `DirectoryMonitor#on_change` method and executing a shell-
|
7
|
+
command whenever changes are detected.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'directory_monitor'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install directory_monitor
|
22
|
+
|
23
|
+
## Usage of Watch
|
24
|
+
|
25
|
+
To use the `watch` executable, type `watch --help` for a short description of
|
26
|
+
the command-line options supported. There are few additional hints, here.
|
27
|
+
|
28
|
+
TODO: Add hits and examples here.
|
29
|
+
|
30
|
+
My personal favorite usage of this utility is as a very simple continuous test
|
31
|
+
monitor. I usually have my project's Rakefile setup with the default task to
|
32
|
+
execute the test suites for my project. Once done, I'll open a command window
|
33
|
+
(sometimes on my desktop and other times just a pane in tumx) and run the
|
34
|
+
following command:
|
35
|
+
|
36
|
+
watch --force --delay=0.5 --suffix='\.rb' "clear; rake 2>&1 | more"
|
37
|
+
|
38
|
+
This command will cause the rake file to run once, at startup, and from that
|
39
|
+
point on, check every half second for updates to my ruby source files. This
|
40
|
+
is occasionally so helpful I'll actually add this command to my Rakefile
|
41
|
+
as a task named "autotest".
|
42
|
+
|
43
|
+
## Usage of DirectoryMonitor Class
|
44
|
+
|
45
|
+
About the best usage example of the class is provided by the `watch` executable
|
46
|
+
script. See bin/watch for the details.
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/watch
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# watch -- The executable script for monitoring file changes in a directory.
|
4
|
+
|
5
|
+
require "directory_monitor"
|
6
|
+
require "directory_monitor/options"
|
7
|
+
|
8
|
+
opts = Options.parse
|
9
|
+
dm = DirectoryMonitor::DirectoryMonitor.new(opts[:suffix], opts[:delay])
|
10
|
+
at_exit { puts "\n#{ProgName} canceled" }
|
11
|
+
dm.on_change(opts[:loop], opts[:force]) do |*changed|
|
12
|
+
shell_cmd = "#{opts[:shell_command].sub(opts[:token], changed.join(' '))}"
|
13
|
+
puts shell_cmd if opts[:verbose]
|
14
|
+
system(shell_cmd, out: $stdout, err: $stderr)
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'directory_monitor/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "directory_monitor"
|
8
|
+
spec.version = DirectoryMonitor::VERSION
|
9
|
+
spec.authors = ["David A. Love"]
|
10
|
+
spec.email = ["DALove1025@gmail.com"]
|
11
|
+
spec.description = %q{Monitor a directory for file changes.}
|
12
|
+
spec.summary = %q{A Directory Monitor}
|
13
|
+
spec.homepage = "https://github.com/DALove1025/directory_monitor#directorymonitor"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'trollop', '~> 2.0'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "simplecov", "~> 0.9"
|
26
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# DirectoryMonitor -- a simple monitor class for detecting file changes in the
|
2
|
+
# current directory.
|
3
|
+
#
|
4
|
+
# A DirectoryMonitor object sleeps for a specified time and then looks in the
|
5
|
+
# current directory-tree for any changed files matching a particular RegEx.
|
6
|
+
# When file changes are discovered, the DirectoryMonitor yields to the caller
|
7
|
+
# with the pathnames of the changed files. After the yield returns, the
|
8
|
+
# DirectoryMonitor sleeps once again.
|
9
|
+
#
|
10
|
+
# File deletions are not detected.
|
11
|
+
#
|
12
|
+
# Examples:
|
13
|
+
#
|
14
|
+
# Look every second for any differences and print the filenames, one on
|
15
|
+
# each line...
|
16
|
+
#
|
17
|
+
# DirectoryMonitor.new.on_change(true) { |file| puts file }
|
18
|
+
#
|
19
|
+
# Check for new or changed Ruby files every 5 minutes...
|
20
|
+
#
|
21
|
+
# DirectoryMonitor.new('\.rb', 300).on_change { puts "Some ruby changed" }
|
22
|
+
#
|
23
|
+
# Note that the suffix parameter to DirectoryMonitor#new is a RegEx, it is not
|
24
|
+
# a glob-style, filename wild-card. For example, to watch only those files
|
25
|
+
# ending with, say, .dat, use a backslash escape, as in '\.dat', to force a
|
26
|
+
# match on a literal period character.
|
27
|
+
|
28
|
+
require 'find'
|
29
|
+
|
30
|
+
module DirectoryMonitor
|
31
|
+
|
32
|
+
class DirectoryMonitor
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def save_ctimes(files)
|
37
|
+
files.each { |f| @ctimes[f] = @File.ctime(f) }
|
38
|
+
files
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_changed
|
42
|
+
@Find.find('.').select { |f| f =~ @re && @ctimes[f] != @File.ctime(f) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def find
|
46
|
+
save_ctimes(find_changed)
|
47
|
+
end
|
48
|
+
|
49
|
+
public
|
50
|
+
|
51
|
+
attr_writer :Find, :File # Used by the unit tests, see below.
|
52
|
+
|
53
|
+
def initialize(suffix = '.*', delay = 1)
|
54
|
+
@re, @delay = /(#{suffix})$/, delay
|
55
|
+
@Find, @File = Find, File # Dependency-injection hooks for unit-tests.
|
56
|
+
@ctimes = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_change(loopflag = false, force = false) # loops forever.
|
60
|
+
# Unless it's inhibited by the force flag, use the find method to
|
61
|
+
# pre-populate the hash of file-names and ctimes.
|
62
|
+
find unless force
|
63
|
+
begin
|
64
|
+
loop do
|
65
|
+
(loopflag ? find : [ find.join(" ") ]).each do |str|
|
66
|
+
yield str unless str == ""
|
67
|
+
end
|
68
|
+
# Now that we are done with all our yields, use find, one more time
|
69
|
+
# to record all the current ctimes. Since we are done, we can safely
|
70
|
+
# go back to sleep.
|
71
|
+
find
|
72
|
+
sleep(@delay)
|
73
|
+
end
|
74
|
+
rescue SystemExit, Interrupt
|
75
|
+
# Since this is an infinite loop, we sort of expect that an app using
|
76
|
+
# this class will be shut down by a signal or interrupt. So, to be a
|
77
|
+
# bit more graceful, we detect these conditions and "go gently into
|
78
|
+
# that good night." If the app needs to do any clean up, it should
|
79
|
+
# probably implement a trap("EXIT") handler.
|
80
|
+
exit
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# options.rb -- command-line options processing for the watch script.
|
2
|
+
|
3
|
+
require "trollop"
|
4
|
+
|
5
|
+
# Define the strings we display to the user for version identification and the
|
6
|
+
# help message.
|
7
|
+
ProgName = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))
|
8
|
+
Version = "#{ProgName} (#{DirectoryMonitor::VERSION})"
|
9
|
+
Banner = <<-eos
|
10
|
+
#{Version} -- Watch a directory for changes
|
11
|
+
Synopsis
|
12
|
+
Executes a shell-command when files change. If the shell-command contains
|
13
|
+
a double-percent, %%, it is replaced with a space delimited list of path
|
14
|
+
names for the changed files. When used with the --loop option, the shell-
|
15
|
+
command is executed repeatedly, once for each changed file. In this case,
|
16
|
+
%%, if present, is replaced with one path name at a time.
|
17
|
+
|
18
|
+
The --suffix option limits the watched files to only those matching a
|
19
|
+
regular expression, anchored at the end of the file name. Note that this
|
20
|
+
is a RegEx, not a glob wildcard; therfore, to match a file name that
|
21
|
+
contains a period, for example, .txt, the period must be escaped with a
|
22
|
+
backslash. See the examples.
|
23
|
+
|
24
|
+
File deletions are not detected.
|
25
|
+
|
26
|
+
Examples
|
27
|
+
watch -l -d 10 \"echo File %% has changed\"
|
28
|
+
# Every 10 seconds, display each changed file on a separate line.
|
29
|
+
|
30
|
+
watch -s "\\.rb|\\.yaml" rake
|
31
|
+
# Every 5 seconds, run a rake task if any ruby or Yaml file changes.
|
32
|
+
|
33
|
+
Usage
|
34
|
+
#{ProgName} [-fhlvV] [-d <float>] [-st <str>] <shell-command>
|
35
|
+
eos
|
36
|
+
|
37
|
+
class Options
|
38
|
+
|
39
|
+
# Use trollop to handle all our options switches and verify we have some
|
40
|
+
# sort of shell-command specified on the command-line.
|
41
|
+
def self.parse
|
42
|
+
opts = Trollop::options do
|
43
|
+
version "#{Version}"
|
44
|
+
banner Banner.gsub(/^#{Banner[/^ +/, 0]}/, "")
|
45
|
+
opt :suffix, "Regex selecting the files being watched", :default => ".*"
|
46
|
+
opt :delay, "Seconds to sleep between watches", :default => 5.0
|
47
|
+
opt :loop, "Execute individual command for each file"
|
48
|
+
opt :force, "Force a first exectuion on all watched files"
|
49
|
+
opt :token, "String used for file name substitution", :default => "%%"
|
50
|
+
opt :verbose, "Print command on standard output", :short => "V"
|
51
|
+
end
|
52
|
+
Trollop::die "shell command is required" if ARGV.empty?
|
53
|
+
opts[:shell_command] = ARGV.join(" ")
|
54
|
+
opts
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
# Unit testing the DirectoryMonitor class requires a file system that knows
|
4
|
+
# about filenames and modification times. The following class allows us to
|
5
|
+
# mock a simple file system; and, in the process, simulate implementations
|
6
|
+
# of the two class methods that are dependencies of the DirectoryMonitor.
|
7
|
+
|
8
|
+
class ErsatzFileSystem
|
9
|
+
|
10
|
+
@@files = {}
|
11
|
+
|
12
|
+
def self.touch(file) # Creates and resets files.
|
13
|
+
@@files[file] = Time.now
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.ctime(filename) # Simulates File::ctime()
|
17
|
+
raise 'No such filename found' unless @@files[filename]
|
18
|
+
@@files[filename]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find(dir) # Simulates Find::find()
|
22
|
+
@@files.map { |filename, modtime| filename }.to_enum
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
# Patch the DirectoryMonitor class to stub-out the call to Kernel::sleep().
|
28
|
+
# This allows the unit-tests to have synchronous control over DirectoryMonitor
|
29
|
+
# by letting us call resume on the DirectoryMonitor#on_change() fiber.
|
30
|
+
|
31
|
+
class DirectoryMonitor::DirectoryMonitor
|
32
|
+
attr_reader :last_parameter
|
33
|
+
def sleep(delay)
|
34
|
+
@last_parameter = delay
|
35
|
+
Fiber.yield
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class DirectoryMonitor_Base_TestCase < MiniTest::Unit::TestCase
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def setup_file_system
|
44
|
+
%w{
|
45
|
+
Abby.txt
|
46
|
+
Billy.rb
|
47
|
+
Cindy.rb
|
48
|
+
Dan.dat
|
49
|
+
Ellie.txt
|
50
|
+
Frank.rb
|
51
|
+
Gloria.txt
|
52
|
+
Hank.dat
|
53
|
+
Ira.rb.foo
|
54
|
+
}.each { |f| ErsatzFileSystem.touch(f) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup_watcher(suffix, loopflag = false, force = false)
|
58
|
+
@dm = DirectoryMonitor::DirectoryMonitor.new(suffix)
|
59
|
+
@dm.Find = ErsatzFileSystem # Dependency injection for these unit tests
|
60
|
+
@dm.File = ErsatzFileSystem
|
61
|
+
@yield_history = []
|
62
|
+
@dm_fiber = Fiber.new do
|
63
|
+
@dm.on_change(loopflag, force) do |file_response|
|
64
|
+
@yield_history << file_response
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@dm_fiber.resume
|
68
|
+
end
|
69
|
+
|
70
|
+
def run_watcher(*changed_files)
|
71
|
+
changed_files.each{ |file| ErsatzFileSystem.touch(file) }
|
72
|
+
@dm_fiber.resume
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
class DirectoryMonitor_TestCase < DirectoryMonitor_Base_TestCase
|
78
|
+
|
79
|
+
# Create the "object under test" with a simulated file system and its own
|
80
|
+
# fiber for the on_change event.
|
81
|
+
def setup
|
82
|
+
setup_file_system
|
83
|
+
setup_watcher("\\.rb|xyzzy")
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_creation
|
87
|
+
assert_instance_of(DirectoryMonitor::DirectoryMonitor, @dm)
|
88
|
+
assert_equal(1, @dm.last_parameter, "Default delay should be 1 sec")
|
89
|
+
assert_equal(0, @yield_history.length, "No yields should have happend")
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_no_yields_without_file_changes
|
93
|
+
run_watcher
|
94
|
+
assert_equal(0, @yield_history.length)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_only_one_yield_per_set_of_changes
|
98
|
+
run_watcher("Cindy.rb")
|
99
|
+
assert_equal(1, @yield_history.length)
|
100
|
+
run_watcher("Billy.rb", "Cindy.rb", "Dan.dat")
|
101
|
+
assert_equal(2, @yield_history.length)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_change_one_watched_file
|
105
|
+
run_watcher("Cindy.rb")
|
106
|
+
assert_equal(1, @yield_history.length)
|
107
|
+
assert_equal("Cindy.rb", @yield_history[0])
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_change_two_watched_files
|
111
|
+
run_watcher("Cindy.rb", "Frank.rb")
|
112
|
+
assert_equal(1, @yield_history.length)
|
113
|
+
assert_equal("Cindy.rb Frank.rb", @yield_history[0])
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_no_yields_on_unwatched_file_change
|
117
|
+
run_watcher("Dan.dat")
|
118
|
+
assert_equal(0, @yield_history.length)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_yield_with_both_watched_and_unwatched_files
|
122
|
+
run_watcher("Abby.txt", "Cindy.rb", "Dan.dat", "Frank.rb")
|
123
|
+
assert_equal(1, @yield_history.length)
|
124
|
+
assert_equal("Cindy.rb Frank.rb", @yield_history[0])
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_regex_suffix_anchored_at_end_of_filename
|
128
|
+
run_watcher("Abby.txt", "Billy.rb", "Helen.dat", "Ira.rb.foo")
|
129
|
+
assert_equal(1, @yield_history.length)
|
130
|
+
assert_equal("Billy.rb", @yield_history[0])
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
class DirectoryMonitor_Looping_TestCase < DirectoryMonitor_Base_TestCase
|
136
|
+
|
137
|
+
def setup
|
138
|
+
setup_file_system
|
139
|
+
setup_watcher("\\.rb|xyzzy", true)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_looping_yields_for_each_watched_file
|
143
|
+
run_watcher("Abby.txt", "Cindy.rb", "Dan.dat", "Frank.rb")
|
144
|
+
assert_equal(2, @yield_history.length)
|
145
|
+
assert_equal("Cindy.rb", @yield_history[0])
|
146
|
+
assert_equal("Frank.rb", @yield_history[1])
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
class DirectoryMonitor_Force_TestCase < DirectoryMonitor_Base_TestCase
|
152
|
+
|
153
|
+
def setup
|
154
|
+
setup_file_system
|
155
|
+
setup_watcher("\\.rb|xyzzy", false, true)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_initial_forced_yields_all_watched_files
|
159
|
+
run_watcher
|
160
|
+
assert_equal(1, @yield_history.length)
|
161
|
+
assert_equal("Billy.rb Cindy.rb Frank.rb", @yield_history[0])
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
class DirectoryMonitor_Loop_And_Force_TestCase < DirectoryMonitor_Base_TestCase
|
167
|
+
|
168
|
+
def setup
|
169
|
+
setup_file_system
|
170
|
+
setup_watcher("\\.rb|xyzzy", true, true)
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_initial_forced_yields_all_watched_files
|
174
|
+
run_watcher
|
175
|
+
assert_equal(3, @yield_history.length)
|
176
|
+
assert_equal("Billy.rb", @yield_history[0])
|
177
|
+
assert_equal("Cindy.rb", @yield_history[1])
|
178
|
+
assert_equal("Frank.rb", @yield_history[2])
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
data/test/options_tc.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "directory_monitor/options"
|
3
|
+
|
4
|
+
class Optionse_TestCase < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
# We need a way to set the ARGV array, to spoof trollop, which means
|
9
|
+
# redefining a constant. Doing that without generating a Ruby run-time
|
10
|
+
# warning message is tricker than I expected. Here's the simplest way
|
11
|
+
# I've come up with.
|
12
|
+
def set_argv(*args)
|
13
|
+
Object.send(:remove_const, "ARGV")
|
14
|
+
Object.const_set("ARGV", args)
|
15
|
+
end
|
16
|
+
|
17
|
+
public
|
18
|
+
|
19
|
+
def test_default_values
|
20
|
+
set_argv("echo")
|
21
|
+
opts = Options.parse
|
22
|
+
assert_equal(".*", opts[:suffix])
|
23
|
+
assert_equal(5.0, opts[:delay])
|
24
|
+
assert_equal(false, opts[:loop])
|
25
|
+
assert_equal(false, opts[:force])
|
26
|
+
assert_equal("%%", opts[:token])
|
27
|
+
assert_equal(false, opts[:verbose])
|
28
|
+
assert_equal("echo", opts[:shell_command])
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_suffix
|
32
|
+
set_argv("-s", "\\.rb", "echo")
|
33
|
+
assert_equal("\\.rb", Options.parse[:suffix])
|
34
|
+
set_argv("--suffix", "\\.rb", "echo")
|
35
|
+
assert_equal("\\.rb", Options.parse[:suffix])
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_delay
|
39
|
+
set_argv("-d", "12.3", "echo")
|
40
|
+
assert_equal(12.3, Options.parse[:delay])
|
41
|
+
set_argv("--delay", "12.3", "echo")
|
42
|
+
assert_equal(12.3, Options.parse[:delay])
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_loop
|
46
|
+
set_argv("-l", "echo")
|
47
|
+
assert_equal(true, Options.parse[:loop])
|
48
|
+
set_argv("--loop", "echo")
|
49
|
+
assert_equal(true, Options.parse[:loop])
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_force
|
53
|
+
set_argv("-f", "echo")
|
54
|
+
assert_equal(true, Options.parse[:force])
|
55
|
+
set_argv("--force", "echo")
|
56
|
+
assert_equal(true, Options.parse[:force])
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_token
|
60
|
+
set_argv("-t", "FILE", "echo")
|
61
|
+
assert_equal("FILE", Options.parse[:token])
|
62
|
+
set_argv("--token", "FILE", "echo")
|
63
|
+
assert_equal("FILE", Options.parse[:token])
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_verbose
|
67
|
+
set_argv("-V", "echo")
|
68
|
+
assert_equal(true, Options.parse[:verbose])
|
69
|
+
set_argv("--verbose", "echo")
|
70
|
+
assert_equal(true, Options.parse[:verbose])
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
data/test/test_helper.rb
ADDED
data/test/watch_tc.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class Watch_Commandline_TestCase < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
# We need a set of tests that run "out of process" in a way that let's us
|
6
|
+
# both verify that the watch script executable is sort of working, as well
|
7
|
+
# as to verify that --help, --version, and error conditions result in an
|
8
|
+
# appropriate behavior the user will understand.
|
9
|
+
|
10
|
+
# Note that since these tests are run "out of process" by using the system
|
11
|
+
# command (back-tick style), that these test runs do generate input into
|
12
|
+
# the code-coverage report. There aren't many, so it really makes little
|
13
|
+
# difference.
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Execute the "watch" script and capture all output, both stdout and
|
18
|
+
# stderr, and pass it to the caller with yield.
|
19
|
+
def watch(*commands)
|
20
|
+
commands.each do |command|
|
21
|
+
yield (`ruby -Ilib bin/watch #{command} 2>&1`)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
public
|
26
|
+
|
27
|
+
def test_no_command_provided
|
28
|
+
watch("") do |response|
|
29
|
+
assert_match("Error: shell command is required", response)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_options_unknown
|
34
|
+
watch("-x", "--xyzzy") do |response|
|
35
|
+
assert_match("Error: unknown argument", response)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_options_version
|
40
|
+
watch("-v", "--version") do |response|
|
41
|
+
assert_match("watch (#{DirectoryMonitor::VERSION})", response)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_options_help
|
46
|
+
watch("-h", "--help") do |response|
|
47
|
+
assert_match("Synopsis", response) # Spot check the help message.
|
48
|
+
assert_match("Executes", response)
|
49
|
+
assert_match("Usage", response)
|
50
|
+
assert_match("Show this message", response)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: directory_monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David A. Love
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: trollop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
description: Monitor a directory for file changes.
|
70
|
+
email:
|
71
|
+
- DALove1025@gmail.com
|
72
|
+
executables:
|
73
|
+
- watch
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/watch
|
83
|
+
- directory_monitor.gemspec
|
84
|
+
- lib/directory_monitor.rb
|
85
|
+
- lib/directory_monitor/directory_monitor.rb
|
86
|
+
- lib/directory_monitor/options.rb
|
87
|
+
- lib/directory_monitor/version.rb
|
88
|
+
- test/directory_monitor_tc.rb
|
89
|
+
- test/options_tc.rb
|
90
|
+
- test/test_helper.rb
|
91
|
+
- test/watch_tc.rb
|
92
|
+
homepage: https://github.com/DALove1025/directory_monitor#directorymonitor
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.0.3
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: A Directory Monitor
|
116
|
+
test_files:
|
117
|
+
- test/directory_monitor_tc.rb
|
118
|
+
- test/options_tc.rb
|
119
|
+
- test/test_helper.rb
|
120
|
+
- test/watch_tc.rb
|