Created
October 11, 2010 13:20
-
-
Save manveru/620493 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'bacon' | |
| Bacon.summary_on_exit | |
| Bacon.extend Bacon::TestUnitOutput | |
| require 'strscan' | |
| module Bacon | |
| class Story | |
| attr_reader :text, :scenarios, :scanner, :indent, :name, :matches | |
| def initialize(text, &block) | |
| @text = text | |
| @meta = {} | |
| @matches = {} | |
| @scenarios = [] | |
| yield self | |
| end | |
| def run | |
| parse | |
| end | |
| def match(regex, &block) | |
| @matches[regex] = block | |
| end | |
| private | |
| def parse | |
| @scanner = StringScanner.new(text) | |
| until scanner.eos? | |
| if scan(/^Story:\s+(.*)$/) | |
| @name = scanner[1].strip | |
| @indent = 1 | |
| @story = parse_story | |
| elsif scan(/\s+/m) | |
| else | |
| raise scanner.inspect | |
| end | |
| end | |
| end | |
| def parse_story | |
| adjust_indentation | |
| @scenario = nil | |
| until @scenario | |
| if scan(/^#{indent}Scenario:\s+(.*)$/) | |
| @scenario = Scenario.new(self, scanner.matched.strip) | |
| parse_scenario | |
| @scenarios << @scenario | |
| elsif scan(/^#{indent}(.*?):\s+(.*)$/) | |
| @meta[$1] = $2 | |
| elsif scan(/\n+/) | |
| else | |
| raise scanner.inspect | |
| end | |
| end | |
| end | |
| def parse_scenario | |
| adjust_indentation | |
| while scanner.scan(/^#{indent}/) | |
| if scan(/(\w.*?)$/) | |
| @scenario.lines << scanner.matched.strip | |
| scan(/\n+/) | |
| else | |
| raise scanner.inspect | |
| end | |
| end | |
| @scenario.run | |
| end | |
| def adjust_indentation | |
| scan(/^\s*/) | |
| @indent = scanner.matched.sub(/^\n+/, '') | |
| scanner.unscan | |
| scanner.scan(/\n+/) | |
| end | |
| def scan(regex) | |
| scanner.scan(regex) | |
| end | |
| end | |
| class Scenario | |
| attr_reader :name, :lines, :matches, :story | |
| def initialize(story, name) | |
| @story, @name = story, name | |
| @lines = [] | |
| end | |
| def run | |
| $scenario_self = self | |
| describe story.name do | |
| @self = s = $scenario_self | |
| @story, @name, @lines = s.story, s.name, s.lines | |
| @matches = s.story.matches | |
| should @name do | |
| @lines.each do |line| | |
| if match = @matches.find{|r,b| line =~ r} | |
| match[1].call(*$~.captures) | |
| else | |
| raise "Unknown match: #{line}" | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end | |
| text = <<TEXT | |
| Story: Publish speakers | |
| As a: conference organizer | |
| I want to: publish the list of speakers | |
| So that: as many people as possible will come | |
| Scenario: 2 new speakers | |
| Given an presentation without speakers | |
| When I add 2 speakers | |
| Then I should see 2 speakers | |
| TEXT | |
| Bacon::Story.new(text) do |story| | |
| story.match(/Given an presentation without speakers/) do | |
| @presentation = [] | |
| end | |
| story.match(/When I add (\d+) speakers/) do |n| | |
| @presentation += Array.new(n.to_i, :speaker) | |
| end | |
| story.match(/Then I should see (\d+) speakers/) do |n| | |
| @presentation.size.should == n.to_i | |
| end | |
| story.run | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment