fswatch-rb 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '068664ab465511d6e4efc65056b4647b5782b2ac2918031a7229d2aa58c757da'
4
+ data.tar.gz: 23dd203bae6b26f25ddd9d3f2d27016ef8389dbb10d3ecf0ff4a22673704e076
5
+ SHA512:
6
+ metadata.gz: 6554d417c403504051503bb0e646f8d5d41b5cb7aa52bb732a29dfdcbf8d72fbe807ea828c1aa29ecba5b781d4afe8f1579ae21458b31c9d7b41a4571238c1ac
7
+ data.tar.gz: 47a793d84e9dad183bf68710203655fcffccfb7b4149df776ade6bf09ef3dc20183d8d1a18bb650acc9205df1ed9f17dba3eaa22a65d5139040136af67fe7ec5
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ # exclude compiled binary
14
+ *.bundle
15
+
16
+ # exclude compiled gem
17
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fswatch-rb (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (10.5.0)
11
+ rake-compiler (1.0.4)
12
+ rake
13
+ rspec (3.7.0)
14
+ rspec-core (~> 3.7.0)
15
+ rspec-expectations (~> 3.7.0)
16
+ rspec-mocks (~> 3.7.0)
17
+ rspec-core (3.7.0)
18
+ rspec-support (~> 3.7.0)
19
+ rspec-expectations (3.7.0)
20
+ diff-lcs (>= 1.2.0, < 2.0)
21
+ rspec-support (~> 3.7.0)
22
+ rspec-mocks (3.7.0)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.7.0)
25
+ rspec-support (3.7.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler (~> 1.16)
32
+ fswatch-rb!
33
+ rake (~> 10.0)
34
+ rake-compiler (~> 1.0)
35
+ rspec (~> 3.7)
36
+
37
+ BUNDLED WITH
38
+ 1.16.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Igor Yamolov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # fswatch-rb
2
+
3
+ fswatch-rb is binding for multi-platform fswatch library.
4
+
5
+ https://github.com/emcrisostomo/fswatch/
6
+
7
+ ## Installation
8
+
9
+ First you need to install fswatch >= 1.11.3
10
+
11
+ ```bash
12
+ $ brew install fswatch
13
+ ```
14
+
15
+ Then add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'fswatch-rb'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install fswatch-rb
28
+
29
+ ## Usage
30
+
31
+ ```ruby
32
+ require 'fswatch'
33
+
34
+ events_array = []
35
+
36
+ watcher = Fswatch::Watcher.new(
37
+ path: '~/my/awesome/project/directory/',
38
+ event_flags: [:created, :updated, :is_file, :renamed, :removed],
39
+ filters: { # global filters, high-perfomance
40
+ /\.tmp$/ix => :exclude, # if file ends with .tmp it will be ignored
41
+ /\(.rb|.slim)$/x => :include # include only .rb and .slim files
42
+ # Please note these reg exps are executed OUTSIDE ruby and not by ruby regexp implementation, so be careful
43
+ },
44
+ latency: 0.1, # 100ms
45
+ recursive: true,
46
+ follow_symlinks: true,
47
+ )
48
+
49
+ watcher.watch do |file, timestamp, flags|
50
+ puts "File #{file} has been changed at #{timestamp} with #{flags}"
51
+ end
52
+
53
+ # local filename filter, low-perfomance
54
+ watcher.watch(match: /\.css$/) do |file, timestamp, flags|
55
+ puts "CSS File #{file} has been changed!"
56
+ end
57
+
58
+ watcher.start! # this will spawn new thread in background
59
+
60
+ watcher.running? # => true
61
+
62
+ # ... do evil stuff ...
63
+
64
+ watcher.stop!
65
+
66
+ watcher.running? # => false
67
+
68
+ ```
69
+
70
+ ## Contributing
71
+
72
+ Bug reports and pull requests are welcome on GitHub at https://github.com/t3hk0d3/fswatch-rb.
73
+
74
+ ## License
75
+
76
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rake/extensiontask'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ Rake::ExtensionTask.new do |ext|
8
+ ext.name = 'fswatch'
9
+ ext.ext_dir = 'ext/fswatch'
10
+ ext.lib_dir = 'lib/fswatch'
11
+ end
12
+
13
+ task :default => [:compile, :spec]
@@ -0,0 +1,264 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ # V=0 quiet, V=1 verbose. other values don't work.
5
+ V = 0
6
+ Q1 = $(V:1=)
7
+ Q = $(Q1:0=@)
8
+ ECHO1 = $(V:1=@ :)
9
+ ECHO = $(ECHO1:0=@ echo)
10
+ NULLCMD = :
11
+
12
+ #### Start of system configuration section. ####
13
+
14
+ srcdir = .
15
+ topdir = /Users/tehkode/.rubies/ruby-2.4.2/include/ruby-2.4.0
16
+ hdrdir = $(topdir)
17
+ arch_hdrdir = /Users/tehkode/.rubies/ruby-2.4.2/include/ruby-2.4.0/x86_64-darwin16
18
+ PATH_SEPARATOR = :
19
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
20
+ prefix = $(DESTDIR)/Users/tehkode/.rubies/ruby-2.4.2
21
+ rubysitearchprefix = $(rubylibprefix)/$(sitearch)
22
+ rubyarchprefix = $(rubylibprefix)/$(arch)
23
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
24
+ exec_prefix = $(prefix)
25
+ vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
26
+ sitearchhdrdir = $(sitehdrdir)/$(sitearch)
27
+ rubyarchhdrdir = $(rubyhdrdir)/$(arch)
28
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
29
+ sitehdrdir = $(rubyhdrdir)/site_ruby
30
+ rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
31
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
32
+ vendorlibdir = $(vendordir)/$(ruby_version)
33
+ vendordir = $(rubylibprefix)/vendor_ruby
34
+ sitearchdir = $(sitelibdir)/$(sitearch)
35
+ sitelibdir = $(sitedir)/$(ruby_version)
36
+ sitedir = $(rubylibprefix)/site_ruby
37
+ rubyarchdir = $(rubylibdir)/$(arch)
38
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
39
+ sitearchincludedir = $(includedir)/$(sitearch)
40
+ archincludedir = $(includedir)/$(arch)
41
+ sitearchlibdir = $(libdir)/$(sitearch)
42
+ archlibdir = $(libdir)/$(arch)
43
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
44
+ mandir = $(datarootdir)/man
45
+ localedir = $(datarootdir)/locale
46
+ libdir = $(exec_prefix)/lib
47
+ psdir = $(docdir)
48
+ pdfdir = $(docdir)
49
+ dvidir = $(docdir)
50
+ htmldir = $(docdir)
51
+ infodir = $(datarootdir)/info
52
+ docdir = $(datarootdir)/doc/$(PACKAGE)
53
+ oldincludedir = $(SDKROOT)/usr/include
54
+ includedir = $(prefix)/include
55
+ localstatedir = $(prefix)/var
56
+ sharedstatedir = $(prefix)/com
57
+ sysconfdir = $(prefix)/etc
58
+ datadir = $(datarootdir)
59
+ datarootdir = $(prefix)/share
60
+ libexecdir = $(exec_prefix)/libexec
61
+ sbindir = $(exec_prefix)/sbin
62
+ bindir = $(exec_prefix)/bin
63
+ archdir = $(rubyarchdir)
64
+
65
+
66
+ CC = clang
67
+ CXX = clang++
68
+ LIBRUBY = $(LIBRUBY_A)
69
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
70
+ LIBRUBYARG_SHARED =
71
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework CoreFoundation
72
+ empty =
73
+ OUTFLAG = -o $(empty)
74
+ COUTFLAG = -o $(empty)
75
+ CSRCFLAG = $(empty)
76
+
77
+ RUBY_EXTCONF_H =
78
+ cflags = $(optflags) $(debugflags) $(warnflags)
79
+ cxxflags = $(optflags) $(debugflags) $(warnflags)
80
+ optflags = -O3 -fno-fast-math
81
+ debugflags = -ggdb3
82
+ warnflags = -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wno-tautological-compare -Wno-parentheses-equality -Wno-constant-logical-operand -Wno-self-assign -Wunused-variable -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -Wdivision-by-zero -Wdeprecated-declarations -Wextra-tokens
83
+ CCDLFLAGS = -fno-common
84
+ CFLAGS = $(CCDLFLAGS) -O3 -Wno-error=shorten-64-to-32 -pipe $(ARCH_FLAG)
85
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
86
+ DEFS =
87
+ CPPFLAGS = -I/usr/local/include -I/usr/include -I/Users/tehkode/.rubies/ruby-2.4.2/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags)
88
+ CXXFLAGS = $(CCDLFLAGS) $(cxxflags) -std=c++11 $(ARCH_FLAG)
89
+ ldflags = -L. -L/Users/tehkode/.rubies/ruby-2.4.2/lib -fstack-protector -L/usr/local/lib
90
+ dldflags = -L/Users/tehkode/.rubies/ruby-2.4.2/lib -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress
91
+ ARCH_FLAG =
92
+ DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
93
+ LDSHARED = $(CC) -dynamic -bundle
94
+ LDSHAREDXX = $(CXX) -dynamic -bundle
95
+ AR = ar
96
+ EXEEXT =
97
+
98
+ RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
99
+ RUBY_SO_NAME = ruby
100
+ RUBYW_INSTALL_NAME =
101
+ RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
102
+ RUBYW_BASE_NAME = rubyw
103
+ RUBY_BASE_NAME = ruby
104
+
105
+ arch = x86_64-darwin16
106
+ sitearch = $(arch)
107
+ ruby_version = 2.4.0
108
+ ruby = $(bindir)/$(RUBY_BASE_NAME)
109
+ RUBY = $(ruby)
110
+ ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
111
+
112
+ RM = rm -f
113
+ RM_RF = $(RUBY) -run -e rm -- -rf
114
+ RMDIRS = rmdir -p
115
+ MAKEDIRS = mkdir -p
116
+ INSTALL = /usr/bin/install -c
117
+ INSTALL_PROG = $(INSTALL) -m 0755
118
+ INSTALL_DATA = $(INSTALL) -m 644
119
+ COPY = cp
120
+ TOUCH = exit >
121
+
122
+ #### End of system configuration section. ####
123
+
124
+ preload =
125
+ libpath = . $(libdir) /usr/local/lib /usr/lib
126
+ LIBPATH = -L. -L$(libdir) -L/usr/local/lib -L/usr/lib
127
+ DEFFILE =
128
+
129
+ CLEANFILES = mkmf.log
130
+ DISTCLEANFILES =
131
+ DISTCLEANDIRS =
132
+
133
+ extout =
134
+ extout_prefix =
135
+ target_prefix = /fswatch
136
+ LOCAL_LIBS =
137
+ LIBS = -lfswatch -lpthread -ldl -lobjc
138
+ ORIG_SRCS = callback.c enums.c fswatch.c listener.c
139
+ SRCS = $(ORIG_SRCS) enums.c callback.c fswatch.c listener.c
140
+ OBJS = enums.o callback.o fswatch.o listener.o
141
+ HDRS = $(srcdir)/fswatch.h
142
+ LOCAL_HDRS =
143
+ TARGET = fswatch
144
+ TARGET_NAME = fswatch
145
+ TARGET_ENTRY = Init_$(TARGET_NAME)
146
+ DLLIB = $(TARGET).bundle
147
+ EXTSTATIC =
148
+ STATIC_LIB =
149
+
150
+ TIMESTAMP_DIR = .
151
+ BINDIR = $(bindir)
152
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
153
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
154
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
155
+ HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
156
+ ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
157
+ TARGET_SO_DIR =
158
+ TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
159
+ CLEANLIBS = $(TARGET_SO)
160
+ CLEANOBJS = *.o *.bak
161
+
162
+ all: $(DLLIB)
163
+ static: $(STATIC_LIB)
164
+ .PHONY: all install static install-so install-rb
165
+ .PHONY: clean clean-so clean-static clean-rb
166
+
167
+ clean-static::
168
+ clean-rb-default::
169
+ clean-rb::
170
+ clean-so::
171
+ clean: clean-so clean-static clean-rb-default clean-rb
172
+ -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
173
+
174
+ distclean-rb-default::
175
+ distclean-rb::
176
+ distclean-so::
177
+ distclean-static::
178
+ distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
179
+ -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
180
+ -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
181
+ -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
182
+
183
+ realclean: distclean
184
+ install: install-so install-rb
185
+
186
+ install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.-.fswatch.time
187
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
188
+ clean-static::
189
+ -$(Q)$(RM) $(STATIC_LIB)
190
+ install-rb: pre-install-rb do-install-rb install-rb-default
191
+ install-rb-default: pre-install-rb-default do-install-rb-default
192
+ pre-install-rb: Makefile
193
+ pre-install-rb-default: Makefile
194
+ do-install-rb:
195
+ do-install-rb-default:
196
+ pre-install-rb-default:
197
+ @$(NULLCMD)
198
+ $(TIMESTAMP_DIR)/.sitearchdir.-.fswatch.time:
199
+ $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
200
+ $(Q) $(TOUCH) $@
201
+
202
+ site-install: site-install-so site-install-rb
203
+ site-install-so: install-so
204
+ site-install-rb: install-rb
205
+
206
+ .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
207
+
208
+ .cc.o:
209
+ $(ECHO) compiling $(<)
210
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
211
+
212
+ .cc.S:
213
+ $(ECHO) translating $(<)
214
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
215
+
216
+ .mm.o:
217
+ $(ECHO) compiling $(<)
218
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
219
+
220
+ .mm.S:
221
+ $(ECHO) translating $(<)
222
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
223
+
224
+ .cxx.o:
225
+ $(ECHO) compiling $(<)
226
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
227
+
228
+ .cxx.S:
229
+ $(ECHO) translating $(<)
230
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
231
+
232
+ .cpp.o:
233
+ $(ECHO) compiling $(<)
234
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
235
+
236
+ .cpp.S:
237
+ $(ECHO) translating $(<)
238
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
239
+
240
+ .c.o:
241
+ $(ECHO) compiling $(<)
242
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
243
+
244
+ .c.S:
245
+ $(ECHO) translating $(<)
246
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
247
+
248
+ .m.o:
249
+ $(ECHO) compiling $(<)
250
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
251
+
252
+ .m.S:
253
+ $(ECHO) translating $(<)
254
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
255
+
256
+ $(TARGET_SO): $(OBJS) Makefile
257
+ $(ECHO) linking shared-object fswatch/$(DLLIB)
258
+ -$(Q)$(RM) $(@)
259
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
260
+ $(Q) $(POSTLINK)
261
+
262
+
263
+
264
+ $(OBJS): $(HDRS) $(ruby_headers)
@@ -0,0 +1,56 @@
1
+ #include <stdint.h>
2
+
3
+ #include "fswatch.h"
4
+
5
+
6
+ void* fswatch_start_monitor_no_gvl(void* data) {
7
+ FSW_HANDLE handle = (FSW_HANDLE)data;
8
+ FSW_STATUS status = fsw_start_monitor(handle);
9
+
10
+ return (void *)(intptr_t)status; // return integer hidden as pointer
11
+ }
12
+
13
+ void* fswatch_callback_handler_with_gvl(void* data) {
14
+ FSW_EVENT_CONTEXT *context = data;
15
+
16
+ VALUE rb_aEvents = rb_ary_new2(context->event_num);
17
+
18
+ for (int i = 0 ; i < context->event_num ; i++) {
19
+ const fsw_cevent event = context->events[i];
20
+
21
+ VALUE rb_aEvent = rb_ary_new2(2 + event.flags_num);
22
+
23
+ rb_ary_push(rb_aEvent, rb_str_new2(event.path));
24
+ rb_ary_push(rb_aEvent, INT2NUM(event.evt_time));
25
+
26
+ for (int c = 0 ; c < event.flags_num ; c++) {
27
+ rb_ary_push(rb_aEvent, fswatch_event_name(event.flags[c]));
28
+ }
29
+
30
+ rb_ary_push(rb_aEvents, rb_aEvent);
31
+ }
32
+
33
+ VALUE rb_proc_obj = rb_ivar_get(context->object, rb_intern("callback"));
34
+
35
+ rb_proc_call(rb_proc_obj, rb_ary_new_from_args(1, rb_aEvents));
36
+
37
+ return NULL;
38
+ }
39
+
40
+ void fswatch_interrupt_monitor_no_gvl(void* data) {
41
+ FSW_HANDLE handle = (FSW_HANDLE)data;
42
+ FSW_STATUS status = fsw_stop_monitor(handle);
43
+
44
+ if (status != FSW_OK) {
45
+ rb_raise(rb_eRuntimeError, "Failed to interrupt monitor - err: %d", status);
46
+ }
47
+
48
+ }
49
+
50
+ void fswatch_callback_handler_no_gvl(fsw_cevent const *const events,
51
+ const unsigned int event_num,
52
+ void *data) {
53
+ FSW_EVENT_CONTEXT context = { .events = events, .event_num = event_num, .object = (VALUE)data };
54
+
55
+ rb_thread_call_with_gvl(fswatch_callback_handler_with_gvl, &context);
56
+ }
@@ -0,0 +1,192 @@
1
+ #include "fswatch.h"
2
+
3
+ #define REGEXP_IGNORECASE (1 << 0) // 1
4
+ #define REGEXP_EXTENDED (1 << 1) // 2
5
+
6
+ static void fswatch_add_path(FSW_HANDLE handle, VALUE rb_settings) {
7
+ VALUE rb_path = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("path")));
8
+
9
+ VALUE path_arr;
10
+
11
+ switch (TYPE(rb_path)) {
12
+ case T_STRING:
13
+ path_arr = rb_ary_new_from_args(1, rb_path);
14
+ break;
15
+ case T_ARRAY:
16
+ path_arr = rb_path;
17
+ break;
18
+ default:
19
+ rb_raise(rb_eTypeError, "path is not valid");
20
+ break;
21
+ }
22
+
23
+ long length = RARRAY_LEN(path_arr);
24
+
25
+ for ( long i = 0 ; i < length ; i++ ){
26
+ VALUE rb_arr_item = rb_ary_entry(path_arr, i);
27
+
28
+ char* path_cstr = StringValueCStr(rb_arr_item);
29
+
30
+
31
+ if(fsw_add_path(handle, path_cstr) != FSW_OK) {
32
+ rb_raise(rb_eRuntimeError, "Unable to monitor specified path - '%s'", path_cstr);
33
+ }
34
+ }
35
+ }
36
+
37
+ static void fswatch_add_properties(FSW_HANDLE handle, VALUE rb_settings) {
38
+ VALUE rb_properties = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("properties")));
39
+
40
+ if (rb_properties == Qnil) {
41
+ return;
42
+ }
43
+
44
+ Check_Type(rb_properties, T_HASH);
45
+
46
+ VALUE rb_property_keys = rb_funcall(rb_properties, rb_intern("keys"), 0);
47
+
48
+ long arr_len = RARRAY_LEN(rb_property_keys);
49
+ for ( long i = 0 ; i < arr_len ; i++ ){
50
+ VALUE rb_key = rb_ary_entry(rb_property_keys, i);
51
+ VALUE rb_value = rb_hash_fetch(rb_properties, rb_key);
52
+
53
+ if (TYPE(rb_key) == T_SYMBOL) {
54
+ rb_key = rb_sym2str(rb_key);
55
+ }
56
+
57
+ Check_Type(rb_key, T_STRING);
58
+ Check_Type(rb_value, T_STRING);
59
+
60
+ char* key_cstr = StringValueCStr(rb_key);
61
+ char* value_cstr = StringValueCStr(rb_value);
62
+
63
+
64
+ if(fsw_add_property(handle, key_cstr, value_cstr) != FSW_OK) {
65
+ rb_raise(rb_eRuntimeError, "Unable to add specified property - '%s' = '%s'", key_cstr, value_cstr);
66
+ }
67
+ }
68
+ }
69
+
70
+ static void fswatch_add_event_type_filters(FSW_HANDLE handle, VALUE rb_settings) {
71
+ VALUE rb_event_types = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("event_flags")));
72
+
73
+ if (rb_event_types == Qnil) {
74
+ return;
75
+ }
76
+
77
+ Check_Type(rb_event_types, T_ARRAY);
78
+
79
+ long arr_len = RARRAY_LEN(rb_event_types);
80
+ for ( long i = 0 ; i < arr_len ; i++ ){
81
+ VALUE rb_event_type = rb_ary_entry(rb_event_types, i);
82
+
83
+ fsw_event_type_filter filter = { .flag = fswatch_event_type(rb_event_type) };
84
+
85
+ VALUE rb_str = rb_sym2str(rb_event_type);
86
+
87
+
88
+ if (fsw_add_event_type_filter(handle, filter) != FSW_OK) {
89
+ rb_raise(rb_eRuntimeError, "Unable to event type filter - '%s' (%d)", StringValueCStr(rb_str), filter.flag);
90
+ }
91
+ }
92
+ }
93
+
94
+ static void fswatch_add_monitor_filters(FSW_HANDLE handle, VALUE rb_settings) {
95
+ VALUE rb_monitor_filters = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("filters")));
96
+
97
+ if (rb_monitor_filters == Qnil) {
98
+ return;
99
+ }
100
+
101
+ Check_Type(rb_monitor_filters, T_HASH);
102
+
103
+ VALUE rb_monitor_keys = rb_funcall(rb_monitor_filters, rb_intern("keys"), 0);
104
+
105
+ long arr_len = RARRAY_LEN(rb_monitor_keys);
106
+ for ( long i = 0 ; i < arr_len ; i++ ){
107
+ VALUE rb_key = rb_ary_entry(rb_monitor_keys, i);
108
+ VALUE rb_value = rb_hash_fetch(rb_monitor_filters, rb_key);
109
+
110
+ Check_Type(rb_key, T_REGEXP);
111
+ Check_Type(rb_value, T_SYMBOL);
112
+
113
+ VALUE rb_regexp = RREGEXP_SRC(rb_key);
114
+ int options = rb_reg_options(rb_key);
115
+
116
+ enum fsw_filter_type filter_type;
117
+
118
+ if (SYM2ID(rb_value) == rb_intern("exclude")) {
119
+ filter_type = filter_exclude;
120
+ } else if (SYM2ID(rb_value) == rb_intern("include")) {
121
+ filter_type = filter_include;
122
+ } else {
123
+ VALUE rb_str = rb_sym2str(rb_value);
124
+ rb_raise(rb_eRuntimeError, "Unknown filter type - '%s'", StringValueCStr(rb_str));
125
+ }
126
+
127
+ const fsw_cmonitor_filter filter = {
128
+ .text = StringValueCStr(rb_regexp),
129
+ .type = filter_type,
130
+ .case_sensitive = (options & REGEXP_IGNORECASE) == 0,
131
+ .extended = (options & REGEXP_EXTENDED) != 0
132
+ };
133
+
134
+
135
+ if(fsw_add_filter(handle, filter) != FSW_OK) {
136
+ rb_raise(rb_eRuntimeError, "Unable to path filter - '%s' => '%s'", filter.text, StringValueCStr(rb_value));
137
+ }
138
+ }
139
+ }
140
+
141
+ void fswatch_configure(FSW_HANDLE handle, VALUE rb_settings) {
142
+ fswatch_add_path(handle, rb_settings);
143
+ fswatch_add_properties(handle, rb_settings);
144
+
145
+ fswatch_add_event_type_filters(handle, rb_settings);
146
+ fswatch_add_monitor_filters(handle, rb_settings);
147
+
148
+ VALUE rb_latency = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("latency")));
149
+ if (rb_latency != Qnil) {
150
+ Check_Type(rb_latency, T_FLOAT);
151
+
152
+
153
+ if (fsw_set_latency(handle, NUM2DBL(rb_latency)) != FSW_OK) {
154
+ rb_raise(rb_eRuntimeError, "Failed to set latency = %0.3f", NUM2DBL(rb_latency));
155
+ }
156
+ }
157
+
158
+ VALUE rb_allow_overflow = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("allow_overflow")));
159
+ if (rb_allow_overflow != Qnil) {
160
+
161
+ if (fsw_set_allow_overflow(handle, rb_allow_overflow != Qfalse) != FSW_OK) {
162
+ rb_raise(rb_eRuntimeError, "Failed to set overflow mode = %d", rb_allow_overflow != Qfalse);
163
+ }
164
+ }
165
+
166
+ VALUE rb_recursive = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("recursive")));
167
+ if (rb_recursive != Qnil) {
168
+ if (fsw_set_recursive(handle, rb_recursive != Qfalse) != FSW_OK) {
169
+ rb_raise(rb_eRuntimeError, "Failed to set recursive mode = %d", rb_recursive != Qfalse);
170
+ }
171
+ }
172
+
173
+ VALUE rb_directory_only = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("directory_only")));
174
+ if (rb_directory_only != Qnil) {
175
+ if (fsw_set_directory_only(handle, rb_directory_only != Qfalse) != FSW_OK) {
176
+ rb_raise(rb_eRuntimeError, "Failed to set directory-only mode = %d", rb_directory_only != Qfalse);
177
+ }
178
+ }
179
+
180
+ VALUE rb_follow_symlinks = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("follow_symlinks")));
181
+ if (rb_follow_symlinks != Qnil) {
182
+ if (fsw_set_directory_only(handle, rb_follow_symlinks != Qfalse) != FSW_OK) {
183
+ rb_raise(rb_eRuntimeError, "Failed to set follow-symlinks mode = %d", rb_follow_symlinks != Qfalse);
184
+ }
185
+ }
186
+
187
+ VALUE rb_verbose = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("debug")));
188
+ if (rb_verbose != Qnil) {
189
+ fsw_set_verbose(rb_verbose != Qfalse);
190
+ }
191
+
192
+ }
@@ -0,0 +1,95 @@
1
+ #include "fswatch.h"
2
+
3
+ VALUE fswatch_event_name(enum fsw_event_flag flag) {
4
+ ID rb_idFlagName;
5
+
6
+ switch (flag) {
7
+ case NoOp: rb_idFlagName = rb_intern("no_op"); break;
8
+ case PlatformSpecific: rb_idFlagName = rb_intern("platform_specific"); break;
9
+ case Created: rb_idFlagName = rb_intern("created"); break;
10
+ case Updated: rb_idFlagName = rb_intern("updated"); break;
11
+ case Removed: rb_idFlagName = rb_intern("removed"); break;
12
+ case Renamed: rb_idFlagName = rb_intern("renamed"); break;
13
+ case OwnerModified: rb_idFlagName = rb_intern("owner_modified"); break;
14
+ case AttributeModified: rb_idFlagName = rb_intern("attribute_modified"); break;
15
+ case MovedFrom: rb_idFlagName = rb_intern("moved_from"); break;
16
+ case MovedTo: rb_idFlagName = rb_intern("moved_to"); break;
17
+ case IsFile: rb_idFlagName = rb_intern("is_file"); break;
18
+ case IsDir: rb_idFlagName = rb_intern("is_dir"); break;
19
+ case IsSymLink: rb_idFlagName = rb_intern("is_symlink"); break;
20
+ case Link: rb_idFlagName = rb_intern("link"); break;
21
+ case Overflow: rb_idFlagName = rb_intern("overflow"); break;
22
+ default:
23
+ rb_idFlagName = rb_intern("unknown");
24
+ }
25
+
26
+ return ID2SYM(rb_idFlagName);
27
+ }
28
+
29
+ enum fsw_event_flag fswatch_event_type(VALUE rb_flag) {
30
+ ID rb_idFlagName = rb_to_id(rb_flag);
31
+
32
+ if ( rb_idFlagName == rb_intern("no_op") ) {
33
+ return NoOp;
34
+ } else if ( rb_idFlagName == rb_intern("platform_specific") ) {
35
+ return PlatformSpecific;
36
+ } else if ( rb_idFlagName == rb_intern("created") ) {
37
+ return Created;
38
+ } else if ( rb_idFlagName == rb_intern("updated") ) {
39
+ return Updated;
40
+ } else if ( rb_idFlagName == rb_intern("removed") ) {
41
+ return Removed;
42
+ } else if ( rb_idFlagName == rb_intern("renamed") ) {
43
+ return Renamed;
44
+ } else if ( rb_idFlagName == rb_intern("owner_modified") ) {
45
+ return OwnerModified;
46
+ } else if ( rb_idFlagName == rb_intern("attribute_modified") ) {
47
+ return AttributeModified;
48
+ } else if ( rb_idFlagName == rb_intern("moved_from") ) {
49
+ return MovedFrom;
50
+ } else if ( rb_idFlagName == rb_intern("moved_to") ) {
51
+ return MovedTo;
52
+ } else if ( rb_idFlagName == rb_intern("is_file") ) {
53
+ return IsFile;
54
+ } else if ( rb_idFlagName == rb_intern("is_dir") ) {
55
+ return IsDir;
56
+ } else if ( rb_idFlagName == rb_intern("is_symlink") ) {
57
+ return IsSymLink;
58
+ } else if ( rb_idFlagName == rb_intern("link") ) {
59
+ return Link;
60
+ } else if ( rb_idFlagName == rb_intern("overflow") ) {
61
+ return Overflow;
62
+ }
63
+
64
+ VALUE rb_str = rb_sym2str(rb_flag);
65
+
66
+ rb_raise(rb_eRuntimeError, "Unknown event type '%s'", StringValueCStr(rb_str));
67
+
68
+ return NoOp;
69
+ }
70
+
71
+ enum fsw_monitor_type fswatch_monitor_type_by(VALUE name) {
72
+ if (name == Qnil) {
73
+ return system_default_monitor_type;
74
+ }
75
+
76
+ VALUE rb_str = StringValue(name);
77
+
78
+ if (rb_str_equal(rb_str, rb_str_new_literal("fsevents"))) {
79
+ return fsevents_monitor_type;
80
+ } else if (rb_str_equal(rb_str, rb_str_new_literal("kqueue"))) {
81
+ return kqueue_monitor_type;
82
+ } else if (rb_str_equal(rb_str, rb_str_new_literal("inotify"))) {
83
+ return inotify_monitor_type;
84
+ } else if (rb_str_equal(rb_str, rb_str_new_literal("windows"))) {
85
+ return windows_monitor_type;
86
+ } else if (rb_str_equal(rb_str, rb_str_new_literal("poll"))) {
87
+ return poll_monitor_type;
88
+ } else if (rb_str_equal(rb_str, rb_str_new_literal("fen"))) {
89
+ return fen_monitor_type;
90
+ }
91
+
92
+ rb_raise(rb_eRuntimeError, "Unknown monitor type '%s'", StringValueCStr(rb_str));
93
+
94
+ return Qnil;
95
+ }
@@ -0,0 +1,33 @@
1
+ require 'mkmf'
2
+
3
+ $CXXFLAGS += " -std=c++11 "
4
+
5
+ HEADER_DIRS = [
6
+ '/opt/local/include',
7
+ '/usr/local/include',
8
+ '/usr/include',
9
+ ].select { |d| Dir.exists?(d) }
10
+
11
+ LIB_DIRS = [
12
+ '/opt/local/lib',
13
+ '/usr/local/lib',
14
+ '/usr/lib',
15
+ ].select { |d| Dir.exists?(d) }
16
+
17
+ $srcs = Dir.glob(File.join(File.expand_path('..', __FILE__), '*.c'))
18
+
19
+ dir_config('fswatch', HEADER_DIRS, LIB_DIRS)
20
+
21
+ unless find_header('libfswatch/c/libfswatch.h')
22
+ abort "libfswatch is missing. please install libfswatch"
23
+ end
24
+
25
+ unless find_library('fswatch', 'fsw_init_library')
26
+ abort "libfswatch is missing. please install libfswatch"
27
+ end
28
+
29
+ unless have_func('fsw_is_running')
30
+ abort 'libfswatch version >= 1.11.3 is required. Please upgrade!'
31
+ end
32
+
33
+ create_makefile('fswatch/fswatch')
@@ -0,0 +1,10 @@
1
+ #include <stdint.h>
2
+
3
+ #include "fswatch.h"
4
+
5
+ void Init_fswatch() {
6
+
7
+ FSW_STATUS error = fsw_init_library();
8
+
9
+ init_fswatch_monitor();
10
+ }
@@ -0,0 +1,34 @@
1
+ #ifndef FSWATCH_H
2
+ #define FSWATCH_H
3
+
4
+ #include <ruby.h>
5
+ #include <ruby/st.h>
6
+ #include <ruby/encoding.h>
7
+ #include <ruby/thread.h>
8
+
9
+ #include <libfswatch/c/libfswatch.h>
10
+
11
+ typedef struct FSW_EVENT_CONTEXT {
12
+ const fsw_cevent *const events;
13
+ unsigned int event_num;
14
+ VALUE object;
15
+ } FSW_EVENT_CONTEXT;
16
+
17
+ /* Configuration */
18
+ extern void fswatch_configure(FSW_HANDLE handle, VALUE rb_settings);
19
+
20
+ /* Callbacks */
21
+ extern void* fswatch_start_monitor_no_gvl(void* data);
22
+ extern void* fswatch_callback_handler_with_gvl(void* data);
23
+ extern void fswatch_callback_handler_no_gvl(fsw_cevent const *const events, const unsigned int event_num, void *data);
24
+ extern void fswatch_interrupt_monitor_no_gvl(void* data);
25
+
26
+ /* Enum functions */
27
+ extern VALUE fswatch_event_name(enum fsw_event_flag flag);
28
+ extern enum fsw_monitor_type fswatch_monitor_type_by(VALUE name);
29
+ extern enum fsw_event_flag fswatch_event_type(VALUE rb_flag);
30
+
31
+ /* Monitor Class */
32
+ extern VALUE init_fswatch_monitor();
33
+
34
+ #endif /* FSWATCH_H */
@@ -0,0 +1,113 @@
1
+ #include "fswatch.h"
2
+
3
+ static VALUE fswatch_monitor_init(VALUE self, VALUE rb_settings) {
4
+ FSW_HANDLE *handle;
5
+ Data_Get_Struct(self, FSW_HANDLE, handle);
6
+
7
+ Check_Type(rb_settings, T_HASH);
8
+
9
+ VALUE rb_system_monitor = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("monitor_type")));
10
+
11
+ enum fsw_monitor_type monitor_type = fswatch_monitor_type_by(rb_system_monitor);
12
+
13
+ *handle = fsw_init_session(monitor_type);
14
+
15
+ VALUE rb_callback = rb_hash_lookup(rb_settings, ID2SYM(rb_intern("callback")));
16
+
17
+ if(rb_obj_is_proc(rb_callback) != Qtrue &&
18
+ rb_obj_is_method(rb_callback) != Qtrue) {
19
+ rb_raise(rb_eArgError, "Callback is not specified!");
20
+ return self;
21
+ }
22
+
23
+ // Saving callback to instance variable to prevent callback being garbage-collected
24
+ rb_ivar_set(self, rb_intern("callback"), rb_callback);
25
+
26
+ fsw_set_callback(*handle, fswatch_callback_handler_no_gvl, (void*)self);
27
+
28
+ fswatch_configure(*handle, rb_settings);
29
+
30
+ return self;
31
+ }
32
+
33
+ static VALUE fswatch_monitor_start(VALUE self) {
34
+ FSW_HANDLE *handle;
35
+ Data_Get_Struct(self, FSW_HANDLE, handle);
36
+
37
+ // fswatch spend most of the time doing nothing
38
+ // so its good idea to remove GIL during wait phase
39
+ // only to temporarily reaquire it for calling ruby callbacks
40
+ FSW_STATUS status = (FSW_STATUS)(intptr_t)
41
+ rb_thread_call_without_gvl(
42
+ fswatch_start_monitor_no_gvl, (void*)(*handle),
43
+ fswatch_interrupt_monitor_no_gvl, (void*)(*handle)
44
+ );
45
+
46
+ if (status != FSW_OK) {
47
+ rb_raise(rb_eRuntimeError, "Failed to start monitor - err: %d", status);
48
+ }
49
+
50
+ return Qtrue;
51
+ }
52
+
53
+ static VALUE fswatch_monitor_stop(VALUE self) {
54
+ FSW_HANDLE *handle;
55
+ Data_Get_Struct(self, FSW_HANDLE, handle);
56
+
57
+ FSW_STATUS status = fsw_stop_monitor(*handle);
58
+ if (status != FSW_OK) {
59
+ rb_raise(rb_eRuntimeError, "Failed to stop monitor - err: %d", status);
60
+ }
61
+
62
+ return Qtrue;
63
+ }
64
+
65
+ static VALUE fswatch_monitor_is_running(VALUE self) {
66
+ FSW_HANDLE *handle;
67
+ Data_Get_Struct(self, FSW_HANDLE, handle);
68
+
69
+ return fsw_is_running(*handle) ? Qtrue : Qfalse;
70
+ }
71
+
72
+ static void fswatch_monitor_free(void *ptr) {
73
+ FSW_HANDLE handle = *(FSW_HANDLE*)ptr;
74
+
75
+ if (handle) {
76
+ FSW_STATUS status = fsw_destroy_session(handle);
77
+
78
+ if (status == FSW_ERR_MONITOR_ALREADY_RUNNING) {
79
+ fsw_stop_monitor(handle);
80
+ fsw_destroy_session(handle); // try to destroy monitor in a blind fate
81
+ } else if (status != FSW_OK) {
82
+ rb_warn("Failed to destroy fswatch session - err:%d", status);
83
+ }
84
+ }
85
+
86
+ ruby_xfree(ptr); // free allocated memory for pointer
87
+ }
88
+
89
+
90
+ static VALUE fswatch_monitor_alloc(VALUE klass) {
91
+ FSW_HANDLE *handle = ruby_xmalloc(sizeof(FSW_HANDLE));
92
+
93
+ *handle = NULL; // IMPORTANT! Initialize handler with NULL
94
+
95
+ return Data_Wrap_Struct(klass, NULL, fswatch_monitor_free, handle);
96
+ }
97
+
98
+
99
+ extern VALUE init_fswatch_monitor() {
100
+ VALUE rb_mFswatch = rb_define_module("Fswatch");
101
+ VALUE rb_cMonitor = rb_define_class_under(rb_mFswatch, "Monitor", rb_cObject);
102
+
103
+ rb_define_alloc_func(rb_cMonitor, fswatch_monitor_alloc);
104
+
105
+ rb_define_method(rb_cMonitor, "initialize", fswatch_monitor_init, 1);
106
+
107
+ rb_define_method(rb_cMonitor, "start", fswatch_monitor_start, 0);
108
+ rb_define_method(rb_cMonitor, "stop", fswatch_monitor_stop, 0);
109
+
110
+ rb_define_method(rb_cMonitor, "running?", fswatch_monitor_is_running, 0);
111
+
112
+ return rb_cMonitor;
113
+ }
@@ -0,0 +1,28 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fswatch-rb"
7
+ spec.version = '0.1.1'
8
+ spec.authors = ['Igor Yamolov']
9
+ spec.email = %w(clouster@yandex.ru)
10
+
11
+ spec.summary = %q{Ruby binding for libfswatch library}
12
+ spec.description = %q{Ruby library to watch filesystem changes}
13
+ spec.homepage = "https://github.com/t3hk0d3/fswatch-rb"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+ spec.extensions = %w[ext/fswatch/extconf.rb]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency 'rake-compiler', '~> 1.0'
27
+ spec.add_development_dependency "rspec", "~> 3.7"
28
+ end
data/lib/fswatch.rb ADDED
@@ -0,0 +1,10 @@
1
+ module Fswatch
2
+
3
+ require 'fswatch/monitor' # stub for Monitor class
4
+
5
+ require 'fswatch/fswatch' # load C-extension
6
+
7
+ require 'fswatch/watcher' # syntax-sugar
8
+
9
+ end
10
+
@@ -0,0 +1,21 @@
1
+ module Fswatch
2
+ class Monitor
3
+ def initialize(options = {})
4
+ # stub method
5
+ # actual implementation is located in C extension - `ext/fswatch/monitor.c`
6
+ raise NotImplementedError, "Called stub method. Looks like C Extension failed to load"
7
+ end
8
+
9
+ def start
10
+ # stub method
11
+ # actual implementation is located in C extension - `ext/fswatch/monitor.c`
12
+ raise NotImplementedError, "Called stub method. Looks like C Extension failed to load"
13
+ end
14
+
15
+ def stop
16
+ # stub method
17
+ # actual implementation is located in C extension - `ext/fswatch/monitor.c`
18
+ raise NotImplementedError, "Called stub method. Looks like C Extension failed to load"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ module Fswatch
2
+ class Watcher
3
+
4
+ def initialize(options = {})
5
+ @event_handlers = []
6
+
7
+ options[:callback] = self.method(:_event_handler)
8
+
9
+ @monitor = Fswatch::Monitor.new(options)
10
+ end
11
+
12
+ def watch(options = {}, &block)
13
+ raise 'Invalid handler' unless block
14
+
15
+ options = nil if options.empty? # reduce memory usage
16
+
17
+ @event_handlers << [block, options]
18
+
19
+ return nil
20
+ end
21
+
22
+ def start!
23
+ raise 'Already running!' if running?
24
+
25
+ @thread = Thread.new { @monitor.start }
26
+ end
27
+
28
+ def stop!
29
+ raise 'Not running!' if running?
30
+
31
+ @monitor.stop
32
+ end
33
+
34
+ def running?
35
+ @monitor.running?
36
+ end
37
+
38
+ private
39
+
40
+ def _event_handler(events)
41
+ events.each do |event|
42
+ filename, timestamp, *event_flags = event
43
+
44
+ @event_handlers.each do |handler, options|
45
+ if options
46
+ # match filename
47
+ next if options[:match] && !options[:match].match?(filename)
48
+
49
+ # event
50
+ next if options[:on] && (options[:on] & event_flags).empty?
51
+ end
52
+
53
+ handler.call(filename, timestamp, event_flags, options)
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fswatch-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Igor Yamolov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.7'
69
+ description: Ruby library to watch filesystem changes
70
+ email:
71
+ - clouster@yandex.ru
72
+ executables: []
73
+ extensions:
74
+ - ext/fswatch/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - ext/fswatch/Makefile
85
+ - ext/fswatch/callback.c
86
+ - ext/fswatch/configure.c
87
+ - ext/fswatch/enums.c
88
+ - ext/fswatch/extconf.rb
89
+ - ext/fswatch/fswatch.c
90
+ - ext/fswatch/fswatch.h
91
+ - ext/fswatch/monitor.c
92
+ - fswatch-rb.gemspec
93
+ - lib/fswatch.rb
94
+ - lib/fswatch/monitor.rb
95
+ - lib/fswatch/watcher.rb
96
+ homepage: https://github.com/t3hk0d3/fswatch-rb
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.7.3
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Ruby binding for libfswatch library
120
+ test_files: []