turnip 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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