wdm 0.0.3 → 0.1.0

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.
data/LICENSE CHANGED
@@ -1,22 +1,22 @@
1
- Copyright (c) 2012 Maher Sallam
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
1
+ Copyright (c) 2012 Maher Sallam
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
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,25 +1,14 @@
1
1
  # Windows Directory Monitor (WDM)
2
2
 
3
- Windows Directory Monitor (WDM) is a library which can be used to monitor directories for changes.
4
- It's mostly implemented in C and uses the Win32 API for a better performance.
5
-
6
- **Note:** This is still a work in progress, so it's not advisable to use
7
- it yet in anything (unless you are testing it, which is very much appreciated :)).
3
+ Windows Directory Monitor (WDM) is a thread-safe ruby library which can be used to monitor directories for changes on Windows.
8
4
 
9
- TODO:
5
+ It's mostly implemented in C and uses the Win32 API for a better performance.
10
6
 
11
- - Fix all the TODO's in the source.
12
- - ~~Enable watching subdirectories.~~
13
- - ~~Add options to the `watch` method.~~
14
- - ~~Provide info about the change in the callback.~~
15
- - ~~Convert \ to / in paths.~~
16
- - ~~Don't allow directories to be watched while the monitor is running.~~
17
- - ~~Check if the passed direcoty exists.~~
18
- - ~~Convert passed directories to absolute paths.~~
7
+ **Important**: WDM only runs on ruby versions >= *1.9.2*!
19
8
 
20
9
  ## Installation
21
10
 
22
- Add this line to your application's Gemfile:
11
+ If you are using Bundler, add the following line to your application's Gemfile:
23
12
 
24
13
  gem 'wdm'
25
14
 
@@ -31,20 +20,180 @@ Or install it yourself as:
31
20
 
32
21
  $ gem install wdm
33
22
 
23
+ ## Usage
24
+
25
+ For a simple example on how to use WDM, you can take a look at the `example` directory of the repository.
26
+
27
+ ## Benchmarks
28
+
29
+ You can find a comparison of different ruby libraries for watching directory changes on Windows in the `benchmark` directory of the repository.
30
+
31
+ ## Reference
32
+
33
+ ### `WDM::Monitor`
34
+
35
+ To start watching directories, you need an instance of `WDM::Monitor`:
36
+
37
+ ```ruby
38
+ monitor = WDM::Monitor.new
39
+ ```
40
+
41
+ After that, register a callback for each directory you want to watch:
42
+
43
+ ```ruby
44
+ # Watch a single directory
45
+ monitor.watch('C:\Users\Maher\Desktop') { |change| puts change.path }
46
+
47
+ # Watch a directory with its subdirectories
48
+ monitor.watch_recursively('C:\Users\Maher\Projects\my_project') { |change| puts change.path }
49
+ ```
50
+
51
+ Both `Monitor#watch` and `Monitor#watch_recursively` can take a series of options after the first parameter to specify the watching options:
52
+
53
+ ```ruby
54
+ # Report changes to directories in the watched directory (Ex.: Addition of an empty directory)
55
+ monitor.watch('C:\Users\Maher\Desktop', :default, :directories)
56
+ ```
57
+
58
+ The supported options are:
59
+
60
+ <table>
61
+ <thead>
62
+ <tr>
63
+ <th>Value</th>
64
+ <th>Meaning</th>
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <tr>
69
+ <td>:default</td>
70
+
71
+ <td>
72
+ The default set of options for watching directories. It's a combination of the :files, :directories and the :last_write options.
73
+ </td>
74
+ </tr>
75
+
76
+ <tr>
77
+ <td>:files</td>
78
+
79
+ <td>
80
+ Any file name change in the watched directory or subtree causes a change
81
+ notification wait operation to return. Changes include renaming, creating, or
82
+ deleting a file.
83
+ </td>
84
+ </tr>
85
+
86
+ <tr>
87
+ <td>:directories</td>
88
+
89
+ <td>
90
+ Any directory-name change in the watched directory or subtree causes a
91
+ change notification wait operation to return. Changes include creating or
92
+ deleting a directory.
93
+ </td>
94
+ </tr>
95
+
96
+ <tr>
97
+ <td>:attributes</td>
98
+
99
+ <td>
100
+ Any attribute change in the watched directory or subtree causes a change
101
+ notification wait operation to return.
102
+ </td>
103
+ </tr>
104
+
105
+ <tr>
106
+ <td>:size</td>
107
+
108
+ <td>
109
+ Any file-size change in the watched directory or subtree causes a change
110
+ notification wait operation to return. The operating system detects a change in
111
+ file size only when the file is written to the disk. For operating systems that
112
+ use extensive caching, detection occurs only when the cache is sufficiently
113
+ flushed.
114
+ </td>
115
+ </tr>
116
+
117
+ <tr>
118
+ <td>:last_write</td>
119
+
120
+ <td>
121
+ Any change to the last write-time of files in the watched directory or
122
+ subtree causes a change notification wait operation to return. The operating
123
+ system detects a change to the last write-time only when the file is written to
124
+ the disk. For operating systems that use extensive caching, detection occurs
125
+ only when the cache is sufficiently flushed.
126
+ </td>
127
+ </tr>
128
+
129
+ <tr>
130
+ <td>:last_access</td>
131
+
132
+ <td>
133
+ Any change to the last access time of files in the watched directory or
134
+ subtree causes a change notification wait operation to return.
135
+ </td>
136
+ </tr>
137
+
138
+ <tr>
139
+ <td>:creation</td>
140
+
141
+ <td>
142
+ Any change to the creation time of files in the watched directory or subtree
143
+ causes a change notification wait operation to return.
144
+ </td>
145
+ </tr>
146
+
147
+ <tr>
148
+ <td>:security</td>
149
+
150
+ <td>
151
+ Any security-descriptor change in the watched directory or subtree causes a
152
+ change notification wait operation to return.
153
+ </td>
154
+ </tr>
155
+ </tbody>
156
+ </table>
157
+
158
+ These options map to the filters that `ReadDirectoryChangesW` takes in its `dwNotifyFilter` parameter. You can find more info on the [docs page](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465.aspx) of `ReadDirectoryChangesW`.
159
+
160
+ Now all that's left to be done is to run the monitor:
161
+
162
+ ```ruby
163
+ monitor.run!
164
+ ```
165
+
166
+ The `Monitor#run!` method blocks the process. Since monitors are thread-safe, you can run them in a thread if you don't want to block your main one:
167
+
168
+ ```ruby
169
+ worker_thread = Thread.new { monitor.run! }
170
+
171
+ # The process won't block; it will continue with the next line of code...
172
+ ```
173
+
174
+ When you are done with the monitor, don't forget to stop it. Here is a snippet to always stop the monitor when the ruby process exits:
175
+
176
+ ```ruby
177
+ at_exit { monitor.stop }
178
+ ```
179
+
180
+ ### `WDM::Change`
181
+
182
+ The passed argument to the block is an instance of `WDM::Change`. This class has two methods:
183
+
184
+ - `Change#path`: The absolute path to the change.
185
+ - `Change#type`: This can be one of the following values: `:added`, `:modified`, `:removed`, `:renamed_old_file` or `:renamed_new_file`.
186
+
34
187
  ## Compiling the extension for developers
