fswatch-rb 0.1.1

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 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: []