codersdojo 1.3.01 → 1.4.00

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,11 +3,13 @@ require 'runner'
3
3
  require 'shell_argument_exception'
4
4
  require 'shell_wrapper'
5
5
  require 'console_view'
6
+ require 'state_reader'
6
7
  require 'help_command'
7
8
  require 'xhelp_command'
8
9
  require 'generate_command'
9
10
  require 'init_session_command'
10
11
  require 'capture_single_run_command'
12
+ require 'revert_to_green_command'
11
13
  require 'upload_command'
12
14
  require 'upload_no_open_command'
13
15
  require 'start_command'
@@ -15,6 +17,7 @@ require 'start_command'
15
17
  class ArgumentParser
16
18
 
17
19
  def initialize shell, view, scaffolder, hostname
20
+ meta_config_file = MetaConfigFile.new shell
18
21
  @help_command = HelpCommand.new view
19
22
  @xhelp_command = XHelpCommand.new view
20
23
  @generate_command = GenerateCommand.new shell, view, scaffolder
@@ -22,9 +25,11 @@ class ArgumentParser
22
25
  @upload_no_open_command = UploadNoOpenCommand.new @upload_command
23
26
  @init_session_command = InitSessionCommand.new shell, view
24
27
  @capture_single_run_command = CaptureSingleRunCommand.new shell, view
25
- @start_command = StartCommand.new shell, view, @upload_command
28
+ @revert_to_green_command = RevertToGreenCommand.new shell, view, meta_config_file, StateReader.new(shell)
29
+ @start_command = StartCommand.new shell, view, [@upload_command, @revert_to_green_command]
26
30
  @commands = [@help_command, @xhelp_command, @generate_command, @init_session_command,
27
- @capture_single_run_command, @start_command, @upload_command, @upload_no_open_command]
31
+ @capture_single_run_command, @start_command, @revert_to_green_command,
32
+ @upload_command, @upload_no_open_command]
28
33
  end
29
34
 
30
35
  def parse params
@@ -28,5 +28,9 @@ class CaptureSingleRunCommand
28
28
  def accepts_shell_command? command
29
29
  command == COMMAND_NAME
30
30
  end
31
+
32
+ def continue_test_loop?
33
+ false
34
+ end
31
35
 
32
36
  end
data/app/console_view.rb CHANGED
@@ -180,6 +180,14 @@ helptext
180
180
  show result
181
181
  end
182
182
 
183
+ def show_revert_to_step step
184
+ show "Revert to step #{step}."
185
+ end
186
+
187
+ def show_no_green_state_to_revert_to
188
+ show "Sorry, no previous green state to revert to."
189
+ end
190
+
183
191
  def show_socket_error command
184
192
  show "Encountered network error while <#{command}>. Is http://www.codersdojo.com down?"
185
193
  end
@@ -194,6 +202,7 @@ helptext
194
202
  show <<-msg
195
203
 
196
204
  You finished your kata. Choose your next action:
205
+ g) Revert to last green state.
197
206
  u) Upload the kata to http://www.codersdojo.com.
198
207
  e) Exit without uploading.
199
208
  r) Resume the kata.
