mislav-rspactor 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Mislav Marohnić
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 3
4
+ :patch: 0
data/bin/rspactor ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rspactor'
3
+
4
+ Runner.load
data/lib/inspector.rb ADDED
@@ -0,0 +1,84 @@
1
+ # Maps the changed filenames to list of specs to run in the next go.
2
+ # Assumes Rails-like directory structure
3
+ class Inspector
4
+
5
+ EXTENSIONS = %w(rb erb builder haml rhtml rxml yml conf opts)
6
+
7
+ def initialize(dir)
8
+ @root = dir
9
+ end
10
+
11
+ def determine_spec_files(file)
12
+ candidates = translate(file)
13
+ spec_files = candidates.select { |candidate| File.exists? candidate }
14
+
15
+ if spec_files.empty?
16
+ $stderr.puts "doesn't exist: #{candidates.inspect}"
17
+ end
18
+ spec_files
19
+ end
20
+
21
+ # mappings for Rails are inspired by autotest mappings in rspec-rails
22
+ def translate(file)
23
+ file = file.sub(%r:^#{Regexp.escape(@root)}/:, '')
24
+ candidates = []
25
+
26
+ if spec_file?(file)
27
+ candidates << file
28
+ else
29
+ spec_file = append_spec_file_extension(file)
30
+
31
+ case file
32
+ when %r:^app/:
33
+ if file =~ %r:^app/controllers/application(_controller)?.rb$:
34
+ candidates << 'controllers'
35
+ elsif file == 'app/helpers/application_helper.rb'
36
+ candidates << 'helpers' << 'views'
37
+ else
38
+ candidates << spec_file.sub('app/', '')
39
+
40
+ if file =~ %r:^app/(views/.+\.[a-z]+)\.[a-z]+$:
41
+ candidates << append_spec_file_extension($1)
42
+ elsif file =~ %r:app/helpers/(\w+)_helper.rb:
43
+ candidates << "views/#{$1}"
44
+ end
45
+ end
46
+ when %r:^lib/:
47
+ candidates << spec_file
48
+ # lib/foo/bar_spec.rb -> lib/bar_spec.rb
49
+ candidates << candidates.last.sub($&, '')
50
+ # lib/bar_spec.rb -> bar_spec.rb
51
+ candidates << candidates.last.sub(%r:\w+/:, '') if candidates.last.index('/')
52
+ when 'config/routes.rb'
53
+ candidates << 'controllers' << 'helpers' << 'views'
54
+ when 'config/database.yml', 'db/schema.rb'
55
+ candidates << 'models'
56
+ when %r:^(spec/(spec_helper|shared/.*)|config/(boot|environment(s/test)?))\.rb$:, 'spec/spec.opts'
57
+ candidates << 'spec'
58
+ else
59
+ candidates << spec_file
60
+ end
61
+ end
62
+
63
+ candidates.map do |candidate|
64
+ if candidate.index('spec') == 0
65
+ candidate
66
+ else
67
+ 'spec/' + candidate
68
+ end
69
+ end
70
+ end
71
+
72
+ def append_spec_file_extension(file)
73
+ if File.extname(file) == ".rb"
74
+ file.sub(/.rb$/, "_spec.rb")
75
+ else
76
+ file + "_spec.rb"
77
+ end
78
+ end
79
+
80
+ def spec_file?(file)
81
+ file =~ /^spec\/.+_spec.rb$/
82
+ end
83
+
84
+ end
data/lib/interactor.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'timeout'
2
+
3
+ class Interactor
4
+
5
+ def initialize
6
+ ticker
7
+ end
8
+
9
+ def wait_for_enter_key(msg, seconds_to_wait)
10
+ begin
11
+ Timeout::timeout(seconds_to_wait) do
12
+ ticker(:start => true, :msg => msg)
13
+ $stdin.gets
14
+ return true
15
+ end
16
+ rescue Timeout::Error
17
+ false
18
+ ensure
19
+ ticker(:stop => true)
20
+ end
21
+ end
22
+
23
+ def start_termination_handler
24
+ @main_thread = Thread.current
25
+ Thread.new do
26
+ loop do
27
+ sleep 0.5
28
+ if $stdin.gets
29
+ if wait_for_enter_key("** Running all specs.. Hit <enter> again to exit RSpactor", 3)
30
+ @main_thread.exit
31
+ exit
32
+ end
33
+ Runner.run_all_specs
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+
40
+ private
41
+
42
+ def ticker(opts = {})
43
+ if opts[:stop]
44
+ $stdout.puts "\n"
45
+ @pointer_running = false
46
+ elsif opts[:start]
47
+ @pointer_running = true
48
+ write(opts[:msg]) if opts[:msg]
49
+ else
50
+ Thread.new do
51
+ loop do
52
+ write('.') if @pointer_running == true
53
+ sleep 1.0
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ def write(msg)
60
+ $stdout.print(msg)
61
+ $stdout.flush
62
+ end
63
+ end
data/lib/listener.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'osx/foundation'
2
+ OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
3
+
4
+ # Some code borrowed from http://rails.aizatto.com/2007/11/28/taming-the-autotest-beast-with-fsevents/
5
+ class Listener
6
+
7
+ attr_reader :last_check, :callback, :valid_extensions
8
+
9
+ def initialize(valid_extensions = nil)
10
+ @valid_extensions = valid_extensions
11
+ timestamp_checked
12
+
13
+ @callback = lambda do |stream, ctx, num_events, paths, marks, event_ids|
14
+ changed_files = extract_changed_files_from_paths(split_paths(paths, num_events))
15
+ timestamp_checked
16
+ yield changed_files unless changed_files.empty?
17
+ end
18
+ end
19
+
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
24
+ $stderr.puts "Failed to create stream"
25
+ exit(1)
26
+ end
27
+
28
+ OSX::FSEventStreamScheduleWithRunLoop(stream, OSX::CFRunLoopGetCurrent(), OSX::KCFRunLoopDefaultMode)
29
+ unless OSX::FSEventStreamStart(stream)
30
+ $stderr.puts "Failed to start stream"
31
+ exit(1)
32
+ end
33
+
34
+ begin
35
+ OSX::CFRunLoopRun()
36
+ rescue Interrupt
37
+ OSX::FSEventStreamStop(stream)
38
+ OSX::FSEventStreamInvalidate(stream)
39
+ OSX::FSEventStreamRelease(stream)
40
+ end
41
+ end
42
+
43
+ def timestamp_checked
44
+ @last_check = Time.now
45
+ end
46
+
47
+ def split_paths(paths, num_events)
48
+ paths.regard_as('*')
49
+ rpaths = []
50
+ num_events.times { |i| rpaths << paths[i] }
51
+ rpaths
52
+ end
53
+
54
+ def extract_changed_files_from_paths(paths)
55
+ changed_files = []
56
+ paths.each do |path|
57
+ next if ignore_path?(path)
58
+ Dir.glob(path + "*").each do |file|
59
+ next if ignore_file?(file)
60
+ changed_files << file if file_changed?(file)
61
+ end
62
+ end
63
+ changed_files
64
+ end
65
+
66
+ def file_changed?(file)
67
+ File.stat(file).mtime > last_check
68
+ end
69
+
70
+ def ignore_path?(path)
71
+ path =~ /(?:^|\/)\.(git|svn)/
72
+ end
73
+
74
+ def ignore_file?(file)
75
+ File.basename(file).index('.') == 0 or not valid_extension?(file)
76
+ end
77
+
78
+ def file_extension(file)
79
+ file =~ /\.(\w+)$/ and $1
80
+ end
81
+
82
+ def valid_extension?(file)
83
+ valid_extensions.nil? or valid_extensions.include?(file_extension(file))
84
+ end
85
+
86
+ end
data/lib/resulting.rb ADDED
@@ -0,0 +1,47 @@
1
+ class RSpactorFormatter
2
+ attr_accessor :example_group, :options, :where
3
+ def initialize(options, where)
4
+ @options = options
5
+ @where = where
6
+ end
7
+
8
+ def dump_summary(duration, example_count, failure_count, pending_count)
9
+ img = (failure_count == 0) ? "rails_ok.png" : "rails_fail.png"
10
+ growl "Test Results", "#{example_count} examples, #{failure_count} failures", File.dirname(__FILE__) + "/../asset/#{img}", 0
11
+ end
12
+
13
+ def start(*ignore_these)
14
+ end
15
+
16
+ def add_example_group(*ignore_these)
17
+ end
18
+
19
+ def example_started(*ignore_these)
20
+ end
21
+
22
+ def example_passed(*ignore_these)
23
+ end
24
+
25
+ def example_failed(*ignore_these)
26
+ end
27
+
28
+ def example_pending( *ignore_these)
29
+ end
30
+
31
+ def start_dump
32
+ end
33
+
34
+ def dump_failure(*ignore_these)
35
+ end
36
+
37
+ def dump_pending
38
+ end
39
+
40
+ def close
41
+ end
42
+
43
+ def growl(title, msg, img, pri = 0)
44
+ system("growlnotify -w -n rspactor --image #{img} -p #{pri} -m #{msg.inspect} #{title} &")
45
+ end
46
+ end
47
+
data/lib/rspactor.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'interactor'
2
+ require 'listener'
3
+ require 'inspector'
4
+ require 'runner'
data/lib/runner.rb ADDED
@@ -0,0 +1,82 @@
1
+ require 'inspector'
2
+ require 'interactor'
3
+ require 'listener'
4
+
5
+ class Runner
6
+
7
+ def self.load
8
+ dotfile = File.join(ENV['HOME'], '.rspactor')
9
+ Kernel.load dotfile if File.exists?(dotfile)
10
+
11
+ dir = Dir.pwd
12
+ @inspector = Inspector.new(dir)
13
+ @interactor = Interactor.new
14
+
15
+ puts "** RSpactor is now watching at '#{dir}'"
16
+
17
+ aborted = initial_spec_run_abort
18
+ @interactor.start_termination_handler
19
+ run_all_specs unless aborted
20
+
21
+ Listener.new(Inspector::EXTENSIONS) do |files|
22
+ files_to_spec = []
23
+ files.each do |file|
24
+ spec_files = @inspector.determine_spec_files(file)
25
+ unless spec_files.empty?
26
+ puts spec_files.join("\n")
27
+ files_to_spec.concat spec_files
28
+ end
29
+ end
30
+ run_spec_command(files_to_spec)
31
+ end.run(dir)
32
+ end
33
+
34
+ def self.initial_spec_run_abort
35
+ @interactor.wait_for_enter_key("** Hit <enter> to skip initial spec run", 3)
36
+ end
37
+
38
+ def self.run_all_specs
39
+ run_spec_command('spec')
40
+ end
41
+
42
+ def self.run_spec_command(paths)
43
+ paths = Array(paths)
44
+ return if paths.empty?
45
+ run_command [ruby_opts, spec_runner, paths, spec_opts].flatten.join(' ')
46
+ end
47
+
48
+ def self.run_command(cmd)
49
+ system(cmd)
50
+ end
51
+
52
+ def self.spec_opts
53
+ if File.exist?('spec/spec.opts')
54
+ opts = File.read('spec/spec.opts').gsub("\n", ' ')
55
+ else
56
+ opts = "--color"
57
+ end
58
+
59
+ opts << ' ' << formatter_opts
60
+ # only add the "progress" formatter unless no other (besides growl) is specified
61
+ opts << ' -f progress' unless opts.scan(/\s(?:-f|--format)\b/).length > 1
62
+
63
+ opts
64
+ end
65
+
66
+ def self.formatter_opts
67
+ "-r #{File.dirname(__FILE__)}/resulting.rb -f RSpactorFormatter:STDOUT"
68
+ end
69
+
70
+ def self.spec_runner
71
+ if File.exist?("script/spec")
72
+ "script/spec"
73
+ else
74
+ "spec"
75
+ end
76
+ end
77
+
78
+ def self.ruby_opts
79
+ other = ENV['RUBYOPT'] ? " #{ENV['RUBYOPT']}" : ''
80
+ %(RUBYOPT='-Ilib:spec#{other}')
81
+ end
82
+ end
@@ -0,0 +1,81 @@
1
+ require 'inspector'
2
+
3
+ describe Inspector do
4
+ before(:all) do
5
+ @inspector = Inspector.new('/project')
6
+ end
7
+
8
+ def translate(file)
9
+ @inspector.translate(file)
10
+ end
11
+
12
+ describe "#translate" do
13
+ it "should consider all controllers when application_controller changes" do
14
+ translate('/project/app/controllers/application_controller.rb').should == ['spec/controllers']
15
+ translate('/project/app/controllers/application.rb').should == ['spec/controllers']
16
+ end
17
+
18
+ it "should translate files under 'app/' directory" do
19
+ translate('/project/app/controllers/foo_controller.rb').should ==
20
+ ['spec/controllers/foo_controller_spec.rb']
21
+ end
22
+
23
+ it "should translate templates" do
24
+ translate('/project/app/views/foo/bar.erb').should == ['spec/views/foo/bar.erb_spec.rb']
25
+ translate('/project/app/views/foo/bar.html.haml').should ==
26
+ ['spec/views/foo/bar.html.haml_spec.rb', 'spec/views/foo/bar.html_spec.rb']
27
+ end
28
+
29
+ it "should consider all views when application_helper changes" do
30
+ translate('/project/app/helpers/application_helper.rb').should == ['spec/helpers', 'spec/views']
31
+ end
32
+
33
+ it "should consider related templates when a helper changes" do
34
+ translate('/project/app/helpers/foo_helper.rb').should ==
35
+ ['spec/helpers/foo_helper_spec.rb', 'spec/views/foo']
36
+ end
37
+
38
+ it "should translate files under deep 'lib/' directory" do
39
+ translate('/project/lib/awesum/rox.rb').should ==
40
+ ['spec/lib/awesum/rox_spec.rb', 'spec/awesum/rox_spec.rb', 'spec/rox_spec.rb']
41
+ end
42
+
43
+ it "should translate files under shallow 'lib/' directory" do
44
+ translate('lib/runner.rb').should == ['spec/lib/runner_spec.rb', 'spec/runner_spec.rb']
45
+ end
46
+
47
+ it "should handle relative paths" do
48
+ translate('foo.rb').should == ['spec/foo_spec.rb']
49
+ end
50
+
51
+ it "should handle files without extension" do
52
+ translate('foo').should == ['spec/foo_spec.rb']
53
+ end
54
+
55
+ it "should consider all controllers, helpers and views when routes.rb changes" do
56
+ translate('config/routes.rb').should == ['spec/controllers', 'spec/helpers', 'spec/views']
57
+ end
58
+
59
+ it "should consider all models when config/database.yml changes" do
60
+ translate('config/database.yml').should == ['spec/models']
61
+ end
62
+
63
+ it "should consider all models when db/schema.rb changes" do
64
+ translate('db/schema.rb').should == ['spec/models']
65
+ end
66
+
67
+ it "should consider all specs when spec_helper changes" do
68
+ translate('spec/spec_helper.rb').should == ['spec']
69
+ end
70
+
71
+ it "should consider all specs when code under spec/shared/ changes" do
72
+ translate('spec/shared/foo.rb').should == ['spec']
73
+ end
74
+
75
+ it "should consider all specs when app configuration changes" do
76
+ translate('config/environment.rb').should == ['spec']
77
+ translate('config/environments/test.rb').should == ['spec']
78
+ translate('config/boot.rb').should == ['spec']
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,35 @@
1
+ require 'listener'
2
+
3
+ describe Listener do
4
+ before(:all) do
5
+ @listener = Listener.new(%w(rb erb haml))
6
+ end
7
+
8
+ it "should be timestamped" do
9
+ @listener.last_check.should be_instance_of(Time)
10
+ end
11
+
12
+ it "should not ignore regular directories" do
13
+ @listener.ignore_path?('/project/foo/bar').should_not be
14
+ end
15
+
16
+ it "should ignore .git directories" do
17
+ @listener.ignore_path?('/project/.git/index').should be
18
+ end
19
+
20
+ it "should ignore dotfiles" do
21
+ @listener.ignore_file?('/project/.foo').should be
22
+ end
23
+
24
+ it "should not ignore files without extension" do
25
+ @listener.ignore_file?('/project/foo.rb').should_not be
26
+ end
27
+
28
+ it "should ignore files without extension" do
29
+ @listener.ignore_file?('/project/foo').should be
30
+ end
31
+
32
+ it "should ignore files with extensions that don't match those specified" do
33
+ @listener.ignore_file?('/project/foo.bar').should be
34
+ end
35
+ end
@@ -0,0 +1,138 @@
1
+ require 'runner'
2
+
3
+ class ::Runner
4
+ def self.run_command(cmd)
5
+ # never shell out in tests
6
+ cmd
7
+ end
8
+ end
9
+
10
+ describe ::Runner do
11
+
12
+ before(:all) do
13
+ @runner = ::Runner
14
+ end
15
+
16
+ def with_env(name, value)
17
+ old_value = ENV[name]
18
+ ENV[name] = value
19
+ begin
20
+ yield
21
+ ensure
22
+ ENV[name] = old_value
23
+ end
24
+ end
25
+
26
+ describe "setup" do
27
+ before(:each) do
28
+ Dir.stub!(:pwd).and_return('/my/path')
29
+ File.stub!(:exists?).and_return(false)
30
+ @runner.stub!(:puts)
31
+ Inspector.stub!(:new)
32
+ Interactor.stub!(:new).and_return(mock('Interactor').as_null_object)
33
+ Listener.stub!(:new).and_return(mock('Listener').as_null_object)
34
+ end
35
+
36
+ def setup
37
+ @runner.load
38
+ end
39
+
40
+ it "should initialize Inspector" do
41
+ Inspector.should_receive(:new).with('/my/path')
42
+ setup
43
+ end
44
+
45
+ it "should start Interactor" do
46
+ interactor = mock('Interactor')
47
+ interactor.should_receive(:wait_for_enter_key).with(instance_of(String), 3)
48
+ interactor.should_receive(:start_termination_handler)
49
+ Interactor.should_receive(:new).and_return(interactor)
50
+ setup
51
+ end
52
+
53
+ it "should run all specs if Interactor isn't interrupted" do
54
+ interactor = mock('Interactor', :start_termination_handler => nil)
55
+ interactor.should_receive(:wait_for_enter_key).and_return(nil)
56
+ Interactor.should_receive(:new).and_return(interactor)
57
+ @runner.should_receive(:run_spec_command).with('spec')
58
+ setup
59
+ end
60
+
61
+ it "should skip running all specs if Interactor is interrupted" do
62
+ interactor = mock('Interactor', :start_termination_handler => nil)
63
+ interactor.should_receive(:wait_for_enter_key).and_return(true)
64
+ Interactor.should_receive(:new).and_return(interactor)
65
+ @runner.should_not_receive(:run_spec_command)
66
+ setup
67
+ end
68
+
69
+ it "should run Listener" do
70
+ listener = mock('Listener')
71
+ listener.should_receive(:run).with('/my/path')
72
+ Listener.should_receive(:new).with(instance_of(Array)).and_return(listener)
73
+ setup
74
+ end
75
+
76
+ it "should output 'watching' message on start" do
77
+ @runner.should_receive(:puts).with("** RSpactor is now watching at '/my/path'")
78
+ setup
79
+ end
80
+
81
+ it "should load dotfile if found" do
82
+ with_env('HOME', '/home/moo') do
83
+ File.should_receive(:exists?).with('/home/moo/.rspactor').and_return(true)
84
+ Kernel.should_receive(:load).with('/home/moo/.rspactor')
85
+ setup
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "#run_spec_command" do
91
+ def with_rubyopt(string, &block)
92
+ with_env('RUBYOPT', string, &block)
93
+ end
94
+
95
+ def run(paths)
96
+ @runner.run_spec_command(paths)
97
+ end
98
+
99
+ it "should exit if the paths argument is empty" do
100
+ @runner.should_not_receive(:run_command)
101
+ run([])
102
+ end
103
+
104
+ it "should specify runner spec runner with joined paths" do
105
+ run(%w(foo bar)).should include(' spec foo bar ')
106
+ end
107
+
108
+ it "should specify default options: --color" do
109
+ run('foo').should include(' --color')
110
+ end
111
+
112
+ it "should setup RUBYOPT environment variable" do
113
+ with_rubyopt(nil) do
114
+ run('foo').should include("RUBYOPT='-Ilib:spec' ")
115
+ end
116
+ end
117
+
118
+ it "should concat existing RUBYOPTs" do
119
+ with_rubyopt('-rubygems -w') do
120
+ run('foo').should include("RUBYOPT='-Ilib:spec -rubygems -w' ")
121
+ end
122
+ end
123
+
124
+ it "should include growl formatter" do
125
+ run('foo').should include(' -f RSpactorFormatter:STDOUT')
126
+ end
127
+
128
+ it "should include 'progress' formatter" do
129
+ run('foo').should include(' -f progress')
130
+ end
131
+
132
+ it "should not include 'progress' formatter if there already are 2 or more formatters" do
133
+ @runner.should_receive(:formatter_opts).and_return('-f foo --format bar')
134
+ run('foo').should_not include('-f progress')
135
+ end
136
+ end
137
+
138
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mislav-rspactor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - "Mislav Marohni\xC4\x87"
8
+ - Andreas Wolff
9
+ - Pelle Braendgaard
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-03-17 00:00:00 -07:00
15
+ default_executable: rspactor
16
+ dependencies: []
17
+
18
+ description:
19
+ email: mislav.marohnic@gmail.com
20
+ executables:
21
+ - rspactor
22
+ extensions: []
23
+
24
+ extra_rdoc_files:
25
+ - LICENSE
26
+ files:
27
+ - VERSION.yml
28
+ - bin/rspactor
29
+ - lib/inspector.rb
30
+ - lib/interactor.rb
31
+ - lib/listener.rb
32
+ - lib/resulting.rb
33
+ - lib/rspactor.rb
34
+ - lib/runner.rb
35
+ - spec/inspector_spec.rb
36
+ - spec/listener_spec.rb
37
+ - spec/runner_spec.rb
38
+ - LICENSE
39
+ has_rdoc: true
40
+ homepage: http://github.com/mislav/rspactor
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --inline-source
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: RSpactor is a command line tool to automatically run your changed specs (much like autotest).
66
+ test_files: []
67
+