turnip 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -1,10 +1,15 @@
1
1
  # Turnip
2
2
 
3
- Turnip is a [Gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin) extension for RSpec. It allows you to write tests in Gherkin and run them through your RSpec environment. Basically you can write cucumber features in RSpec.
3
+ Turnip is a [Gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin)
4
+ extension for RSpec. It allows you to write tests in Gherkin and run them
5
+ through your RSpec environment. Basically you can write cucumber features in
6
+ RSpec.
4
7
 
5
8
  ## DISCLAIMER, READ THIS!!!
6
9
 
7
- Turnip is a proof of concept, there are currently NO TESTS, and there is a lot of cucumber's syntax it does NOT support. There are currently no tables, multiline string or scenario outlines.
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.
8
13
 
9
14
  ## Installation
10
15
 
@@ -22,12 +27,17 @@ group :test do
22
27
  end
23
28
  ```
24
29
 
25
- Now edit the `.rspec` file in your project directory (create it if doesn't exist), and add the following line:
30
+ Now edit the `.rspec` file in your project directory (create it if doesn't
31
+ exist), and add the following line:
26
32
 
27
33
  ```
28
34
  -r turnip
29
35
  ```
30
36
 
37
+ ## Compatibility
38
+
39
+ Turnip does not work on Ruby 1.8.X.
40
+
31
41
  ## Usage
32
42
 
33
43
  Add a feature file anywhere in your `spec` directory:
@@ -49,13 +59,16 @@ Now you can run it just like you would run any other rspec spec:
49
59
  rspec spec/acceptance/attack_monster.feature
50
60
  ```
51
61
 
52
- It will automatically be run if you run all your specs with `rake spec` or `rspec spec`.
62
+ It will automatically be run if you run all your specs with `rake spec` or
63
+ `rspec spec`.
53
64
 
54
65
  Yes, that's really it.
55
66
 
56
67
  ## Defining steps
57
68
 
58
- You might want to define some steps. You can put them anywhere. Turnip automatically requires your `spec_helper`, so you can add them there or put them in separate files (recommended). Define them like this:
69
+ You might want to define some steps. You can put them anywhere. Turnip
70
+ automatically requires your `spec_helper`, so you can add them there or put
71
+ them in separate files (recommended). Define them like this:
59
72
 
60
73
  ``` ruby
61
74
  step "there is a monster" do
@@ -64,3 +77,94 @@ end
64
77
  ```
65
78
 
66
79
  Note that unlike Cucumber, Turnip does not support regexps in step definitions.
80
+ You can however use placeholders in your step definitions, like this:
81
+
82
+ ``` ruby
83
+ step "there is a monster called :name" do |name|
84
+ @monster = Monster.new(name)
85
+ end
86
+ ```
87
+
88
+ You can now put values in this placeholder, either quoted or not:
89
+
90
+ ``` cucumber
91
+ Given there is a monster called Jonas
92
+ And there is a monster called "Jonas Nicklas"
93
+ ```
94
+
95
+ ## Defining placeholders
96
+
97
+ But what if you want to be more specific in what to match in those
98
+ placeholders, and it is bothersome to have to constantly cast them to the
99
+ correct type. Turnip's placeholder solve both problems, like this:
100
+
101
+ ``` ruby
102
+ step "there are :count monsters" do |count|
103
+ count.times { Monster.new(name) }
104
+ end
105
+
106
+ placeholder :count do
107
+ match /\d+/ do |count|
108
+ count.to_i
109
+ end
110
+
111
+ match /no/ do
112
+ 0
113
+ end
114
+ end
115
+ ```
116
+
117
+ You would now be able to use these steps like this:
118
+
119
+ ``` cucumber
120
+ Given there are 4 monsters
121
+ Given there are no monsters
122
+ ```
123
+
124
+ Placeholders can extract matches from the regular expressions as well. For
125
+ example:
126
+
127
+ ``` ruby
128
+ placeholder :monster do
129
+ match /(blue|green|red) (furry|bald) monster/ do |color, hair|
130
+ Monster.new(color, hair)
131
+ end
132
+ end
133
+ ```
134
+
135
+ These regular expressions must not use anchors, e.g. `^` or `$`. They may not
136
+ contain named capture groups, e.g. `(?<color>blue|green)`.
137
+
138
+ ## Using with Capybara
139
+
140
+ Just require `turnip/capybara`, either in your `spec_helper` or by
141
+ adding `-r turnip/capybara` to your `.rspec` file. You can now use the
142
+ same tags you'd use in Cucumber to switch between drivers e.g.
143
+ `@javascript` or `@selenium`. Your Turnip features will also be run
144
+ with the `:type => :request` metadata, so that Capybara is included and
145
+ also any other extensions you might want to add.
146
+
147
+ ## License
148
+
149
+ (The MIT License)
150
+
151
+ Copyright (c) 2011 Jonas Nicklas
152
+
153
+ Permission is hereby granted, free of charge, to any person obtaining
154
+ a copy of this software and associated documentation files (the
155
+ 'Software'), to deal in the Software without restriction, including
156
+ without limitation the rights to use, copy, modify, merge, publish,
157
+ distribute, sublicense, and/or sell copies of the Software, and to
158
+ permit persons to whom the Software is furnished to do so, subject to
159
+ the following conditions:
160
+
161
+ The above copyright notice and this permission notice shall be
162
+ included in all copies or substantial portions of the Software.
163
+
164
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
165
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
166
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
167
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
168
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
169
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
170
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -5,6 +5,15 @@ require "turnip/version"
5
5
  require "turnip/loader"
