turnip 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ .rvmrc
data/README.md CHANGED
@@ -5,12 +5,6 @@ extension for RSpec. It allows you to write tests in Gherkin and run them
5
5
  through your RSpec environment. Basically you can write cucumber features in
6
6
  RSpec.
7
7
 
8
- ## DISCLAIMER, READ THIS!!!
9
-
10
- Turnip is a proof of concept, there are currently VERY FEW TESTS, and there is
11
- a lot of cucumber's syntax it does NOT support. There are currently no tables,
12
- multiline string or scenario outlines.
13
-
14
8
  ## Installation
15
9
 
16
10
  Install the gem
@@ -92,6 +86,16 @@ Given there is a monster called Jonas
92
86
  And there is a monster called "Jonas Nicklas"
93
87
  ```
94
88
 
89
+ You can also specify alternative words and optional parts of words, like this:
90
+
91
+ ``` ruby
92
+ step "there is/are :count monster(s)" do |count|
93
+ @monsters = Array.new(count) { Monster.new }
94
+ end
95
+ ```
96
+
97
+ That will match both "there is X monster" or "there are X monsters".
98
+
95
99
  ## Defining placeholders
96
100
 
97
101
  But what if you want to be more specific in what to match in those
@@ -135,6 +139,42 @@ end
135
139
  These regular expressions must not use anchors, e.g. `^` or `$`. They may not
136
140
  contain named capture groups, e.g. `(?<color>blue|green)`.
137
141
 
142
+ ## Specific steps
143
+
144
+ Sometimes you might want to limit where steps are matched. Turnip allows you to
145
+ do this, through the `:for` option on your steps:
146
+
147
+ ``` ruby
148
+ step "I do it", :for => :interface do
149
+ click_link('Do it')
150
+ end
151
+
152
+ step "I do it", :for => :database do
153
+ Do.it!
154
+ end
155
+ ```
156
+
157
+ Not you can use tags in your feature files to decide which step is going to get
158
+ run:
159
+
160
+ ``` cucumber
161
+ @interface
162
+ Scenario: do it through the interface
163
+
164
+ @database
165
+ Scenario: do it through the database
166
+ ```
167
+
168
+ If you have many steps for the same tag, you can use the `steps_for` helper:
169
+
170
+ ``` ruby
171
+ steps_for :interface do
172
+ step "I do it" do
173
+ ...
174
+ end
175
+ end
176
+ ```
177
+
138
178
  ## Using with Capybara
139
179
 
140
180
  Just require `turnip/capybara`, either in your `spec_helper` or by
File without changes
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ Feature: A feature with multiline strings
2
+ Scenario: This is a feature with multiline strings
3
+ When the monster sings the following song
4
+ """
5
+ Oh here be monsters
6
+ This is cool
7
+ """
8
+ Then the song should have 2 lines
File without changes
@@ -0,0 +1,10 @@
1
+ Feature: using scenario outlines
2
+ Scenario Outline: a simple outline
3
+ Given there is a monster with <hp> hitpoints
4
+ When I attack the monster and do <damage> points damage
5
+ Then the monster should be <state>
6
+
7
+ Examples:
8
+ | hp | damage | state |
9
+ | 10 | 13 | dead |
10
+ | 8 | 5 | alive |
File without changes
data/examples/steps.rb ADDED
@@ -0,0 +1,102 @@
1
+ step "there is a monster" do
2
+ @monster = 1
3
+ end
4
+
5
+ step "there is a strong monster" do
6
+ @monster = 2
7
+ end
8
+
9
+ step "I attack it" do
10
+ @monster -= 1
11
+ end
12
+
13
+ step "it should die" do
14
+ @monster.should eq(0)
15
+ end
16
+
17
+ step "this is ambiguous" do
18
+ end
19
+
20
+ step "this is ambiguous" do
21
+ end
22
+
23
+ step "there is a monster called :name" do |name|
24
+ @monster_name = name
25
+ end
26
+
27
+ step 'it should be called "John Smith"' do
28
+ @monster_name.should == "John Smith"
29
+ end
30
+
31
+ step 'it should be called "John"' do
32
+ @monster_name.should == "John"
33
+ end
34
+
35
+ step "there are :count monkeys with :color hair" do |count, color|
36
+ @monkeys = Array.new(count) { color }
37
+ end
38
+
39
+ step "there should be 3 monkeys with blue hair" do
40
+ @monkeys.should == [:blue, :blue, :blue]
41
+ end
42
+
43
+ step "there is a monster with :count hitpoints" do |count|
44
+ @monster = count
45
+ end
46
+
47
+ step "I attack the monster and do :count points damage" do |count|
48
+ @monster -= count
49
+ end
50
+
51
+ step "the monster should be alive" do
52
+ @monster.should > 0
53
+ end
54
+
55
+ step "the monster should be dead" do
56
+ @monster.should <= 0
57
+ end
58
+
59
+ step "there are the following monsters:" do |table|
60
+ @monsters = {}
61
+ table.hashes.each do |hash|
62
+ @monsters[hash['Name']] = hash['Hitpoints'].to_i
63
+ end
64
+ end
65
+
66
+ step ":name should have :count hitpoints" do |name, count|
67
+ @monsters[name].should eq(count.to_i)
68
+ end
69
+
70
+ step "the monster sings the following song" do |song|
71
+ @song = song
72
+ end
73
+
74
+ step "the song should have :count lines" do |count|
75
+ @song.to_s.split("\n").length.should eq(count)
76
+ end
77
+
78
+ step "the monster has an alignment", :for => :evil do
79
+ @alignment = 'Evil'
80
+ end
81
+
82
+ steps_for :neutral do
83
+ step "the monster has an alignment" do
84
+ @alignment = 'Neutral'
85
+ end
86
+ end
87
+
88
+ step "that alignment should be :alignment" do |alignment|
89
+ @alignment.should eq(alignment)
90
+ end
91
+
92
+ placeholder :count do
93
+ match /\d+/ do |count|
94
+ count.to_i
95
+ end
96
+ end
97
+
98
+ placeholder :color do
99
+ match /blue|green|red/ do |color|
100
+ color.to_sym
101
+ end
102
+ end
@@ -0,0 +1,10 @@
1
+ Feature: Steps for a feature
2
+ @evil
3
+ Scenario:
4
+ Given the monster has an alignment
5
+ Then that alignment should be "Evil"
6
+
7
+ @neutral
8
+ Scenario:
9
+ Given the monster has an alignment
10
+ Then that alignment should be "Neutral"
@@ -0,0 +1,8 @@
1
+ Feature: A feature with tables
2
+ Scenario: This is a feature with a table
3
+ Given there are the following monsters:
4
+ | Name | Hitpoints |
5
+ | Blaaarg | 23 |
6
+ | Moorg | 12 |
7
+ Then "Blaaarg" should have 23 hitpoints
8
+ And "Moorg" should have 12 hitpoints
File without changes
@@ -0,0 +1,12 @@
1
+ # Hi.
2
+ Feature: some feature
3
+ Comments can be (almost) everywhere.
4
+ # And another comment
5
+
6
+ Scenario: some scenario
7
+ # Yet another one.
8
+ Given there is a monster
9
+ When I attack it
10
+ Then it should die
11
+ # Oh my, comments are everywhere.
12
+ # Thank you for reading.
data/lib/turnip.rb CHANGED
@@ -2,18 +2,47 @@ require "gherkin"
2
2
  require "gherkin/formatter/tag_count_formatter"
3
3
 
4
4
  require "turnip/version"
5
- require "turnip/loader"
6
- require "turnip/builder"
7
- require "turnip/run"
8
- require "turnip/step_definition"
9
- require "turnip/placeholder"
10
5
  require "turnip/dsl"
11
- require "turnip/rspec"
12
6
 
13
7
  module Turnip
8
+ autoload :Loader, 'turnip/loader'
9
+ autoload :Builder, 'turnip/builder'
10
+ autoload :StepDefinition, 'turnip/step_definition'
11
+ autoload :Placeholder, 'turnip/placeholder'
12
+ autoload :Table, 'turnip/table'
13
+
14
14
  class << self
15
15
  attr_accessor :type
16
+
17
+ def run(content)
18
+ Turnip::Builder.build(content).features.each do |feature|
19
+ describe feature.name, feature.metadata_hash do
20
+ feature.backgrounds.each do |background|
21
+ before do
22
+ background.steps.each do |step|
23
+ Turnip::StepDefinition.execute(self, step)
24
+ end
25
+ end
26
+ end
27
+ feature.scenarios.each do |scenario|
28
+ it scenario.name, scenario.metadata_hash do
29
+ scenario.steps.each do |step|
30
+ Turnip::StepDefinition.execute(self, step)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
16
37
  end
17
38
  end
18
39
 
19
40
  Turnip.type = :turnip
41
+
42
+ RSpec::Core::Configuration.send(:include, Turnip::Loader)
43
+
44
+ RSpec.configure do |config|
45
+ config.pattern << ",**/*.feature"
46
+ end
47
+
48
+ self.extend Turnip::DSL
@@ -49,7 +49,7 @@ module Turnip
49
49
  include Tags
50
50
  include Name
51
51
 
52
- attr_reader :steps
52
+ attr_accessor :steps
53
53
 
54
54
  def initialize(raw)
55
55
  @raw = raw
@@ -57,16 +57,46 @@ module Turnip
57
57
  end
58
58
  end
59
59
 
60
- class Step
60
+ class ScenarioOutline
61
+ include Tags
61
62
  include Name
62
63
 
64
+ attr_reader :steps
65
+
63
66
  def initialize(raw)
64
67
  @raw = raw
68
+ @steps = []
65
69
  end
70
+
71
+ def to_scenarios(examples)
72
+ rows = examples.rows.map(&:cells)
73
+ headers = rows.shift
74
+ rows.map do |row|
75
+ Scenario.new(@raw).tap do |scenario|
76
+ scenario.steps = steps.map do |step|
77
+ new_description = step.description.gsub(/<([^>]*)>/) { |_| Hash[headers.zip(row)][$1] }
78
+ Step.new(new_description, step.extra_arg)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ class Step < Struct.new(:description, :extra_arg)
66
86
  end
67
87
 
68
88
  attr_reader :features
69
89
 
90
+ class << self
91
+ def build(content)
92
+ Turnip::Builder.new.tap do |builder|
93
+ formatter = Gherkin::Formatter::TagCountFormatter.new(builder, {})
94
+ parser = Gherkin::Parser::Parser.new(formatter, true, "root", false)
95
+ parser.parse(content, nil, 0)
96
+ end
97
+ end
98
+ end
99
+
70
100
  def initialize
71
101
  @features = []
72
102
  end
@@ -86,9 +116,21 @@ module Turnip
86
116
  @current_feature.scenarios << @current_step_context
87
117
  end
88
118
 
119
+ def scenario_outline(outline)
120
+ @current_step_context = ScenarioOutline.new(outline)
121
+ end
122
+
123
+ def examples(examples)
124
+ @current_feature.scenarios.push(*@current_step_context.to_scenarios(examples))
125
+ end
126
+
89
127
  def step(step)
90
- @current_step = Step.new(step)
91
- @current_step_context.steps << @current_step
128
+ if step.doc_string
129
+ extra_arg = step.doc_string.value
130
+ elsif step.rows
131
+ extra_arg = Turnip::Table.new(step.rows.map { |row| row.cells(&:value) })
132
+ end
133
+ @current_step_context.steps << Step.new(step.name, extra_arg)
92
134
  end
93
135
 
94
136
  def eof
data/lib/turnip/dsl.rb CHANGED
@@ -1,7 +1,20 @@
1
1
  module Turnip
2
2
  module DSL
3
- def step(description, &block)
4
- Turnip::StepDefinition.add(description, &block)
3
+ class << self
4
+ attr_accessor :current_taggings
5
+ end
6
+
7
+ def step(description, options={}, &block)
8
+ if Turnip::DSL.current_taggings
9
+ options[:for] = [options[:for], *Turnip::DSL.current_taggings].compact.flatten
10
+ end
11
+ Turnip::StepDefinition.add(description, options, &block)
12
+ end
13
+
14
+ def steps_for(*taggings)
15
+ Turnip::DSL.current_taggings = [taggings, *Turnip::DSL.current_taggings].compact.flatten
16
+ yield
17
+ Turnip::DSL.current_taggings = nil
5
18
  end
6
19
 
7
20
  def placeholder(name, &block)
@@ -9,5 +22,3 @@ module Turnip
9
22
  end
10
23
  end
11
24
  end
12
-
13
- self.extend Turnip::DSL
@@ -1,62 +1,85 @@
1
1
  module Turnip
2
2
  class StepDefinition
3
- class Match < Struct.new(:params, :block); end
3
+ class Match < Struct.new(:step_definition, :params, :block)
4
+ def expression; step_definition.expression; end
5
+ def options; step_definition.options; end
6
+ end
7
+
4
8
  class Pending < StandardError; end
5
9
  class Ambiguous < StandardError; end
6
10
 
7
- attr_reader :expression, :block
11
+ attr_reader :expression, :block, :options
8
12
 
9
13
  class << self
10
- def execute(context, description)
11
- match = find(description)
12
- context.instance_exec(*match.params, &match.block)
14
+ def execute(context, step)
15
+ match = find(step.description, context.example.metadata)
16
+ params = match.params
17
+ params << step.extra_arg if step.extra_arg
18
+ context.instance_exec(*params, &match.block)
13
19
  rescue Pending
14
- context.pending "the step '#{description}' is not implemented"
20
+ context.pending "the step '#{step.description}' is not implemented"
15
21
  end
16
22
 
17
- def add(expression, &block)
18
- steps << StepDefinition.new(expression, &block)
23
+ def add(expression, options={}, &block)
24
+ all << StepDefinition.new(expression, options, &block)
19
25
  end
20
26
 
21
- def find(description)
22
- found = steps.map do |step|
23
- step.match(description)
27
+ def find(description, metadata={})
28
+ found = all.map do |step|
29
+ step.match(description, metadata)
24
30
  end.compact
25
31
  raise Pending, description if found.length == 0
26
32
  raise Ambiguous, description if found.length > 1
27
33
  found[0]
28
34
  end
29
35
 
30
- def steps
31
- @steps ||= []
36
+ def all
37
+ @all ||= []
32
38
  end
33
39
  end
34
40
 
35
- def initialize(expression, &block)
41
+ def initialize(expression, options={}, &block)
36
42
  @expression = expression
37
43
  @block = block
44
+ @options = options
38
45
  end
39
46
 
40
47
  def regexp
41
48
  @regexp ||= compile_regexp
42
49
  end
43
50
 
44
- def match(description)
45
- result = description.match(regexp)
46
- if result
47
- params = result.captures
48
- result.names.each_with_index do |name, index|
49
- params[index] = Turnip::Placeholder.apply(name.to_sym, params[index])
51
+ def match(description, metadata={})
52
+ if matches_metadata?(metadata)
53
+ result = description.match(regexp)
54
+ if result
55
+ params = result.captures
56
+ result.names.each_with_index do |name, index|
57
+ params[index] = Turnip::Placeholder.apply(name.to_sym, params[index])
58
+ end
59
+ Match.new(self, params, block)
50
60
  end
51
- Match.new(params, block)
52
61
  end
53
62
  end
54
63
 
55
64
  protected
56
65
 
66
+ def matches_metadata?(metadata)
67
+ not options[:for] or [options[:for]].flatten.any? { |option| metadata.has_key?(option) }
68
+ end
69
+
70
+ OPTIONAL_WORD_REGEXP = /(\\\s)?\\\(([^)]+)\\\)(\\\s)?/
71
+ PLACEHOLDER_REGEXP = /:([\w]+)/
72
+ ALTERNATIVE_WORD_REGEXP = /(\w+)((\/\w+)+)/
73
+
57
74
  def compile_regexp
58
75
  regexp = Regexp.escape(expression)
59
- regexp = expression.gsub(/:([\w]+)/) do |_|
76
+ regexp.gsub!(OPTIONAL_WORD_REGEXP) do |_|
77
+ [$1, $2, $3].compact.map { |m| "(#{m})?" }.join
78
+ end
79
+ regexp.gsub!(ALTERNATIVE_WORD_REGEXP) do |_|
80
+ "(#{$1}#{$2.tr('/', '|')})"
81
+ end
82
+ regexp.gsub!(PLACEHOLDER_REGEXP) do |_|
60
83
  "(?<#{$1}>#{Placeholder.resolve($1.to_sym)})"
61
84
  end
62
85
  Regexp.new("^#{regexp}$")
@@ -0,0 +1,28 @@
1
+ module Turnip
2
+ class Table
3
+ attr_reader :raw
4
+ alias_method :to_a, :raw
5
+
6
+ include Enumerable
7
+
8
+ def initialize(raw)
9
+ @raw = raw
10
+ end
11
+
12
+ def headers
13
+ @raw.first
14
+ end
15
+
16
+ def rows
17
+ @raw.drop(1)
18
+ end
19
+
20
+ def hashes
21
+ rows.map { |row| Hash[headers.zip(row)] }
22
+ end
23
+
24
+ def each
25
+ @raw.each { |row| yield(row) }
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module Turnip
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnip::Builder do
4
+ context "with scenario outlines" do
5
+ let(:gherkin) { File.read(File.expand_path('../examples/scenario_outline.feature', File.dirname(__FILE__))) }
6
+ let(:builder) { Turnip::Builder.build(gherkin) }
7
+ let(:feature) { builder.features.first }
8
+
9
+
10
+ it "extracts scenarios" do
11
+ feature.scenarios.map(&:name).should eq([
12
+ 'a simple outline',
13
+ 'a simple outline'
14
+ ])
15
+ end
16
+
17
+ it "replaces placeholders in steps" do
18
+ feature.scenarios[0].steps.map(&:description).should eq([
19
+ "there is a monster with 10 hitpoints",
20
+ "I attack the monster and do 13 points damage",
21
+ "the monster should be dead"
22
+ ])
23
+ feature.scenarios[1].steps.map(&:description).should eq([
24
+ "there is a monster with 8 hitpoints",
25
+ "I attack the monster and do 5 points damage",
26
+ "the monster should be alive"
27
+ ])
28
+ end
29
+ end
30
+ end
data/spec/dsl_spec.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnip::DSL do
4
+ before do
5
+ @context = stub
6
+ @context.extend(Turnip::DSL)
7
+ end
8
+
9
+ describe '#step' do
10
+ it 'adds a step to the list of step definitions' do
11
+ Turnip::StepDefinition.should_receive(:add).with('this is a :thing test', {})
12
+ @context.step 'this is a :thing test'
13
+ end
14
+
15
+ it 'sends through options' do
16
+ Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:monkey]})
17
+ @context.step 'foo', :for => [:monkey]
18
+ end
19
+ end
20
+
21
+ describe '#steps_for' do
22
+ it 'executes the given block and adds steps with for set' do
23
+ Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:gorilla]})
24
+ @context.steps_for :gorilla do
25
+ @context.step 'foo'
26
+ end
27
+ end
28
+
29
+ it 'combines step for option and block options' do
30
+ Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:a, :b, :gorilla]})
31
+ @context.steps_for :gorilla do
32
+ @context.step 'foo', :for => [:a, :b]
33
+ end
34
+ end
35
+
36
+ it 'can be nested' do
37
+ Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:c, :b, :a]})
38
+ @context.steps_for :a do
39
+ @context.steps_for :b do
40
+ @context.step 'foo', :for => :c
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '#placeholder' do
47
+ it 'adds a placeholder to the list of placeholders' do
48
+ @context.placeholder :quox do
49
+ match(/foo/) { 'bar' }
50
+ end
51
+ Turnip::Placeholder.apply(:quox, 'foo').should == 'bar'
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The CLI', :type => :integration do
4
+ before do
5
+ @result = %x(rspec -fs examples/*.feature)
6
+ end
7
+
8
+ it "shows the correct description" do
9
+ @result.should include('A simple feature')
10
+ @result.should include('is a simple feature')
11
+ end
12
+
13
+ it "prints out failures and successes" do
14
+ @result.should include('16 examples, 1 failure, 1 pending')
15
+ end
16
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,53 +1,5 @@
1
- step "there is a monster" do
2
- @monster = 1
3
- end
4
-
5
- step "there is a strong monster" do
6
- @monster = 2
7
- end
8
-
9
- step "I attack it" do
10
- @monster -= 1
11
- end
12
-
13
- step "it should die" do
14
- @monster.should eq(0)
15
- end
16
-
17
- step "this is ambiguous" do
18
- end
19
-
20
- step "this is ambiguous" do
21
- end
22
-
23
- step "there is a monster called :name" do |name|
24
- @monster_name = name
25
- end
26
-
27
- step 'it should be called "John Smith"' do
28
- @monster_name.should == "John Smith"
29
- end
30
-
31
- step 'it should be called "John"' do
32
- @monster_name.should == "John"
33
- end
34
-
35
- step "there are :count monkeys with :color hair" do |count, color|
36
- @monkeys = Array.new(count) { color }
37
- end
38
-
39
- step "there should be 3 monkeys with blue hair" do
40
- @monkeys.should == [:blue, :blue, :blue]
41
- end
42
-
43
- placeholder :count do
44
- match /\d+/ do |count|
45
- count.to_i
46
- end
47
- end
48
-
49
- placeholder :color do
50
- match /blue|green|red/ do |color|
51
- color.to_sym
1
+ RSpec.configure do |config|
2
+ config.before(:each, :turnip => true) do
3
+ require File.expand_path('../examples/steps', File.dirname(__FILE__))
52
4
  end
53
5
  end
@@ -0,0 +1,118 @@
1
+ describe Turnip::StepDefinition do
2
+ after do
3
+ Turnip::StepDefinition.all.clear
4
+ end
5
+
6
+ describe ".add" do
7
+ it "adds a step definition to the list of definitions" do
8
+ Turnip::StepDefinition.add "this is a test"
9
+ Turnip::StepDefinition.all.first.expression.should eq("this is a test")
10
+ end
11
+ end
12
+
13
+ describe ".find" do
14
+ it "returns a step definition that matches the description" do
15
+ Turnip::StepDefinition.add "there are :count monsters"
16
+ Turnip::StepDefinition.find("there are 23 monsters").expression.should eq("there are :count monsters")
17
+ end
18
+
19
+ it "respects the for option" do
20
+ Turnip::StepDefinition.add "alignment", :for => [:evil]
21
+ Turnip::StepDefinition.add "alignment", :for => [:good]
22
+ Turnip::StepDefinition.find("alignment", :evil => true, :bad => true).options[:for].should == [:evil]
23
+ end
24
+
25
+ it "raises an error if the match is ambiguous" do
26
+ Turnip::StepDefinition.add "there are :count monsters"
27
+ Turnip::StepDefinition.add "there are 23 monsters"
28
+ expect { Turnip::StepDefinition.find("there are 23 monsters") }.to raise_error(Turnip::StepDefinition::Ambiguous)
29
+ end
30
+
31
+ it "raises an error if there is no match" do
32
+ expect { Turnip::StepDefinition.find("there are 23 monsters") }.to raise_error(Turnip::StepDefinition::Pending)
33
+ end
34
+ end
35
+
36
+ describe ".execute" do
37
+ it "executes a step in the given context" do
38
+ context = stub(:example => stub(:metadata => {}))
39
+ Turnip::StepDefinition.add("there are :count monsters") { @testing = 123 }
40
+ Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => nil))
41
+ context.instance_variable_get(:@testing).should == 123
42
+ end
43
+
44
+ it "tells the context that the step is pending" do
45
+ context = stub(:example => stub(:metadata => {}))
46
+ context.should_receive(:pending).with("the step 'there are 23 monsters' is not implemented")
47
+ Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => nil))
48
+ end
49
+
50
+ it "sends along arguments" do
51
+ context = stub(:example => stub(:metadata => {}))
52
+ Turnip::StepDefinition.add("there are :count monsters") { |count| @testing = count.to_i }
53
+ Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => nil))
54
+ context.instance_variable_get(:@testing).should == 23
55
+ end
56
+
57
+ it "sends along extra arguments" do
58
+ context = stub(:example => stub(:metadata => {}))
59
+ Turnip::StepDefinition.add("there are :count monsters") { |count, extra| @testing = extra }
60
+ Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => 'foo'))
61
+ context.instance_variable_get(:@testing).should == 'foo'
62
+ end
63
+ end
64
+
65
+ describe "#match" do
66
+ it "matches a simple step" do
67
+ step = Turnip::StepDefinition.new("there are monsters") {}
68
+ step.should match("there are monsters")
69
+ step.should_not match("there are monsters around")
70
+ step.should_not match("there are people")
71
+ end
72
+
73
+ it "matches placeholders" do
74
+ Turnip::Placeholder.stub(:resolve).with(:count).and_return(/\d+/)
75
+ step = Turnip::StepDefinition.new("there are :count monsters") {}
76
+ step.should match("there are 4 monsters")
77
+ step.should match("there are 324 monsters")
78
+ step.should_not match("there are no monsters")
79
+ end
80
+
81
+ it "matches alternative words" do
82
+ step = Turnip::StepDefinition.new("there is/are monsters") {}
83
+ step.should match("there are monsters")
84
+ step.should match("there is monsters")
85
+ step.should_not match("there be monsters")
86
+ end
87
+
88
+ it "matches several alternative words" do
89
+ step = Turnip::StepDefinition.new("monsters are cool/nice/scary") {}
90
+ step.should match("monsters are cool")
91
+ step.should match("monsters are nice")
92
+ step.should match("monsters are scary")
93
+ step.should_not match("monsters are sexy")
94
+ end
95
+
96
+ it "matches optional parts of words" do
97
+ step = Turnip::StepDefinition.new("there is/are X monster(s)") {}
98
+ step.should match("there is X monster")
99
+ step.should_not match("there is X monsterQ")
100
+ end
101
+
102
+ it "matches optional words" do
103
+ step = Turnip::StepDefinition.new("there is a (scary) monster") {}
104
+ step.should match("there is a monster")
105
+ step.should match("there is a scary monster")
106
+ step.should_not match("there is a terrifying monster")
107
+
108
+ step = Turnip::StepDefinition.new("there is a monster (that is scary)") {}
109
+ step.should match("there is a monster that is scary")
110
+ step.should match("there is a monster")
111
+
112
+ step = Turnip::StepDefinition.new("(there is) a monster") {}
113
+ step.should match("there is a monster")
114
+ step.should match("a monster")
115
+ end
116
+ end
117
+ end
118
+
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnip::Table do
4
+ describe '#raw' do
5
+ it 'returns the raw table' do
6
+ table = Turnip::Table.new([['foo', 'bar'], ['quox', '42']])
7
+ table.raw.should == [['foo', 'bar'], ['quox', '42']]
8
+ end
9
+ end
10
+
11
+ describe '#to_a' do
12
+ it 'returns the raw table' do
13
+ table = Turnip::Table.new([['foo', 'bar'], ['quox', '42']])
14
+ table.to_a.should == [['foo', 'bar'], ['quox', '42']]
15
+ end
16
+ end
17
+
18
+ describe '#headers' do
19
+ it 'returns the first row' do
20
+ table = Turnip::Table.new([['foo', 'bar'], ['quox', '42']])
21
+ table.headers.should == ['foo', 'bar']
22
+ end
23
+ end
24
+
25
+ describe '#rows' do
26
+ it 'returns the rows beyond the first' do
27
+ table = Turnip::Table.new([['foo', 'bar'], ['moo', '55'], ['quox', '42']])
28
+ table.rows.should == [['moo', '55'], ['quox', '42']]
29
+ end
30
+ end
31
+
32
+ describe '#hashes' do
33
+ it 'returns a list of hashe based on the headers' do
34
+ table = Turnip::Table.new([['foo', 'bar'], ['moo', '55'], ['quox', '42']])
35
+ table.hashes.should == [
36
+ {'foo' => 'moo', 'bar' => '55'},
37
+ {'foo' => 'quox', 'bar' => '42'}
38
+ ]
39
+ end
40
+ end
41
+
42
+ describe '#map' do
43
+ it 'iterates over the raw table' do
44
+ table = Turnip::Table.new([['moo', '55'], ['quox', '42']])
45
+ table.map(&:first).should == ['moo', 'quox']
46
+ end
47
+ end
48
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turnip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-25 00:00:00.000000000Z
12
+ date: 2011-11-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &2153850520 !ruby/object:Gem::Requirement
16
+ requirement: &2152642360 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '2.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153850520
24
+ version_requirements: *2152642360
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: gherkin
27
- requirement: &2153850100 !ruby/object:Gem::Requirement
27
+ requirement: &2152641940 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153850100
35
+ version_requirements: *2152641940
36
36
  description: Provides the ability to define steps and run Gherkin files from with
37
37
  RSpec
38
38
  email:
@@ -46,24 +46,34 @@ files:
46
46
  - Gemfile
47
47
  - README.md
48
48
  - Rakefile
49
+ - examples/ambiguous.feature
50
+ - examples/backgrounds.feature
51
+ - examples/interpolation.feature
52
+ - examples/multiline_string.feature
53
+ - examples/pending.feature
54
+ - examples/scenario_outline.feature
55
+ - examples/simple_feature.feature
56
+ - examples/steps.rb
57
+ - examples/steps_for.feature
58
+ - examples/table.feature
59
+ - examples/tags.feature
60
+ - examples/with_comments.feature
49
61
  - lib/turnip.rb
50
62
  - lib/turnip/builder.rb
51
63
  - lib/turnip/capybara.rb
52
64
  - lib/turnip/dsl.rb
53
65
  - lib/turnip/loader.rb
54
66
  - lib/turnip/placeholder.rb
55
- - lib/turnip/rspec.rb
56
- - lib/turnip/run.rb
57
67
  - lib/turnip/step_definition.rb
68
+ - lib/turnip/table.rb
58
69
  - lib/turnip/version.rb
59
- - spec/fixture/ambiguous.feature
60
- - spec/fixture/backgrounds.feature
61
- - spec/fixture/interpolation.feature
62
- - spec/fixture/pending.feature
63
- - spec/fixture/simple_feature.feature
64
- - spec/fixture/tags.feature
70
+ - spec/builder_spec.rb
71
+ - spec/dsl_spec.rb
72
+ - spec/integration_spec.rb
65
73
  - spec/placeholder_spec.rb
66
74
  - spec/spec_helper.rb
75
+ - spec/step_definition_spec.rb
76
+ - spec/table_spec.rb
67
77
  - turnip.gemspec
68
78
  homepage: ''
69
79
  licenses: []
@@ -85,16 +95,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
95
  version: '0'
86
96
  requirements: []
87
97
  rubyforge_project: turnip
88
- rubygems_version: 1.8.6
98
+ rubygems_version: 1.8.10
89
99
  signing_key:
90
100
  specification_version: 3
91
101
  summary: Gherkin extension for RSpec
92
102
  test_files:
93
- - spec/fixture/ambiguous.feature
94
- - spec/fixture/backgrounds.feature
95
- - spec/fixture/interpolation.feature
96
- - spec/fixture/pending.feature
97
- - spec/fixture/simple_feature.feature
98
- - spec/fixture/tags.feature
103
+ - spec/builder_spec.rb
104
+ - spec/dsl_spec.rb
105
+ - spec/integration_spec.rb
99
106
  - spec/placeholder_spec.rb
100
107
  - spec/spec_helper.rb
108
+ - spec/step_definition_spec.rb
109
+ - spec/table_spec.rb
data/lib/turnip/rspec.rb DELETED
@@ -1,5 +0,0 @@
1
- RSpec::Core::Configuration.send(:include, Turnip::Loader)
2
-
3
- RSpec.configure do |config|
4
- config.pattern << ",**/*.feature"
5
- end
data/lib/turnip/run.rb DELETED
@@ -1,27 +0,0 @@
1
- module Turnip
2
- def self.run(content)
3
- builder = Turnip::Builder.new
4
- formatter = Gherkin::Formatter::TagCountFormatter.new(builder, {})
5
- parser = Gherkin::Parser::Parser.new(formatter, true, "root", false)
6
- parser.parse(content, nil, 0)
7
-
8
- builder.features.each do |feature|
9
- describe feature.name, feature.metadata_hash do
10
- feature.backgrounds.each do |background|
11
- before do
12
- background.steps.each do |step|
13
- Turnip::StepDefinition.execute(self, step.name)
14
- end
15
- end
16
- end
17
- feature.scenarios.each do |scenario|
18
- it scenario.name, scenario.metadata_hash do
19
- scenario.steps.each do |step|
20
- Turnip::StepDefinition.execute(self, step.name)
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end