kicker 2.3.0 → 2.3.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.
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