mislav-rspactor 0.3.3 → 0.4.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.
- data/Rakefile +1 -52
- data/bin/rspactor-system +93 -0
- data/lib/rspactor.rb +1 -0
- data/lib/rspactor/growl.rb +16 -0
- data/lib/rspactor/inspector.rb +1 -1
- data/lib/rspactor/listener.rb +41 -15
- data/lib/rspactor/runner.rb +2 -2
- data/lib/rspec_growler.rb +4 -5
- data/spec/listener_spec.rb +1 -1
- data/spec/runner_spec.rb +3 -2
- metadata +27 -12
data/Rakefile
CHANGED
|
@@ -2,56 +2,5 @@ task :default => :spec
|
|
|
2
2
|
|
|
3
3
|
desc "starts RSpactor"
|
|
4
4
|
task :spec do
|
|
5
|
-
system "ruby -Ilib bin/rspactor"
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
desc "generates .gemspec file"
|
|
9
|
-
task :gemspec => "version:read" do
|
|
10
|
-
spec = Gem::Specification.new do |gem|
|
|
11
|
-
gem.name = "rspactor"
|
|
12
|
-
gem.summary = "RSpactor is a command line tool to automatically run your changed specs (much like autotest)."
|
|
13
|
-
gem.email = "mislav.marohnic@gmail.com"
|
|
14
|
-
gem.homepage = "http://github.com/mislav/rspactor"
|
|
15
|
-
gem.authors = ["Mislav Marohnić", "Andreas Wolff", "Pelle Braendgaard"]
|
|
16
|
-
gem.has_rdoc = false
|
|
17
|
-
|
|
18
|
-
gem.version = GEM_VERSION
|
|
19
|
-
gem.files = FileList['Rakefile', '{bin,lib,images,spec}/**/*', 'README*', 'LICENSE*']
|
|
20
|
-
gem.executables = Dir['bin/*'].map { |f| File.basename(f) }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
spec_string = spec.to_ruby
|
|
24
|
-
|
|
25
|
-
begin
|
|
26
|
-
Thread.new { eval("$SAFE = 3\n#{spec_string}", binding) }.join
|
|
27
|
-
rescue
|
|
28
|
-
abort "unsafe gemspec: #{$!}"
|
|
29
|
-
else
|
|
30
|
-
File.open("#{spec.name}.gemspec", 'w') { |file| file.write spec_string }
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
task :bump => ["version:bump", :gemspec]
|
|
35
|
-
|
|
36
|
-
namespace :version do
|
|
37
|
-
task :read do
|
|
38
|
-
unless defined? GEM_VERSION
|
|
39
|
-
GEM_VERSION = File.read("VERSION")
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
task :bump => :read do
|
|
44
|
-
if ENV['VERSION']
|
|
45
|
-
GEM_VERSION.replace ENV['VERSION']
|
|
46
|
-
else
|
|
47
|
-
GEM_VERSION.sub!(/\d+$/) { |num| num.to_i + 1 }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
File.open("VERSION", 'w') { |v| v.write GEM_VERSION }
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
task :release => :bump do
|
|
55
|
-
system %(git commit VERSION *.gemspec -m "release v#{GEM_VERSION}")
|
|
56
|
-
system %(git tag -am "release v#{GEM_VERSION}" v#{GEM_VERSION})
|
|
5
|
+
system "/usr/bin/ruby -Ilib bin/rspactor"
|
|
57
6
|
end
|
data/bin/rspactor-system
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'rspactor'
|
|
3
|
+
Growl = RSpactor::Growl
|
|
4
|
+
|
|
5
|
+
root = ENV['HOME']
|
|
6
|
+
$mappings = []
|
|
7
|
+
$libs = []
|
|
8
|
+
|
|
9
|
+
def map(regex, &block)
|
|
10
|
+
$mappings << [regex, block]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def libs
|
|
14
|
+
$libs
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def title
|
|
18
|
+
$title
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
listener = RSpactor::Listener.new do |changed_files|
|
|
22
|
+
changed_files.reject! do |file|
|
|
23
|
+
file.index(root + "/Library/") == 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if changed_files.size == 1
|
|
27
|
+
changed_file = changed_files.first
|
|
28
|
+
dir = changed_file
|
|
29
|
+
hook = nil
|
|
30
|
+
|
|
31
|
+
until hook or (dir = File.dirname(dir)) == root
|
|
32
|
+
candidate = dir + "/.rspactor"
|
|
33
|
+
hook = candidate if File.exists?(candidate)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if hook
|
|
37
|
+
targets = []
|
|
38
|
+
$title = "Test results"
|
|
39
|
+
$mappings.clear
|
|
40
|
+
$libs.replace ['lib']
|
|
41
|
+
load hook
|
|
42
|
+
|
|
43
|
+
unless $mappings.empty?
|
|
44
|
+
relative_path = changed_file.sub(dir + '/', '')
|
|
45
|
+
|
|
46
|
+
for regex, block in $mappings
|
|
47
|
+
if match = relative_path.match(regex)
|
|
48
|
+
targets.concat Array(block.call(relative_path, match))
|
|
49
|
+
break
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
existing_targets = targets.select { |file| File.exist?(File.join(dir, file)) }
|
|
54
|
+
else
|
|
55
|
+
inspector = RSpactor::Inspector.new(dir)
|
|
56
|
+
existing_targets = inspector.determine_spec_files(changed_file).map do |file|
|
|
57
|
+
file.sub(dir + '/', '')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if not existing_targets.empty?
|
|
62
|
+
case existing_targets.first
|
|
63
|
+
when %r{^test/}
|
|
64
|
+
$libs << 'test'
|
|
65
|
+
when %r{^spec/}
|
|
66
|
+
$libs << 'spec'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Dir.chdir(dir) do
|
|
70
|
+
unless 'spec' == $libs.last
|
|
71
|
+
command = "ruby -I#{$libs.join(':')} -e 'ARGV.each{|f| load f}' "
|
|
72
|
+
else
|
|
73
|
+
command = "RUBYOPT='-I#{$libs.join(':')}' spec --color "
|
|
74
|
+
end
|
|
75
|
+
command << existing_targets.join(' ')
|
|
76
|
+
# puts command
|
|
77
|
+
puts changed_file
|
|
78
|
+
system command
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if $?.success?
|
|
82
|
+
Growl::notify $title, "You rock!", Growl::image_path('success')
|
|
83
|
+
else
|
|
84
|
+
Growl::notify $title, "YOU LOSE", Growl::image_path('failed')
|
|
85
|
+
end
|
|
86
|
+
elsif $mappings.empty?
|
|
87
|
+
$stderr.puts "-- don't know how to run #{changed_file}"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
listener.run(root)
|
data/lib/rspactor.rb
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module RSpactor
|
|
2
|
+
module Growl
|
|
3
|
+
extend self
|
|
4
|
+
|
|
5
|
+
IMAGE_PATH = File.expand_path File.dirname(__FILE__) + "/../../images/%s.png"
|
|
6
|
+
|
|
7
|
+
def notify(title, msg, img, pri = 0)
|
|
8
|
+
system("growlnotify -w -n rspactor --image #{img} -p #{pri} -m #{msg.inspect} #{title} &")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# failed | pending | success
|
|
12
|
+
def image_path(icon)
|
|
13
|
+
IMAGE_PATH % icon
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/rspactor/inspector.rb
CHANGED
|
@@ -2,7 +2,7 @@ module RSpactor
|
|
|
2
2
|
# Maps the changed filenames to list of specs to run in the next go.
|
|
3
3
|
# Assumes Rails-like directory structure
|
|
4
4
|
class Inspector
|
|
5
|
-
|
|
5
|
+
DEFAULT_EXTENSIONS = %w(rb erb builder haml rhtml rxml yml conf opts)
|
|
6
6
|
|
|
7
7
|
def initialize(dir)
|
|
8
8
|
@root = dir
|
data/lib/rspactor/listener.rb
CHANGED
|
@@ -4,41 +4,63 @@ OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Framewo
|
|
|
4
4
|
module RSpactor
|
|
5
5
|
# based on http://rails.aizatto.com/2007/11/28/taming-the-autotest-beast-with-fsevents/
|
|
6
6
|
class Listener
|
|
7
|
-
attr_reader :last_check, :callback, :
|
|
7
|
+
attr_reader :last_check, :callback, :options, :dirs, :force_changed
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
# Options examples:
|
|
10
|
+
# {:extensions => ['rb', 'haml'], :relative_paths => true, :latency => .5}
|
|
11
|
+
def initialize(options = {})
|
|
12
|
+
@options = options
|
|
11
13
|
timestamp_checked
|
|
12
|
-
|
|
14
|
+
@force_changed = []
|
|
15
|
+
|
|
13
16
|
@callback = lambda do |stream, ctx, num_events, paths, marks, event_ids|
|
|
14
17
|
changed_files = extract_changed_files_from_paths(split_paths(paths, num_events))
|
|
15
18
|
timestamp_checked
|
|
19
|
+
changed_files = relativize_path_names(changed_files) if options[:relative_paths]
|
|
16
20
|
yield changed_files unless changed_files.empty?
|
|
17
21
|
end
|
|
18
22
|
end
|
|
23
|
+
|
|
24
|
+
def relativize_path_names(files)
|
|
25
|
+
for file in files
|
|
26
|
+
if dir = @dirs.find { |p| file.index(p) == 0 }
|
|
27
|
+
file.sub!(dir + '/', '')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
19
31
|
|
|
20
|
-
def
|
|
21
|
-
dirs = Array(directories)
|
|
22
|
-
|
|
23
|
-
|
|
32
|
+
def start(directories)
|
|
33
|
+
@dirs = Array(directories)
|
|
34
|
+
since = OSX::KFSEventStreamEventIdSinceNow
|
|
35
|
+
|
|
36
|
+
@stream = OSX::FSEventStreamCreate(OSX::KCFAllocatorDefault, callback, nil, @dirs, since, options[:latency] || 0.0, 0)
|
|
37
|
+
unless @stream
|
|
24
38
|
$stderr.puts "Failed to create stream"
|
|
25
39
|
exit(1)
|
|
26
40
|
end
|
|
27
41
|
|
|
28
|
-
OSX::FSEventStreamScheduleWithRunLoop(stream, OSX
|
|
29
|
-
unless OSX::FSEventStreamStart(stream)
|
|
42
|
+
OSX::FSEventStreamScheduleWithRunLoop(@stream, OSX.CFRunLoopGetCurrent, OSX::KCFRunLoopDefaultMode)
|
|
43
|
+
unless OSX::FSEventStreamStart(@stream)
|
|
30
44
|
$stderr.puts "Failed to start stream"
|
|
31
45
|
exit(1)
|
|
32
46
|
end
|
|
47
|
+
|
|
48
|
+
return self
|
|
49
|
+
end
|
|
33
50
|
|
|
51
|
+
def enter_run_loop
|
|
34
52
|
begin
|
|
35
53
|
OSX::CFRunLoopRun()
|
|
36
54
|
rescue Interrupt
|
|
37
|
-
|
|
38
|
-
OSX::FSEventStreamInvalidate(stream)
|
|
39
|
-
OSX::FSEventStreamRelease(stream)
|
|
55
|
+
stop
|
|
40
56
|
end
|
|
41
57
|
end
|
|
58
|
+
|
|
59
|
+
def stop
|
|
60
|
+
OSX::FSEventStreamStop(@stream)
|
|
61
|
+
OSX::FSEventStreamInvalidate(@stream)
|
|
62
|
+
OSX::FSEventStreamRelease(@stream)
|
|
63
|
+
end
|
|
42
64
|
|
|
43
65
|
def timestamp_checked
|
|
44
66
|
@last_check = Time.now
|
|
@@ -64,7 +86,11 @@ module RSpactor
|
|
|
64
86
|
end
|
|
65
87
|
|
|
66
88
|
def file_changed?(file)
|
|
67
|
-
|
|
89
|
+
return true if force_changed.delete(file)
|
|
90
|
+
file_mtime = File.stat(file).mtime
|
|
91
|
+
file_mtime > last_check
|
|
92
|
+
rescue Errno::ENOENT
|
|
93
|
+
false
|
|
68
94
|
end
|
|
69
95
|
|
|
70
96
|
def ignore_path?(path)
|
|
@@ -80,7 +106,7 @@ module RSpactor
|
|
|
80
106
|
end
|
|
81
107
|
|
|
82
108
|
def valid_extension?(file)
|
|
83
|
-
|
|
109
|
+
options[:extensions].nil? or options[:extensions].include?(file_extension(file))
|
|
84
110
|
end
|
|
85
111
|
end
|
|
86
112
|
end
|
data/lib/rspactor/runner.rb
CHANGED
|
@@ -31,9 +31,9 @@ module RSpactor
|
|
|
31
31
|
def start_listener
|
|
32
32
|
@inspector = Inspector.new(dir)
|
|
33
33
|
|
|
34
|
-
Listener.new(Inspector::
|
|
34
|
+
Listener.new(:extensions => Inspector::DEFAULT_EXTENSIONS) do |files|
|
|
35
35
|
spec_changed_files(files) unless git_head_changed?
|
|
36
|
-
end.
|
|
36
|
+
end.start(dir).enter_run_loop
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def load_dotfile
|
data/lib/rspec_growler.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
require 'spec/runner/formatter/base_formatter'
|
|
2
|
+
require File.dirname(__FILE__) + '/rspactor/growl'
|
|
2
3
|
|
|
3
4
|
class RSpecGrowler < Spec::Runner::Formatter::BaseFormatter
|
|
5
|
+
include RSpactor::Growl
|
|
6
|
+
|
|
4
7
|
def dump_summary(duration, total, failures, pending)
|
|
5
8
|
icon = if failures > 0
|
|
6
9
|
'failed'
|
|
@@ -17,11 +20,7 @@ class RSpecGrowler < Spec::Runner::Formatter::BaseFormatter
|
|
|
17
20
|
message << " (#{pending} pending)"
|
|
18
21
|
end
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def growl(title, msg, img, pri = 0)
|
|
24
|
-
system("growlnotify -w -n rspactor --image #{img} -p #{pri} -m #{msg.inspect} #{title} &")
|
|
23
|
+
notify "Test Results", message, image_path(icon)
|
|
25
24
|
end
|
|
26
25
|
end
|
|
27
26
|
|
data/spec/listener_spec.rb
CHANGED
data/spec/runner_spec.rb
CHANGED
|
@@ -96,8 +96,9 @@ describe RSpactor::Runner do
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
it "should run Listener" do
|
|
99
|
-
@listener.should_receive(:
|
|
100
|
-
|
|
99
|
+
@listener.should_receive(:start).with('/my/path').and_return(@listener)
|
|
100
|
+
@listener.should_receive(:enter_run_loop).with()
|
|
101
|
+
RSpactor::Listener.should_receive(:new).with(:extensions => instance_of(Array)).and_return(@listener)
|
|
101
102
|
setup
|
|
102
103
|
end
|
|
103
104
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mislav-rspactor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
4
|
+
hash: 15
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 4
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.4.0
|
|
5
11
|
platform: ruby
|
|
6
12
|
authors:
|
|
7
13
|
- "Mislav Marohni\xC4\x87"
|
|
@@ -11,14 +17,14 @@ autorequire:
|
|
|
11
17
|
bindir: bin
|
|
12
18
|
cert_chain: []
|
|
13
19
|
|
|
14
|
-
date:
|
|
15
|
-
default_executable:
|
|
20
|
+
date: 2010-07-21 00:00:00 +02:00
|
|
21
|
+
default_executable:
|
|
16
22
|
dependencies: []
|
|
17
23
|
|
|
18
|
-
description:
|
|
24
|
+
description: RSpactor is a command line tool to automatically run your changed specs (much like autotest).
|
|
19
25
|
email: mislav.marohnic@gmail.com
|
|
20
|
-
executables:
|
|
21
|
-
|
|
26
|
+
executables: []
|
|
27
|
+
|
|
22
28
|
extensions: []
|
|
23
29
|
|
|
24
30
|
extra_rdoc_files: []
|
|
@@ -26,7 +32,8 @@ extra_rdoc_files: []
|
|
|
26
32
|
files:
|
|
27
33
|
- Rakefile
|
|
28
34
|
- bin/rspactor
|
|
29
|
-
-
|
|
35
|
+
- bin/rspactor-system
|
|
36
|
+
- lib/rspactor/growl.rb
|
|
30
37
|
- lib/rspactor/inspector.rb
|
|
31
38
|
- lib/rspactor/interactor.rb
|
|
32
39
|
- lib/rspactor/listener.rb
|
|
@@ -42,29 +49,37 @@ files:
|
|
|
42
49
|
- LICENSE
|
|
43
50
|
has_rdoc: false
|
|
44
51
|
homepage: http://github.com/mislav/rspactor
|
|
52
|
+
licenses: []
|
|
53
|
+
|
|
45
54
|
post_install_message:
|
|
46
55
|
rdoc_options: []
|
|
47
56
|
|
|
48
57
|
require_paths:
|
|
49
58
|
- lib
|
|
50
59
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
51
61
|
requirements:
|
|
52
62
|
- - ">="
|
|
53
63
|
- !ruby/object:Gem::Version
|
|
64
|
+
hash: 3
|
|
65
|
+
segments:
|
|
66
|
+
- 0
|
|
54
67
|
version: "0"
|
|
55
|
-
version:
|
|
56
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
|
+
none: false
|
|
57
70
|
requirements:
|
|
58
71
|
- - ">="
|
|
59
72
|
- !ruby/object:Gem::Version
|
|
73
|
+
hash: 3
|
|
74
|
+
segments:
|
|
75
|
+
- 0
|
|
60
76
|
version: "0"
|
|
61
|
-
version:
|
|
62
77
|
requirements: []
|
|
63
78
|
|
|
64
79
|
rubyforge_project:
|
|
65
|
-
rubygems_version: 1.
|
|
80
|
+
rubygems_version: 1.3.7
|
|
66
81
|
signing_key:
|
|
67
|
-
specification_version:
|
|
68
|
-
summary:
|
|
82
|
+
specification_version: 3
|
|
83
|
+
summary: File watcher that automatically runs changed specs
|
|
69
84
|
test_files: []
|
|
70
85
|
|