sensei 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ coverage
2
+ pkg
3
+ .DS_Store
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/sensei ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # Add '.rb' to work around a bug in IronRuby's File#dirname
3
+ $:.unshift(File.dirname(__FILE__ + '.rb') + '/../lib') unless $:.include?(File.dirname(__FILE__ + '.rb') + '/../lib')
4
+
5
+ require 'sensei'
6
+ begin
7
+ failure = run_dojo(RealGit.new)
8
+ Kernel.exit(failure ? 1 : 0)
9
+ rescue SystemExit => e
10
+ Kernel.exit(e.status)
11
+ rescue Exception => e
12
+ STDERR.puts("#{e.message} (#{e.class})")
13
+ STDERR.puts(e.backtrace.join("\n"))
14
+ Kernel.exit 1
15
+ end
data/lib/sensei.rb ADDED
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'sensei/iteration_list'
5
+ require 'sensei/git_tag_lister'
6
+ require 'sensei/repository'
7
+ require 'sensei/dojo'
8
+
9
+ def get_name
10
+ print "Enter your name: "
11
+ STDIN.gets
12
+ end
13
+
14
+ def run_dojo(git)
15
+ Dojo.new(get_name, git).run
16
+ end
@@ -0,0 +1,128 @@
1
+ class Dojo
2
+
3
+ def initialize(name, git)
4
+ @git = git
5
+ @name = name
6
+ @iteration = 1
7
+ @git.do("checkout iteration-1")
8
+ @git.do("branch -D #{name}")
9
+ @git.do("checkout -b #{name}")
10
+ end
11
+
12
+ def suggest_write_specs
13
+ puts
14
+ puts "FAIL: how about writing some specs in ./spec ?"
15
+ puts "FAIL! Hit [ENTER] to run them when you're ready..."
16
+ STDIN.gets
17
+ end
18
+
19
+ def cukes_failed
20
+ puts
21
+ puts "FAIL: Your cukes failed!"
22
+ end
23
+
24
+ def specs_failed
25
+ puts
26
+ puts "FAIL: Better fix those specs!"
27
+ puts "FAIL! Hit [ENTER] to run them when you're ready..."
28
+ STDIN.gets
29
+ end
30
+
31
+ def specs_passed
32
+ puts
33
+ puts "Your specs passed :-). Hit [ENTER] to try the cukes again"
34
+ STDIN.gets
35
+ end
36
+
37
+ def run
38
+ @max_iterations = IterationList.new(Dir.pwd).iterations
39
+ until @iteration > @max_iterations
40
+
41
+ run_cukes
42
+ unless @cukes_passed
43
+ cukes_failed
44
+ suggest_write_specs
45
+ run_specs
46
+ until @specs_passed
47
+ specs_failed
48
+ run_specs
49
+ end
50
+ specs_passed
51
+ run_cukes
52
+ end
53
+
54
+ if success?
55
+ if @iteration < @max_iterations
56
+ commit("iteration #{@iteration} tests passing.")
57
+
58
+ puts
59
+ puts
60
+ puts "WIN!"
61
+ puts "Perhaps you would care for a spot of refactoring at this point?"
62
+
63
+ refactoring_loop
64
+ next_iteration
65
+ else
66
+ puts "EPIC WIN! Now to play the refactoring game..."
67
+ until false
68
+ system("rake spec features")
69
+ if success?
70
+ flog
71
+ commit "refactoring"
72
+ end
73
+ puts "Not bad. Can you do any better? (Hit a key to re-run the flog)"
74
+ STDIN.gets
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def success?
82
+ $?.exitstatus == 0
83
+ end
84
+
85
+ def run_cukes
86
+ system("cucumber features")
87
+ @cukes_passed = success?
88
+ end
89
+
90
+ def run_specs
91
+ system("rake spec")
92
+ @specs_passed = success?
93
+ end
94
+
95
+ def next_iteration
96
+ commit("iteration #{@iteration} refactored.")
97
+ @iteration = @iteration+1
98
+ @git.do("merge iteration-#{@iteration}")
99
+ end
100
+
101
+ def commit message
102
+ @git.do("add .")
103
+ @git.do(%Q{commit -m "#{message}"})
104
+ end
105
+
106
+ def flog
107
+ system("flog lib/*.rb")
108
+ end
109
+
110
+ def refactoring_loop
111
+ go_next = false
112
+ until go_next
113
+ message = "Press [ENTER] to run the tests again (with refactoring tips)"
114
+ message << ", [SPACE ENTER] to move to the next iteration" if success?
115
+ puts message
116
+
117
+ go_next = (STDIN.gets == " \n")
118
+
119
+ unless go_next && success?
120
+ system("rake spec features")
121
+ if success?
122
+ flog
123
+ end
124
+ go_next = false
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,11 @@
1
+ class GitTagLister
2
+ def initialize(path)
3
+ @path = path
4
+ end
5
+
6
+ def tags
7
+ Dir.chdir(@path) do
8
+ `git tag`.split "\n"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class IterationList
2
+ def initialize(path)
3
+ @path = path
4
+ end
5
+
6
+ def iterations
7
+ GitTagLister.new(@path).tags.select do |tag|
8
+ /iteration-\d*/.match(tag)
9
+ end.size
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class RealGit
2
+ def do command
3
+ system("git #{command}")
4
+ end
5
+ end
6
+
7
+ class FakeGit
8
+ def do command
9
+ end
10
+ end
data/rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require "spec/rake/spectask"
2
+
3
+ task :default => :spec do
4
+ end
5
+
6
+ desc "Run all specs"
7
+ Spec::Rake::SpecTask.new do |t|
8
+ t.spec_files = FileList["spec/**/*.rb"]
9
+ t.spec_opts = ['--format specdoc --color']
10
+ end
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gemspec|
15
+ gemspec.name = "sensei"
16
+ gemspec.summary = "Sensei runs your coding dojo for you."
17
+ gemspec.description = "Sensei runs your dojo for you. You start with a single failing cucumber feature. As you make each feature pass, the next feature is brought into play. While you have failing features, you have the opportunity to write rspec specifications. Sensei will encourage you to refactor at appropriate moments, showing you your flog score as encouragement."
18
+ gemspec.email = "alex.scordellis@gmail.com"
19
+ gemspec.homepage = "http://github.com/alexscordellis/sensei"
20
+ gemspec.authors = ["Alex Scordellis"]
21
+
22
+ # gemspec.test_files = Dir['spec/**/*'] + Dir['spec/*']
23
+
24
+ gemspec.add_dependency('rake', '>= 0.8.7')
25
+ gemspec.add_dependency('rspec', '>= 1.2.6')
26
+ gemspec.add_dependency('cucumber', '>= 0.3.3')
27
+ gemspec.add_dependency('flog', '>= 2.1.0')
28
+
29
+ end
30
+ Jeweler::GemcutterTasks.new
31
+ rescue LoadError
32
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
33
+ end
data/readme.markdown ADDED
@@ -0,0 +1,63 @@
1
+ # Sensei
2
+
3
+ Sensei runs your dojo for you. You start with a single failing cucumber feature. As you make each feature pass, the next feature is brought into play. While you have failing features, you have the opportunity to write rspec specifications. Sensei will encourage you to refactor at appropriate moments, showing you your [flog](http://blog.zenspider.com/rubysadism/flog/) score as encouragement.
4
+
5
+ This should replicate an outside-in development style, where the cucumber features represent acceptance/integration tests and the specs are lower level unit tests that help you develop the individual methods and classes.
6
+
7
+ # Running a dojo
8
+
9
+ gem install sensei
10
+ git clone git://github.com/alexscordellis/kata-minesweeper.git (or other dojo repository)
11
+ cd kata-minesweeper
12
+ sensei
13
+
14
+ Then follow the instructions. Each time you get to green, sensei will make a commit to git. This way you'll have a history of all your implementation and refactorings. You could then push those changes to a github fork of the dojo repository and compare your solution to others'.
15
+
16
+ ## Tips
17
+
18
+ * Try to write the simplest code that will make the next cucumber scenario pass. Try not to anticipate future requirements.
19
+ * If the jump from one scenario to the next is too big, or affects more than one behaviour of your program, consider writing rspec specifications that make smaller steps.
20
+ * If the cucumber scenario requires a significant change in the implementation, consider refactoring before implementing the new scenario. Make sure that all the previous scenarios are still passing after your refactoring and before you add support for the new scenario.
21
+ * Make sure you refactor each time you get to green, to make sure that you're in a good state for the net scenario. Use the flog score to guide your refactoring - a lower flog score is better.
22
+
23
+
24
+ # Prepared dojos
25
+
26
+ ## Minesweeper
27
+
28
+ Source is [on github](http://github.com/alexscordellis/kata-minesweeper "Minesweeper source"). This is a simple implementation of the classic Windows minesweeper game. The features currently available specify how the completed board should appear given the size and the mine locations. This is the original dojo from Matt's session.
29
+
30
+ ## Bowling Game
31
+
32
+ Source is [on github](http://github.com/alexscordellis/sensei-bowling-game "Bowling Game source"). This is an interpretation of Uncle Bob's classic Bowling Game kata.
33
+
34
+ # Prerequisites
35
+
36
+ You will need the following gems
37
+
38
+ * rake
39
+ * rspec
40
+ * cucumber
41
+ * flog
42
+
43
+ # Preparing your own dojo
44
+
45
+ Your project must respond to the commands `rake spec` and `cucumber features`, issued from the command line in the root directory. Only code matching `./lib/*.rb` will be included in the flog score.
46
+
47
+ # Credits
48
+
49
+ The original idea came from [Matt Wynne](http://blog.mattwynne.net/)'s session at the [September 2009 London Ruby Users Group](http://lrug.org/meetings/2009/09/18/october-2009-meeting/). I've added the rspec part of the workflow and I'm working on the packaging. The features for the minesweeper kata are his.
50
+
51
+ # Future plans
52
+
53
+ * Get gem published somewhere
54
+ * Provide online repository of known katas
55
+ * Add reset functionality (reset current iteration, or reset whole kata, cleaning up branches).
56
+ * Autodetect number of iterations (currently assumes 5).
57
+
58
+ Ultimately the user should be able to do something like:
59
+
60
+ gem install sensei
61
+ sensei init minesweeper (downloads dojo code for minesweeper)
62
+ cd minesweeper
63
+ sensei start
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe GitTagLister, "when listing tags in a git repo containing tags" do
4
+
5
+ before do
6
+ Dir.mkdir '/tmp/foo'
7
+ Dir.chdir '/tmp/foo' do
8
+ `git init`
9
+ `touch first.txt`
10
+ `git add .`
11
+ `git commit -am "Initial commit"`
12
+ `git tag tag-1`
13
+ `touch test.txt`
14
+ `git add test.txt`
15
+ `git commit -m "Added test file"`
16
+ `git tag otherOne`
17
+ end
18
+ @current_dir = Dir.pwd
19
+ @tags = GitTagLister.new("/tmp/foo").tags
20
+ end
21
+
22
+ after do
23
+ `rm -rf /tmp/foo`
24
+ end
25
+
26
+ it "should list the available tags" do
27
+ @tags.should == ["otherOne", "tag-1"]
28
+ end
29
+
30
+ it "should put the pwd back when it's done" do
31
+ Dir.pwd.should == @current_dir
32
+ end
33
+
34
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe IterationList, "when listing sensei iterations in a git repo containing appropriate tags" do
4
+
5
+ before do
6
+ Dir.mkdir '/tmp/foo'
7
+ Dir.chdir '/tmp/foo' do
8
+ `git init`
9
+ `touch first.txt`
10
+ `git add .`
11
+ `git commit -am "Initial commit"`
12
+ `git tag iteration-1`
13
+ `touch test.txt`
14
+ `git add test.txt`
15
+ `git commit -m "Added test file"`
16
+ `git tag not-an-iteration`
17
+ `touch test2.txt`
18
+ `git add test2.txt`
19
+ `git commit -m "Added test2 file"`
20
+ `git tag iteration-2`
21
+ end
22
+ end
23
+
24
+ after do
25
+ `rm -rf /tmp/foo`
26
+ end
27
+
28
+ it "should count the number of iterations, ignoring tags that are not iterations" do
29
+ IterationList.new("/tmp/foo").iterations.should == 2
30
+ end
31
+
32
+ end
@@ -0,0 +1,2 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/../lib")
2
+ Dir.glob(File.join(File.dirname(__FILE__), '../lib/*.rb')).each {|f| require f }
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sensei
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alex Scordellis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-22 00:00:00 +01:00
13
+ default_executable: sensei
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.8.7
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.6
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: cucumber
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.3.3
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: flog
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.1.0
54
+ version:
55
+ description: Sensei runs your dojo for you. You start with a single failing cucumber feature. As you make each feature pass, the next feature is brought into play. While you have failing features, you have the opportunity to write rspec specifications. Sensei will encourage you to refactor at appropriate moments, showing you your flog score as encouragement.
56
+ email: alex.scordellis@gmail.com
57
+ executables:
58
+ - sensei
59
+ extensions: []
60
+
61
+ extra_rdoc_files: []
62
+
63
+ files:
64
+ - .gitignore
65
+ - VERSION
66
+ - bin/sensei
67
+ - lib/sensei.rb
68
+ - lib/sensei/dojo.rb
69
+ - lib/sensei/git_tag_lister.rb
70
+ - lib/sensei/iteration_list.rb
71
+ - lib/sensei/repository.rb
72
+ - rakefile
73
+ - readme.markdown
74
+ - spec/sensei/git_tag_lister_spec.rb
75
+ - spec/sensei/iteration_list_spec.rb
76
+ - spec/spec_helper.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/alexscordellis/sensei
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: "0"
97
+ version:
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.3.5
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Sensei runs your coding dojo for you.
105
+ test_files:
106
+ - spec/sensei/git_tag_lister_spec.rb
107
+ - spec/sensei/iteration_list_spec.rb
108
+ - spec/spec_helper.rb