6
6
  require "turnip/builder"
7
7
  require "turnip/run"
8
- require "turnip/steps"
8
+ require "turnip/step_definition"
9
+ require "turnip/placeholder"
9
10
  require "turnip/dsl"
10
11
  require "turnip/rspec"
12
+
13
+ module Turnip
14
+ class << self
15
+ attr_accessor :type
16
+ end
17
+ end
18
+
19
+ Turnip.type = :turnip
@@ -1,61 +1,70 @@
1
1
  module Turnip
2
- class Feature
3
- attr_reader :scenarios, :backgrounds
4
- def initialize(raw)
5
- @raw = raw
6
- @scenarios = []
7
- @backgrounds = []
8
- end
2
+ class Builder
3
+ module Tags
4
+ def tags
5
+ @raw.tags.map { |tag| tag.name.sub(/^@/, '') }
6
+ end
9
7
 
10
- def name
11
- @raw.name
12
- end
13
- end
8
+ def tags_hash
9
+ Hash[tags.map { |t| [t.to_sym, true] }]
10
+ end
14
11
 
15
- class Background
16
- attr_reader :steps
17
- def initialize(raw)
18
- @raw = raw
19
- @steps = []
12
+ def metadata_hash
13
+ tags_hash
14
+ end
20
15
  end
21
- end
22
16
 
23
- class Scenario
24
- attr_reader :name, :steps
25
- def initialize(raw)
26
- @raw = raw
27
- @steps = []
17
+ module Name
18
+ def name
19
+ @raw.name
20
+ end
28
21
  end
29
22
 
30
- def name
31
- @raw.name
32
- end
23
+ class Feature
24
+ include Tags
25
+ include Name
33
26
 
34
- def tags
35
- @raw.tags.map { |tag| tag.name.sub(/^@/, '').to_sym }
36
- end
27
+ attr_reader :scenarios, :backgrounds
37
28
 
38
- def tags_hash
39
- Hash[tags.map { |t| [t, true] }]
29
+ def initialize(raw)
30
+ @raw = raw
31
+ @scenarios = []
32
+ @backgrounds = []
33
+ end
34
+
35
+ def metadata_hash
36
+ super.merge(:type => Turnip.type, :turnip => true)
37
+ end
40
38
  end
41
39
 
42
- def metadata_hash
43
- tags_hash
40
+ class Background
41
+ attr_reader :steps
42
+ def initialize(raw)
43
+ @raw = raw
44
+ @steps = []
45
+ end
44
46
  end
45
- end
46
47
 
47
- class Step
48
- attr_reader :name
49
- def initialize(raw)
50
- @raw = raw
48
+ class Scenario
49
+ include Tags
50
+ include Name
51
+
52
+ attr_reader :steps
53
+
54
+ def initialize(raw)
55
+ @raw = raw
56
+ @steps = []
57
+ end
51
58
  end
52
59
 
53
- def name
54
- @raw.name
60
+ class Step
61
+ include Name
62
+
63
+ def initialize(raw)
64
+ @raw = raw
65
+ end
55
66
  end
56
- end
57
67
 
58
- class Builder
59
68
  attr_reader :features
60
69
 
61
70
  def initialize
@@ -63,22 +72,22 @@ module Turnip
63
72
  end
64
73
 
65
74
  def background(background)
