ruby-fsevent 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.
@@ -0,0 +1,5 @@
1
+ ext/Makefile
2
+ ext/*.o
3
+ ext/*.bundle
4
+ ext/mkmf.log
5
+ pkg/*
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Sandro Turriate
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ ruby-fsevent
2
+ ============
3
+
4
+ A native extension exposing the OS X FSEvent API.
5
+ Register directories you want to watch and a callback will fire whenever a
6
+ change occurs in the registered directories.
7
+
8
+ I got tired of reinstalling RubyCocoa every time I installed a new version of
9
+ Ruby just to rspactor working. Watchr has changed the game by allowing generic
10
+ file handlers but I started waiting 4-5 seconds for an event to fire. With a
11
+ generic, native interface to the FSEvent API we can harness the speed of
12
+ FSEvents without depending on RubyCocoa.
13
+
14
+ Demo
15
+ ----
16
+
17
+ 1. cd ext/
18
+ 2. ruby extconf.rb
19
+ 3. make
20
+ 4. cd ../
21
+ 5. ruby examples/print_changes.rb
22
+ 6. Notice that the examples directory and the /tmp directories are being monitored
23
+ 7. Make a change to either directory and watch the callback fire
24
+
25
+ TODO
26
+ ----
27
+
28
+ * Add ability to register a block as a callback handler, on_change would then
29
+ call the block. This removes the need for subclassing.
30
+
31
+ Note on Patches/Pull Requests
32
+ -----------------------------
33
+
34
+ * Fork the project.
35
+ * Make your feature addition or bug fix.
36
+ * Add tests for it. This is important so I don't break it in a
37
+ future version unintentionally.
38
+ * Commit, do not mess with rakefile, version, or history.
39
+ (if you want to have your own version, that is fine but
40
+ bump version in a commit by itself I can ignore when I pull)
41
+ * Send me a pull request. Bonus points for topic branches.
42
+
43
+ Copyright
44
+ ---------
45
+
46
+ Copyright (c) 2009 Sandro Turriate. See LICENSE for details.
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruby-fsevent"
8
+ gem.summary = %Q{A native extension exposing the OS X FSEvent API.}
9
+ gem.description = %Q{
10
+ A native extension exposing the OS X FSEvent API. Register directories you want to watch and a callback will fire whenever a change occurs in the registered directories.
11
+ }
12
+ gem.email = "sandro.turriate@gmail.com"
13
+ gem.homepage = "http://github.com/sandro/ruby-fsevent"
14
+ gem.authors = ["Sandro Turriate"]
15
+ gem.add_development_dependency "rspec"
16
+ gem.extensions << 'ext/extconf.rb'
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :spec => :check_dependencies
37
+
38
+ task :default => :spec
39
+
40
+ require 'rake/rdoctask'
41
+ Rake::RDocTask.new do |rdoc|
42
+ if File.exist?('VERSION')
43
+ version = File.read('VERSION')
44
+ else
45
+ version = ""
46
+ end
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "ruby-fsevent #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/../ext/fsevent'
2
+
3
+ class PrintChange < FSEvent
4
+ def on_change(directories)
5
+ puts "Detected change in: #{directories.inspect}"
6
+ end
7
+
8
+ def run
9
+ puts "watching #{registered_directories.join(", ")} for changes"
10
+ super
11
+ end
12
+ end
13
+
14
+ printer = PrintChange.new
15
+ printer.latency = 0.2
16
+ printer.watch_directories %W(#{Dir.pwd} /tmp)
17
+ printer.run
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ with_ldflags("-framework CoreServices") do
3
+ create_makefile("fsevent")
4
+ end
@@ -0,0 +1,124 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <unistd.h>
5
+ #include <signal.h>
6
+ #include <CoreServices/CoreServices.h>
7
+
8
+ /*
9
+ * Thanks to fswatch.c for providing a starting point
10
+ * http://github.com/alandipert/fswatch
11
+ */
12
+
13
+
14
+ void callback(
15
+ ConstFSEventStreamRef streamRef,
16
+ void *context,
17
+ size_t numEvents,
18
+ void *eventPaths,
19
+ const FSEventStreamEventFlags eventFlags[],
20
+ const FSEventStreamEventId eventIds[]
21
+ ) {
22
+ VALUE self = (VALUE)context;
23
+ int i;
24
+ char **paths = eventPaths;
25
+ VALUE rb_paths[numEvents];
26
+ for (i = 0; i < numEvents; i++) {
27
+ VALUE name = rb_str_new2(paths[i]);
28
+ rb_paths[i] = name;
29
+ }
30
+ rb_funcall(self, rb_intern("on_change"), 1, rb_ary_new4(numEvents, rb_paths));
31
+ }
32
+
33
+ void watch_directory(VALUE self) {
34
+ VALUE rb_registered_directories = rb_iv_get(self, "@registered_directories");
35
+ int i, dir_size;
36
+ dir_size = RARRAY(rb_registered_directories)->len;
37
+
38
+ VALUE *rb_dir_names = RARRAY(rb_registered_directories)->ptr;
39
+ CFStringRef dir_names[dir_size];
40
+ for (i = 0; i < dir_size; i++) {
41
+ dir_names[i] = CFStringCreateWithCString(NULL, (char *)RSTRING(rb_dir_names[i])->ptr, kCFStringEncodingUTF8);
42
+ }
43
+
44
+ CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&dir_names, dir_size, NULL);
45
+
46
+
47
+ VALUE rb_latency = rb_iv_get(self, "@latency");
48
+ CFAbsoluteTime latency = NUM2DBL(rb_latency);
49
+
50
+ FSEventStreamContext context;
51
+ context.version = 0;
52
+ context.info = (VALUE *)self;
53
+ context.retain = NULL;
54
+ context.release = NULL;
55
+ context.copyDescription = NULL;
56
+
57
+ FSEventStreamRef stream;
58
+ stream = FSEventStreamCreate(NULL,
59
+ &callback,
60
+ &context,
61
+ pathsToWatch,
62
+ kFSEventStreamEventIdSinceNow,
63
+ latency,
64
+ kFSEventStreamCreateFlagNone
65
+ );
66
+
67
+ FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
68
+ FSEventStreamStart(stream);
69
+ CFRunLoopRun();
70
+ }
71
+
72
+ static VALUE t_init(VALUE self) {
73
+ rb_iv_set(self, "@latency", rb_float_new(0.5));
74
+ return self;
75
+ }
76
+
77
+ static VALUE t_on_change(VALUE self, VALUE original_directory_name) {
78
+ return Qnil;
79
+ }
80
+
81
+ static VALUE t_watch_directories(VALUE self, VALUE directories) {
82
+ if (TYPE(directories) == T_ARRAY) {
83
+ rb_iv_set(self, "@registered_directories", rb_ary_new4(RARRAY(directories)->len, RARRAY(directories)->ptr));
84
+ }
85
+ else {
86
+ rb_iv_set(self, "@registered_directories", rb_ary_new3(1, directories));
87
+ }
88
+ VALUE rb_registered_directories = rb_iv_get(self, "@registered_directories");
89
+ return rb_registered_directories;
90
+ }
91
+
92
+ int pid, status;
93
+ static VALUE t_run(VALUE self) {
94
+ VALUE rb_registered_directories = rb_iv_get(self, "@registered_directories");
95
+ Check_Type(rb_registered_directories, T_ARRAY);
96
+ if (pid = fork()) {
97
+ wait(&status);
98
+ }
99
+ else {
100
+ watch_directory(self);
101
+ }
102
+ return self;
103
+ }
104
+
105
+ void kill_watcher() {
106
+ if (pid) {
107
+ kill(pid, SIGKILL);
108
+ printf("\n");
109
+ }
110
+ }
111
+
112
+ VALUE fsevent_class;
113
+ void Init_fsevent() {
114
+ fsevent_class = rb_define_class("FSEvent", rb_cObject);
115
+ rb_define_method(fsevent_class, "initialize", t_init, 0);
116
+ rb_define_method(fsevent_class, "on_change", t_on_change, 1);
117
+ rb_define_method(fsevent_class, "watch_directories", t_watch_directories, 1);
118
+ rb_define_method(fsevent_class, "run", t_run, 0);
119
+
120
+ rb_define_attr(fsevent_class, "latency", 1, 1);
121
+ rb_define_attr(fsevent_class, "registered_directories", 1, 1);
122
+
123
+ atexit(kill_watcher);
124
+ }
@@ -0,0 +1,58 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruby-fsevent}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Sandro Turriate"]
12
+ s.date = %q{2009-10-15}
13
+ s.description = %q{
14
+ A native extension exposing the OS X FSEvent API. Register directories you want to watch and a callback will fire whenever a change occurs in the registered directories.
15
+ }
16
+ s.email = %q{sandro.turriate@gmail.com}
17
+ s.extensions = ["ext/extconf.rb"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE",
20
+ "README.md"
21
+ ]
22
+ s.files = [
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "examples/print_changes.rb",
29
+ "ext/extconf.rb",
30
+ "ext/fsevent.c",
31
+ "ruby-fsevent.gemspec",
32
+ "spec/fsevent_spec.rb",
33
+ "spec/spec_helper.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/sandro/ruby-fsevent}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.5}
39
+ s.summary = %q{A native extension exposing the OS X FSEvent API.}
40
+ s.test_files = [
41
+ "spec/fsevent_spec.rb",
42
+ "spec/spec_helper.rb",
43
+ "examples/print_changes.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_development_dependency(%q<rspec>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<rspec>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<rspec>, [">= 0"])
57
+ end
58
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe FSEvent do
4
+ describe "accessors" do
5
+ it "reads and writes registered_directories" do
6
+ subject.registered_directories = %w(one two)
7
+ subject.registered_directories.should == %w(one two)
8
+ end
9
+
10
+ it "reads and writes latency" do
11
+ subject.latency = 1.5
12
+ subject.latency.should == 1.5
13
+ end
14
+ end
15
+
16
+ describe "#watch_directories" do
17
+ it "register a single directory" do
18
+ subject.watch_directories '/Users'
19
+ subject.registered_directories.should == ['/Users']
20
+ end
21
+ it "registers an array of directories" do
22
+ subject.watch_directories %w(/Users /tmp)
23
+ subject.registered_directories.should == %w(/Users /tmp)
24
+ end
25
+ end
26
+
27
+ describe "API" do
28
+ it { should respond_to(:on_change) }
29
+ it { should respond_to(:run) }
30
+ end
31
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'ext'))
3
+ require 'fsevent'
4
+ require 'spec/autorun'
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-fsevent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sandro Turriate
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-15 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: "\n A native extension exposing the OS X FSEvent API. Register directories you want to watch and a callback will fire whenever a change occurs in the registered directories.\n "
26
+ email: sandro.turriate@gmail.com
27
+ executables: []
28
+
29
+ extensions:
30
+ - ext/extconf.rb
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.md
34
+ files:
35
+ - .gitignore
36
+ - LICENSE
37
+ - README.md
38
+ - Rakefile
39
+ - VERSION
40
+ - examples/print_changes.rb
41
+ - ext/extconf.rb
42
+ - ext/fsevent.c
43
+ - ruby-fsevent.gemspec
44
+ - spec/fsevent_spec.rb
45
+ - spec/spec_helper.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/sandro/ruby-fsevent
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.5
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A native extension exposing the OS X FSEvent API.
74
+ test_files:
75
+ - spec/fsevent_spec.rb
76
+ - spec/spec_helper.rb
77
+ - examples/print_changes.rb