rbehave 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/CHANGELOG.txt +5 -0
  2. data/Manifest.txt +44 -17
  3. data/NOTES.txt +2 -7
  4. data/behaviour/everything.rb +1 -1
  5. data/behaviour/examples/{everything.rb → examples.rb} +0 -0
  6. data/behaviour/examples/rbehave/documenter/plain_text_documenter_behaviour.rb +1 -0
  7. data/behaviour/examples/rbehave/given_scenario_behaviour.rb +26 -0
  8. data/behaviour/examples/rbehave/runner/options_behaviour.rb +39 -0
  9. data/behaviour/examples/rbehave/runner/runner_behaviour.rb +39 -0
  10. data/behaviour/examples/rbehave/runner/story_runner_behaviour.rb +58 -2
  11. data/behaviour/examples/rbehave/simple_step_behaviour.rb +35 -0
  12. data/behaviour/examples/rbehave/step_mother_behaviour.rb +32 -0
  13. data/behaviour/examples/rbehave/world_behaviour.rb +44 -5
  14. data/behaviour/examples/rspec_adapter.rb +3 -1
  15. data/examples/game-of-life/.loadpath +5 -0
  16. data/examples/game-of-life/.project +18 -0
  17. data/examples/game-of-life/README.txt +21 -0
  18. data/examples/game-of-life/behaviour/everything.rb +2 -0
  19. data/examples/game-of-life/behaviour/examples/examples.rb +2 -0
  20. data/examples/game-of-life/behaviour/examples/game_behaviour.rb +17 -0
  21. data/examples/game-of-life/behaviour/examples/grid_behaviour.rb +68 -0
  22. data/examples/game-of-life/behaviour/examples/helper.rb +2 -0
  23. data/examples/game-of-life/behaviour/stories/CellsWithLessThanTwoNeighboursDie.story +21 -0
  24. data/examples/game-of-life/behaviour/stories/CellsWithMoreThanThreeNeighboursDie.story +21 -0
  25. data/examples/game-of-life/behaviour/stories/EmptySpacesWithThreeNeighboursCreateACell.story +42 -0
  26. data/examples/game-of-life/behaviour/stories/ICanCreateACell.story +42 -0
  27. data/examples/game-of-life/behaviour/stories/ICanKillACell.story +17 -0
  28. data/examples/game-of-life/behaviour/stories/TheGridWraps.story +53 -0
  29. data/examples/game-of-life/behaviour/stories/create_a_cell.rb +58 -0
  30. data/examples/game-of-life/behaviour/stories/stories.txt +22 -0
  31. data/examples/game-of-life/life.rb +2 -0
  32. data/examples/game-of-life/life/game.rb +6 -0
  33. data/examples/game-of-life/life/grid.rb +38 -0
  34. data/lib/rbehave.rb +6 -71
  35. data/lib/rbehave/documenter/plain_text_documenter.rb +2 -2
  36. data/lib/rbehave/exceptions.rb +3 -3
  37. data/lib/rbehave/given_scenario.rb +12 -0
  38. data/lib/rbehave/runner.rb +52 -0
  39. data/lib/rbehave/runner/options.rb +26 -0
  40. data/lib/rbehave/runner/story_runner.rb +26 -5
  41. data/lib/rbehave/simple_step.rb +14 -0
  42. data/lib/rbehave/step_mother.rb +19 -0
  43. data/lib/rbehave/story.rb +8 -3
  44. data/lib/rbehave/version.rb +1 -1
  45. data/lib/rbehave/world.rb +31 -23
  46. metadata +47 -19
  47. data/Rakefile +0 -54