data/app/filename.rb ADDED
@@ -0,0 +1,61 @@
1
+ class Filename
2
+
3
+ DIR_SEPARATOR = '/'
4
+ WINDOWS_DIR_SEPARATOR = '\\'
5
+
6
+ attr_accessor :path_items
7
+
8
+ def initialize filename
9
+ filename = filename.gsub(WINDOWS_DIR_SEPARATOR, DIR_SEPARATOR)
10
+ @path_items = filename.split(DIR_SEPARATOR).delete_if{|item| item.empty?}
11
+ @absolute_path = filename.start_with? DIR_SEPARATOR
12
+ end
13
+
14
+ def absolute_path?
15
+ @absolute_path
16
+ end
17
+
18
+ def relative_path?
19
+ not absolute_path?
20
+ end
21
+
22
+ def without_extension
23
+ if @path_items.size > 0 and @path_items.last.include? '.' then
24
+ Filename.new(to_s.split('.')[0..-2].join('.'))
25
+ else
26
+ clone
27
+ end
28
+ end
29
+
30
+ def extract_last_path_item
31
+ Filename.new(nil_to_empty_string @path_items.last)
32
+ end
33
+
34
+ def remove_last_path_item
35
+ Filename.new(make_string(@path_items[0..-2]))
36
+ end
37
+
38
+ def to_unix_s
39
+ make_string @path_items
40
+ end
41
+
42
+ def to_windows_s
43
+ make_string @path_items, WINDOWS_DIR_SEPARATOR
44
+ end
45
+
46
+ def to_s
47
+ to_unix_s
48
+ end
49
+
50
+ private
51
+
52
+ def make_string the_path_items, seperator=DIR_SEPARATOR
53
+ prefix = absolute_path? ? seperator : ''
54
+ prefix + the_path_items.join(seperator)
55
+ end
56
+
57
+ def nil_to_empty_string object
58
+ object.nil? ? "" : object
59
+ end
60
+
61
+ end
@@ -1,9 +1,12 @@
1
+ require 'shell_wrapper'
2
+
1
3
  class FilenameFormatter
2
4
 
3
5
  CODERSDOJO_WORKSPACE = ".codersdojo"
4
6
  RESULT_FILE = "result.txt"
5
7
  INFO_FILE = "info.yml"
6
8
  STATE_DIR_PREFIX = "state_"
9
+ DIR_SEPARATOR = '/'
7
10
 
8
11
  def self.state_dir_prefix
9
12
  STATE_DIR_PREFIX
@@ -14,7 +17,7 @@ class FilenameFormatter
14
17
  end
15
18
 
16
19
  def source_file_in_state_dir? file
17
- file = extract_last_path_item file
20
+ file = Filename.new(file).extract_last_path_item.to_s
18
21
  file != '..' and file != '.' and file != INFO_FILE and file != RESULT_FILE
19
22
  end
20
23
 
@@ -27,12 +30,12 @@ class FilenameFormatter
27
30
  end
28
31
 
29
32
  def state_file state_dir, file
30
- "#{state_dir}/#{file}"
33
+ concat_path state_dir, file
31
34
  end
32
35
 
33
36
  def state_dir session_id, step
34
37
  session_directory = session_dir session_id
35
- "#{session_directory}/#{STATE_DIR_PREFIX}#{step}"
38
+ concat_path session_directory, "#{STATE_DIR_PREFIX}#{step}"
36
39
  end
37
40
 
38
41
  def step_number_from_state_dir state_dir
@@ -40,29 +43,13 @@ class FilenameFormatter
40
43
  end
41
44
 
42
45
  def session_dir session_id
43
- "#{CODERSDOJO_WORKSPACE}/#{session_id}"
46
+ concat_path CODERSDOJO_WORKSPACE, session_id
44
47
  end
45
48
 
46
- def without_extension filename
47
- if filename.include? '.' then
48
- filename.split('.')[0..-2].join('.')
49
- else
50
- filename
51
- end
52
- end
53
-
54
- def extract_last_path_item dir_path
55
- last_separated_by_slash = dir_path.split('/').last
56
- last_separated_by_native = dir_path.split(ShellWrapper.new.dir_separator).last
57
- last = [last_separated_by_slash, last_separated_by_native].min_by {|item| item.nil? ? 0 : item.size}
58
- nil_to_empty_string last
49
+ def concat_path path, item
50
+ separator = path.end_with?(DIR_SEPARATOR) ? '' : DIR_SEPARATOR
51
+ "#{path}#{separator}#{item}"
59
52
  end
60
53
 
61
- private
62
-
63
- def nil_to_empty_string object
64
- object.nil? ? "" : object
65
- end
66
-
67
54
  end
68
55
 
@@ -26,5 +26,9 @@ class GenerateCommand
26
26
  def accepts_shell_command? command
27
27
  command == 'setup'
28
28
  end
