ruby-fsevent 0.1.0 → 0.2.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,21 @@
1
+ History
2
+ =======
3
+
4
+ 0.2.0 2009-10-23
5
+ ----------------
6
+
7
+ **enhancements**
8
+
9
+ - No More Forking! The event loop used to fork to ensure signal handlers would be observed.
10
+ A custom signal handling solution has replaced the need to fork.
11
+ - The Event listener can now be stopped and restarted using FSEvent#stop and FSEvent#restart
12
+
13
+ **deprecations**
14
+
15
+ - FSEvent#run now FSEvent#start
16
+
17
+
18
+ 0.1.0 2009-10-15
19
+ ----------------
20
+ - Listen for events using OSX's FSEvents API
21
+
data/Rakefile CHANGED
@@ -12,7 +12,8 @@ begin
12
12
  gem.email = "sandro.turriate@gmail.com"
13
13
  gem.homepage = "http://github.com/sandro/ruby-fsevent"
14
14
  gem.authors = ["Sandro Turriate"]
15
- gem.add_development_dependency "rspec"
15
+ gem.add_development_dependency "rspec", '>=1.2.8'
16
+ gem.require_paths = %w(lib ext)
16
17
  gem.extensions << 'ext/extconf.rb'
17
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
19
  end
@@ -37,6 +38,10 @@ task :spec => :check_dependencies
37
38
 
38
39
  task :default => :spec
39
40
 
41
+ task :make do
42
+ system "cd ext && ruby extconf.rb && make"
43
+ end
44
+
40
45
  require 'rake/rdoctask'
41
46
  Rake::RDocTask.new do |rdoc|
42
47
  if File.exist?('VERSION')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -1,11 +1,13 @@
1
- require File.dirname(__FILE__) + '/../ext/fsevent'
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../ext')
3
+ require 'fsevent'
2
4
 
3
5
  class PrintChange < FSEvent
4
6
  def on_change(directories)
5
7
  puts "Detected change in: #{directories.inspect}"
6
8
  end
7
9
 
8
- def run
10
+ def start
9
11
  puts "watching #{registered_directories.join(", ")} for changes"
10
12
  super
11
13
  end
@@ -14,4 +16,4 @@ end
14
16
  printer = PrintChange.new
15
17
  printer.latency = 0.2
