loris 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +2 -0
  2. data/README.rdoc +9 -0
  3. data/Rakefile +41 -0
  4. data/TODO +21 -0
  5. data/VERSION +1 -0
  6. data/bin/loris +15 -0
  7. data/cucumber.yml +1 -0
  8. data/examples/self_test/jsl.conf +1 -0
  9. data/examples/self_test/spec/spec.rhino.js +6 -0
  10. data/features/javascript_lint.feature +34 -0
  11. data/features/run.feature +36 -0
  12. data/features/step_definitons/all.rb +69 -0
  13. data/features/support/env.rb +145 -0
  14. data/lib/always_continuer.rb +7 -0
  15. data/lib/browser_finder.rb +23 -0
  16. data/lib/file_actioner.rb +16 -0
  17. data/lib/file_finder.rb +31 -0
  18. data/lib/filters/ends_with_filter.rb +17 -0
  19. data/lib/filters/extension_filter.rb +20 -0
  20. data/lib/filters/file_filter.rb +14 -0
  21. data/lib/filters/modified_filter.rb +21 -0
  22. data/lib/icons/error.png +0 -0
  23. data/lib/icons/failure.png +0 -0
  24. data/lib/icons/info.png +0 -0
  25. data/lib/icons/success.png +0 -0
  26. data/lib/icons/warning.png +0 -0
  27. data/lib/js-test-driver/JsTestDriver-1.1.jar +0 -0
  28. data/lib/js-test-driver/plugins/coverage-1.1.jar +0 -0
  29. data/lib/loris.rb +170 -0
  30. data/lib/outputs/growl_output.rb +26 -0
  31. data/lib/outputs/output_collection.rb +23 -0
  32. data/lib/outputs/shell_output.rb +17 -0
  33. data/lib/outputs/unix_console_clearing_output.rb +13 -0
  34. data/lib/outputs/windows_console_clearing_output.rb +13 -0
  35. data/lib/pinger.rb +23 -0
  36. data/lib/poller.rb +16 -0
  37. data/lib/sleep_waiter.rb +11 -0
  38. data/lib/task_manager.rb +45 -0
  39. data/lib/tasks/command_line_task.rb +28 -0
  40. data/lib/tasks/javascript_lint/javascript_lint_parser.rb +45 -0
  41. data/lib/tasks/javascript_lint/javascript_lint_runner.rb +25 -0
  42. data/lib/tasks/js_test_driver/js_test_driver_config.rb +22 -0
  43. data/lib/tasks/js_test_driver/js_test_driver_parser.rb +28 -0
  44. data/lib/tasks/js_test_driver/js_test_driver_runner.rb +28 -0
  45. data/lib/tasks/js_test_driver/js_test_driver_server.rb +38 -0
  46. data/lib/tasks/jspec/jspec_parser.rb +30 -0
  47. data/lib/tasks/jspec/jspec_runner.rb +25 -0
  48. data/lib/tasks/list_task.rb +34 -0
  49. data/lib/tasks/rspec/rspec_parser.rb +25 -0
  50. data/lib/tasks/rspec/rspec_runner.rb +25 -0
  51. data/lib/unix_process.rb +7 -0
  52. data/lib/windows_process.rb +12 -0
  53. data/loris.gemspec +133 -0
  54. data/loris.tmproj +232 -0
  55. data/spec/file_actioner_spec.rb +41 -0
  56. data/spec/file_finder_spec.rb +73 -0
  57. data/spec/filters/ends_with_filter_spec.rb +26 -0
  58. data/spec/filters/file_filter_spec.rb +28 -0
  59. data/spec/filters/modified_filter_spec.rb +47 -0
  60. data/spec/growl_output_spec.rb +33 -0
  61. data/spec/list_task_spec.rb +58 -0
  62. data/spec/poller_spec.rb +28 -0
  63. data/spec/shell_output_spec.rb +25 -0
  64. data/spec/task_manager_spec.rb +64 -0
  65. data/spec/tasks/javascript_lint/javascript_lint_runner_spec.rb +90 -0
  66. data/spec/tasks/js_test_driver/js_test_driver_runner_spec.rb +92 -0
  67. data/spec/tasks/jspec/jspec_parser_spec.rb +28 -0
  68. data/spec/tasks/jspec/jspec_runner_spec.rb +78 -0
  69. metadata +174 -0
