mislav-rspactor 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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)
@@ -3,4 +3,5 @@ module RSpactor
3
3
  autoload :Listener, 'rspactor/listener'
4
4
  autoload :Inspector, 'rspactor/inspector'
5
5
  autoload :Runner, 'rspactor/runner'
6
+ autoload :Growl, 'rspactor/growl'
6
7
  end
@@ -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
@@ -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
- EXTENSIONS = %w(rb erb builder haml rhtml rxml yml conf opts)
5
+ DEFAULT_EXTENSIONS = %w(rb erb builder haml rhtml rxml yml conf opts)
6
6
 
7
7
  def initialize(dir)
8
8
  @root = dir
@@ -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, :valid_extensions
7
+ attr_reader :last_check, :callback, :options, :dirs, :force_changed
8
8
 
9
- def initialize(valid_extensions = nil)
10
- @valid_extensions = valid_extensions
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 run(directories)
21
- dirs = Array(directories)
22
- stream = OSX::FSEventStreamCreate(OSX::KCFAllocatorDefault, callback, nil, dirs, OSX::KFSEventStreamEventIdSinceNow, 0.5, 0)
23
- unless stream
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::CFRunLoopGetCurrent(), OSX::KCFRunLoopDefaultMode)
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
- OSX::FSEventStreamStop(stream)
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
- File.stat(file).mtime > last_check
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
- valid_extensions.nil? or valid_extensions.include?(file_extension(file))
109
+ options[:extensions].nil? or options[:extensions].include?(file_extension(file))
84
110
  end
85
111
  end
86
112
  end
@@ -31,9 +31,9 @@ module RSpactor
31
31
  def start_listener
32
32
  @inspector = Inspector.new(dir)
33
33
 
34
- Listener.new(Inspector::EXTENSIONS) do |files|
34
+ Listener.new(:extensions => Inspector::DEFAULT_EXTENSIONS) do |files|
35
35
  spec_changed_files(files) unless git_head_changed?
36
- end.run(dir)
36
+ end.start(dir).enter_run_loop
37
37
  end
38
38
 
39
39
  def load_dotfile
@@ -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
- growl "Test Results", message, image_path, 0
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
 
@@ -2,7 +2,7 @@ require 'rspactor/listener'
2
2
 
3
3
  describe RSpactor::Listener do
4
4
  before(:all) do
5
- @listener = described_class.new(%w(rb erb haml))
5
+ @listener = described_class.new(:extensions => %w(rb erb haml))
6
6
  end
7
7
 
8
8
  it "should be timestamped" do
@@ -96,8 +96,9 @@ describe RSpactor::Runner do
96
96
  end
97
97
 
98
98
  it "should run Listener" do
99
- @listener.should_receive(:run).with('/my/path')
100
- RSpactor::Listener.should_receive(:new).with(instance_of(Array)).and_return(@listener)
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
- version: 0.3.3
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: 2009-03-27 00:00:00 -07:00
15
- default_executable: rspactor
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
- - rspactor
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
- - lib/rspactor
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.2.0
80
+ rubygems_version: 1.3.7
66
81
  signing_key:
67
- specification_version: 2
68
- summary: RSpactor is a command line tool to automatically run your changed specs (much like autotest).
82
+ specification_version: 3
83
+ summary: File watcher that automatically runs changed specs
69
84
  test_files: []
70
85