rspactor 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Binary file
Binary file
data/bin/rspactor ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'interactor')
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'listener')
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'inspector')
6
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'runner')
7
+
8
+ Runner.load
data/lib/inspector.rb ADDED
@@ -0,0 +1,92 @@
1
+ # The inspector make some assumptions about how your project is structured and where your spec files are located.
2
+ # That said: The 'spec' directory, containing all your test files, must rest in the root directory of your project.
3
+ # Futhermore it tries to locate controller, model, helper and view specs for a rails app (or projects with an identical structure)
4
+ # in root/spec/controllers, root/spec/models, root/spec/helpers and root/spec/views.
5
+
6
+ class Inspector
7
+
8
+ attr_accessor :base_spec_root
9
+
10
+ def self.file_is_invalid?(file)
11
+ return true unless File.basename(file) =~ /.rb\z|.rhtml\z|.erb\z|.haml\z/
12
+ false
13
+ end
14
+
15
+ def find_spec_file(file)
16
+ begin
17
+ return file if file_is_a_spec?(file)
18
+ spec_root = find_base_spec_root_by_file(file)
19
+ if spec_root
20
+ guessed_spec_location = guess_spec_location(file, spec_root)
21
+ if File.exist?(guessed_spec_location)
22
+ @base_spec_root = spec_root
23
+ return guessed_spec_location
24
+ end
25
+ end
26
+ nil
27
+ rescue => e
28
+ puts "Error while parsing a file: '#{file}'"
29
+ puts e
30
+ end
31
+ end
32
+
33
+ def inner_spec_directory(path)
34
+ spec_base_root = find_base_spec_root_by_file(Dir.pwd + "/.")
35
+ inner_location = extract_inner_project_location(Dir.pwd, spec_base_root)
36
+ File.join(spec_base_root, inner_location)
37
+ end
38
+
39
+ def find_base_spec_root_by_file(file)
40
+ if @base_spec_root
41
+ return @base_spec_root
42
+ else
43
+ dir_parts = File.dirname(file).split("/")
44
+ dir_parts.size.times do |i|
45
+ search_dir = dir_parts[0..dir_parts.length - i - 1].join("/") + "/"
46
+ if Dir.entries(search_dir).include?('spec')
47
+ @assumed_spec_root = search_dir + "spec"
48
+ break
49
+ end
50
+ end
51
+ return @assumed_spec_root
52
+ end
53
+ end
54
+
55
+ def guess_spec_location(file, spec_root)
56
+ inner_location = extract_inner_project_location(file, spec_root)
57
+ append_spec_file_extension(File.join(spec_root, inner_location))
58
+ end
59
+
60
+ def project_root(spec_root)
61
+ spec_root.split("/")[0...-1].join("/")
62
+ end
63
+
64
+ def extract_inner_project_location(file, spec_root)
65
+ location = file.sub(project_root(spec_root), "")
66
+ adapt_rails_specific_app_structure(location)
67
+ end
68
+
69
+ def adapt_rails_specific_app_structure(location)
70
+ # Removing 'app' if its a rails controller, model, helper or view
71
+ fu = location.split("/")
72
+ if fu[1] == "app" && (fu[2] == 'controllers' || fu[2] == 'helpers' || fu[2] == 'models' || fu[2] == 'views')
73
+ return "/" + fu[2..fu.length].join("/")
74
+ end
75
+ location
76
+ end
77
+
78
+ def append_spec_file_extension(spec_file)
79
+ if File.extname(spec_file) == ".rb"
80
+ return File.join(File.dirname(spec_file), File.basename(spec_file, ".rb")) + "_spec.rb"
81
+ else
82
+ return spec_file + "_spec.rb"
83
+ end
84
+ end
85
+
86
+ def file_is_a_spec?(file)
87
+ if file.split("/").include?('spec') && File.basename(file).match(/_spec.rb\z/)
88
+ return true
89
+ end
90
+ false
91
+ end
92
+ end
data/lib/interactor.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'timeout'
2
+
3
+ class Interactor
4
+
5
+ def wait_for_enter_key(seconds_to_wait)
6
+ begin
7
+ Timeout::timeout(seconds_to_wait) do
8
+ loop do
9
+ sleep 0.2
10
+ return true if $stdin.gets
11
+ end
12
+ end
13
+ rescue Timeout::Error
14
+ false
15
+ end
16
+ end
17
+
18
+ def start_termination_handler
19
+ @main_thread = Thread.current
20
+ Thread.new do
21
+ loop do
22
+ sleep 0.5
23
+ if $stdin.gets
24
+ puts "** Running all specs.. Hit <enter> twice to exit RSpactor."
25
+ if wait_for_enter_key(1)
26
+ @main_thread.exit
27
+ exit
28
+ end
29
+ Runner.run_all_specs
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/listener.rb ADDED
@@ -0,0 +1,55 @@
1
+ # Some code borrowed from http://rails.aizatto.com/2007/11/28/taming-the-autotest-beast-with-fsevents/
2
+
3
+ class Listener
4
+
5
+ def initialize(&block)
6
+ require 'osx/foundation'
7
+ begin
8
+ @spec_run_time = Time.now
9
+ callback = lambda do |stream, ctx, num_events, paths, marks, event_ids|
10
+ changed_files = extract_changed_files_from_paths(split_paths(paths, num_events))
11
+ @spec_run_time = Time.now
12
+ yield changed_files
13
+ end
14
+
15
+ OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
16
+ stream = OSX::FSEventStreamCreate(OSX::KCFAllocatorDefault, callback, nil, [Dir.pwd], OSX::KFSEventStreamEventIdSinceNow, 0.5, 0)
17
+ unless stream
18
+ puts "Failed to create stream"
19
+ exit
20
+ end
21
+
22
+ OSX::FSEventStreamScheduleWithRunLoop(stream, OSX::CFRunLoopGetCurrent(), OSX::KCFRunLoopDefaultMode)
23
+ unless OSX::FSEventStreamStart(stream)
24
+ puts "Failed to start stream"
25
+ exit
26
+ end
27
+
28
+ OSX::CFRunLoopRun()
29
+ rescue Interrupt
30
+ OSX::FSEventStreamStop(stream)
31
+ OSX::FSEventStreamInvalidate(stream)
32
+ OSX::FSEventStreamRelease(stream)
33
+ end
34
+ end
35
+
36
+ def split_paths(paths, num_events)
37
+ paths.regard_as('*')
38
+ rpaths = []
39
+ num_events.times { |i| rpaths << paths[i] }
40
+ rpaths
41
+ end
42
+
43
+ def extract_changed_files_from_paths(paths)
44
+ changed_files = []
45
+ paths.each do |path|
46
+ Dir.glob(path + "*").each do |file|
47
+ next if Inspector.file_is_invalid?(file)
48
+ file_time = File.stat(file).mtime
49
+ changed_files << file if file_time > @spec_run_time
50
+ end
51
+ end
52
+ changed_files
53
+ end
54
+
55
+ 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(example_count)
14
+ end
15
+
16
+ def add_example_group(example_group)
17
+ end
18
+
19
+ def example_started(example)
20
+ end
21
+
22
+ def example_passed(example)
23
+ end
24
+
25
+ def example_failed(example, counter, failure)
26
+ end
27
+
28
+ def example_pending(example_group_description, example, message)
29
+ end
30
+
31
+ def start_dump
32
+ end
33
+
34
+ def dump_failure(counter, failure)
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
+ %x(growlnotify -w -n rspactor --image #{img} -p #{pri} -m #{msg.inspect} #{title})
45
+ end
46
+ end
47
+
data/lib/runner.rb ADDED
@@ -0,0 +1,78 @@
1
+ class Runner
2
+
3
+ def self.load
4
+ @inspector = Inspector.new
5
+ @interactor = Interactor.new
6
+
7
+ puts ">> RSpactor is now watching at '#{Dir.pwd}'"
8
+
9
+ run_all_specs unless initial_spec_run_abort
10
+
11
+ @interactor.start_termination_handler
12
+ Listener.new do |files|
13
+ files_to_spec = []
14
+ files.each do |file|
15
+ spec_file = @inspector.find_spec_file(file)
16
+ if spec_file
17
+ puts spec_file
18
+ files_to_spec << spec_file
19
+ end
20
+ end
21
+ run_spec_command(files_to_spec) unless files_to_spec.empty?
22
+ end
23
+ end
24
+
25
+ def self.run_all_specs
26
+ run_spec_command([@inspector.inner_spec_directory(Dir.pwd)])
27
+ end
28
+
29
+ def self.run_specs_for_files(files, verbose = false)
30
+ files_to_spec = []
31
+ files.each do |file|
32
+ spec_file = @inspector.find_spec_file(file)
33
+ if spec_file
34
+ puts spec_file if verbose
35
+ files_to_spec << spec_file
36
+ end
37
+ end
38
+ run_spec_command(files_to_spec) unless files_to_spec.empty?
39
+ end
40
+
41
+ def self.run_spec_command(locations)
42
+ base_spec_root = extract_spec_root(locations.first)
43
+ spec_runner_bin = script_runner(locations.first)
44
+ locations = locations.join(" ")
45
+ cmd = "RAILS_ENV=test; "
46
+ cmd << "#{spec_runner_bin} "
47
+ cmd << "#{locations} #{spec_opts(base_spec_root)} "
48
+ cmd << "-r #{File.dirname(__FILE__)}/../lib/resulting.rb -f RSpactorFormatter:STDOUT"
49
+ #puts cmd
50
+ system(cmd)
51
+ end
52
+
53
+ def self.extract_spec_root(file)
54
+ file[0..file.index("spec") + 4]
55
+ end
56
+
57
+ def self.spec_opts(base_spec_root)
58
+ if File.exist?("#{base_spec_root}spec.opts")
59
+ return "-O #{base_spec_root}spec.opts"
60
+ else
61
+ return "-c -f progress"
62
+ end
63
+ end
64
+
65
+ def self.initial_spec_run_abort
66
+ puts "** Hit <enter> to skip initial spec run.."
67
+ @interactor.wait_for_enter_key(2)
68
+ end
69
+
70
+ def self.script_runner(file)
71
+ root = file[0..file.index("spec") - 1]
72
+ if File.exist?(root + "script/spec")
73
+ return root + "script/spec"
74
+ else
75
+ "spec"
76
+ end
77
+ end
78
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspactor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Andreas Wolff
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-11 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: treas@dynamicdudes.com
18
+ executables:
19
+ - rspactor
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - bin/rspactor
26
+ - lib/inspector.rb
27
+ - lib/interactor.rb
28
+ - lib/listener.rb
29
+ - lib/resulting.rb
30
+ - lib/runner.rb
31
+ - asset/rails_fail.png
32
+ - asset/rails_ok.png
33
+ has_rdoc: true
34
+ homepage: http://rubyphunk.com
35
+ post_install_message:
36
+ rdoc_options: []
37
+
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements: []
53
+
54
+ rubyforge_project: rspactor
55
+ rubygems_version: 1.0.1
56
+ signing_key:
57
+ specification_version: 2
58
+ summary: RSpactor is a little command line tool to automatically run your changed specs (much like autotest).
59
+ test_files: []
60
+