Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add Monitor#watch_recursively to enable watching subdirs changes

  • Loading branch information...
commit 9a9028c55d49e6ff0fbd03c3b664237d229975ab 1 parent 751bf06
@Maher4Ever authored
View
2  README.md
@@ -9,7 +9,7 @@ it yet in anything (unless you are testing it, which is very much appreciated :)
TODO:
- Fix all the TODO's in the source.
-- Enable watching subdirectories.
+- ~~Enable watching subdirectories.~~
- ~~Add options to the `watch` method.~~
- ~~Provide info about the change in the callback.~~
- ~~Convert \ to / in paths.~~
View
17 ext/wdm/rb_monitor.c
@@ -41,8 +41,11 @@ static VALUE rb_monitor_alloc(VALUE);
static DWORD id_to_flag(ID);
static DWORD extract_flags_from_rb_array(VALUE);
+static VALUE combined_watch(BOOL, int, VALUE*, VALUE);
static VALUE rb_monitor_watch(int, VALUE*, VALUE);
+static VALUE rb_monitor_watch_recursively(int, VALUE*, VALUE);
+
static void CALLBACK handle_entry_change(DWORD, DWORD, LPOVERLAPPED);
static void register_monitoring_entry(WDM_PEntry);
static DWORD WINAPI start_monitoring(LPVOID);
@@ -137,7 +140,7 @@ extract_flags_from_rb_array(VALUE flags_array) {
}
static VALUE
-rb_monitor_watch(int argc, VALUE *argv, VALUE self) {
+combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self) {
WDM_PMonitor monitor;
WDM_PEntry entry;
int directory_letters_count;
@@ -162,6 +165,7 @@ rb_monitor_watch(int argc, VALUE *argv, VALUE self) {
Check_Type(directory, T_STRING);
entry = wdm_entry_new();
+ entry->user_data->watch_childeren = recursively;
entry->user_data->callback = rb_block_proc();
entry->user_data->flags = RARRAY_LEN(flags) == 0 ? WDM_MONITOR_FLAGS_DEFAULT : extract_flags_from_rb_array(flags);
@@ -232,6 +236,16 @@ rb_monitor_watch(int argc, VALUE *argv, VALUE self) {
return Qnil;
}
+static VALUE
+rb_monitor_watch(int argc, VALUE *argv, VALUE self) {
+ return combined_watch(FALSE, argc, argv, self);
+}
+
+static VALUE
+rb_monitor_watch_recursively(int argc, VALUE *argv, VALUE self) {
+ return combined_watch(TRUE, argc, argv, self);
+}
+
static void CALLBACK
handle_entry_change(
DWORD err_code, // completion code
@@ -511,6 +525,7 @@ wdm_rb_monitor_init() {
rb_define_alloc_func(cWDM_Monitor, rb_monitor_alloc);
rb_define_method(cWDM_Monitor, "watch", RUBY_METHOD_FUNC(rb_monitor_watch), -1);
+ rb_define_method(cWDM_Monitor, "watch_recursively", RUBY_METHOD_FUNC(rb_monitor_watch_recursively), -1);
rb_define_method(cWDM_Monitor, "run!", RUBY_METHOD_FUNC(rb_monitor_run_bang), 0);
rb_define_method(cWDM_Monitor, "stop", RUBY_METHOD_FUNC(rb_monitor_stop), 0);
}
View
90 spec/support/monitor_helper.rb
@@ -9,13 +9,71 @@ module SpecSupport
#
# @yield
#
- def run_and_collect_multiple_changes(monitor, times, directory, *flags)
+ def run_and_collect_multiple_changes(monitor, times, directory, *flags, &block)
+ watch_and_run(monitor, times, false, directory, *flags, &block)
+ end
+
+ # Helper method for running the monitor one time.
+ #
+ # @yield
+ #
+ def run(monitor, directory, *flags, &block)
+ result = watch_and_run(monitor, 1, false, directory, *flags, &block)
+ result.changes[0].directory = result.directory
+ result.changes[0]
+ end
+
+ # Helper method for using the run method with the fixture helper.
+ #
+ # @yield
+ #
+ def run_with_fixture(monitor, *flags, &block)
+ fixture do |f|
+ run(monitor, f, *flags, &block)
+ end
+ end
+
+ # Runs the monitor recursively and collects changes for the specified amount of times
+ # on the given directory. It stops the monitor afterwards.
+ #
+ # @yield
+ #
+ def run_recursively_and_collect_multiple_changes(monitor, times, directory, *flags, &block)
+ watch_and_run(monitor, times, true, directory, *flags, &block)
+ end
+
+ # Helper method for running the monitor recursively one time.
+ #
+ # @yield
+ #
+ def run_recursively(monitor, directory, *flags, &block)
+ result = watch_and_run(monitor, 1, true, directory, *flags, &block)
+ result.changes[0].directory = result.directory
+ result.changes[0]
+ end
+
+ # Helper method for using the run method recursively with the fixture helper.
+ #
+ # @yield
+ #
+ def run_recursively_with_fixture(monitor, *flags, &block)
+ fixture do |f|
+ run_recursively(monitor, f, *flags, &block)
+ end
+ end
+
+ private
+
+ # Very customizable method to watch directories and then run the monitor
+ #
+ # @yield
+ #
+ def watch_and_run(monitor, times, recursively, directory, *flags)
result = OpenStruct.new(directory: directory, changes: [])
i = 0
result.changes[i] = OpenStruct.new(called: false)
can_return = false
-
- monitor.watch(directory, *flags) do |change|
+ callback = Proc.new do |change|
next if can_return
result.changes[i].called = true;
@@ -30,6 +88,12 @@ def run_and_collect_multiple_changes(monitor, times, directory, *flags)
end
end
+ if recursively
+ monitor.watch_recursively(directory, *flags, &callback)
+ else
+ monitor.watch(directory, *flags, &callback)
+ end
+
thread = Thread.new(monitor) { |m| m.run! }
sleep(0.2) # give time for the monitor to bootup
@@ -50,25 +114,5 @@ def run_and_collect_multiple_changes(monitor, times, directory, *flags)
monitor.stop
thread.join if thread
end
-
- # Helper method for running the monitor one time.
- #
- # @yield
- #
- def run(monitor, directory, *flags, &block)
- result = run_and_collect_multiple_changes(monitor, 1, directory, *flags, &block)
- result.changes[0].directory = result.directory
- result.changes[0]
- end
-
- # Helper method for using the run method with the fixture helper.
- #
- # @yield
- #
- def run_with_fixture(monitor, *flags, &block)
- fixture do |f|
- run(monitor, f, *flags, &block)
- end
- end
end
end
View
95 spec/wdm/monitor_spec.rb
@@ -1,44 +1,56 @@
require 'spec_helper'
-describe WDM::Monitor do
- describe '#watch' do
- it 'throws an exception when no block is given' do
- expect {
- subject.watch('does not matter')
- }.to raise_error(LocalJumpError, 'no block given')
- end
+shared_examples_for :watch_method do
+ it 'throws an exception when no block is given' do
+ expect {
+ watch_method.call('does not matter')
+ }.to raise_error(LocalJumpError, 'no block given')
+ end
- it 'throws an exception when the passed directory does not exist' do
- expect {
- subject.watch('nonexistent_directory') {}
- }.to raise_error(WDM::InvalidDirectoryError)
- end
+ it 'throws an exception when the passed directory does not exist' do
+ expect {
+ watch_method.call('nonexistent_directory') {}
+ }.to raise_error(WDM::InvalidDirectoryError)
+ end
- it 'throws an exception when the passed directory is a file' do
- expect {
- subject.watch(__FILE__) {}
- }.to raise_error(WDM::InvalidDirectoryError)
- end
+ it 'throws an exception when the passed directory is a file' do
+ expect {
+ watch_method.call(__FILE__) {}
+ }.to raise_error(WDM::InvalidDirectoryError)
+ end
- it 'throws an exception when a non-symbol flag is passed' do
- expect {
- subject.watch('does not matter', "not a symbol") {}
- }.to raise_error(TypeError)
- end
+ it 'throws an exception when a non-symbol flag is passed' do
+ expect {
+ watch_method.call('does not matter', "not a symbol") {}
+ }.to raise_error(TypeError)
+ end
- it 'throws an exception when an unknown flag is passed' do
- expect {
- subject.watch('does not matter', :not_a_flag) {}
- }.to raise_error(WDM::UnknownFlagError)
- end
+ it 'throws an exception when an unknown flag is passed' do
+ expect {
+ watch_method.call('does not matter', :not_a_flag) {}
+ }.to raise_error(WDM::UnknownFlagError)
+ end
- it 'throws an exception when it is called while the monitor is running' do
- expect {
- run_with_fixture(subject) do
- subject.watch('does not matter') {}
- end
- }.to raise_error(WDM::MonitorRunningError)
- end
+ it 'throws an exception when it is called while the monitor is running' do
+ expect {
+ run_with_fixture(subject) do
+ watch_method.call('does not matter') {}
+ end
+ }.to raise_error(WDM::MonitorRunningError)
+ end
+end
+
+describe WDM::Monitor do
+ describe '#watch' do
+ let(:watch_method) { Proc.new { |*args, &block| subject.watch(*args, &block) } }
+
+ it_should_behave_like :watch_method
+ end
+
+ describe '#watch_recursively' do
+ let(:watch_method) { Proc.new { |*args, &block| subject.watch_recursively(*args, &block) } }
+
+ it_should_behave_like :watch_method
end
describe 'run!' do
@@ -143,6 +155,21 @@
end
end
+ context 'when directories are registered with (watch_recursively)' do
+ it 'detects changes in subdirectories' do
+ fixture do |dir|
+ mkdir 'some_dir'
+
+ result = run_recursively(subject, dir) do
+ touch 'some_dir/file.txt'
+ end
+
+ result.change.path.should == "#{result.directory}/some_dir/file.txt"
+ result.change.type.should == :added
+ end
+ end
+ end
+
it 'marks changed paths as tainted' do
result = run_with_fixture(subject) do
touch 'file.txt'
Please sign in to comment.
Something went wrong with that request. Please try again.