66
- @current_step_context = Turnip::Background.new(background)
75
+ @current_step_context = Background.new(background)
67
76
  @current_feature.backgrounds << @current_step_context
68
77
  end
69
78
 
70
79
  def feature(feature)
71
- @current_feature = Turnip::Feature.new(feature)
80
+ @current_feature = Feature.new(feature)
72
81
  @features << @current_feature
73
82
  end
74
83
 
75
84
  def scenario(scenario)
76
- @current_step_context = Turnip::Scenario.new(scenario)
85
+ @current_step_context = Scenario.new(scenario)
77
86
  @current_feature.scenarios << @current_step_context
78
87
  end
79
88
 
80
89
  def step(step)
81
- @current_step = Turnip::Step.new(step)
90
+ @current_step = Step.new(step)
82
91
  @current_step_context.steps << @current_step
83
92
  end
84
93
 
@@ -0,0 +1,16 @@
1
+ require 'capybara/rspec'
2
+
3
+ Turnip.type = :request
4
+
5
+ RSpec.configure do |config|
6
+ config.before do
7
+ if self.class.include?(Capybara::DSL) and example.metadata[:turnip]
8
+ Capybara.current_driver = Capybara.javascript_driver if example.metadata.has_key?(:javascript)
9
+ example.metadata.each do |tag, value|
10
+ if Capybara.drivers.has_key?(tag)
11
+ Capybara.current_driver = tag
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,10 +1,13 @@
1
1
  module Turnip
2
2
  module DSL
3
3
  def step(description, &block)
4
- Turnip::Steps.add_step(description, &block)
4
+ Turnip::StepDefinition.add(description, &block)
5
+ end
6
+
7
+ def placeholder(name, &block)
8
+ Turnip::Placeholder.add(name, &block)
5
9
  end
6
10
  end
7
11
  end
8
12
 
9
13
  self.extend Turnip::DSL
10
-
@@ -0,0 +1,66 @@
1
+ module Turnip
2
+ class Placeholder
3
+ class Match < Struct.new(:regexp, :block);end
4
+
5
+ class << self
6
+ def add(name, &block)
7
+ placeholders[name] = Placeholder.new(name, &block)
8
+ end
9
+
10
+ def resolve(name)
11
+ find(name).regexp
12
+ end
13
+
14
+ def apply(name, value)
15
+ find(name).apply(value)
16
+ end
17
+
18
+ def find(name)
19
+ placeholders[name] or default
20
+ end
21
+
22
+ private
23
+
24
+ def placeholders
25
+ @placeholders ||= {}
26
+ end
27
+
28
+ def default
29
+ @default ||= new(:default) do
30
+ match %r((?:"([^"]+)"|([a-zA-Z0-9_-]+))) do |first, second|
31
+ first or second
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def initialize(name, &block)
38
+ @name = name
39
+ @matches = []
40
+ instance_eval(&block)
41
+ end
42
+
43
+ def apply(value)
44
+ match, params = find_match(value)
45
+ if match and match.block then match.block.call(*params) else value end
46
+ end
47
+
48
+ def match(regexp, &block)
49
+ @matches << Match.new(regexp, block)
50
+ end
51
+
52
+ def regexp
53
+ Regexp.new(@matches.map(&:regexp).join('|'))
54
+ end
55
+
56
+ private
57
+
58
+ def find_match(value)
59
+ @matches.each do |m|
60
+ result = value.scan(m.regexp)
61
+ return m, result.flatten unless result.empty?
62
+ end
63
+ nil
64
+ end
65
+ end
66
+ end
@@ -6,18 +6,18 @@ module Turnip
6
6
  parser.parse(content, nil, 0)
7
7
 
8
8
  builder.features.each do |feature|
9
- describe feature.name do
9
+ describe feature.name, feature.metadata_hash do
10
10
  feature.backgrounds.each do |background|
11
11
  before do
12
12
  background.steps.each do |step|
13
- Turnip::Steps.execute_step(self, step.name)
13
+ Turnip::StepDefinition.execute(self, step.name)
14
14
  end
15
15
  end
16
16
  end
17
17
  feature.scenarios.each do |scenario|
18
18
  it scenario.name, scenario.metadata_hash do
19
19
  scenario.steps.each do |step|
20
- Turnip::Steps.execute_step(self, step.name)
20
+ Turnip::StepDefinition.execute(self, step.name)
21
21
  end
22
22
  end
23
23
  end