29
+
30
+ def continue_test_loop?
31
+ false
32
+ end
29
33
 
30
34
  end
data/app/help_command.rb CHANGED
@@ -20,4 +20,8 @@ class HelpCommand
20
20
  ['help', '-h', '--help'].member? command
21
21
  end
22
22
 
23
+ def continue_test_loop?
24
+ false
25
+ end
26
+
23
27
  end
@@ -20,5 +20,9 @@ class InitSessionCommand
20
20
  def accepts_shell_command? command
21
21
  command == 'init-session'
22
22
  end
23
+
24
+ def continue_test_loop?
25
+ false
26
+ end
23
27
 
24
28
  end
@@ -0,0 +1,52 @@
1
+
2
+ class RevertToGreenCommand
3
+
4
+ def initialize shell, view, meta_config_file, state_reader
5
+ @shell = shell
6
+ @view = view
7
+ @meta_config_file = meta_config_file
8
+ @state_reader = state_reader
9
+ end
10
+
11
+ def execute_from_shell params
12
+ revert_to_green
13
+ end
14
+
15
+ def execute
16
+ revert_to_green
17
+ end
18
+
19
+ def revert_to_green
20
+ formatter = FilenameFormatter.new
21
+ @state_reader.session_dir = formatter.session_dir @shell.newest_dir_entry(FilenameFormatter.codersdojo_workspace)
22
+ @state_reader.goto_last_state
23
+ state = @state_reader.read_previous_state if @state_reader.state_exist?
24
+ while @state_reader.state_exist? and state.red?
25
+ state = @state_reader.read_previous_state
26
+ end
27
+ if @state_reader.state_exist? and state.green?
28
+ @view.show_revert_to_step @state_reader.next_step+1
29
+ @shell.rm_r @meta_config_file.source_files
30
+ state.files.each do |file|
31
+ dest_file = Filename.new(file).extract_last_path_item.to_s
32
+ @shell.write_file dest_file, @shell.read_file(file)
33
+ end
34
+ else
35
+ @view.show_no_green_state_to_revert_to
36
+ @state_reader.goto_last_state
37
+ end
38
+ end
39
+
40
+ def command_key
41
+ 'g'
42
+ end
43
+
44
+ def accepts_shell_command? command
45
+ command == 'revert-to-green'
46
+ end
47
+
48
+ def continue_test_loop?
49
+ true
50
+ end
51
+
52
+ end
data/app/scaffolder.rb CHANGED
@@ -32,7 +32,7 @@ class Scaffolder
32
32
 
33
33
  def scaffold template, kata_file
34
34
  @template_machine.placeholder_values['kata_file.ext'] = kata_file
35
- @template_machine.placeholder_values['kata_file'] = @filename_formatter.without_extension kata_file
35
+ @template_machine.placeholder_values['kata_file'] = Filename.new(kata_file).without_extension.to_s
36
36
  template = template == '???' ? ANY_TEMPLATE : template
37
37
  dir_path = "#{template_path}/#{template}"
38
38
  to_copy = @shell.real_dir_entries dir_path
data/app/scheduler.rb CHANGED
@@ -5,6 +5,7 @@ class Scheduler
5
5
  @view = view
6
6
  @last_action = ""
7
7
  @commands = commands
8
+ @continue_after_command = false
8
9
  end
9
10
 
10
11
  def start
@@ -24,11 +25,13 @@ class Scheduler
24
25
  end
25
26
 
26
27
  def interrupt_kata
28
+ @continue_after_command = false
27
29
  @view.show_kata_exit_message
28
30
  @last_action = @view.read_user_input.downcase
29
31
  @commands.each do |command|
30
32
  if @last_action.start_with? command.command_key
31
33
  command.execute
34
+ @continue_after_command = command.continue_test_loop?
32
35
  end
33
36
  end
34
37
  if last_action_was_exit? then
@@ -37,7 +40,7 @@ class Scheduler
37
40
  end
38
41
 
39
42
  def continue?
40
- @last_action == '' or last_action_was_resume?
43
+ @last_action == '' or last_action_was_resume? or @continue_after_command
41
44
  end