data/lib/loris.rb ADDED
@@ -0,0 +1,170 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'bind'
6
+ require 'rbconfig'
7
+ require 'find'
8
+ require 'Growl'
9
+ require 'yaml'
10
+ require 'uri'
11
+
12
+
13
+ require 'file_finder'
14
+ require 'poller'
15
+ require 'sleep_waiter'
16
+ require 'always_continuer'
17
+ require 'file_actioner'
18
+ require 'task_manager'
19
+ require 'pinger'
20
+
21
+ require 'filters/extension_filter'
22
+ require 'filters/modified_filter'
23
+ require 'filters/file_filter'
24
+ require 'filters/ends_with_filter'
25
+
26
+ require 'outputs/output_collection'
27
+ require 'outputs/shell_output'
28
+ require 'outputs/windows_console_clearing_output'
29
+ require 'outputs/unix_console_clearing_output'
30
+ require 'outputs/growl_output'
31
+
32
+ require 'tasks/list_task'
33
+ require 'tasks/command_line_task'
34
+ require 'tasks/jspec/jspec_runner'
35
+ require 'tasks/jspec/jspec_parser'
36
+ require 'tasks/javascript_lint/javascript_lint_runner'
37
+ require 'tasks/javascript_lint/javascript_lint_parser'
38
+ require 'tasks/rspec/rspec_runner'
39
+ require 'tasks/rspec/rspec_parser'
40
+
41
+
42
+ include Config
43
+
44
+ class DebugObserver
45
+ def update
46
+ puts '[Poll complete]'
47
+ end
48
+ end
49
+
50
+
51
+ module Loris
52
+ BINARY = File.expand_path(File.dirname(__FILE__) + '/../bin/loris')
53
+ LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../lib')
54
+ RUBY_BINARY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
55
+
56
+ module CLI
57
+
58
+ class Main
59
+
60
+ class DummyActioner
61
+
62
+ def initialize(actioner, stream)
63
+ @actioner = actioner
64
+ @stream = stream
65
+ end
66
+
67
+ def run
68
+ @actioner.run
69
+ @stream.puts '[Poll complete]'
70
+ @stream.flush
71
+ end
72
+
73
+ end
74
+
75
+ class << self
76
+ def execute(args)
77
+
78
+ # Get config variables
79
+ debug = args.length > 0
80
+ is_windows = RUBY_PLATFORM =~ /mswin32/
81
+ dir = Dir.pwd
82
+ sleep_duration = 1
83
+ browser = is_windows ? 'C:/Program Files/Internet Explorer/iexplore.exe' : 'open'
84
+
85
+ # Create object graph
86
+ w = SleepWaiter.new(sleep_duration)
87
+ c = AlwaysContinuer.new
88
+ ff = FileFinder.new(Find, dir)
89
+ ff.add_filter(FileFilter.new(File))
90
+ ff.add_filter(ModifiedFilter.new(File))
91
+
92
+ cco = is_windows ? WindowsConsoleClearingOutput.new : UnixConsoleClearingOutput.new
93
+
94
+ oc = OutputCollection.new
95
+ oc.add(ShellOutput.new($stdout))
96
+ oc.add(cco) unless debug
97
+ oc.add(GrowlOutput.new(Growl)) unless debug
98
+
99
+ tm = TaskManager.new(oc)
100
+ tm.add(ListTask.new) if debug
101
+ tm.add(CommandLineTask.new(JavascriptLintRunner.new(dir, ExtensionFilter.new(File, 'js')), JavascriptLintParser.new(dir)))
102
+ tm.add(CommandLineTask.new(JSpecRunner.new(dir, ExtensionFilter.new(File, 'js')), JSpecParser.new)) unless is_windows
103
+ tm.add(jsTestDriverTask(dir))
104
+ tm.add(CommandLineTask.new(RSpecRunner.new(dir, ExtensionFilter.new(File, 'rb'), EndsWithFilter.new('_spec.rb')), RSpecParser.new))
105
+
106
+ a = FileActioner.new(ff, tm)
107
+
108
+ da = DummyActioner.new(a, $stdout)
109
+
110
+ p = Poller.new(w, c, debug ? da : a)
111
+
112
+ # Start!
113
+ p.start
114
+
115
+ end
116
+
117
+ # Will need to be refactored into a factory
118
+ def jsTestDriverTask(dir)
119
+ require 'tasks/js_test_driver/js_test_driver_runner'
120
+ require 'tasks/js_test_driver/js_test_driver_parser'
121
+ require 'tasks/js_test_driver/js_test_driver_config'
122
+ require 'tasks/js_test_driver/js_test_driver_server'
123
+
124
+ jar = File.join(LIBDIR, 'js-test-driver/JsTestDriver-1.1.jar')
125
+ is_windows = RUBY_PLATFORM =~ /mswin32/
126
+
127
+ if is_windows
128
+ require 'browser_finder'
129
+ browser = BrowserFinder.new.getDefault
130
+ else
131
+ browser = 'open "%1"'
132
+ end
133
+
134
+ sleep_time = is_windows ? 3 : 2
135
+
136
+ if is_windows
137
+ require 'windows_process'
138
+ else
139
+ require 'unix_process'
140
+ end
141
+
142
+ return CommandLineTask.new(
143
+ JsTestDriverRunner.new(
144
+ dir,
145
+ jar,
146
+ ExtensionFilter.new(File, 'js'),
147
+ JsTestDriverServer.new(
148
+ JsTestDriverConfig.new(
149
+ dir,
150
+ YAML,
151
+ URI
152
+ ),
153
+ Pinger.new,
154
+ is_windows ? WindowsProcess.new : UnixProcess.new,
155
+ jar,
156
+ browser,
157
+ sleep_time
158
+ )
159
+ ),
160
+ JsTestDriverParser.new
161
+ )
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+
168
+ end
169
+
170
+ end
@@ -0,0 +1,26 @@
1
+ class GrowlOutput
2
+
3
+ def initialize(growler)
4
+ @growler = growler
5
+ end
6
+
7
+ def start_run
8
+ end
9
+
10
+ def add_result(result)
11
+ icon = get_icon(result[:state])
12
+
13
+ if @growler.installed?
14
+ @growler.notify {
15
+ self.title = result[:title] + (result[:summary].nil? ? '' : ' - ' + result[:summary])
16
+ self.message = result[:first]
17
+ self.image = icon
18
+ }
19
+ end
20
+ end
21
+
22
+ def get_icon(state)
23
+ return File.join(File.expand_path(File.dirname(__FILE__)), '..', 'icons', "#{state.to_s}.png")
24
+ end
25
+
26
+ end
@@ -0,0 +1,23 @@
1
+ class OutputCollection
2
+
3
+ def initialize
4
+ @outputs = []
5
+ end
6
+
7
+ def start_run
8
+ @outputs.each do |output|
9
+ output.start_run
10
+ end
11
+ end
12
+
13
+ def add(output)
14
+ @outputs << output
15
+ end
16
+
17
+ def add_result(result)
18
+ @outputs.each do |output|
19
+ output.add_result(result)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,17 @@
1
+ class ShellOutput
2
+
3
+ def initialize(output)
4
+ @output = output
5
+ end
6
+
7
+ def start_run
8
+ end
9
+
10
+ def add_result(result)
11
+ @output.puts result[:title]
12
+ @output.puts result[:state]
13
+ @output.puts result[:summary]
14
+ @output.puts result[:detail]
15
+ end
16
+
17
+ end
@@ -0,0 +1,13 @@
1
+ class UnixConsoleClearingOutput
2
+
3
+ def initialize
4
+ end
5
+
6
+ def start_run
7
+ system 'clear'
8
+ end
9
+
10
+ def add_result(result)
11
+ end
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ class WindowsConsoleClearingOutput
2
+
3
+ def initialize
4
+ end
5
+
6
+ def start_run
7
+ system 'cls'
8
+ end
9
+
10
+ def add_result(result)
11
+ end
12
+
13
+ end
data/lib/pinger.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'socket'
2
+ require 'timeout'
3
+
4
+ class Pinger
5
+
6
+ def is_port_open?(ip, port)
7
+ begin
8
+ Timeout::timeout(1) do
9
+ begin
10
+ s = TCPSocket.new(ip, port)
11
+ s.close
12
+ return true
13
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
14
+ return false
15
+ end
16
+ end
17
+ rescue Timeout::Error
18
+ end
19
+
20
+ return false
21
+ end
22
+
23
+ end
data/lib/poller.rb ADDED
@@ -0,0 +1,16 @@
1
+ class Poller
2
+
3
+ def initialize(waiter, continuer, action)
4
+ @waiter = waiter
5
+ @continuer = continuer
6
+ @action = action
7
+ end
8
+
9
+ def start
10
+ while @continuer.continue?
11
+ @waiter.wait
12
+ @action.run
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,11 @@
1
+ class SleepWaiter
2
+
3
+ def initialize(sleep_time = 1)
4
+ @sleep_time = sleep_time
5
+ end
6
+
7
+ def wait
8
+ sleep @sleep_time
9
+ end
10
+
11
+ end
@@ -0,0 +1,45 @@
1
+ class TaskManager
2
+
3
+ def initialize(output)
4
+ @output = output
5
+ @tasks = []
6
+ end
7
+
8
+ def add(task)
9
+ @tasks << task
10
+ end
11
+
12
+ def run(files)
13
+ @output.start_run;
14
+
15
+ @tasks.each do |task|
16
+
17
+ begin
18
+ break if !run_task(files, task)
19
+ rescue Exception => ex
20
+ output_exception(ex)
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ def run_task(files, task)
28
+ result = task.run(files)
29
+ return true if result.nil?
30
+
31
+ @output.add_result(result)
32
+ return !([:error, :failure].include? result[:state])
33
+ end
34
+
35
+ def output_exception(ex)
36
+ @output.add_result({
37
+ :state => :error,
38
+ :title => 'Task',
39
+ :summary => 'Exception',
40
+ :first => ex.message,
41
+ :detail => ex.backtrace
42
+ })
43
+ end
44
+
45
+ end
@@ -0,0 +1,28 @@
1
+ class CommandLineTask
2
+
3
+ def initialize(runner, parser)
4
+ @runner = runner
5
+ @parser = parser
6
+ end
7
+
8
+ def run(files)
9
+ all_files = files[:all]
10
+ modified_files = files[:filtered]
11
+
12
+ return nil if (!@runner.is_configured? all_files)
13
+ return nil if (!@runner.should_run? modified_files)
14
+
15
+ detail = @runner.execute
16
+
17
+ state, summary, first = @parser.parse_result(detail)
18
+
19
+ return {
20
+ :state => state,
21
+ :title => @runner.name,
22
+ :summary => summary,
23
+ :first => first,
24
+ :detail => detail
25
+ }
26
+ end
27
+
28
+ end
@@ -0,0 +1,45 @@
1
+ class JavascriptLintParser
2
+
3
+ def initialize(dir)
4
+ @dir = dir
5
+
6
+ # TODO: Tidy!
7
+ if (RUBY_PLATFORM =~ /mswin32/)
8
+ @dir = @dir.gsub('/', '\\')
9
+ end
10
+ end
11
+
12
+ def parse_result(detail)
13
+ summary_line = detail.grep( /\d+\s+error.*,\s+\d+\s+warning.*/ )[0]
14
+
15
+ if summary_line.nil?
16
+ # error
17
+ error_info = (detail + "\nUnknown Error!").to_a[0].strip
18
+ return :error, 'Error', error_info
19
+ end
20
+
21
+ if summary_line =~ /([1-9]+)\d*\s+error/
22
+ num_failures = $1
23
+ error_info = detail.grep(/\([0-9]+\):([^:]*)Error:/)[0].strip
24
+ return :failure, num_failures + ' Errors', strip_dir(error_info)
25
+ end
26
+
27
+ if summary_line =~ /([1-9]+)\d*\s+warning/
28
+ num_failures = $1
29
+ error_info = detail.grep(/\([0-9]+\)/)[0].strip
30
+ return :warning, num_failures + ' Warnings', strip_dir(error_info)
31
+ end
32
+
33
+ return :success, 'All files are clean', ''
34
+ end
35
+
36
+ def strip_dir(text)
37
+
38
+ # Move to function/class w/ win32 related code
39
+ if (text[0, @dir.length] == @dir)
40
+ text = text[(@dir.length + 1)..-1]
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,25 @@
1
+ class JavascriptLintRunner
2
+
3
+ def initialize(dir, filter)
4
+ @config = dir + '/jsl.conf'
5
+ @dir = dir
6
+ @filter = filter
7
+ end
8
+
9
+ def name
10
+ return 'Javascript Lint'
11
+ end
12
+
13
+ def execute
14
+ return `jsl -conf "#{@config}" -nologo -nofilelisting 2>&1`
15
+ end
16
+
17
+ def is_configured?(all_files)
18
+ return all_files.include?(@config)
19
+ end
20
+
21
+ def should_run?(modified_files)
22
+ return !(modified_files.detect { |file| @filter.filter(file) }).nil? || modified_files.include?(@config)
23
+ end
24
+
25
+ end
@@ -0,0 +1,22 @@
1
+ class JsTestDriverConfig
2
+
3
+ def initialize(dir, yaml, uri)
4
+ @config_file = dir + '/jsTestDriver.conf'
5
+ @yaml = yaml
6
+ @uri = uri
7
+ end
8
+
9
+ def reload
10
+ @conf = @yaml.load_file(@config_file)
11
+ @server = @uri.parse(@conf['server'])
12
+ end
13
+
14
+ def host
15
+ return @server.host
16
+ end
17
+
18
+ def port
19
+ return @server.port
20
+ end
21
+
22
+ end
@@ -0,0 +1,28 @@
1
+ class JsTestDriverParser
2
+
3
+ def parse_result(detail)
4
+ summary_line = detail.grep( /Total \d+ tests/ )[0]
5
+
6
+ if summary_line.nil?
7
+ # error
8
+ error_info = (detail + "\nUnknown Error!").to_a[0].strip
9
+ return :error, 'Error', error_info
10
+ end
11
+
12
+ if summary_line =~ /Errors: ([1-9]+)/
13
+ num_errors = $1
14
+ error_info = detail.grep(/error \([0-9]+.[0-9]+ ms\)/)[0].strip
15
+ return :failure, num_errors + ' Errors', error_info
16
+ end
17
+
18
+ if summary_line =~ /Fails: ([1-9]+)/
19
+ num_failures = $1
20
+ error_info = detail.grep(/failed \([0-9]+.[0-9]+ ms\)/)[0].strip
21
+ return :failure, num_failures + ' Failures', error_info
22
+ end
23
+
24
+ return :success, 'All tests pass', ''
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ class JsTestDriverRunner
2
+
3
+ def initialize(dir, jar, filter, server)
4
+ @config = dir + '/jsTestDriver.conf'
5
+ @dir = dir
6
+ @jar = jar
7
+ @filter = filter
8
+ @server = server
9
+ end
10
+
11
+ def name
12
+ return 'JS Test Driver'
13
+ end
14
+
15
+ def execute
16
+ @server.start_if_required
17
+ return `java -jar "#{@jar}" --config "#{@config}" --tests all --verbose 2>&1`
18
+ end
19
+
20
+ def is_configured?(all_files)
21
+ return all_files.include?(@dir + '/jsTestDriver.conf')
22
+ end
23
+
24
+ def should_run?(modified_files)
25
+ return !(modified_files.detect { |file| @filter.filter(file) }).nil? || modified_files.include?(@config)
26
+ end
27
+
28
+ end
@@ -0,0 +1,38 @@
1
+ class JsTestDriverServer
2
+
3
+ def initialize(config, pinger, process, jar, browser, sleep_time)
4
+ @config = config
5
+ @pinger = pinger
6
+ @process = process
7
+ @jar = jar
8
+ @browser = browser
9
+ @sleep_time = sleep_time
10
+ end
11
+
12
+ def start_if_required
13
+ @config.reload
14
+
15
+ if @config.host == 'localhost' && server_not_running
16
+ start_server(@config.port)
17
+ start_and_capture_browser(@config.port)
18
+ end
19
+ end
20
+
21
+ def server_not_running
22
+ return !@pinger.is_port_open?('127.0.0.1', @config.port)
23
+ end
24
+
25
+ def start_server(port)
26
+ command = "java -jar \"#{@jar}\" --port #{port}" #" --browser \"#{@browser}\" "
27
+ @process.create(command)
28
+ sleep @sleep_time
29
+ end
30
+
31
+ def start_and_capture_browser(port)
32
+ capture_url = "http://localhost:#{port}/capture"
33
+ command = @browser.gsub('%1', capture_url)
34
+ @process.create(command)
35
+ sleep @sleep_time
36
+ end
37
+
38
+ end
@@ -0,0 +1,30 @@
1
+ class JSpecParser
2
+
3
+ def parse_result(detail)
4
+ summary_line = detail.grep( /Passes:/ )[0]
5
+
6
+ if summary_line.nil?
7
+ # error
8
+ error_info = (detail + "\nUnknown Error!").to_a[0]
9
+ return :error, 'Error', error_info
10
+ end
11
+
12
+ # remove console colour information and trim start and end white space
13
+ summary_line = remove_colour(summary_line).strip
14
+
15
+ if summary_line =~ /Failures:\s+([1-9]+)\d*/
16
+ num_failures = $1
17
+ error_line = detail.grep(/\[31m/)[1] || ''
18
+ error_info = remove_colour(error_line).strip
19
+ return :failure, num_failures + ' Failures', error_info
20
+ end
21
+
22
+
23
+ return :success, 'All Passed', summary_line
24
+ end
25
+
26
+ def remove_colour(string)
27
+ return string.gsub(/\e\[[0-9]+m?/, '')
28
+ end
29
+
30
+ end
@@ -0,0 +1,25 @@
1
+ class JSpecRunner
2
+
3
+ def initialize(dir, filter)
4
+ @config = dir + '/spec/spec.rhino.js'
5
+ @dir = dir
6
+ @filter = filter
7
+ end
8
+
9
+ def name
10
+ return 'JSpec'
11
+ end
12
+
13
+ def execute
14
+ return `jspec run --rhino --trace 2>&1`
15
+ end
16
+
17
+ def is_configured?(all_files)
18
+ return all_files.include?(@config)
19
+ end
20
+
21
+ def should_run?(modified_files)
22
+ return !(modified_files.detect { |file| @filter.filter(file) }).nil?
23
+ end
24
+
25
+ end
@@ -0,0 +1,34 @@
1
+ class ListTask
2
+
3
+ def initialize(format_string = "%s")
4
+ @format_string = format_string
5
+ end
6
+
7
+ def run(files)
8
+ all_files = files[:all]
9
+ mofified_files = files[:filtered]
10
+
11
+ return {
12
+ :state => :success,
13
+ :title => 'List',
14
+ :first => mofified_files.length == 1 ? mofified_files[0] : '%s files.' % mofified_files.length,
15
+ :detail => get_detail(mofified_files)
16
+ }
17
+ end
18
+
19
+ def get_detail(paths)
20
+ detail = ""
21
+ limit = [paths.length - 1, 14].min
22
+ (0..limit).each do |i|
23
+ path = paths[i]
24
+ detail += (@format_string % path)
25
+ detail += "\n"
26
+ end
27
+ if limit < paths.length - 1
28
+ detail += " - Plus #{(paths.length - 1) - limit} more files."
29
+ end
30
+
31
+ return detail
32
+ end
33
+
34
+ end