@@ -0,0 +1,2 @@
1
+ require 'life/game'
2
+ require 'life/grid'
@@ -0,0 +1,6 @@
1
+ class Game
2
+ attr_accessor :grid
3
+ def initialize(rows,cols)
4
+ @grid = Grid.new(rows, cols)
5
+ end
6
+ end
@@ -0,0 +1,38 @@
1
+ class Grid
2
+
3
+ attr_accessor :contents
4
+
5
+ def initialize(rows, cols)
6
+ @contents = []
7
+ rows.times do @contents << [0] * cols end
8
+ end
9
+
10
+ def rows
11
+ @contents.size
12
+ end
13
+
14
+ def columns
15
+ @contents[0].size
16
+ end
17
+
18
+ def ==(other)
19
+ self.contents == other.contents
20
+ end
21
+
22
+ def create_at(row,col)
23
+ @contents[row][col] = 1
24
+ end
25
+
26
+ def self.from_s(str)
27
+ row_strings = str.split
28
+ grid = Grid.new(row_strings.size, row_strings[0].size)
29
+
30
+ row_strings.each_with_index do |row, r|
31
+ row.split(//).each_with_index do |col, c|
32
+ grid.create_at(r,c) if col == 'X'
33
+ end
34
+ end
35
+ return grid
36
+ end
37
+
38
+ end
data/lib/rbehave.rb CHANGED
@@ -1,72 +1,7 @@
1
- Dir[File.join(File.dirname(__FILE__), 'rbehave/**/*.rb')].sort.each { |lib| require lib }
1
+ Dir.chdir(File.dirname(__FILE__)) do
2
+ Dir['rbehave/**/*.rb'].each { |f| require f }
3
+ end
2
4
 
3
- module RBehave
4
- def Story(title, narrative, &body)
5
- RBehave::Runner::story_runner.Story(title, narrative, &body)
6
- end
7
-
8
- def self.included(into)
9
- RBehave::Runner.register_instance
10
- end
11
-
12
- module Runner
13
- class << self
14
- def story_runner
15
- unless @story_runner
16
- scenario_runner = ScenarioRunner.new
17
- world_creator = World
18
- @story_runner = StoryRunner.new(scenario_runner, world_creator)
19
- if ARGV.empty?
20
- reporter = RBehave::Reporter::PlainTextReporter.new($stdout)
21
- scenario_runner.add_listener(reporter)
22
- @story_runner.add_listener(reporter)
23
- else
24
- documenter = RBehave::Documenter::PlainTextDocumenter.new($stdout)
25
- scenario_runner.add_listener(documenter)
26
- @story_runner.add_listener(documenter)
27
- world_creator.add_listener(documenter)
28
- self.dry_run = true
29
- end
30
- end
31
- @story_runner
32
- end
33
-
34
- def register_instance
35
- return if registered?
36
- unless registered?
37
- registered = true
38
- Exception.add_backtrace_filter(/lib\/rbehave/)
39
- Exception.add_backtrace_filter(/gems\/rspec/)
40
- at_exit do
41
- exit RBehave::Runner.run unless $! || RBehave::Runner.run?
42
- end
43
- end
44
- end
45
-
46
- def registered?
47
- @registered ||= false
48
- end
49
-
50
- def run?
51
- @run ||= false
52
- end
53
-
54
- def run=(value)
55
- @run = value
56
- end
57
-
58
- def run
59
- story_runner.run_stories
60
- self.run = true
61
- end
62
-
63
- def dry_run?
64
- @dry_run ||= false
65
- end
66
-
67
- def dry_run=(value)
68
- @dry_run = value
69
- end
70
- end
71
- end
72
- end
5
+ def Story(title, narrative, params = {}, &body)
6
+ RBehave::Runner.story_runner.Story(title, narrative, params, &body)
7
+ end
@@ -17,8 +17,8 @@ module RBehave
17
17
  @out << "\nScenario: #{scenario_name}\n"
18
18
  end
19
19
 
20
- def found_step(name, description)
21
- @out << " #{name.to_s.capitalize} #{description}\n"
20
+ def found_step(name, description, *args)
21
+ @out << " #{name.to_s.capitalize} #{description} #{args.join ','}\n"
22
22
  end
23
23
 
24
24
  def method_missing(meth, *args, &block)
@@ -1,6 +1,6 @@
1
1
  module RBehave
2
- class PendingException < StandardError
3
- end
2
+ class PendingException < StandardError; end
3
+ class UnknownStepException < StandardError; end
4
4
  end
5
5
 
6
6
  class Exception
@@ -14,7 +14,7 @@ class Exception
14
14
  end
15
15
 
16
16
  def filtered_backtrace
17
- trace = backtrace || []
17
+ return trace = backtrace || []
18
18
  trace.reject do |line|
19
19
  Exception.backtrace_filters.inject(false) do |already_matched, filter|
20
20
  already_matched || line =~ filter
@@ -0,0 +1,12 @@
1
+ module RBehave
2
+ class GivenScenario
3
+ def initialize name
4
+ @name = name
5
+ end
6
+
7
+ def perform(instance, *args)
8
+ scenario = Runner::StoryRunner.scenario_from_current_story @name
9
+ Runner::ScenarioRunner.new.run(scenario, instance)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,52 @@
1
+ module RBehave
2
+ module Runner
3
+ class << self
4
+ def options
5
+ @options ||= Options.new.parse ARGV
6
+ end
7
+
8
+ def story_runner
9
+ unless @story_runner
10
+ scenario_runner = ScenarioRunner.new
11
+ RBehave::Runner.register_exit_hook
12
+ world_creator = World
13
+ @story_runner = StoryRunner.new(scenario_runner, world_creator)
14
+ unless options.dry_run
15
+ reporter = RBehave::Reporter::PlainTextReporter.new($stdout)
16
+ scenario_runner.add_listener(reporter)
17
+ @story_runner.add_listener(reporter)
18
+ end
19
+ case options.format
20
+ when :simple then documenter = RBehave::Documenter::PlainTextDocumenter.new($stdout)
21
+ when nil ;
22
+ else raise "Unimplemented format - #{options.format.to_s}"
23
+ end
24
+ if documenter
25
+ scenario_runner.add_listener(documenter)
26
+ @story_runner.add_listener(documenter)
27
+ world_creator.add_listener(documenter)
28
+ end
29
+ end
30
+ @story_runner
31
+ end
32
+
33
+ def register_exit_hook
34
+ Exception.add_backtrace_filter(/lib\/rbehave/)
35
+ Exception.add_backtrace_filter(/gems\/rbehave/)
36
+ Exception.add_backtrace_filter(/gems\/rspec/)
37
+ at_exit do
38
+ RBehave::Runner.story_runner.run_stories unless $!
39
+ # TODO exit with non-zero status if run fails
40
+ end
41
+ end
42
+
43
+ def dry_run?
44
+ @dry_run ||= false
45
+ end
46
+
47
+ def dry_run=(value)
48
+ @dry_run = value
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ require 'optparse'
2
+
3
+ module RBehave
4
+ module Runner
5
+ class Options
6
+ attr_accessor :format, :dry_run
7
+
8
+ def parse(args)
9
+ parser = OptionParser.new do |p|
10
+ p.banner = "Usage: ruby your_stories.rb [options]"
11
+ p.separator ""
12
+ p.separator "Options:"
13
+ p.on "-n", "--dry-run", "dry run - no execution" do
14
+ @dry_run = true
15
+ end
16
+ formats = [:simple, :rdoc, :html, :xml]
17
+ p.on "-f", "--format ", formats, "format (#{formats.join(',')})" do |fmt|
18
+ @format = fmt.to_sym
19
+ end
20
+ end
21
+ parser.parse(args)
22
+ self
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,9 +1,22 @@
1
1
  module RBehave
2
2
  module Runner
3
3
  class StoryRunner
4
- attr_accessor :stories, :scenarios
4
+ class << self
5
+ attr_accessor :current_story_runner
6
+
7
+ def current_story
8
+ current_story_runner.current_story
9
+ end
10
+
11
+ def scenario_from_current_story(scenario_name)
12
+ current_story_runner.scenario_from_current_story(scenario_name)
13
+ end
14
+ end
15
+
16
+ attr_accessor :stories, :scenarios, :current_story
5
17
 
6
18
  def initialize(scenario_runner, world_creator = World)
19
+ StoryRunner.current_story_runner = self
7
20
  @scenario_runner = scenario_runner
8
21
  @world_creator = world_creator
9
22
  @stories = []
@@ -12,8 +25,8 @@ module RBehave
12
25
  @listeners = []
13
26
  end
14
27
 
15
- def Story(title, narrative, &body)
16
- story = Story.new(title, narrative, &body)
28
+ def Story(title, narrative, params = {}, &body)
29
+ story = Story.new(title, narrative, params, &body)
17
30
  @stories << story
18
31
 
19
32
  # collect scenarios
@@ -24,12 +37,16 @@ module RBehave
24
37
  end
25
38
 
26
39
  def run_stories
40
+ return if @stories.empty?
27
41
  @listeners.each { |l| l.run_started(scenarios.size) }
28
42
  @stories.each do |story|
43
+ @current_story = story
29
44
  @listeners.each { |l| l.story_started(story.title, story.narrative) }
30
45
  scenarios = @scenarios_by_story[story.title]
31
46
  scenarios.each do |scenario|
32
- @scenario_runner.run(scenario, @world_creator.create)
47
+ type = story[:type] || Object
48
+ args = story[:args] || []
49
+ @scenario_runner.run(scenario, @world_creator.create(type, *args))
33
50
  end
34
51
  @listeners.each { |l| l.story_ended(story.title, story.narrative) }
35
52
  end
@@ -39,6 +56,10 @@ module RBehave
39
56
  def add_listener(listener)
40
57
  @listeners << listener
41
58
  end
59
+
60
+ def scenario_from_current_story(scenario_name)
61
+ @scenarios_by_story[@current_story.title].find {|s| s.name == scenario_name }
62
+ end
42
63
  end
43
64
  end
44
- end
65
+ end
@@ -0,0 +1,14 @@
1
+ module RBehave
2
+ class SimpleStep
3
+ def initialize(name, &block)
4
+ @name = name
5
+ @mod = Module.new
6
+ @mod.__send__(:define_method, @name, &block)
7
+ end
8
+
9
+ def perform(instance, *args)
10
+ instance.extend(@mod)
11
+ instance.__send__(@name, *args)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module RBehave
2
+ class StepMother
3
+ def initialize
4
+ @steps = Hash.new do |hsh,key|
5
+ hsh[key] = Hash.new do |hsh,key|
6
+ raise UnknownStepException, key
7
+ end
8
+ end
9
+ end
10
+
11
+ def store(type, name, step)
12
+ @steps[type][name] = step
13
+ end
14
+
15
+ def find(type, name)
16
+ @steps[type][name]
17
+ end
18
+ end
19
+ end
data/lib/rbehave/story.rb CHANGED
@@ -2,14 +2,19 @@ module RBehave
2
2
  class Story
3
3
  attr_reader :title, :narrative
4
4
 
5
- def initialize(title, narrative, &body)
5
+ def initialize(title, narrative, params = {}, &body)
6
6
  @body = body
7
7
  @title = title
8
8
  @narrative = narrative
9
+ @params = params
9
10
  end
10
11
 
11
- def run_in(container)
12
- container.instance_eval(&@body)
12
+ def [](key)
13
+ @params[key]
14
+ end
15
+
16
+ def run_in(obj)
17
+ obj.instance_eval(&@body)
13
18
  end
14
19
  end
15
20
  end
@@ -1,7 +1,7 @@
1
1
  module Rbehave #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 1
4
+ MINOR = 2
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
data/lib/rbehave/world.rb CHANGED
@@ -9,22 +9,11 @@ module RBehave
9
9
  =end
10
10
  module World
11
11
  # store steps and listeners in the singleton metaclass.
12
- # This serves both to keep them out of the way and to
13
- # make them available to all instances.
12
+ # This serves both to keep them out of the way of runtime Worlds
13
+ # and to make them available to all instances.
14
14
  class << self
15
- def create(cls = Object)
16
- cls.new.extend(World)
17
- end
18
-
19
- def store_and_call(instance, type, name, &block)
20
- @step_mother ||= Hash.new {|hsh,key| hsh[key] = Hash.new }
21
- if block_given?
22
- @step_mother[type][name] = block
23
- else
24
- block = @step_mother[type][name]
25
- end
26
- listeners.each { |l| l.found_step(type, name) }
27
- instance.instance_eval(&block) unless RBehave::Runner.dry_run?
15
+ def create(cls = Object, *args)
16
+ cls.new(*args).extend(World)
28
17
  end
29
18
 
30
19
  def listeners
@@ -32,24 +21,43 @@ module RBehave
32
21
  end
33
22
 
34
23
  def add_listener(listener)
35
- listeners << listener
24
+ listeners() << listener
25
+ end
26
+
27
+ def step_mother
28
+ @step_mother ||= StepMother.new
36
29
  end
30
+
31
+ def store_and_call(instance, type, name, *args, &block)
32
+ if block_given?
33
+ step_mother.store(type, name, SimpleStep.new(name, &block))
34
+ end
35
+ step = step_mother.find(type, name)
36
+ listeners.each { |l| l.found_step(type, name, *args) }
37
+ step.perform(instance, *args) unless RBehave::Runner.dry_run?
38
+ end
39
+ end
40
+
41
+ def GivenScenario(name)
42
+ step = GivenScenario.new name
43
+ World.step_mother.store(:given_scenario, name, step)
44
+ World.store_and_call self, :given_scenario, name
37
45
  end
38
46
 
39
- def Given(name, &block)
40
- World.store_and_call self, :given, name, &block
47
+ def Given(name, *args, &block)
48
+ World.store_and_call self, :given, name, *args, &block
41
49
  end
42
50
 
43
- def When(name, &block)
44
- World.store_and_call self, :when, name, &block
51
+ def When(name, *args, &block)
52
+ World.store_and_call self, :when, name, *args, &block
45
53
  end
46
54
 
47
- def Then(name, &block)
48
- World.store_and_call self, :then, name, &block
55
+ def Then(name, *args, &block)
56
+ World.store_and_call self, :then, name, *args, &block
49
57
  end
50
58
 
51
59
  def pending(message = 'todo')
52
- raise PendingException, message
60
+ raise PendingException, message unless RBehave::Runner.dry_run?
53
61
  end
54
62
  end
55
63
  end