ruby-fsevent 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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