42
45
 
43
46
  def last_action_was_resume?
data/app/shell_wrapper.rb CHANGED
@@ -14,6 +14,12 @@ class ShellWrapper
14
14
  FileUtils.cp_r source, destination
15
15
  end
16
16
 
17
+ def rm_r file_regex
18
+ files_in_dir_tree('.', file_regex).each do |file|
19
+ FileUtils.rm file
20
+ end
21
+ end
22
+
17
23
  def mkdir dir
18
24
  FileUtils.mkdir dir
19
25
  end
data/app/start_command.rb CHANGED
@@ -3,11 +3,11 @@ require 'scheduler'
3
3
 
4
4
  class StartCommand
5
5
 
6
- def initialize shell, view, upload_command
6
+ def initialize shell, view, eval_loop_commands
7
7
  @shell = shell
8
8
  @view = view
9
9
  @meta_file = MetaConfigFile.new @shell
10
- @upload_command = upload_command
10
+ @eval_loop_commands = eval_loop_commands
11
11
  end
12
12
 
13
13
  def execute_from_shell params
@@ -21,7 +21,7 @@ class StartCommand
21
21
  runner = Runner.new @shell, SessionIdGenerator.new, @view
22
22
  runner.source_files = @meta_file.source_files
23
23
  runner.run_command = command
24
- scheduler = Scheduler.new runner, @view, [@upload_command]
24
+ scheduler = Scheduler.new runner, @view, @eval_loop_commands
25
25
  scheduler.start
26
26
  end
27
27
 
@@ -29,4 +29,8 @@ class StartCommand
29
29
  command == 'start'
30
30
  end
31
31
 
32
+ def continue_test_loop?
33
+ true
34
+ end
35
+
32
36
  end
data/app/state.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  class State
2
2
 
3
- attr_accessor :time, :files, :result, :return_code
3
+ attr_accessor :time, :files, :result, :return_code, :file_contents
4
4
 
5
- def initialize time=nil, files=nil, result=nil, return_code=nil
6
- @time = time
7
- @files = files
8
- @result = result
9
- @return_code = return_code
10
- end
5
+ def green?
6
+ @return_code == 0
7
+ end
8
+
9
+ def red?
10
+ not green?
11
+ end
11
12
 
12
13
  end
data/app/state_reader.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'info_property_file'
2
+ require 'filename'
2
3
  require 'filename_formatter'
3
4
  require 'state'
4
5
 
@@ -18,7 +19,7 @@ class StateReader
18
19
 
19
20
  def session_dir= session_dir
20
21
  @session_dir = session_dir
21
- @session_id = @filename_formatter.extract_last_path_item @session_dir
22
+ @session_id = Filename.new(@session_dir).extract_last_path_item.to_s
22
23
  end
23
24
 
24
25
  def state_count
@@ -33,32 +34,57 @@ class StateReader
33
34
  2
34
35
  end
35
36
 
36
- def get_state_dir
37
- @filename_formatter.state_dir(@session_id, @next_step)
37
+ def get_state_dir step=@next_step
38
+ @filename_formatter.state_dir(@session_id, step)
38
39
  end
39
40
 
40
41
  def has_next_state
41
- File.exist?(get_state_dir)
42
+ state_exist? @next_step
42
43
  end
43
44
 
44
- def read_next_state
45
- state = State.new
45
+ def state_exist? step=@next_step
46
+ File.exist?(get_state_dir step)
47
+ end
48
+
49
+ def goto_last_state
50
+ step = 0
51
+ while state_exist?(step) do step += 1 end
52
+ @next_step = step-1
53
+ end
54
+
55
+ def read_state
56
+ state = State.new
46
57
  state_dir = get_state_dir
47
58
  state.time = @shell.creation_time state_dir
48
- state.files = read_source_files state_dir
59
+ state.files = read_source_files state_dir
60
+ state.file_contents = read_source_file_contents state.files
49
61
  state.result = @shell.read_file @filename_formatter.result_file(state_dir)