16
18
  printer.watch_directories %W(#{Dir.pwd} /tmp)
17
- printer.run
19
+ printer.start
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../ext')
3
+ require 'fsevent'
4
+
5
+ class Restart < FSEvent
6
+ def on_change(directories)
7
+ puts "Detected change in: #{directories.inspect}"
8
+ unless @restarted
9
+ self.stop
10
+ @restarted = true
11
+ self.watch_directories "#{Dir.pwd}/spec"
12
+ self.start
13
+ end
14
+ end
15
+
16
+ def start
17
+ puts "watching #{registered_directories.join(", ")} for changes"
18
+ super
19
+ end
20
+ end
21
+
22
+ Signal.trap("INT"){ puts "\nCustom INT handler called."; exit }
23
+
24
+ restarter = Restart.new
25
+ restarter.watch_directories "#{Dir.pwd}/examples"
26
+ restarter.start
@@ -10,6 +10,8 @@
10
10
  * http://github.com/alandipert/fswatch
11
11
  */
12
12
 
13
+ FSEventStreamRef stream;
14
+ VALUE fsevent_class;
13
15
 
14
16
  void callback(
15
17
  ConstFSEventStreamRef streamRef,
@@ -54,7 +56,6 @@ void watch_directory(VALUE self) {
54
56
  context.release = NULL;
55
57
  context.copyDescription = NULL;
56
58
 
57
- FSEventStreamRef stream;
58
59
  stream = FSEventStreamCreate(NULL,
59
60
  &callback,
60
61
  &context,
@@ -89,36 +90,58 @@ static VALUE t_watch_directories(VALUE self, VALUE directories) {
89
90
  return rb_registered_directories;
90
91
  }
91
92
 
92
- int pid, status;
93
- static VALUE t_run(VALUE self) {
93
+ static VALUE t_start(VALUE self) {
94
94
  VALUE rb_registered_directories = rb_iv_get(self, "@registered_directories");
95
95
  Check_Type(rb_registered_directories, T_ARRAY);
96
- if (pid = fork()) {
97
- wait(&status);
96
+
97
+ watch_directory(self);
98
+ return self;
99
+ }
100
+
101
+ static VALUE t_stop(VALUE self) {
102
+ FSEventStreamStop(stream);
103
+ FSEventStreamInvalidate(stream);
104
+ FSEventStreamRelease(stream);
105
+ CFRunLoopStop(CFRunLoopGetCurrent());
106
+ return self;
107
+ }
108
+
109
+ static VALUE t_restart(VALUE self) {
110
+ t_stop(self);
111
+ watch_directory(self);
112
+ return self;
113
+ }
114
+
115
+ void delegate_signal_to_ruby(int signal) {
116
+ VALUE signal_mod = rb_const_get(rb_cObject, rb_intern("Signal"));
117
+ if (rb_funcall(signal_mod, rb_intern("handles?"), 1, INT2FIX(signal)) == Qtrue) {
118
+ rb_funcall(signal_mod, rb_intern("handle"), 1, INT2FIX(signal));
98
119
  }
99
120
  else {
100
- watch_directory(self);
121
+ ruby_default_signal(signal);
101
122
  }
102
- return self;
103
123
  }
104
124
 
105
- void kill_watcher() {
106
- if (pid) {
107
- kill(pid, SIGKILL);
108
- printf("\n");
125
+ void register_signal_delegation() {
126
+ int i;
127
+ for(i = 0; i < 33; i++) { // Signal.list.values.size yields 32 different signals
128
+ (void) signal(i, delegate_signal_to_ruby);
109
129
  }
110
130
  }
111
131
 
112
- VALUE fsevent_class;
113
132
  void Init_fsevent() {
133
+ rb_require("fsevent/signal_ext");
134
+
114
135
  fsevent_class = rb_define_class("FSEvent", rb_cObject);
115
136
  rb_define_method(fsevent_class, "initialize", t_init, 0);
116
137
  rb_define_method(fsevent_class, "on_change", t_on_change, 1);
117
138
  rb_define_method(fsevent_class, "watch_directories", t_watch_directories, 1);
118
- rb_define_method(fsevent_class, "run", t_run, 0);
139
+ rb_define_method(fsevent_class, "start", t_start, 0);
140
+ rb_define_method(fsevent_class, "stop", t_stop, 0);
141
+ rb_define_method(fsevent_class, "restart", t_restart, 0);
119
142
 
120
143
  rb_define_attr(fsevent_class, "latency", 1, 1);
121
144
  rb_define_attr(fsevent_class, "registered_directories", 1, 1);
122
145
 
123
- atexit(kill_watcher);
146
+ register_signal_delegation();
124
147
  }
@@ -0,0 +1,48 @@
1
+ module Signal
2
+ class << self
3
+ alias trap_without_custom_handlers trap
4
+
5
+ def handlers
6
+ @handlers ||= {}
7
+ end
8
+
9
+ def trap(signal, &block)
10
+ handlers[int_for_signal(signal)] = block
11
+ end
12
+
13
+ def handles?(signal)
14
+ handlers.has_key? int_for_signal(signal)
15
+ end
16
+
17
+ def handle(signal)
18
+ if handler = handlers[int_for_signal(signal)]
19
+ handler.call
20
+ end
21
+ end
22
+
23
+ protected
24
+
25
+ def int_for_signal(signal)
26
+ error_msg = "Check Signal.list for a list of valid signals."
27
+ case signal
28
+ when Numeric
29
+ list.values.include?(signal) ? signal : raise(ArgumentError, "Invalid signal number. #{error_msg}")
30
+ when String
31
+ signal = signal.upcase
32
+ list.keys.include?(signal) ? list[signal] : raise(ArgumentError, "Invalid signal identifier. #{error_msg}")
33
+ else
34
+ raise ArgumentError, error_msg
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ module Kernel
41
+ def self.trap(signal, &block)
42
+ Signal.trap(signal, &block)
43
+ end
44
+ end
45
+
46
+ def trap(signal, &block)
47
+ Signal.trap(signal, &block)
48
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruby-fsevent}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sandro Turriate"]
12
- s.date = %q{2009-10-15}
12
+ s.date = %q{2009-10-24}
13
13
  s.description = %q{
14
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
15
  }
@@ -21,26 +21,32 @@ Gem::Specification.new do |s|
21
21
  ]
22
22
  s.files = [
23
23
  ".gitignore",
24
+ "History.md",
24
25
  "LICENSE",
25
26
  "README.md",
26
27
  "Rakefile",
27
28
  "VERSION",
28
29
  "examples/print_changes.rb",
30
+ "examples/restart.rb",
29
31
  "ext/extconf.rb",
30
32
  "ext/fsevent.c",
33
+ "lib/fsevent/signal_ext.rb",
31
34
  "ruby-fsevent.gemspec",
32
35
  "spec/fsevent_spec.rb",
36
+ "spec/signal_ext_spec.rb",
33
37
  "spec/spec_helper.rb"
34
38
  ]
35
39
  s.homepage = %q{http://github.com/sandro/ruby-fsevent}
36
40
  s.rdoc_options = ["--charset=UTF-8"]
37
- s.require_paths = ["lib"]
41
+ s.require_paths = ["lib", "ext"]
38
42
  s.rubygems_version = %q{1.3.5}
39
43
  s.summary = %q{A native extension exposing the OS X FSEvent API.}
40
44
  s.test_files = [
41
45
  "spec/fsevent_spec.rb",
46
+ "spec/signal_ext_spec.rb",
42
47
  "spec/spec_helper.rb",
43
- "examples/print_changes.rb"
48
+ "examples/print_changes.rb",
49
+ "examples/restart.rb"
44
50
  ]
45
51
 
46
52
  if s.respond_to? :specification_version then
@@ -48,11 +54,11 @@ Gem::Specification.new do |s|
48
54
  s.specification_version = 3
49
55
 
50
56
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
- s.add_development_dependency(%q<rspec>, [">= 0"])
57
+ s.add_development_dependency(%q<rspec>, [">= 1.2.8"])
52
58
  else
53
- s.add_dependency(%q<rspec>, [">= 0"])
59
+ s.add_dependency(%q<rspec>, [">= 1.2.8"])
54
60
  end
55
61
  else
56
- s.add_dependency(%q<rspec>, [">= 0"])
62
+ s.add_dependency(%q<rspec>, [">= 1.2.8"])
57
63
  end
58
64
  end
@@ -26,6 +26,8 @@ describe FSEvent do
26
26
 
27
27
  describe "API" do
28
28
  it { should respond_to(:on_change) }
29
- it { should respond_to(:run) }
29
+ it { should respond_to(:start) }
30
+ it { should respond_to(:stop) }
31
+ it { should respond_to(:restart) }
30
32
  end
31
33
  end
@@ -0,0 +1,76 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Signal do
4
+ describe "#trap" do
5
+ it "captures the block argument as the signal handler" do
6
+ Signal.trap(2) { :int }
7
+ Signal.handlers[2].call.should == :int
8
+ end
9
+
10
+ it "converts the signal name into an integer when storing the handler" do
11
+ Signal.trap('INT')
12
+ Signal.handlers.should include(Signal.list['INT'])
13
+ end
14
+
15
+ it "allows lowercase signal names" do
16
+ Signal.trap('int')
17
+ Signal.handlers.should include(Signal.list['INT'])
18
+ end
19
+
20
+ it "does not allow unknown signal names" do
21
+ expect {
22
+ Signal.trap('interrupt')
23
+ }.to raise_error(ArgumentError)
24
+ end
25
+
26
+ it "does not allow unknown signal numbers" do
27
+ expect {
28
+ Signal.trap(12111211221)
29
+ }.to raise_error(ArgumentError)
30
+ end
31
+
32
+ it "does not allow unknown data types" do
33
+ expect {
34
+ Signal.trap(['int'])
35
+ }.to raise_error(ArgumentError)
36
+ end
37
+ end
38
+
39
+ describe "#handles?" do
40
+ it "returns true when a handler is registered for the signal" do
41
+ Signal.trap('INT')
42
+ Signal.handles?('INT').should be_true
43
+ end
44
+
45
+ it "returns false when no handler was registered for the signal" do
46
+ Signal.handles?('EXIT').should be_false
47
+ end
48
+ end
49
+
50
+ describe "#handle" do
51
+ it "does not raise when trying to call a non-existant handler" do
52
+ expect do
53
+ Signal.handle('EXIT')
54
+ end.should_not raise_error
55
+ end
56
+
57
+ it "calls the handler" do
58
+ Signal.trap('INT') { :int }
59
+ Signal.handle('INT').should == :int
60
+ end
61
+ end
62
+ end
63
+
64
+ describe Kernel do
65
+ it "delegates .trap to Signal" do
66
+ Signal.should_receive(:trap).with('INT')
67
+ Kernel.trap('INT')
68
+ end
69
+ end
70
+
71
+ context "global" do
72
+ it "delegates .trap to Signal" do
73
+ Signal.should_receive(:trap).with('INT')
74
+ trap('INT')
75
+ end
76
+ end
@@ -1,4 +1,5 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'ext'))
1
+ $:.unshift(File.dirname(__FILE__) + '/../ext')
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
3
  require 'fsevent'
4
+ require 'fsevent/signal_ext'
4
5
  require 'spec/autorun'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-fsevent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Turriate
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-15 00:00:00 -04:00
12
+ date: 2009-10-24 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: "0"
23
+ version: 1.2.8
24
24
  version:
25
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
26
  email: sandro.turriate@gmail.com
@@ -33,15 +33,19 @@ extra_rdoc_files:
33
33
  - README.md
34
34
  files:
35
35
  - .gitignore
36
+ - History.md
36
37
  - LICENSE
37
38
  - README.md
38
39
  - Rakefile
39
40
  - VERSION
40
41
  - examples/print_changes.rb
42
+ - examples/restart.rb
41
43
  - ext/extconf.rb
42
44
  - ext/fsevent.c
45
+ - lib/fsevent/signal_ext.rb
43
46
  - ruby-fsevent.gemspec
44
47
  - spec/fsevent_spec.rb
48
+ - spec/signal_ext_spec.rb
45
49
  - spec/spec_helper.rb
46
50
  has_rdoc: true
47
51
  homepage: http://github.com/sandro/ruby-fsevent
@@ -52,6 +56,7 @@ rdoc_options:
52
56
  - --charset=UTF-8
53
57
  require_paths:
54
58
  - lib
59
+ - ext
55
60
  required_ruby_version: !ruby/object:Gem::Requirement
56
61
  requirements:
57
62
  - - ">="
@@ -73,5 +78,7 @@ specification_version: 3
73
78
  summary: A native extension exposing the OS X FSEvent API.
74
79
  test_files:
75
80
  - spec/fsevent_spec.rb
81
+ - spec/signal_ext_spec.rb
76
82
  - spec/spec_helper.rb
77
83
  - examples/print_changes.rb
84
+ - examples/restart.rb