@@ -0,0 +1,65 @@
1
+ module Turnip
2
+ class StepDefinition
3
+ class Match < Struct.new(:params, :block); end
4
+ class Pending < StandardError; end
5
+ class Ambiguous < StandardError; end
6
+
7
+ attr_reader :expression, :block
8
+
9
+ class << self
10
+ def execute(context, description)
11
+ match = find(description)
12
+ context.instance_exec(*match.params, &match.block)
13
+ rescue Pending
14
+ context.pending "the step '#{description}' is not implemented"
15
+ end
16
+
17
+ def add(expression, &block)
18
+ steps << StepDefinition.new(expression, &block)
19
+ end
20
+
21
+ def find(description)
22
+ found = steps.map do |step|
23
+ step.match(description)
24
+ end.compact
25
+ raise Pending, description if found.length == 0
26
+ raise Ambiguous, description if found.length > 1
27
+ found[0]
28
+ end
29
+
30
+ def steps
31
+ @steps ||= []
32
+ end
33
+ end
34
+
35
+ def initialize(expression, &block)
36
+ @expression = expression
37
+ @block = block
38
+ end
39
+
40
+ def regexp
41
+ @regexp ||= compile_regexp
42
+ end
43
+
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])
50
+ end
51
+ Match.new(params, block)
52
+ end
53
+ end
54
+
55
+ protected
56
+
57
+ def compile_regexp
58
+ regexp = Regexp.escape(expression)
59
+ regexp = expression.gsub(/:([\w]+)/) do |_|
60
+ "(?<#{$1}>#{Placeholder.resolve($1.to_sym)})"
61
+ end
62
+ Regexp.new("^#{regexp}$")
63
+ end
64
+ end
65
+ end
@@ -1,3 +1,3 @@
1
1
  module Turnip
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,12 @@
1
+ Feature: A simple feature
2
+ Scenario: Interpolation with quotes
3
+ Given there is a monster called "John Smith"
4
+ Then it should be called "John Smith"
5
+
6
+ Scenario: Interpolation without quotes
7
+ Given there is a monster called John
8
+ Then it should be called "John"
9
+
10
+ Scenario: Interpolation with customer regexp
11
+ Given there are 3 monkeys with blue hair
12
+ Then there should be 3 monkeys with blue hair
@@ -0,0 +1,67 @@
1
+ require 'turnip/placeholder'
2
+
3
+ describe Turnip::Placeholder do
4
+ def anchor(exp)
5
+ Regexp.new("^#{exp}$")
6
+ end
7
+
8
+ describe ".resolve" do
9
+ it "returns a regexp for the given placeholder" do
10
+ placeholder = Turnip::Placeholder.add(:test) { match(/foo/); match(/\d/) }
11
+ resolved = Turnip::Placeholder.resolve(:test)
12
+ "foo".should =~ anchor(resolved)
13
+ "5".should =~ anchor(resolved)
14
+ "bar".should_not =~ anchor(resolved)
15
+ end
16
+
17
+ it "fall through to using the standard placeholder regexp" do
18
+ resolved = Turnip::Placeholder.resolve(:does_not_exist)
19
+ "foo".should =~ anchor(resolved)
20
+ '"this is a test"'.should =~ anchor(resolved)
21
+ "foo bar".should_not =~ anchor(resolved)
22
+ end
23
+ end
24
+
25
+ describe ".apply" do
26
+ it "returns a regexp for the given placeholder" do
27
+ placeholder = Turnip::Placeholder.add(:test) do
28
+ match(/foo/) { :foo_bar }
29
+ match(/\d/) { |num| num.to_i }
30
+ end
31
+ Turnip::Placeholder.apply(:test, "foo").should eq(:foo_bar)
32
+ Turnip::Placeholder.apply(:test, "5").should eq(5)
33
+ Turnip::Placeholder.apply(:test, "bar").should eq("bar")
34
+ end
35
+
36
+ it "extracts any captured expressions and passes them to the block" do
37
+ placeholder = Turnip::Placeholder.add(:test) do
38
+ match(/mo(nk)(ey)/) { |nk, ey| nk.to_s.reverse + '|' + ey.to_s.upcase }
39
+ end
40
+ Turnip::Placeholder.apply(:test, "monkey").should eq('kn|EY')
41
+ Turnip::Placeholder.apply(:test, "bar").should eq("bar")
42
+ end
43
+ end
44
+
45
+ describe "#regexp" do
46
+ it "should match a given fragment" do
47
+ placeholder = Turnip::Placeholder.new(:test) { match(/foo/) }
48
+ "foo".should =~ placeholder.regexp
49
+ end
50
+
51
+ it "should match multiple fragments" do
52
+ placeholder = Turnip::Placeholder.new(:test) { match(/foo/); match(/\d/) }
53
+ "foo".should =~ placeholder.regexp
54
+ "5".should =~ placeholder.regexp
55
+ end
56
+
57
+ it "should not match an incorrect fragment" do
58
+ placeholder = Turnip::Placeholder.new(:test) { match(/foo/) }
59
+ "bar".should_not =~ placeholder.regexp
60
+ end
61
+
62
+ it "should not multiple incorrect fragments" do
63
+ placeholder = Turnip::Placeholder.new(:test) { match(/foo/); match(/\d/) }
64
+ "bar".should_not =~ placeholder.regexp
65
+ end
66
+ end
67
+ end
@@ -19,3 +19,35 @@ end
19
19
 
