kicker 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A lean, agnostic, flexible file-change watcher, using OS X FSEvents.
4
4
 
5
- http://github.com/alloy/kicker/raw/master/html/images/kikker.jpg
5
+ https://github.com/alloy/kicker/raw/master/html/images/kikker.jpg
6
6
 
7
7
  Meet king kikker, kicking stuff in your computers is his dream come true!
8
8
 
data/Rakefile CHANGED
@@ -14,6 +14,7 @@ begin
14
14
  gem.files.concat FileList['vendor/**/*']
15
15
  gem.require_paths = ["lib", "vendor"]
16
16
  gem.has_rdoc = true
17
+ gem.add_dependency 'rb-fsevent'
17
18
  end
18
19
  rescue LoadError
19
20
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
@@ -33,4 +34,4 @@ namespace :docs do
33
34
  end
34
35
  end
35
36
 
36
- task :default => :test
37
+ task :default => :test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.0
1
+ 2.3.1
data/bin/kicker CHANGED
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
- $:.unshift File.expand_path('../../lib', __FILE__) if $0 == __FILE__
2
+
3
+ if $0 == __FILE__
4
+ $:.unshift File.expand_path('../../lib', __FILE__)
5
+ $:.unshift File.expand_path('../../vendor', __FILE__)
6
+ require 'rubygems'
7
+ end
3
8
 
4
9
  require 'kicker'
5
10
  Kicker.run
data/kicker.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{kicker}
8
- s.version = "2.3.0"
8
+ s.version = "2.3.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Eloy Duran"]
12
- s.date = %q{2010-07-27}
12
+ s.date = %q{2011-05-27}
13
13
  s.default_executable = %q{kicker}
14
14
  s.email = %q{eloy.de.enige@gmail.com}
15
15
  s.executables = ["kicker"]
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
  "lib/kicker.rb",
32
32
  "lib/kicker/callback_chain.rb",
33
33
  "lib/kicker/core_ext.rb",
34
+ "lib/kicker/fsevents.rb",
34
35
  "lib/kicker/growl.rb",
35
36
  "lib/kicker/log_status_helper.rb",
36
37
  "lib/kicker/options.rb",
@@ -47,6 +48,7 @@ Gem::Specification.new do |s|
47
48
  "test/core_ext_test.rb",
48
49
  "test/filesystem_change_test.rb",
49
50
  "test/fixtures/a_file_thats_reloaded.rb",
51
+ "test/fsevents_test.rb",
50
52
  "test/growl_test.rb",
51
53
  "test/initialization_test.rb",
52
54
  "test/log_status_helper_test.rb",
@@ -62,19 +64,19 @@ Gem::Specification.new do |s|
62
64
  "test/test_helper.rb",
63
65
  "test/utils_test.rb",
64
66
  "vendor/growlnotifier/growl.rb",
65
- "vendor/growlnotifier/growl_helpers.rb",
66
- "vendor/rucola/fsevents.rb"
67
+ "vendor/growlnotifier/growl_helpers.rb"
67
68
  ]
