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 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