50
62
  properties = @shell.read_properties @filename_formatter.info_file(state_dir)
51
63
  fill_state_with_properties state, properties
64
+ state
65
+ end
66
+
67
+ def read_next_state
68
+ state = read_state
52
69
  @next_step += 1
53
70
  state
54
71
  end
55
72
 
73
+ def read_previous_state
74
+ state = read_state
75
+ @next_step -= 1
76
+ state
77
+ end
78
+
56
79
  def read_source_files state_dir
57
80
  files = @shell.files_in_dir_tree state_dir
58
- source_files = files.find_all{|file| @filename_formatter.source_file_in_state_dir? file}
81
+ files.find_all{|file| @filename_formatter.source_file_in_state_dir? file}
82
+ end
83
+
84
+ def read_source_file_contents source_files
59
85
  marker = "=========="
60
86
  source_files.collect {|file|
61
- filename = @filename_formatter.extract_last_path_item file
87
+ filename = Filename.new(file).extract_last_path_item.to_s
62
88
  code = @shell.read_file(file)
63
89
  "#{marker} #{filename} #{marker}\n\n#{code}"
64
90
  }
@@ -25,7 +25,7 @@ class UploadCommand
25
25
  formatter = FilenameFormatter.new
26
26
  framework = @meta_file.framework_property
27
27
  if not session_directory then
28
- session_directory = formatter.session_dir @shell.newest_dir_entry(FilenameFormatter.codersdojo_workspace)
28
+ session_directory = formatter.session_dir @shell.newest_dir_entry(FilenameFormatter.codersdojo_workspace)
29
29
  end
30
30
  @view.show_upload_start session_directory, @hostname, framework
31
31
  @uploader.framework = framework
@@ -45,5 +45,9 @@ class UploadCommand
45
45
  def accepts_shell_command? command
46
46
  command == 'upload'
47
47
  end
48
-
48
+
49
+ def continue_test_loop?
50
+ false
51
+ end
52
+
49
53
  end
@@ -16,4 +16,8 @@ class UploadNoOpenCommand
16
16
  command == 'upload-no-open'
17
17
  end
18
18
 
19
+ def continue_test_loop?
20
+ false
21
+ end
22
+
19
23
  end
data/app/uploader.rb CHANGED
@@ -47,7 +47,7 @@ class Uploader
47
47
  kata_data = {:framework => @framework}
48
48
  states_data = states.each_with_index do |state,index|
49
49
  green = state.return_code == 0
50
- kata_data["states[#{index}]"] = {:code => state.files, :result => state.result, :green => green,
50
+ kata_data["states[#{index}]"] = {:code => state.file_contents, :result => state.result, :green => green,
51
51
  :created_at => state.time}
52
52
  end
53
53
  RestClient.post "#{@hostname}#{@@kata_path}", kata_data
@@ -0,0 +1,13 @@
1
+ ; Adapt the code to your code kata %kata_file%.
2
+
3
+ (ns %kata_file%
4
+ (:use [midje.sweet]))
5
+
6
+ (use 'clojure.test)
7
+
8
+ (defn %kata_file% []
9
+ "fixme")
10
+
11
+ (fact (%kata_file%) => "foo")
12
+
13
+ (run-tests)
@@ -0,0 +1,3 @@
1
+ framework: clojure.midje
2
+ source_files: .*\.clj
3
+
@@ -0,0 +1,12 @@
1
+ These files were created:
2
+ README is what you are currently reading
3
+ run-once.%sh% runs your tests once
4
+ run-endless.%sh% runs your tests endlessly via run-once.%sh%
5
+
6
+ Run run-endless.%sh% and start your kata. (On Mac/Linux you have to call ./run-endless.%sh%.)
7
+
8
+ Assumptions:
9
+ - Java is installed on your system and 'java' is in the path.
10
+ - clojure.jar, clojure-contrib.jar, midje.jar and unifycle.jar are placed in the 'lib' directory.
11
+
12
+ The support for Clojure/Midje was contributed by Stefan Roock.
File without changes
@@ -0,0 +1,7 @@
1
+ (defproject %kata_file% "0.1"
2
+ :dependencies [[org.clojure/clojure
3
+ "1.1.0-master-SNAPSHOT"]
4
+ [org.clojure/clojure-contrib
5
+ "1.0-SNAPSHOT"]
6
+ [lein-midje "1.0.1"]]
7
+ :main %kata_file%)
@@ -0,0 +1,2 @@
1
+ codersdojo start run-once.%sh%
2
+
@@ -0,0 +1 @@
1
+ java -cp lib/clojure-contrib.jar%:%lib/clojure.jar%:%lib/midje.jar%:%lib/unifycle.jar clojure.main %kata_file%.clj
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codersdojo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 3
9
- - 1
10
- version: 1.3.01
8
+ - 4
9
+ - 0
10
+ version: 1.4.00
11
11
  platform: ruby
12
12
  authors:
13
13
  - CodersDojo-Team
@@ -15,13 +15,29 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-02 00:00:00 +02:00
18
+ date: 2011-07-30 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: rest-client
22
+ name: json
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 11
30
+ segments:
31
+ - 1
32
+ - 4
33
+ - 6
34
+ version: 1.4.6
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rest-client
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
25
41
  none: false
26
42
  requirements:
27
43
  - - ">="
@@ -33,11 +49,11 @@ dependencies:
33
49
  - 1
34
50
  version: 1.6.1
35
51
  type: :runtime
36
- version_requirements: *id001
52
+ version_requirements: *id002
37
53
  - !ruby/object:Gem::Dependency
38
54
  name: term-ansicolor
39
55
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
56
+ requirement: &id003 !ruby/object:Gem::Requirement
41
57
  none: false
42
58
  requirements:
43
59
  - - ">="
@@ -49,7 +65,7 @@ dependencies:
49
65
  - 5
50
66
  version: 1.0.5
51
67
  type: :runtime
52
- version_requirements: *id002
68
+ version_requirements: *id003
53
69
  description: Client executes tests in an endless loop and logs source code and test result for later uplaod.
54
70
  email: codersdojo@it-agile.de
55
71
  executables:
@@ -63,6 +79,7 @@ files:
63
79
  - app/capture_single_run_command.rb
64
80
  - app/codersdojo.rb
65
81
  - app/console_view.rb
82
+ - app/filename.rb
66
83
  - app/filename_formatter.rb
67
84
  - app/generate_command.rb
68
85
  - app/help_command.rb
@@ -71,6 +88,7 @@ files:
71
88
  - app/meta_config_file.rb
72
89
  - app/progress.rb
73
90
  - app/property_file_missing_exception.rb
91
+ - app/revert_to_green_command.rb
74
92
  - app/runner.rb
75
93
  - app/scaffolder.rb
76
94
  - app/scheduler.rb
@@ -96,6 +114,12 @@ files:
96
114
  - templates/clojure.is-test/README
97
115
  - templates/clojure.is-test/run-endless.%sh%
98
116
  - templates/clojure.is-test/run-once.%sh%
117
+ - templates/clojure.midje/%kata_file%.clj
118
+ - templates/clojure.midje/lib/place_your_libs_here
119
+ - templates/clojure.midje/project.clj
120
+ - templates/clojure.midje/README
121
+ - templates/clojure.midje/run-endless.%sh%
122
+ - templates/clojure.midje/run-once.%sh%
99
123
  - templates/cpp.gtest/%Kata_file%.cc
100
124
  - templates/cpp.gtest/Makefile
101
125
  - templates/cpp.gtest/README
@@ -171,6 +195,7 @@ files:
171
195
  - templates/shell.shunit/run-once.%sh%
172
196
  - templates/any/.meta
173
197
  - templates/clojure.is-test/.meta
198
+ - templates/clojure.midje/.meta
174
199
  - templates/cpp.gtest/.meta
175
200
  - templates/csharp.nunit.dotnet/.meta
176
201
  - templates/csharp.nunit.mono/.meta