20
20
  step "this is ambiguous" do
21
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
52
+ end
53
+ 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.0
4
+ version: 0.1.1
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-21 00:00:00.000000000Z
12
+ date: 2011-10-25 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &2153440840 !ruby/object:Gem::Requirement
16
+ requirement: &2153850520 !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: *2153440840
24
+ version_requirements: *2153850520
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: gherkin
27
- requirement: &2153440340 !ruby/object:Gem::Requirement
27
+ requirement: &2153850100 !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: *2153440340
35
+ version_requirements: *2153850100
36
36
  description: Provides the ability to define steps and run Gherkin files from with
37
37
  RSpec
38
38
  email:
@@ -46,20 +46,23 @@ files:
46
46
  - Gemfile
47
47
  - README.md
48
48
  - Rakefile
49
- - lib/carrot.rb
50
49
  - lib/turnip.rb
51
50
  - lib/turnip/builder.rb
51
+ - lib/turnip/capybara.rb
52
52
  - lib/turnip/dsl.rb
53
53
  - lib/turnip/loader.rb
54
+ - lib/turnip/placeholder.rb
54
55
  - lib/turnip/rspec.rb
55
56
  - lib/turnip/run.rb
56
- - lib/turnip/steps.rb
57
+ - lib/turnip/step_definition.rb
57
58
  - lib/turnip/version.rb
58
59
  - spec/fixture/ambiguous.feature
59
60
  - spec/fixture/backgrounds.feature
61
+ - spec/fixture/interpolation.feature
60
62
  - spec/fixture/pending.feature
61
63
  - spec/fixture/simple_feature.feature
62
64
  - spec/fixture/tags.feature
65
+ - spec/placeholder_spec.rb
63
66
  - spec/spec_helper.rb
64
67
  - turnip.gemspec
65
68
  homepage: ''
@@ -89,7 +92,9 @@ summary: Gherkin extension for RSpec
89
92
  test_files:
90
93
  - spec/fixture/ambiguous.feature
91
94
  - spec/fixture/backgrounds.feature
95
+ - spec/fixture/interpolation.feature
92
96
  - spec/fixture/pending.feature
93
97
  - spec/fixture/simple_feature.feature
94
98
  - spec/fixture/tags.feature
99
+ - spec/placeholder_spec.rb
95
100
  - spec/spec_helper.rb
@@ -1,10 +0,0 @@
1
- require "gherkin"
2
- require "gherkin/formatter/tag_count_formatter"
3
-
4
- require "carrot/version"
5
- require "carrot/loader"
6
- require "carrot/builder"
7
- require "carrot/run"
8
- require "carrot/steps"
9
- require "carrot/dsl"
10
- require "carrot/rspec"
@@ -1,31 +0,0 @@
1
- module Turnip
2
- module Steps
3
- class Pending < StandardError; end
4
- class Ambiguous < StandardError; end
5
-
6
- extend self
7
-
8
- def execute_step(context, description)
9
- context.instance_eval(&find_step(description))
10
- rescue Pending
11
- context.pending "the step '#{description}' is not implemented"
12
- end
13
-
14
- def add_step(description, &block)
15
- steps << [description, block]
16
- end
17
-
18
- def find_step(description)
19
- found = steps.select do |step|
20
- step.first == description
21
- end
22
- raise Pending, description if found.length == 0
23
- raise Ambiguous, description if found.length > 1
24
- found[0][1]
25
- end
26
-
27
- def steps
28
- @steps ||= []
29
- end
30
- end
31
- end