35
188
 
36
189
  Download the source, then run the following:
37
190
 
38
- $ rake compile
191
+ $ bundle exec rake compile
39
192
 
40
193
  To get debug messages, you need to enable them in the `global.h` file:
41
194
 
42
195
  #define WDM_DEBUG_ENABLED TRUE // This is disabled by default
43
196
 
44
- ## Usage
45
-
46
- TODO: Write usage instructions here
47
-
48
197
  ## Contributing
49
198
 
50
199
  1. Fork it
@@ -8,7 +8,8 @@
8
8
  // ---------------------------------------------------------
9
9
 
10
10
  WDM_PEntryUserData
11
- wdm_entry_user_data_new() {
11
+ wdm_entry_user_data_new()
12
+ {
12
13
  WDM_PEntryUserData user_data;
13
14
 
14
15
  user_data = WDM_ALLOC(WDM_EntryUserData);
@@ -20,7 +21,8 @@ wdm_entry_user_data_new() {
20
21
  }
21
22
 
22
23
  void
23
- wdm_entry_user_data_free(WDM_PEntryUserData user_data) {
24
+ wdm_entry_user_data_free(WDM_PEntryUserData user_data)
25
+ {
24
26
  if ( user_data->dir != NULL ) free(user_data->dir);
25
27
  free(user_data);
26
28
  }
@@ -30,7 +32,8 @@ wdm_entry_user_data_free(WDM_PEntryUserData user_data) {
30
32
  // ---------------------------------------------------------
31
33
 
32
34
  WDM_PEntry
33
- wdm_entry_new() {
35
+ wdm_entry_new()
36
+ {
34
37
  WDM_PEntry entry;
35
38
 
36
39
  entry = WDM_ALLOC(WDM_Entry);
@@ -46,7 +49,8 @@ wdm_entry_new() {
46
49
  }
47
50
 
48
51
  void
49
- wdm_entry_free(WDM_PEntry entry) {
52
+ wdm_entry_free(WDM_PEntry entry)
53
+ {
50
54
  if ( entry->dir_handle != INVALID_HANDLE_VALUE ) {
51
55
  CancelIo(entry->dir_handle); // Stop monitoring changes
52
56
  CloseHandle(entry->dir_handle);
@@ -56,7 +60,8 @@ wdm_entry_free(WDM_PEntry entry) {
56
60
  }
57
61
 
58
62
  void
59
- wdm_entry_list_free(WDM_PEntry entry) {
63
+ wdm_entry_list_free(WDM_PEntry entry)
64
+ {
60
65
  WDM_PEntry tmp;
61
66
 
62
67
  while(entry != NULL) {
@@ -1,9 +1,27 @@
1
1
  require 'mkmf'
2
+ require 'rbconfig'
2
3
 
3
- if have_library("kernel32") and
4
+ def generate_makefile
5
+ create_makefile("wdm_ext")
6
+ end
7
+
8
+ def generate_dummy_makefile
9
+ File.open("Makefile", "w") do |f|
10
+ f.puts dummy_makefile('wdm_ext').join
11
+ end
12
+ end
13
+
14
+ def windows?
15
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
16
+ end
17
+
18
+ if windows? and
19
+ have_library("kernel32") and
4
20
  have_header("windows.h") and
5
21
  have_header("ruby.h") and
6
22
  have_const('HAVE_RUBY_ENCODING_H')
7
23
  then
8
- create_makefile("wdm")
24
+ generate_makefile()
25
+ else
26
+ generate_dummy_makefile()
9
27
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  #include "memory.h"
4
4
 
5
- void *
5
+ void*
6
6
  wdm_memory_malloc (size_t size)
7
7
  {
8
8
  void *memory = malloc(size);
@@ -14,7 +14,7 @@ wdm_memory_malloc (size_t size)
14
14
  return memory;
15
15
  }
16
16
 
17
- void *
17
+ void*
18
18
  wdm_memory_realloc (void *ptr, size_t size)
19
19
  {
20
20
  void *memory = realloc(ptr, size);
@@ -9,11 +9,9 @@ extern "C" {
9
9
  // Prototypes
10
10
  // ---------------------------------------------------------
11
11
 
12
- void *
13
- wdm_memory_malloc (size_t);
12
+ void* wdm_memory_malloc (size_t);
14
13
 
15
- void *
16
- wdm_memory_realloc (void *, size_t);
14
+ void* wdm_memory_realloc (void*, size_t);
17
15
 
18
16
  // ---------------------------------------------------------
19
17
  // Macros
@@ -7,7 +7,8 @@
7
7
  #include "monitor.h"
8
8
 
9
9
  WDM_PMonitor
10
- wdm_monitor_new() {
10
+ wdm_monitor_new()
11
+ {
11
12
  WDM_PMonitor monitor;
12
13
 
13
14
  monitor = WDM_ALLOC(WDM_Monitor);
@@ -32,7 +33,8 @@ wdm_monitor_new() {
32
33
  }
33
34
 
34
35
  void
35
- wdm_monitor_free(WDM_PMonitor monitor) {
36
+ wdm_monitor_free(WDM_PMonitor monitor)
37
+ {
36
38
  if ( monitor->monitoring_thread != INVALID_HANDLE_VALUE ) CloseHandle(monitor->monitoring_thread);
37
39
 
38
40
  wdm_entry_list_free(monitor->head);
@@ -45,7 +47,8 @@ wdm_monitor_free(WDM_PMonitor monitor) {
45
47
  }
46
48
 
47
49
  void
48
- wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head) {
50
+ wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head)
51
+ {
49
52
  EnterCriticalSection(&monitor->lock);
50
53
  new_head->next = monitor->head;
51
54
  monitor->head = new_head;
@@ -53,7 +56,8 @@ wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head) {
53
56
  }
54
57
 
55
58
  WDM_PMonitorCallbackParam
56
- wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry) {
59
+ wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry)
60
+ {
57
61
  WDM_PMonitorCallbackParam param;
58
62
 
59
63
  param = WDM_ALLOC(WDM_MonitorCallbackParam);
@@ -65,6 +69,7 @@ wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry) {
65
69
  }
66
70
 
67
71
  void
68
- wdm_monitor_callback_param_free(WDM_PMonitorCallbackParam param) {
72
+ wdm_monitor_callback_param_free(WDM_PMonitorCallbackParam param)
73
+ {
69
74
  free(param);
70
75
  }
@@ -5,11 +5,19 @@
5
5
  #include "memory.h"
6
6
  #include "queue.h"
7
7
 
8
+ // ---------------------------------------------------------
9
+ // Prototypes of static functions
10
+ // ---------------------------------------------------------
11
+
12
+ static WDM_PQueueItem do_queue_dequeue(WDM_PQueue queue);
13
+
8
14
  // ---------------------------------------------------------
9
15
  // Queue item functions
10
16
  // ---------------------------------------------------------
11
17
 
12
- WDM_PQueueItemError wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...) {
18
+ WDM_PQueueItemError
19
+ wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...)
20
+ {
13
21
  WDM_PQueueItemError error;
14
22
  va_list ap;
15
23
  int length;
@@ -27,15 +35,19 @@ WDM_PQueueItemError wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...
27
35
  return error;
28
36
  }
29
37
 
30
- void wdm_queue_item_error_free(WDM_PQueueItemError error) {
38
+ void
39
+ wdm_queue_item_error_free(WDM_PQueueItemError error)
40
+ {
31
41
  if ( error->message != NULL ) free(error->message);
32
42
  free(error);
33
43
  }
34
44
 
35
- WDM_PQueueItemData wdm_queue_item_data_new() {
45
+ WDM_PQueueItemData
46
+ wdm_queue_item_data_new()
47
+ {
36
48
  WDM_PQueueItemData data;
37
49
 
38
- data = ALLOC(WDM_QueueItemData);
50
+ data = WDM_ALLOC(WDM_QueueItemData);
39
51
  data->user_data = NULL;
40
52
 
41
53
  ZeroMemory(&data->buffer, WDM_BUFFER_SIZE);
@@ -43,12 +55,15 @@ WDM_PQueueItemData wdm_queue_item_data_new() {
43
55
  return data;
44
56
  }
45
57
 
46
- void wdm_queue_item_data_free(WDM_PQueueItemData data) {
58
+ void
59
+ wdm_queue_item_data_free(WDM_PQueueItemData data)
60
+ {
47
61
  free(data);
48
62
  }
49
63
 
50
64
  WDM_PQueueItem
51
- wdm_queue_item_new(WDM_QueueItemType type) {
65
+ wdm_queue_item_new(WDM_QueueItemType type)
66
+ {
52
67
  WDM_PQueueItem item;
53
68
 
54
69
  item = WDM_ALLOC(WDM_QueueItem);
@@ -61,14 +76,14 @@ wdm_queue_item_new(WDM_QueueItemType type) {
61
76
  item->data = NULL;
62
77
  }
63
78
 
64
- item->previous = NULL;
65
79
  item->next = NULL;
66
80
 
67
81
  return item;
68
82
  }
69
83
 
70
84
  void
71
- wdm_queue_item_free(WDM_PQueueItem item) {
85
+ wdm_queue_item_free(WDM_PQueueItem item)
86
+ {
72
87
  if ( item->type == WDM_QUEUE_ITEM_TYPE_ERROR ) {
73
88
  if ( item->error != NULL ) wdm_queue_item_error_free(item->error);
74
89
  }
@@ -76,8 +91,8 @@ wdm_queue_item_free(WDM_PQueueItem item) {
76
91
  if ( item->data != NULL ) wdm_queue_item_data_free(item->data);
77
92
  }
78
93
 
79
- // We can't really do anything to the prev pointer nor the next pointer,
80
- // because we might break any linking the user has established.
94
+ // We can't really do anything to the next pointer because
95
+ // we might break any linking the user has established.
81
96
  free(item);
82
97
  }
83
98
 
@@ -86,7 +101,8 @@ wdm_queue_item_free(WDM_PQueueItem item) {
86
101
  // ---------------------------------------------------------
87
102
 
88
103
  WDM_PQueue
89
- wdm_queue_new() {
104
+ wdm_queue_new()
105
+ {
90
106
  WDM_PQueue queue;
91
107
 
92
108
  queue = WDM_ALLOC(WDM_Queue);
@@ -103,21 +119,22 @@ wdm_queue_new() {
103
119
  }
104
120
 
105
121
  void
106
- wdm_queue_free(WDM_PQueue queue) {
122
+ wdm_queue_free(WDM_PQueue queue)
123
+ {
107
124
  wdm_queue_empty(queue);
108
125
  free(queue);
109
126
  }
110
127
 
111
128
  void
112
- wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item) {
129
+ wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item)
130
+ {
113
131
  EnterCriticalSection(&queue->lock);
114
132
 
115
- if ( queue->rear == NULL && queue->front == NULL ) {
133
+ if ( wdm_queue_is_empty(queue) ) {
116
134
  queue->front = queue->rear = item;
117
135
  }
118
136
  else {
119
137
  queue->rear->next = item;
120
- item->previous = queue->rear;
121
138
  queue->rear = item;
122
139
  }
123
140
 
@@ -125,12 +142,11 @@ wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item) {
125
142
  }
126
143
 
127
144
  WDM_PQueueItem
128
- wdm_queue_dequeue(WDM_PQueue queue) {
145
+ do_queue_dequeue(WDM_PQueue queue)
146
+ {
129
147
  WDM_PQueueItem item;
130
148
 
131
- EnterCriticalSection(&queue->lock);
132
-
133
- if ( queue->rear == NULL && queue->front == NULL ) {
149
+ if ( wdm_queue_is_empty(queue) ) {
134
150
  item = NULL;
135
151
  }
136
152
  else {
@@ -141,21 +157,40 @@ wdm_queue_dequeue(WDM_PQueue queue) {
141
157
  if ( queue->front == NULL ) queue->rear = NULL;
142
158
 
143
159
  // Don't allow the user to mess with the queue
144
- item->previous = item->next = NULL;
160
+ item->next = NULL;
145
161
  }
146
162
 
163
+ return item;
164
+ }
165
+
166
+ WDM_PQueueItem
167
+ wdm_queue_dequeue(WDM_PQueue queue)
168
+ {
169
+ WDM_PQueueItem item;
170
+
171
+ EnterCriticalSection(&queue->lock);
172
+
173
+ item = do_queue_dequeue(queue);
174
+
147
175
  LeaveCriticalSection(&queue->lock);
148
176
 
149
177
  return item;
150
178
  }
151
179
 
152
- void wdm_queue_empty(WDM_PQueue queue) {
180
+ void
181
+ wdm_queue_empty(WDM_PQueue queue)
182
+ {
183
+ EnterCriticalSection(&queue->lock);
184
+
153
185
  while( ! wdm_queue_is_empty(queue) ) {
154
- wdm_queue_item_free(wdm_queue_dequeue(queue));
186
+ wdm_queue_item_free( do_queue_dequeue(queue) );
155
187
  }
188
+
189
+ LeaveCriticalSection(&queue->lock);
156
190
  }
157
191
 
158
- BOOL
159
- wdm_queue_is_empty(WDM_PQueue queue) {
192
+ inline BOOL
193
+ wdm_queue_is_empty(WDM_PQueue queue)
194
+ {
160
195
  return queue->front == NULL && queue->rear == NULL;
161
196
  }
@@ -34,11 +34,10 @@ typedef struct WDM_QueueItem {
34
34
  WDM_PQueueItemData data;
35
35
  WDM_PQueueItemError error;
36
36
  };
37
- struct WDM_QueueItem* previous;
38
37
  struct WDM_QueueItem* next;
39
38
  } WDM_QueueItem, *WDM_PQueueItem;
40
39
 
41
- typedef struct WDM_Queue {
40
+ typedef struct {
42
41
  CRITICAL_SECTION lock;
43
42
  WDM_PQueueItem front;
44
43
  WDM_PQueueItem rear;
@@ -11,7 +11,7 @@
11
11
  // Internal constants
12
12
  // ---------------------------------------------------------
13
13
 
14
- // The _wsplitpat constants account for two NULL chars, so substract 1 because we only need one!
14
+ // The _wsplitpat constants account for two NULL chars, so subtract 1 because we only need one!
15
15
  #define WDM_MAX_FILENAME (_MAX_FNAME + _MAX_EXT - 1)
16
16
 
17
17
  // ----------------------------------------------------------
@@ -38,10 +38,11 @@ static VALUE extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATIO
38
38
  // ----------------------------------------------------------
39
39
 
40
40
  // TODO:
41
- // 1. this function uses a lot of 'alloca' calls, which AFAIK is not recommeneded! Can this be avoided?
41
+ // 1. this function uses a lot of 'alloca' calls, which AFAIK is not recommended! Can this be avoided?
42
42
  // 2. all wcscat calls can be done faster with memcpy, but is it worth sacrificing the readability?
43
43
  static VALUE
44
- extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info) {
44
+ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
45
+ {
45
46
  LPWSTR buffer, absolute_filepath;
46
47
  WCHAR file[_MAX_FNAME], ext[_MAX_EXT], filename[WDM_MAX_FILENAME];
47
48
  DWORD filename_len, absolute_filepath_len;
@@ -115,7 +116,7 @@ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIF
115
116
  }
116
117
  }
117
118
 
118
- // The convention in Ruby is to use forward-slashes to seprarate dirs on all platforms.
119
+ // The convention in Ruby is to use forward-slashes to separate dirs on all platforms.
119
120
  wdm_utils_convert_back_to_forward_slashes(absolute_filepath, absolute_filepath_len + 1);
120
121
 
121
122
  // Convert the path from WCHAR to multibyte CHAR to use it in a ruby string
@@ -141,7 +142,8 @@ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIF
141
142
  }
142
143
 
143
144
  static VALUE
144
- extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info) {
145
+ extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info)
146
+ {
145
147
  ID type;
146
148
 
147
149
  switch(info->Action) {
@@ -162,7 +164,8 @@ extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info) {
162
164
  }
163
165
 
164
166
  VALUE
165
- wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info) {
167
+ wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
168
+ {
166
169
  VALUE change;
167
170
 
168
171
  change = rb_class_new_instance(0, NULL, cWDM_Change);
@@ -177,7 +180,8 @@ wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_IN
177
180
  }
178
181
 
179
182
  void
180
- wdm_rb_change_init() {
183
+ wdm_rb_change_init()
184
+ {
181
185
  WDM_DEBUG("Registering WDM::Event with Ruby!");
182
186
 
183
187
  wdm_rb_sym_at_path = rb_intern("@path");
@@ -60,7 +60,8 @@ static VALUE rb_monitor_stop(VALUE);
60
60
  // ----------------------------------------------------------
61
61
 
62
62
  static void
63
- monitor_mark(LPVOID param) {
63
+ monitor_mark(LPVOID param)
64
+ {
64
65
  WDM_PMonitor monitor;
65
66
  WDM_PEntry entry;
66
67
 
@@ -74,7 +75,8 @@ monitor_mark(LPVOID param) {
74
75
  }
75
76
 
76
77
  static void
77
- monitor_free(LPVOID param) {
78
+ monitor_free(LPVOID param)
79
+ {
78
80
  WDM_PMonitor monitor;
79
81
  WDM_PEntry entry;
80
82
 
@@ -98,7 +100,8 @@ monitor_free(LPVOID param) {
98
100
  }
99
101
 
100
102
  static VALUE
101
- rb_monitor_alloc(VALUE self) {
103
+ rb_monitor_alloc(VALUE self)
104
+ {
102
105
  WDM_DEBUG("--------------------------------");
103
106
  WDM_DEBUG("Allocating a new monitor object!");
104
107
  WDM_DEBUG("--------------------------------");
@@ -107,10 +110,11 @@ rb_monitor_alloc(VALUE self) {
107
110
  }
108
111
 
109
112
  static DWORD
110
- id_to_flag(ID id) {
113
+ id_to_flag(ID id)
114
+ {
111
115
  if ( id == wdm_rb_sym_default ) return WDM_MONITOR_FLAGS_DEFAULT;
112
116
 
113
- // TODO: Maybe reorder the if's in the frequentie of use for better performance?
117
+ // TODO: Maybe reorder the if's in the frequency of use for better performance?
114
118
  if ( id == wdm_rb_sym_files ) return FILE_NOTIFY_CHANGE_FILE_NAME;
115
119
  if ( id == wdm_rb_sym_directories ) return FILE_NOTIFY_CHANGE_DIR_NAME;
116
120
  if ( id == wdm_rb_sym_attributes ) return FILE_NOTIFY_CHANGE_ATTRIBUTES;
@@ -124,7 +128,8 @@ id_to_flag(ID id) {
124
128
  }
125
129
 
126
130
  static DWORD
127
- extract_flags_from_rb_array(VALUE flags_array) {
131
+ extract_flags_from_rb_array(VALUE flags_array)
132
+ {
128
133
  VALUE flag_symbol;
129
134
  DWORD flags;
130
135
 
@@ -140,7 +145,8 @@ extract_flags_from_rb_array(VALUE flags_array) {
140
145
  }
141
146
 
142
147
  static VALUE
143
- combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self) {
148
+ combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self)
149
+ {
144
150
  WDM_PMonitor monitor;
145
151
  WDM_PEntry entry;
146
152
  int directory_letters_count;
@@ -237,12 +243,14 @@ combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self) {
237
243
  }
238
244
 
239
245
  static VALUE
240
- rb_monitor_watch(int argc, VALUE *argv, VALUE self) {
246
+ rb_monitor_watch(int argc, VALUE *argv, VALUE self)
247
+ {
241
248
  return combined_watch(FALSE, argc, argv, self);
242
249
  }
243
250
 
244
251
  static VALUE
245
- rb_monitor_watch_recursively(int argc, VALUE *argv, VALUE self) {
252
+ rb_monitor_watch_recursively(int argc, VALUE *argv, VALUE self)
253
+ {
246
254
  return combined_watch(TRUE, argc, argv, self);
247
255
  }
248
256
 
@@ -256,7 +264,7 @@ handle_entry_change(
256
264
  WDM_PQueueItem data_to_process;
257
265
 
258
266
  if ( err_code == ERROR_OPERATION_ABORTED ) {
259
- // Async operation was canceld. This shouldn't happen.
267
+ // Async operation was canceled. This shouldn't happen.
260
268
  // TODO:
261
269
  // 1. Maybe add a union in the queue for errors?
262
270
  // 2. What's the best action when this happens?
@@ -293,7 +301,8 @@ handle_entry_change(
293
301
  }
294
302
 
295
303
  static BOOL
296
- register_monitoring_entry(WDM_PEntry entry) {
304
+ register_monitoring_entry(WDM_PEntry entry)
305
+ {
297
306
  BOOL success;
298
307
  DWORD bytes;
299
308
  bytes = 0; // Not used because the process callback gets passed the written bytes
@@ -318,7 +327,8 @@ register_monitoring_entry(WDM_PEntry entry) {
318
327
  }
319
328
 
320
329
  static DWORD WINAPI
321
- start_monitoring(LPVOID param) {
330
+ start_monitoring(LPVOID param)
331
+ {
322
332
  WDM_PMonitor monitor;
323
333
  WDM_PEntry curr_entry;
324
334
 
@@ -361,7 +371,8 @@ start_monitoring(LPVOID param) {
361
371
  }
362
372
 
363
373
  static VALUE
364
- wait_for_changes(LPVOID param) {
374
+ wait_for_changes(LPVOID param)
375
+ {
365
376
  HANDLE process_event;
366
377
 
367
378
  process_event = (HANDLE)param;
@@ -370,7 +381,8 @@ wait_for_changes(LPVOID param) {
370
381
  }
371
382
 
372
383
  static void
373
- process_changes(WDM_PQueue changes) {
384
+ process_changes(WDM_PQueue changes)
385
+ {
374
386
  WDM_PQueueItem item;
375
387
  LPBYTE current_info_entry_offset;
376
388
  PFILE_NOTIFY_INFORMATION info;
@@ -412,7 +424,8 @@ process_changes(WDM_PQueue changes) {
412
424
  }
413
425
 
414
426
  static void
415
- stop_monitoring(LPVOID param) {
427
+ stop_monitoring(LPVOID param)
428
+ {
416
429
  BOOL already_stopped;
417
430
  WDM_PMonitor monitor;
418
431
  WDM_PEntry entry;
@@ -449,8 +462,8 @@ stop_monitoring(LPVOID param) {
449
462
  }
450
463
 
451
464
  static VALUE
452
- rb_monitor_run_bang(VALUE self) {
453
- DWORD thread_id;
465
+ rb_monitor_run_bang(VALUE self)
466
+ {
454
467
  BOOL already_running,
455
468
  waiting_succeeded;
456
469
  WDM_PMonitor monitor;
@@ -484,7 +497,7 @@ rb_monitor_run_bang(VALUE self) {
484
497
  start_monitoring, // thread function name
485
498
  monitor, // argument to thread function
486
499
  0, // use default creation flags
487
- &thread_id // returns the thread identifier
500
+ NULL // Ignore thread identifier
488
501
  );
489
502
 
490
503
  if ( monitor->monitoring_thread == NULL ) {
@@ -514,7 +527,8 @@ rb_monitor_run_bang(VALUE self) {
514
527
  }
515
528
 
516
529
  static VALUE
517
- rb_monitor_stop(VALUE self) {
530
+ rb_monitor_stop(VALUE self)
531
+ {
518
532
  WDM_PMonitor monitor;
519
533
 
520
534
  Data_Get_Struct(self, WDM_Monitor, monitor);
@@ -527,7 +541,8 @@ rb_monitor_stop(VALUE self) {
527
541
  }
528
542
 
529
543
  void
530
- wdm_rb_monitor_init() {
544
+ wdm_rb_monitor_init()
545
+ {
531
546
  WDM_DEBUG("Registering WDM::Monitor with Ruby!");
532
547
 
533
548
  wdm_rb_sym_call = rb_intern("call");
@@ -8,7 +8,8 @@
8
8
  // ---------------------------------------------------------
9
9
 
10
10
  LPWSTR
11
- wdm_utils_convert_back_to_forward_slashes(LPWSTR path, DWORD path_len) {
11
+ wdm_utils_convert_back_to_forward_slashes(LPWSTR path, DWORD path_len)
12
+ {
12
13
  UINT i;
13
14
 
14
15
  for(i = 0; i < (path_len - 1); ++i) { // path_len-1 because we don't need to check the NULL-char!
@@ -19,7 +20,8 @@ wdm_utils_convert_back_to_forward_slashes(LPWSTR path, DWORD path_len) {
19
20
  }
20
21
 
21
22
  LPWSTR
22
- wdm_utils_full_pathname(const LPWSTR path) {
23
+ wdm_utils_full_pathname(const LPWSTR path)
24
+ {
23
25
  WCHAR maxed_path[WDM_MAX_WCHAR_LONG_PATH];
24
26
  LPWSTR full_path;
25
27
  size_t full_path_len;
@@ -42,7 +44,8 @@ wdm_utils_full_pathname(const LPWSTR path) {
42
44
  }
43
45
 
44
46
  BOOL
45
- wdm_utils_unicode_is_directory(const LPWSTR path) {
47
+ wdm_utils_unicode_is_directory(const LPWSTR path)
48
+ {
46
49
  WCHAR unicode_path[WDM_MAX_WCHAR_LONG_PATH];
47
50
 
48
51
  wcscpy(unicode_path, L"\\\\?\\");
@@ -59,7 +62,8 @@ wdm_utils_unicode_is_directory(const LPWSTR path) {
59
62
  }
60
63
 
61
64
  BOOL
62
- wdm_utils_is_directory(const LPWSTR path) {
65
+ wdm_utils_is_directory(const LPWSTR path)
66
+ {
63
67
  DWORD dwAttrib = GetFileAttributesW(path);
64
68
 
65
69
  return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
@@ -67,6 +71,7 @@ wdm_utils_is_directory(const LPWSTR path) {
67
71
  }
68
72
 
69
73
  BOOL
70
- wdm_utils_is_unc_path(const LPWSTR path) {
74
+ wdm_utils_is_unc_path(const LPWSTR path)
75
+ {
71
76
  return path[0] == path[1] && path[0] == L'\\';
72
77
  }
@@ -32,7 +32,8 @@ rb_encoding *wdm_rb_enc_utf8;
32
32
  // ----------------------------------------------------------
33
33
 
34
34
  void
35
- Init_wdm() {
35
+ Init_wdm_ext()
36
+ {
36
37
  WDM_DEBUG("Registering WDM with Ruby!");
37
38
 
38
39
  wdm_rb_enc_utf8 = rb_utf8_encoding();
@@ -57,6 +57,12 @@ extern VALUE eWDM_Error;
57
57
 
58
58
  extern rb_encoding *wdm_rb_enc_utf8;
59
59
 
60
+ // ---------------------------------------------------------
61
+ // Prototypes
62
+ // ---------------------------------------------------------
63
+
64
+ void Init_wdm_ext();
65
+
60
66
  // ---------------------------------------------------------
61
67
 
62
68
  #ifdef __cplusplus
@@ -20,12 +20,14 @@
20
20
  <ConfigurationType>Application</ConfigurationType>
21
21
  <UseDebugLibraries>true</UseDebugLibraries>
22
22
  <CharacterSet>Unicode</CharacterSet>
23
+ <PlatformToolset>v110</PlatformToolset>
23
24
  </PropertyGroup>
24
25
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
25
26
  <ConfigurationType>Application</ConfigurationType>
26
27
  <UseDebugLibraries>false</UseDebugLibraries>
27
28
  <WholeProgramOptimization>true</WholeProgramOptimization>
28
29
  <CharacterSet>Unicode</CharacterSet>
30
+ <PlatformToolset>v110</PlatformToolset>
29
31
  </PropertyGroup>
30
32
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31
33
  <ImportGroup Label="ExtensionSettings">
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'wdm_ext'
3
+ rescue LoadError
4
+ raise LoadError.new(<<-EOS)
5
+ Can't load WDM!
6
+
7
+ WDM is not supported on your system. For a cross-platform alternative,
8
+ we recommend using Listen: http://github.com/guard/listen
9
+ EOS
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wdm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-15 00:00:00.000000000 Z
12
+ date: 2013-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -153,6 +153,7 @@ files:
153
153
  - ext/wdm/wdm.sln
154
154
  - ext/wdm/wdm.vcxproj
155
155
  - ext/wdm/wdm.vcxproj.filters
156
+ - lib/wdm.rb
156
157
  - LICENSE
157
158
  - README.md
158
159
  homepage: https://github.com/Maher4Ever/wdm
@@ -173,9 +174,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
174
  - - ! '>='
174
175
  - !ruby/object:Gem::Version
175
176
  version: '0'
176
- segments:
177
- - 0
178
- hash: 341068911
179
177
  requirements: []
180
178
  rubyforge_project:
181
179
  rubygems_version: 1.8.24