68
69
  s.homepage = %q{http://github.com/alloy/kicker}
69
70
  s.rdoc_options = ["--charset=UTF-8"]
70
71
  s.require_paths = ["lib", "vendor"]
71
- s.rubygems_version = %q{1.3.5}
72
+ s.rubygems_version = %q{1.3.7}
72
73
  s.summary = %q{A lean, agnostic, flexible file-change watcher, using OS X FSEvents.}
73
74
  s.test_files = [
74
75
  "test/callback_chain_test.rb",
75
76
  "test/core_ext_test.rb",
76
77
  "test/filesystem_change_test.rb",
77
78
  "test/fixtures/a_file_thats_reloaded.rb",
79
+ "test/fsevents_test.rb",
78
80
  "test/growl_test.rb",
79
81
  "test/initialization_test.rb",
80
82
  "test/log_status_helper_test.rb",
@@ -95,10 +97,13 @@ Gem::Specification.new do |s|
95
97
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
96
98
  s.specification_version = 3
97
99
 
98
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
100
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
101
+ s.add_runtime_dependency(%q<rb-fsevent>, [">= 0"])
99
102
  else
103
+ s.add_dependency(%q<rb-fsevent>, [">= 0"])
100
104
  end
101
105
  else
106
+ s.add_dependency(%q<rb-fsevent>, [">= 0"])
102
107
  end
103
108
  end
104
109
 
data/lib/kicker.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  $:.unshift File.expand_path('../../vendor', __FILE__)
2
- require 'rucola/fsevents'
3
2
 
3
+ require 'kicker/fsevents'
4
4
  require 'kicker/callback_chain'
5
5
  require 'kicker/core_ext'
6
6
  require 'kicker/growl'
@@ -30,11 +30,9 @@ class Kicker #:nodoc:
30
30
  log "Watching for changes on: #{paths.join(', ')}"
31
31
  log ''
32
32
 
33
- run_watch_dog!
34
33
  Kicker::Growl.start! if Kicker::Growl.use?
35
34
  run_startup_chain
36
-
37
- OSX.CFRunLoopRun
35
+ run_watch_dog!
38
36
  end
39
37
 
40
38
  private
@@ -62,12 +60,12 @@ class Kicker #:nodoc:
62
60
 
63
61
  def run_watch_dog!
64
62
  dirs = @paths.map { |path| File.directory?(path) ? path : File.dirname(path) }
65
- watch_dog = Rucola::FSEvents.start_watching(dirs, :latency => self.class.latency) do |events|
63
+ watch_dog = Kicker::FSEvents.start_watching(dirs, :latency => self.class.latency) do |events|
66
64
  process events
67
65
  end
68
66
 
69
67
  trap('INT') do
70
- log "Exiting"
68
+ log "Exiting ..."
71
69
  watch_dog.stop
72
70
  exit
73
71
  end
@@ -121,4 +119,4 @@ end
121
119
 
122
120
  # Load this as last, because it actually loads all recipes, so everything has
123
121
  # to be defined before that.
124
- require 'kicker/recipes'
122
+ require 'kicker/recipes'
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rb-fsevent'
4
+
5
+ class Kicker
6
+ class FSEvents
7
+ class FSEvent
8
+ attr_reader :path
9
+
10
+ def initialize(path)
11
+ @path = path
12
+ end
13
+
14
+ def files
15
+ Dir.glob("#{File.expand_path(path)}/*").map do |filename|
16
+ begin
17
+ [File.mtime(filename), filename]
18
+ rescue Errno::ENOENT
19
+ nil
20
+ end
21
+ end.compact.sort.reverse.map { |_, filename| filename }
22
+ end
23
+ end
24
+
25
+ def self.start_watching(paths, options={}, &block)
26
+ fsevent = ::FSEvent.new
27
+ fsevent.watch(paths, options) do |directories|
28
+ yield directories.map { |directory| Kicker::FSEvents::FSEvent.new(directory) }
29
+ end
30
+ fsevent.run
31
+ end
32
+ end
33
+ end
data/lib/kicker/growl.rb CHANGED
@@ -1,59 +1,79 @@
1
- require 'growlnotifier/growl_helpers'
2
-
3
1
  class Kicker
4
2
  module Growl #:nodoc:
5
- NOTIFICATIONS = {
6
- :change => 'Change occured',
7
- :succeeded => 'Command succeeded',
8
- :failed => 'Command failed'
9
- }
10
-
11
- DEFAULT_CALLBACK = lambda do
12
- OSX::NSWorkspace.sharedWorkspace.launchApplication('Terminal')
13
- end
14
-
15
3
  class << self
16
- include ::Growl
17
4
  attr_accessor :use, :command
18
5
 
19
- Growl.use = true
20
- Growl.command = nil
6
+ def usable?
7
+ false
8
+ end
21
9
 
22
10
  def use?
23
11
  @use
24
12
  end
13
+ end
14
+ end
15
+ end
16
+
17
+ begin
18
+ require 'osx/cocoa'
19
+ require 'growlnotifier/growl_helpers'
20
+
21
+ class Kicker
22
+ module Growl #:nodoc:
23
+ NOTIFICATIONS = {
24
+ :change => 'Change occured',
25
+ :succeeded => 'Command succeeded',
26
+ :failed => 'Command failed'
27
+ }
25
28
 
26
- def notifications
27
- NOTIFICATIONS
28
- end
29
-
30
- def start!
31
- ::Growl::Notifier.sharedInstance.register('Kicker', NOTIFICATIONS.values)
32
- end
33
-
34
- def change_occured(status)
35
- growl(notifications[:change], 'Kicker: Executing', status.call(:growl) || status.command)
36
- end
37
-
38
- def command_callback
39
- lambda { system(command) } if command
40
- end
41
-
42
- def result(status)
43
- status.success? ? succeeded(status) : failed(status)
44
- end
45
-
46
- def succeeded(status)
47
- callback = command_callback || DEFAULT_CALLBACK
48
- body = status.call(:growl) || (Kicker.silent? ? '' : status.output)
49
- growl(notifications[:succeeded], "Kicker: Success", body, &callback)
29
+ DEFAULT_CALLBACK = lambda do
30
+ OSX::NSWorkspace.sharedWorkspace.launchApplication('Terminal')
50
31
  end
51
32
 
52
- def failed(status)
53
- message = "Kicker: Failed (#{status.exit_code})"
54
- body = status.call(:growl) || (Kicker.silent? ? '' : status.output)
55
- growl(notifications[:failed], message, body, &DEFAULT_CALLBACK)
33
+ class << self
34
+ include ::Growl
35
+
36
+ Growl.use = true
37
+ Growl.command = nil
38
+
39
+ def usable?
40
+ true
41
+ end
42
+
43
+ def notifications
44
+ NOTIFICATIONS
45
+ end
46
+
47
+ def start!
48
+ ::Growl::Notifier.sharedInstance.register('Kicker', NOTIFICATIONS.values)
49
+ end
50
+
51
+ def change_occured(status)
52
+ growl(notifications[:change], 'Kicker: Executing', status.call(:growl) || status.command)
53
+ end
54
+
55
+ def command_callback
56
+ lambda { system(command) } if command
57
+ end
58
+
59
+ def result(status)
60
+ status.success? ? succeeded(status) : failed(status)
61
+ end
62
+
63
+ def succeeded(status)
64
+ callback = command_callback || DEFAULT_CALLBACK
65
+ body = status.call(:growl) || (Kicker.silent? ? '' : status.output)
66
+ growl(notifications[:succeeded], "Kicker: Success", body, &callback)
67
+ end
68
+
69
+ def failed(status)
70
+ message = "Kicker: Failed (#{status.exit_code})"
71
+ body = status.call(:growl) || (Kicker.silent? ? '' : status.output)
72
+ growl(notifications[:failed], message, body, &DEFAULT_CALLBACK)
73
+ end
56
74
  end
57
75
  end
58
76
  end
59
- end
77
+
78
+ rescue LoadError
79
+ end
@@ -15,6 +15,10 @@ class Kicker
15
15
  def clear_console?
16
16
  @clear_console
17
17
  end
18
+
19
+ def has_growl?
20
+ Kicker.const_defined?(:Growl)
21
+ end
18
22
  end
19
23
 
20
24
  self.latency = 1
@@ -49,12 +53,16 @@ class Kicker
49
53
  Kicker.clear_console = true
50
54
  end
51
55
 
52
- opt.on('--[no-]growl', 'Whether or not to use Growl. Default is to use growl.') do |growl|
53
- Kicker::Growl.use = growl
54
- end
55
-
56
- opt.on('--growl-command [COMMAND]', 'The command to execute when the Growl succeeded message is clicked.') do |command|
57
- Kicker::Growl.command = command
56
+ if Kicker::Growl.usable?
57
+ opt.on('--[no-]growl', 'Whether or not to use Growl. Default is to use growl.') do |growl|
58
+ Kicker::Growl.use = growl
59
+ end
60
+
61
+ opt.on('--growl-command [COMMAND]', 'The command to execute when the Growl succeeded message is clicked.') do |command|
62
+ Kicker::Growl.command = command
63
+ end
64
+ else
65
+ Kicker::Growl.use = false
58
66
  end
59
67
 
60
68
  opt.on('-l', '--latency [FLOAT]', "The time to collect file change events before acting on them. Defaults to #{Kicker.latency} second.") do |latency|
@@ -0,0 +1,35 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class FakeFSEvent
4
+ def watch(paths, options={}, &block)
5
+ @paths = paths
6
+ @block = block
7
+ end
8
+
9
+ def run
10
+ end
11
+
12
+ def fake_event(paths)
13
+ @block.call(paths)
14
+ end
15
+ end
16
+
17
+ describe "Kicker::FSEvents" do
18
+ it "calls the provided block with changed directories wrapped in an event instance" do
19
+ events = nil
20
+ faker = FakeFSEvent.new
21
+ ::FSEvent.expects(:new).returns(faker)
22
+ Kicker::FSEvents.start_watching(%w(/path/to/first /path/to/second)) do |events|
23
+ end
24
+ paths = %w(/path/to/first)
25
+ faker.fake_event(paths)
26
+ events.map { |e| e.path }.should == paths
27
+ end
28
+ end
29
+
30
+ describe "Kicker::FSEvents::FSEvent" do
31
+ it "returns the files from the changed directory ordered by mtime and filename" do
32
+ fsevent = Kicker::FSEvents::FSEvent.new(File.expand_path('../fixtures', __FILE__))
33
+ fsevent.files.should == [File.expand_path('../fixtures/a_file_thats_reloaded.rb', __FILE__)]
34
+ end
35
+ end
data/test/growl_test.rb CHANGED
@@ -1,85 +1,89 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
- describe "Kicker::Growl" do
4
- before do
5
- @growler = Kicker::Growl
6
- end
7
-
8
- after do
9
- Kicker.silent = false
10
- end
11
-
12
- it "should growl that an event occurred" do
13
- status = Kicker::LogStatusHelper.new(nil, 'ls -l')
14
- @growler.expects(:growl).with(@growler.notifications[:change], 'Kicker: Executing', 'ls -l')
15
- @growler.change_occured(status)
16
- end
17
-
18
- it "should growl that an event occurred with the status callback" do
19
- status = Kicker::LogStatusHelper.new(proc { |s| 'foo' if s.growl? }, 'ls -l')
20
- @growler.expects(:growl).with(@growler.notifications[:change], 'Kicker: Executing', 'foo')
21
- @growler.change_occured(status)
22
- end
23
-
24
- it "should use the default click callback if a command succeeded and no user callback is defined" do
25
- status = Kicker::LogStatusHelper.new(nil, 'ls -l')
26
- status.result("line 1\nline 2", true, 0)
3
+ if Kicker::Growl.usable?
4
+ describe "Kicker::Growl" do
5
+ before do
6
+ @growler = Kicker::Growl
7
+ end
27
8
 
28
- OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal')
29
- @growler.expects(:growl).with(
30
- @growler.notifications[:succeeded],
31
- 'Kicker: Success',
32
- "line 1\nline 2"
33
- ).yields
9
+ after do
10
+ Kicker.silent = false
11
+ end
34
12
 
35
- @growler.result(status)
36
- end
37
-
38
- it "should use the default click callback if a command failed and no user callback is defined" do
39
- status = Kicker::LogStatusHelper.new(nil, 'ls -l')
40
- status.result("line 1\nline 2", false, 123)
13
+ it "should growl that an event occurred" do
14
+ status = Kicker::LogStatusHelper.new(nil, 'ls -l')
15
+ @growler.expects(:growl).with(@growler.notifications[:change], 'Kicker: Executing', 'ls -l')
16
+ @growler.change_occured(status)
17
+ end
41
18
 
42
- OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal')
43
- @growler.expects(:growl).with(
44
- @growler.notifications[:failed],
45
- 'Kicker: Failed (123)',
46
- "line 1\nline 2"
47
- ).yields
19
+ it "should growl that an event occurred with the status callback" do
20
+ status = Kicker::LogStatusHelper.new(proc { |s| 'foo' if s.growl? }, 'ls -l')
21
+ @growler.expects(:growl).with(@growler.notifications[:change], 'Kicker: Executing', 'foo')
22
+ @growler.change_occured(status)
23
+ end
48
24
 
49
- @growler.failed(status)
50
- end
51
-
52
- it "should only growl that the command succeeded in silent mode" do
53
- Kicker.silent = true
54
- status = Kicker::LogStatusHelper.new(nil, 'ls -l')
55
- status.result("line 1\nline 2", true, 0)
25
+ it "should use the default click callback if a command succeeded and no user callback is defined" do
26
+ status = Kicker::LogStatusHelper.new(nil, 'ls -l')
27
+ status.result("line 1\nline 2", true, 0)
28
+
29
+ OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal')
30
+ @growler.expects(:growl).with(
31
+ @growler.notifications[:succeeded],
32
+ 'Kicker: Success',
33
+ "line 1\nline 2"
34
+ ).yields
35
+
36
+ @growler.result(status)
37
+ end
56
38
 
57
- @growler.expects(:growl).with(@growler.notifications[:succeeded], 'Kicker: Success', '')
58
- @growler.result(status)
59
- end
60
-
61
- it "should only growl that the command failed in silent mode" do
62
- Kicker.silent = true
63
- status = Kicker::LogStatusHelper.new(nil, 'ls -l')
64
- status.result("line 1\nline 2", false, 123)
39
+ it "should use the default click callback if a command failed and no user callback is defined" do
40
+ status = Kicker::LogStatusHelper.new(nil, 'ls -l')
41
+ status.result("line 1\nline 2", false, 123)
42
+
43
+ OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal')
44
+ @growler.expects(:growl).with(
45
+ @growler.notifications[:failed],
46
+ 'Kicker: Failed (123)',
47
+ "line 1\nline 2"
48
+ ).yields
49
+
50
+ @growler.failed(status)
51
+ end
65
52
 
66
- @growler.expects(:growl).with(@growler.notifications[:failed], 'Kicker: Failed (123)', '')
67
- @growler.failed(status)
68
- end
69
-
70
- it "should growl that the command succeeded with the status callback" do
71
- status = Kicker::LogStatusHelper.new(proc { |s| 'foo' if s.growl? }, 'ls -l')
72
- status.result("line 1\nline 2", true, 0)
53
+ it "should only growl that the command succeeded in silent mode" do
54
+ Kicker.silent = true
55
+ status = Kicker::LogStatusHelper.new(nil, 'ls -l')
56
+ status.result("line 1\nline 2", true, 0)
57
+
58
+ @growler.expects(:growl).with(@growler.notifications[:succeeded], 'Kicker: Success', '')
59
+ @growler.result(status)
60
+ end
73
61
 
74
- @growler.expects(:growl).with(@growler.notifications[:succeeded], 'Kicker: Success', 'foo')
75
- @growler.succeeded(status)
76
- end
77
-
78
- it "should growl that the command failed with the status callback" do
79
- status = Kicker::LogStatusHelper.new(proc { |s| 'foo' if s.growl? }, 'ls -l')
80
- status.result("line 1\nline 2", false, 123)
62
+ it "should only growl that the command failed in silent mode" do
63
+ Kicker.silent = true
64
+ status = Kicker::LogStatusHelper.new(nil, 'ls -l')
65
+ status.result("line 1\nline 2", false, 123)
66
+
67
+ @growler.expects(:growl).with(@growler.notifications[:failed], 'Kicker: Failed (123)', '')
68
+ @growler.failed(status)
69
+ end
70
+
71
+ it "should growl that the command succeeded with the status callback" do
72
+ status = Kicker::LogStatusHelper.new(proc { |s| 'foo' if s.growl? }, 'ls -l')
73
+ status.result("line 1\nline 2", true, 0)
74
+
75
+ @growler.expects(:growl).with(@growler.notifications[:succeeded], 'Kicker: Success', 'foo')
76
+ @growler.succeeded(status)
77
+ end
81
78
 
82
- @growler.expects(:growl).with(@growler.notifications[:failed], 'Kicker: Failed (123)', 'foo')
83
- @growler.failed(status)
79
+ it "should growl that the command failed with the status callback" do
80
+ status = Kicker::LogStatusHelper.new(proc { |s| 'foo' if s.growl? }, 'ls -l')
81
+ status.result("line 1\nline 2", false, 123)
82
+
83
+ @growler.expects(:growl).with(@growler.notifications[:failed], 'Kicker: Failed (123)', 'foo')
84
+ @growler.failed(status)
85
+ end
84
86
  end
87
+ else
88
+ puts "Poo"
85
89
  end
@@ -42,8 +42,7 @@ describe "Kicker, when starting" do
42
42
  @kicker = Kicker.new
43
43
  @kicker.stubs(:log)
44
44
  @kicker.startup_chain.stubs(:call)
45
- Rucola::FSEvents.stubs(:start_watching)
46
- OSX.stubs(:CFRunLoopRun)
45
+ Kicker::FSEvents.stubs(:start_watching)
47
46
  end
48
47
 
49
48
  after do
@@ -77,7 +76,7 @@ describe "Kicker, when starting" do
77
76
  @kicker.stubs(:validate_options!)
78
77
 
79
78
  Kicker.latency = 2.34
80
- Rucola::FSEvents.expects(:start_watching).with(['/some'], :latency => 2.34)
79
+ Kicker::FSEvents.expects(:start_watching).with(['/some'], :latency => 2.34)
81
80
  @kicker.start
82
81
  end
83
82
 
@@ -85,14 +84,14 @@ describe "Kicker, when starting" do
85
84
  @kicker.stubs(:validate_options!)
86
85
  File.stubs(:directory?).with('/some/file.rb').returns(false)
87
86
 
88
- Rucola::FSEvents.expects(:start_watching).with(['/some'], :latency => Kicker.latency)
87
+ Kicker::FSEvents.expects(:start_watching).with(['/some'], :latency => Kicker.latency)
89
88
  @kicker.start
90
89
  end
91
90
 
92
91
  it "should start a FSEvents stream with a block which calls #process with any generated events" do
93
92
  @kicker.stubs(:validate_options!)
94
93
 
95
- Rucola::FSEvents.expects(:start_watching).yields(['event'])
94
+ Kicker::FSEvents.expects(:start_watching).yields(['event'])
96
95
  @kicker.expects(:process).with(['event'])
97
96
 
98
97
  @kicker.start
@@ -101,8 +100,8 @@ describe "Kicker, when starting" do
101
100
  it "should setup a signal handler for `INT' which stops the FSEvents stream and exits" do
102
101
  @kicker.stubs(:validate_options!)
103
102
 
104
- watch_dog = stub('Rucola::FSEvents')
105
- Rucola::FSEvents.stubs(:start_watching).returns(watch_dog)
103
+ watch_dog = stub('Kicker::FSEvents')
104
+ Kicker::FSEvents.stubs(:start_watching).returns(watch_dog)
106
105
 
107
106
  @kicker.expects(:trap).with('INT').yields
108
107
  watch_dog.expects(:stop)
@@ -111,20 +110,22 @@ describe "Kicker, when starting" do
111
110
  @kicker.start
112
111
  end
113
112
 
114
- it "should register with growl if growl should be used" do
115
- @kicker.stubs(:validate_options!)
116
- Kicker::Growl.use = true
117
-
118
- Growl::Notifier.sharedInstance.expects(:register).with('Kicker', Kicker::Growl::NOTIFICATIONS.values)
119
- @kicker.start
120
- end
121
-
122
- it "should _not_ register with growl if growl should not be used" do
123
- @kicker.stubs(:validate_options!)
124
- Kicker::Growl.use = false
113
+ if Kicker::Growl.usable?
114
+ it "should register with growl if growl should be used" do
115
+ @kicker.stubs(:validate_options!)
116
+ Kicker::Growl.use = true
117
+
118
+ Growl::Notifier.sharedInstance.expects(:register).with('Kicker', Kicker::Growl::NOTIFICATIONS.values)
119
+ @kicker.start
120
+ end
125
121
 
126
- Growl::Notifier.sharedInstance.expects(:register).never
127
- @kicker.start
122
+ it "should _not_ register with growl if growl should not be used" do
123
+ @kicker.stubs(:validate_options!)
124
+ Kicker::Growl.use = false
125
+
126
+ Growl::Notifier.sharedInstance.expects(:register).never
127
+ @kicker.start
128
+ end
128
129
  end
129
130
 
130
131
  it "should call the startup chain" do
@@ -133,11 +134,4 @@ describe "Kicker, when starting" do
133
134
  @kicker.startup_chain.expects(:call).with([], false)
134
135
  @kicker.start
135
136
  end
136
-
137
- it "should start a CFRunLoop" do
138
- @kicker.stubs(:validate_options!)
139
-
140
- OSX.expects(:CFRunLoopRun)
141
- @kicker.start
142
- end
143
137
  end
data/test/options_test.rb CHANGED
@@ -21,12 +21,14 @@ describe "Kicker::Options.parse" do
21
21
  Kicker.paths.should == %w{ /some/file.rb /a/dir /and/some/other/file.rb }
22
22
  end
23
23
 
24
- it "should parse if growl shouldn't be used" do
25
- Kicker::Options.parse([])
26
- Kicker::Growl.should.use
24
+ if Kicker::Growl.usable?
25
+ it "should parse if growl shouldn't be used" do
26
+ Kicker::Options.parse([])
27
+ Kicker::Growl.should.use
27
28
 
28
- Kicker::Options.parse(%w{ --no-growl })
29
- Kicker::Growl.should.not.use
29
+ Kicker::Options.parse(%w{ --no-growl })
30
+ Kicker::Growl.should.not.use
31
+ end
30
32
  end
31
33
 
32
34
  it "should parse if we should keep output to a minimum" do
@@ -55,9 +57,11 @@ describe "Kicker::Options.parse" do
55
57
  Kicker.should.clear_console
56
58
  end
57
59
 
58
- it "should parse the Growl command to use when the user clicks the Growl succeeded message" do
59
- Kicker::Options.parse(%w{ --growl-command ls })
60
- Kicker::Growl.command.should == 'ls'
60
+ if Kicker::Growl.usable?
61
+ it "should parse the Growl command to use when the user clicks the Growl succeeded message" do
62
+ Kicker::Options.parse(%w{ --growl-command ls })
63
+ Kicker::Growl.command.should == 'ls'
64
+ end
61
65
  end
62
66
 
63
67
  it "should parse the latency to pass to FSEvents" do
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kicker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ hash: 1
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 3
9
+ - 1
10
+ version: 2.3.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Eloy Duran
@@ -9,10 +15,23 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-07-27 00:00:00 +02:00
18
+ date: 2011-05-27 00:00:00 +02:00
13
19
  default_executable: kicker
14
- dependencies: []
15
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rb-fsevent
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
16
35
  description:
17
36
  email: eloy.de.enige@gmail.com
18
37
  executables:
@@ -36,6 +55,7 @@ files:
36
55
  - lib/kicker.rb
37
56
  - lib/kicker/callback_chain.rb
38
57
  - lib/kicker/core_ext.rb
58
+ - lib/kicker/fsevents.rb
39
59
  - lib/kicker/growl.rb
40
60
  - lib/kicker/log_status_helper.rb
41
61
  - lib/kicker/options.rb
@@ -52,6 +72,7 @@ files:
52
72
  - test/core_ext_test.rb
53
73
  - test/filesystem_change_test.rb
54
74
  - test/fixtures/a_file_thats_reloaded.rb
75
+ - test/fsevents_test.rb
55
76
  - test/growl_test.rb
56
77
  - test/initialization_test.rb
57
78
  - test/log_status_helper_test.rb
@@ -68,7 +89,6 @@ files:
68
89
  - test/utils_test.rb
69
90
  - vendor/growlnotifier/growl.rb
70
91
  - vendor/growlnotifier/growl_helpers.rb
71
- - vendor/rucola/fsevents.rb
72
92
  has_rdoc: true
73
93
  homepage: http://github.com/alloy/kicker
74
94
  licenses: []
@@ -80,21 +100,27 @@ require_paths:
80
100
  - lib
81
101
  - vendor
82
102
  required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
83
104
  requirements:
84
105
  - - ">="
85
106
  - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
86
110
  version: "0"
87
- version:
88
111
  required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
89
113
  requirements:
90
114
  - - ">="
91
115
  - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
92
119
  version: "0"
93
- version:
94
120
  requirements: []
95
121
 
96
122
  rubyforge_project:
97
- rubygems_version: 1.3.5
123
+ rubygems_version: 1.3.7
98
124
  signing_key:
99
125
  specification_version: 3
100
126
  summary: A lean, agnostic, flexible file-change watcher, using OS X FSEvents.
@@ -103,6 +129,7 @@ test_files:
103
129
  - test/core_ext_test.rb
104
130
  - test/filesystem_change_test.rb
105
131
  - test/fixtures/a_file_thats_reloaded.rb
132
+ - test/fsevents_test.rb
106
133
  - test/growl_test.rb
107
134
  - test/initialization_test.rb
108
135
  - test/log_status_helper_test.rb
@@ -1,136 +0,0 @@
1
- require 'osx/cocoa'
2
- OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
3
-
4
- module Rucola
5
- class FSEvents
6
- class FSEvent
7
- attr_reader :fsevents_object
8
- attr_reader :id
9
- attr_reader :path
10
- def initialize(fsevents_object, id, path)
11
- @fsevents_object, @id, @path = fsevents_object, id, path
12
- end
13
-
14
- # Returns an array of the files/dirs in the path that the event occurred in.
15
- # The files are sorted by the modification time, the first entry is the last modified file.
16
- def files
17
- Dir.glob("#{File.expand_path(path)}/*").map do |filename|
18
- begin
19
- [File.mtime(filename), filename]
20
- rescue Errno::ENOENT
21
- nil
22
- end
23
- end.compact.sort.reverse.map { |mtime, filename| filename }
24
- end
25
-
26
- # Returns the last modified file in the path that the event occurred in.
27
- def last_modified_file
28
- files.first
29
- end
30
- end
31
-
32
- class StreamError < StandardError; end
33
-
34
- attr_reader :paths
35
- attr_reader :stream
36
-
37
- attr_accessor :allocator
38
- attr_accessor :context
39
- attr_accessor :since
40
- attr_accessor :latency
41
- attr_accessor :flags
42
-
43
- # Initializes a new FSEvents `watchdog` object and starts watching the directories you specify for events. The
44
- # block is used as a handler for events, which are passed as the block's argument. This method is the easiest
45
- # way to start watching some directories if you don't care about the details of setting up the event stream.
46
- #
47
- # Rucola::FSEvents.start_watching('/tmp') do |events|
48
- # events.each { |event| log.debug("#{event.files.inspect} were changed.") }
49
- # end
50
- #
51
- # Rucola::FSEvents.start_watching('/var/log/system.log', '/var/log/secure.log', :since => last_id, :latency => 5) do
52
- # Growl.notify("Something was added to your log files!")
53
- # end
54
- #
55
- # Note that the method also returns the FSEvents object. This enables you to control the event stream if you want to.
56
- #
57
- # fsevents = Rucola::FSEvents.start_watching('/Volumes') do |events|
58
- # events.each { |event| Growl.notify("Volume changes: #{event.files.to_sentence}") }
59
- # end
60
- # fsevents.stop
61
- def self.start_watching(*params, &block)
62
- fsevents = new(*params, &block)
63
- fsevents.create_stream
64
- fsevents.start
65
- fsevents
66
- end
67
-
68
- # Creates a new FSEvents `watchdog` object. You can specify a list of paths to watch and options to control the
69
- # behaviour of the watchdog. The block you pass serves as a callback when an event is generated on one of the
70
- # specified paths.
71
- #
72
- # fsevents = FSEvents.new('/etc/passwd') { Mailer.send_mail("Someone touched the password file!") }
73
- # fsevents.create_stream
74
- # fsevents.start
75
- #
76
- # fsevents = FSEvents.new('/home/upload', :since => UploadWatcher.last_event_id) do |events|
77
- # events.each do |event|
78
- # UploadWatcher.last_event_id = event.id
79
- # event.files.each do |file|
80
- # UploadWatcher.logfile.append("#{file} was changed")
81
- # end
82
- # end
83
- # end
84
- #
85
- # *:since: The service will report events that have happened after the supplied event ID. Never use 0 because that
86
- # will cause every fsevent since the "beginning of time" to be reported. Use OSX::KFSEventStreamEventIdSinceNow
87
- # if you want to receive events that have happened after this call. (Default: OSX::KFSEventStreamEventIdSinceNow).
88
- # You can find the ID's passed with :since in the events passed to your block.
89
- # *:latency: Number of seconds to wait until an FSEvent is reported, this allows the service to bundle events. (Default: 0.0)
90
- #
91
- # Please refer to the Cocoa documentation for the rest of the options.
92
- def initialize(*params, &block)
93
- raise ArgumentError, 'No callback block was specified.' unless block_given?
94
-
95
- options = params.last.kind_of?(Hash) ? params.pop : {}
96
- @paths = params.flatten
97
-
98
- paths.each { |path| raise ArgumentError, "The specified path (#{path}) does not exist." unless File.exist?(path) }
99
-
100
- @allocator = options[:allocator] || OSX::KCFAllocatorDefault
101
- @context = options[:context] || nil
102
- @since = options[:since] || OSX::KFSEventStreamEventIdSinceNow
103
- @latency = options[:latency] || 0.0
104
- @flags = options[:flags] || 0
105
- @stream = options[:stream] || nil
106
-
107
- @user_callback = block
108
- @callback = Proc.new do |stream, client_callback_info, number_of_events, paths_pointer, event_flags, event_ids|
109
- paths_pointer.regard_as('*')
110
- events = []
111
- number_of_events.times {|i| events << Rucola::FSEvents::FSEvent.new(self, event_ids[i], paths_pointer[i]) }
112
- @user_callback.call(events)
113
- end
114
- end
115
-
116
- # Create the stream.
117
- # Raises a Rucola::FSEvents::StreamError if the stream could not be created.
118
- def create_stream
119
- @stream = OSX.FSEventStreamCreate(@allocator, @callback, @context, @paths, @since, @latency, @flags)
120
- raise(StreamError, 'Unable to create FSEvents stream.') unless @stream
121
- OSX.FSEventStreamScheduleWithRunLoop(@stream, OSX.CFRunLoopGetCurrent, OSX::KCFRunLoopDefaultMode)
122
- end
123
-
124
- # Start the stream.
125
- # Raises a Rucola::FSEvents::StreamError if the stream could not be started.
126
- def start
127
- raise(StreamError, 'Unable to start FSEvents stream.') unless OSX.FSEventStreamStart(@stream)
128
- end
129
-
130
- # Stop the stream.
131
- # You can resume it by calling `start` again.
132
- def stop
133
- OSX.FSEventStreamStop(@stream)
134
- end
135
- end
136
- end