elight-cucumber 0.1.9

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.
Files changed (186) hide show
  1. data/History.txt +150 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +186 -0
  4. data/README.txt +41 -0
  5. data/Rakefile +5 -0
  6. data/TODO.txt +26 -0
  7. data/bin/cucumber +4 -0
  8. data/config/hoe.rb +69 -0
  9. data/config/requirements.rb +15 -0
  10. data/cucumber.yml +1 -0
  11. data/examples/calculator/README.txt +5 -0
  12. data/examples/calculator/Rakefile +5 -0
  13. data/examples/calculator/features/addition.feature +17 -0
  14. data/examples/calculator/features/division.feature +10 -0
  15. data/examples/calculator/features/steps/calculator_steps.rb +31 -0
  16. data/examples/calculator/lib/calculator.rb +16 -0
  17. data/examples/calculator_ruby_features/Rakefile +6 -0
  18. data/examples/calculator_ruby_features/features/addition.rb +23 -0
  19. data/examples/calculator_ruby_features/features/steps/calculator_steps.rb +43 -0
  20. data/examples/calculatrice_francaise_avec_soit_scenario/Rakefile +6 -0
  21. data/examples/calculatrice_francaise_avec_soit_scenario/features/addition.feature +13 -0
  22. data/examples/calculatrice_francaise_avec_soit_scenario/features/calculatrice_steps.rb +31 -0
  23. data/examples/chinese_simplified_calculator/Rakefile +6 -0
  24. data/examples/chinese_simplified_calculator/features/addition.feature +17 -0
  25. data/examples/chinese_simplified_calculator/features/steps/calculator_steps.rb +24 -0
  26. data/examples/chinese_simplified_calculator/lib/calculator.rb +10 -0
  27. data/examples/cs/README.textile +22 -0
  28. data/examples/cs/Rakefile +12 -0
  29. data/examples/cs/features/hello.feature +11 -0
  30. data/examples/cs/features/steps/hello_steps.rb +25 -0
  31. data/examples/cs/features/steps/tree_steps.rb +14 -0
  32. data/examples/cs/features/tree.feature +9 -0
  33. data/examples/cs/src/Hello.cs +18 -0
  34. data/examples/danish_calculator/Rakefile +6 -0
  35. data/examples/danish_calculator/features/steps/kalkulator_steps.rb +22 -0
  36. data/examples/danish_calculator/features/summering.feature +17 -0
  37. data/examples/danish_calculator/lib/kalkulator.rb +11 -0
  38. data/examples/dos_line_endings/Rakefile +6 -0
  39. data/examples/dos_line_endings/features/dos_line_endings.feature +9 -0
  40. data/examples/estonian_calculator/Rakefile +6 -0
  41. data/examples/estonian_calculator/features/kalkulaator_steps.rb +35 -0
  42. data/examples/estonian_calculator/features/liitmine.feature +16 -0
  43. data/examples/japanese_calculator/README.txt +5 -0
  44. data/examples/japanese_calculator/Rakefile +6 -0
  45. data/examples/japanese_calculator/features/addition.feature +17 -0
  46. data/examples/japanese_calculator/features/division.feature +10 -0
  47. data/examples/japanese_calculator/features/steps/calculator_steps.rb +30 -0
  48. data/examples/japanese_calculator/lib/calculator.rb +16 -0
  49. data/examples/java/README.textile +22 -0
  50. data/examples/java/Rakefile +12 -0
  51. data/examples/java/features/hello.feature +11 -0
  52. data/examples/java/features/steps/hello_steps.rb +25 -0
  53. data/examples/java/features/steps/tree_steps.rb +14 -0
  54. data/examples/java/features/tree.feature +9 -0
  55. data/examples/java/src/cucumber/demo/Hello.java +16 -0
  56. data/examples/norwegian_calculator/Rakefile +6 -0
  57. data/examples/norwegian_calculator/features/steps/kalkulator_steps.rb +22 -0
  58. data/examples/norwegian_calculator/features/summering.feature +17 -0
  59. data/examples/norwegian_calculator/lib/kalkulator.rb +11 -0
  60. data/examples/portuguese_calculator/Rakefile +6 -0
  61. data/examples/portuguese_calculator/features/adicao.feature +10 -0
  62. data/examples/portuguese_calculator/features/calculadora_steps.rb +31 -0
  63. data/examples/selenium/Rakefile +6 -0
  64. data/examples/selenium/features/search.feature +9 -0
  65. data/examples/selenium/features/steps/stories_steps.rb +41 -0
  66. data/examples/spanish_calculator/Rakefile +6 -0
  67. data/examples/spanish_calculator/features/adicion.feature +17 -0
  68. data/examples/spanish_calculator/features/steps/calculador_steps.rb +22 -0
  69. data/examples/swedish_calculator/Rakefile +5 -0
  70. data/examples/swedish_calculator/features/steps/kalkulator_steps.rb +22 -0
  71. data/examples/swedish_calculator/features/summering.feature +17 -0
  72. data/examples/swedish_calculator/lib/kalkulator.rb +11 -0
  73. data/examples/tickets/Rakefile +11 -0
  74. data/examples/tickets/cucumber.yml +2 -0
  75. data/examples/tickets/features/steps/tickets_steps.rb +32 -0
  76. data/examples/tickets/features/tickets.feature +22 -0
  77. data/examples/watir/Rakefile +6 -0
  78. data/examples/watir/features/search.feature +9 -0
  79. data/examples/watir/features/steps/stories_steps.rb +51 -0
  80. data/features/see_features.feature +8 -0
  81. data/features/steps/features_steps.rb +9 -0
  82. data/gem_tasks/deployment.rake +34 -0
  83. data/gem_tasks/environment.rake +7 -0
  84. data/gem_tasks/features.rake +6 -0
  85. data/gem_tasks/fix_cr_lf.rake +10 -0
  86. data/gem_tasks/flog.rake +4 -0
  87. data/gem_tasks/gemspec.rake +6 -0
  88. data/gem_tasks/rspec.rake +21 -0
  89. data/gem_tasks/treetop.rake +49 -0
  90. data/lib/cucumber.rb +35 -0
  91. data/lib/cucumber/cli.rb +191 -0
  92. data/lib/cucumber/core_ext/proc.rb +55 -0
  93. data/lib/cucumber/core_ext/string.rb +22 -0
  94. data/lib/cucumber/executor.rb +143 -0
  95. data/lib/cucumber/formatters.rb +1 -0
  96. data/lib/cucumber/formatters/ansicolor.rb +112 -0
  97. data/lib/cucumber/formatters/cucumber.css +132 -0
  98. data/lib/cucumber/formatters/cucumber.js +11 -0
  99. data/lib/cucumber/formatters/html_formatter.rb +128 -0
  100. data/lib/cucumber/formatters/jquery.js +32 -0
  101. data/lib/cucumber/formatters/pretty_formatter.rb +211 -0
  102. data/lib/cucumber/formatters/profile_formatter.rb +92 -0
  103. data/lib/cucumber/formatters/progress_formatter.rb +51 -0
  104. data/lib/cucumber/languages.yml +142 -0
  105. data/lib/cucumber/model.rb +1 -0
  106. data/lib/cucumber/model/table.rb +28 -0
  107. data/lib/cucumber/rails/rspec.rb +12 -0
  108. data/lib/cucumber/rails/world.rb +73 -0
  109. data/lib/cucumber/rake/task.rb +75 -0
  110. data/lib/cucumber/step_methods.rb +49 -0
  111. data/lib/cucumber/step_mother.rb +83 -0
  112. data/lib/cucumber/tree.rb +18 -0
  113. data/lib/cucumber/tree/feature.rb +60 -0
  114. data/lib/cucumber/tree/features.rb +21 -0
  115. data/lib/cucumber/tree/given_scenario.rb +13 -0
  116. data/lib/cucumber/tree/scenario.rb +150 -0
  117. data/lib/cucumber/tree/step.rb +133 -0
  118. data/lib/cucumber/tree/table.rb +26 -0
  119. data/lib/cucumber/tree/top_down_visitor.rb +23 -0
  120. data/lib/cucumber/treetop_parser/feature.treetop.erb +201 -0
  121. data/lib/cucumber/treetop_parser/feature_da.rb +1593 -0
  122. data/lib/cucumber/treetop_parser/feature_de.rb +1593 -0
  123. data/lib/cucumber/treetop_parser/feature_en-tx.rb +1593 -0
  124. data/lib/cucumber/treetop_parser/feature_en.rb +1593 -0
  125. data/lib/cucumber/treetop_parser/feature_es.rb +1593 -0
  126. data/lib/cucumber/treetop_parser/feature_et.rb +1593 -0
  127. data/lib/cucumber/treetop_parser/feature_fr.rb +1593 -0
  128. data/lib/cucumber/treetop_parser/feature_ja.rb +1593 -0
  129. data/lib/cucumber/treetop_parser/feature_nl.rb +1593 -0
  130. data/lib/cucumber/treetop_parser/feature_no.rb +1593 -0
  131. data/lib/cucumber/treetop_parser/feature_parser.rb +34 -0
  132. data/lib/cucumber/treetop_parser/feature_pt.rb +1593 -0
  133. data/lib/cucumber/treetop_parser/feature_ru.rb +1593 -0
  134. data/lib/cucumber/treetop_parser/feature_se.rb +1593 -0
  135. data/lib/cucumber/treetop_parser/feature_zh-CN.rb +1593 -0
  136. data/lib/cucumber/version.rb +9 -0
  137. data/rails_generators/cucumber/cucumber_generator.rb +29 -0
  138. data/rails_generators/cucumber/templates/common_webrat.rb +42 -0
  139. data/rails_generators/cucumber/templates/cucumber +2 -0
  140. data/rails_generators/cucumber/templates/cucumber.rake +12 -0
  141. data/rails_generators/cucumber/templates/cucumber.yml +1 -0
  142. data/rails_generators/cucumber/templates/env.rb +8 -0
  143. data/rails_generators/feature/feature_generator.rb +17 -0
  144. data/rails_generators/feature/templates/feature.erb +28 -0
  145. data/rails_generators/feature/templates/steps.erb +22 -0
  146. data/script/console +10 -0
  147. data/script/console.cmd +1 -0
  148. data/script/destroy +14 -0
  149. data/script/destroy.cmd +1 -0
  150. data/script/generate +14 -0
  151. data/script/generate.cmd +1 -0
  152. data/script/txt2html +74 -0
  153. data/script/txt2html.cmd +1 -0
  154. data/setup.rb +1585 -0
  155. data/spec/cucumber/cli_spec.rb +56 -0
  156. data/spec/cucumber/core_ext/proc_spec.rb +45 -0
  157. data/spec/cucumber/core_ext/string_spec.rb +34 -0
  158. data/spec/cucumber/executor_spec.rb +130 -0
  159. data/spec/cucumber/formatters/ansicolor_spec.rb +35 -0
  160. data/spec/cucumber/formatters/features.html +269 -0
  161. data/spec/cucumber/formatters/html_formatter_spec.rb +74 -0
  162. data/spec/cucumber/formatters/pretty_formatter_spec.rb +111 -0
  163. data/spec/cucumber/formatters/profile_formatter_spec.rb +193 -0
  164. data/spec/cucumber/formatters/progress_formatter_spec.rb +45 -0
  165. data/spec/cucumber/model/table_spec.rb +20 -0
  166. data/spec/cucumber/rails/stubs/mini_rails.rb +17 -0
  167. data/spec/cucumber/rails/stubs/test_help.rb +1 -0
  168. data/spec/cucumber/rails/world_spec.rb +11 -0
  169. data/spec/cucumber/sell_cucumbers.feature +9 -0
  170. data/spec/cucumber/step_mother_spec.rb +53 -0
  171. data/spec/cucumber/tree/feature_spec.rb +12 -0
  172. data/spec/cucumber/tree/scenario_spec.rb +37 -0
  173. data/spec/cucumber/tree/step_spec.rb +31 -0
  174. data/spec/cucumber/treetop_parser/empty_feature.feature +4 -0
  175. data/spec/cucumber/treetop_parser/empty_scenario.feature +9 -0
  176. data/spec/cucumber/treetop_parser/feature_parser_spec.rb +96 -0
  177. data/spec/cucumber/treetop_parser/fit_scenario.feature +8 -0
  178. data/spec/cucumber/treetop_parser/given_scenario.feature +9 -0
  179. data/spec/cucumber/treetop_parser/multiline_steps.feature +13 -0
  180. data/spec/cucumber/treetop_parser/multiple_tables.feature +29 -0
  181. data/spec/cucumber/treetop_parser/spaces.feature +10 -0
  182. data/spec/cucumber/treetop_parser/test_dos.feature +25 -0
  183. data/spec/cucumber/treetop_parser/with_comments.feature +10 -0
  184. data/spec/spec.opts +2 -0
  185. data/spec/spec_helper.rb +19 -0
  186. metadata +288 -0
@@ -0,0 +1,35 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+ require 'rubygems'
4
+ require 'treetop/runtime'
5
+ require 'treetop/ruby_extensions'
6
+ require 'cucumber/version'
7
+ require 'cucumber/step_methods'
8
+ require 'cucumber/tree'
9
+ require 'cucumber/model'
10
+ require 'cucumber/executor'
11
+ require 'cucumber/step_mother'
12
+ require 'cucumber/formatters'
13
+ require 'cucumber/treetop_parser/feature_parser'
14
+ require 'cucumber/cli'
15
+
16
+ module Cucumber
17
+ LANGUAGE_FILE = File.expand_path(File.dirname(__FILE__) + '/cucumber/languages.yml')
18
+
19
+ class << self
20
+ attr_reader :language
21
+
22
+ def load_language(lang)
23
+ @language = config[lang]
24
+ end
25
+
26
+ def languages
27
+ config.keys.sort
28
+ end
29
+
30
+ def config
31
+ require 'yaml'
32
+ @config ||= YAML.load_file(LANGUAGE_FILE)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,191 @@
1
+ require 'optparse'
2
+ require 'cucumber'
3
+
4
+ module Cucumber
5
+ class CLI
6
+ class << self
7
+ attr_writer :step_mother, :executor, :features
8
+
9
+ def execute
10
+ @execute_called = true
11
+ parse(ARGV).execute!(@step_mother, @executor, @features)
12
+ end
13
+
14
+ def execute_called?
15
+ @execute_called
16
+ end
17
+
18
+ def parse(args)
19
+ cli = new
20
+ cli.parse_options!(args)
21
+ cli
22
+ end
23
+ end
24
+
25
+ attr_reader :options
26
+ FORMATS = %w{pretty profile progress html}
27
+
28
+ def initialize
29
+ @paths = []
30
+ @options = {
31
+ :require => nil,
32
+ :lang => 'en',
33
+ :format => 'pretty',
34
+ :dry_run => false,
35
+ :source => true,
36
+ :out => STDOUT,
37
+ :excludes => []
38
+ }
39
+ end
40
+
41
+ def parse_options!(args)
42
+ return parse_args_from_profile('default') if args.empty?
43
+ args.extend(OptionParser::Arguable)
44
+
45
+ args.options do |opts|
46
+ opts.banner = "Usage: cucumber [options] FILES|DIRS"
47
+ opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR", "Require files before executing the features.",
48
+ "If this option is not specified, all *.rb files that",
49
+ "are siblings or below the features will be autorequired") do |v|
50
+ @options[:require] ||= []
51
+ @options[:require] << v
52
+ end
53
+ opts.on("-l LINE", "--line LINE", "Only execute the scenario at the given line") do |v|
54
+ @options[:line] = v
55
+ end
56
+ opts.on("-a LANG", "--language LANG", "Specify language for features (Default: #{@options[:lang]})",
57
+ "Available languages: #{Cucumber.languages.join(", ")}",
58
+ "Look at #{Cucumber::LANGUAGE_FILE} for keywords") do |v|
59
+ @options[:lang] = v
60
+ end
61
+ opts.on("-f FORMAT", "--format FORMAT", "How to format features (Default: #{@options[:format]})",
62
+ "Available formats: #{FORMATS.join(", ")}") do |v|
63
+ unless FORMATS.index(v)
64
+ STDERR.puts "Invalid format: #{v}\n"
65
+ STDERR.puts opts.help
66
+ exit 1
67
+ end
68
+ @options[:format] = v
69
+ end
70
+ opts.on("--exclude=PATTERN", "Don't run features matching a pattern") do |v|
71
+ @options[:excludes] << v
72
+ end
73
+ opts.on("-p=PROFILE", "--profile=PROFILE", "Pull commandline arguments from cucumber.yml.") do |v|
74
+ parse_args_from_profile(v)
75
+ end
76
+ opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.") do
77
+ @options[:dry_run] = true
78
+ end
79
+ opts.on("-n", "--no-source", "Don't show the file and line of the step definition with the steps.") do
80
+ @options[:source] = false
81
+ end
82
+ opts.on("-o", "--out=FILE", "Write output to a file instead of STDOUT.") do |v|
83
+ @options[:out] = File.open(v, 'w')
84
+ end
85
+ opts.on_tail("--version", "Show version") do
86
+ puts VERSION::STRING
87
+ exit
88
+ end
89
+ opts.on_tail("--help", "You're looking at it") do
90
+ puts opts.help
91
+ exit
92
+ end
93
+ end.parse!
94
+
95
+ # Whatever is left after option parsing is the FILE arguments
96
+ @paths += args
97
+ end
98
+
99
+ def parse_args_from_profile(profile)
100
+ return unless File.exist?('cucumber.yml')
101
+ require 'yaml'
102
+ cucumber_yml = YAML::load(IO.read('cucumber.yml'))
103
+ args_from_yml = cucumber_yml[profile]
104
+ raise "Expected to find a String, got #{args_from_yml.inspect}. cucumber.yml:\n#{cucumber_yml}" unless String === args_from_yml
105
+ parse_options!(args_from_yml.split(' '))
106
+ end
107
+
108
+ def execute!(step_mother, executor, features)
109
+ Cucumber.load_language(@options[:lang])
110
+ executor.formatter = formatter(step_mother)
111
+ require_files
112
+ load_plain_text_features(features)
113
+ executor.line = @options[:line].to_i if @options[:line]
114
+ executor.visit_features(features)
115
+ exit 1 if executor.failed
116
+ end
117
+
118
+ private
119
+
120
+ # Requires files - typically step files and ruby feature files.
121
+ def require_files
122
+ ARGV.clear # Shut up RSpec
123
+ require "cucumber/treetop_parser/feature_#{@options[:lang]}"
124
+ require "cucumber/treetop_parser/feature_parser"
125
+
126
+ requires = @options[:require] || feature_dirs
127
+ libs = requires.map do |path|
128
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
129
+ File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
130
+ end.flatten.uniq
131
+ libs.each do |lib|
132
+ begin
133
+ require lib
134
+ rescue LoadError => e
135
+ e.message << "\nFailed to load #{lib}"
136
+ raise e
137
+ end
138
+ end
139
+ end
140
+
141
+ def feature_files
142
+ potential_feature_files = @paths.map do |path|
143
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
144
+ File.directory?(path) ? Dir["#{path}/**/*.feature"] : path
145
+ end.flatten.uniq
146
+
147
+ @options[:excludes].each do |exclude|
148
+ potential_feature_files.reject! do |path|
149
+ path =~ /#{Regexp.escape(exclude)}/
150
+ end
151
+ end
152
+
153
+ potential_feature_files
154
+ end
155
+
156
+ def feature_dirs
157
+ feature_files.map{|f| File.directory?(f) ? f : File.dirname(f)}.uniq
158
+ end
159
+
160
+ def load_plain_text_features(features)
161
+ parser = TreetopParser::FeatureParser.new
162
+
163
+ feature_files.each do |f|
164
+ features << parser.parse_feature(f)
165
+ end
166
+ end
167
+
168
+ def formatter(step_mother)
169
+ case @options[:format]
170
+ when 'pretty'
171
+ Formatters::PrettyFormatter.new(@options[:out], step_mother, @options)
172
+ when 'progress'
173
+ Formatters::ProgressFormatter.new(@options[:out])
174
+ when 'profile'
175
+ Formatters::ProfileFormatter.new(@options[:out], step_mother)
176
+ when 'html'
177
+ Formatters::HtmlFormatter.new(@options[:out], step_mother)
178
+ else
179
+ raise "Unknown formatter: #{@options[:format]}"
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+
186
+ extend Cucumber::StepMethods
187
+ Cucumber::CLI.step_mother = step_mother
188
+ Cucumber::CLI.executor = executor
189
+
190
+ extend Cucumber::Tree
191
+ Cucumber::CLI.features = features
@@ -0,0 +1,55 @@
1
+ module Cucumber
2
+ class ArityMismatchError < StandardError
3
+ end
4
+
5
+ module CoreExt
6
+ # Proc extension that allows a proc to be called in the context of any object.
7
+ # Also makes it possible to tack a name onto a Proc.
8
+ module CallIn
9
+ attr_accessor :name
10
+
11
+ def call_in(obj, *args)
12
+ obj.extend(mod)
13
+ a = arity == -1 ? 0 : arity
14
+ if self != StepMother::PENDING && args.length != a
15
+ # We have to manually raise when the block has arity -1 (no pipes)
16
+ raise ArityMismatchError.new("expected #{arity == -1 ? 0 : arity} block argument(s), got #{args.length}")
17
+ else
18
+ obj.__send__(meth, *args)
19
+ end
20
+ end
21
+
22
+ def arity2
23
+ arity == -1 ? 0 : arity
24
+ end
25
+
26
+ def to_backtrace_line
27
+ "#{file_colon_line}:in `#{name}'"
28
+ end
29
+
30
+ def to_comment_line
31
+ "# #{file_colon_line}"
32
+ end
33
+
34
+ def file_colon_line
35
+ path, line = *to_s.match(/[\d\w]+@(.*):(.*)>/)[1..2]
36
+ path = File.expand_path(path)
37
+ pwd = Dir.pwd
38
+ path = path[pwd.length+1..-1]
39
+ "#{path}:#{line}"
40
+ end
41
+
42
+ def meth
43
+ @meth ||= "__cucumber_#{object_id}"
44
+ end
45
+
46
+ def mod
47
+ p = self
48
+ m = meth
49
+ @mod ||= Module.new do
50
+ define_method(m, &p)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,22 @@
1
+ class String
2
+ def gzub(regexp, format=nil, &proc)
3
+ md = match(regexp)
4
+ raise "#{self.inspect} doesn't match #{regexp.inspect}" if md.nil?
5
+
6
+ s = dup
7
+ pos = 0
8
+ md.captures.each_with_index do |m, n|
9
+ replacement = if block_given?
10
+ proc.call(m)
11
+ else
12
+ format % m
13
+ end
14
+
15
+ if md.offset(n+1)[0]
16
+ s[md.offset(n+1)[0] + pos, m.length] = replacement
17
+ pos += replacement.length - m.length
18
+ end
19
+ end
20
+ s
21
+ end
22
+ end
@@ -0,0 +1,143 @@
1
+ require 'cucumber/core_ext/proc'
2
+
3
+ module Cucumber
4
+ class Executor
5
+ attr_reader :failed
6
+ attr_accessor :formatter
7
+
8
+ def line=(line)
9
+ @line = line
10
+ end
11
+
12
+ def initialize(step_mother)
13
+ @world_proc = lambda do
14
+ Object.new
15
+ end
16
+ @before_scenario_procs = []
17
+ @after_scenario_procs = []
18
+ @after_step_procs = []
19
+ @step_mother = step_mother
20
+ end
21
+
22
+ def register_world_proc(&proc)
23
+ @world_proc = proc
24
+ end
25
+
26
+ def register_before_scenario_proc(&proc)
27
+ proc.extend(CoreExt::CallIn)
28
+ @before_scenario_procs << proc
29
+ end
30
+
31
+ def register_after_scenario_proc(&proc)
32
+ proc.extend(CoreExt::CallIn)
33
+ @after_scenario_procs << proc
34
+ end
35
+
36
+ def register_after_step_proc(&proc)
37
+ proc.extend(CoreExt::CallIn)
38
+ @after_step_procs << proc
39
+ end
40
+
41
+ def visit_features(features)
42
+ raise "Line number can only be specified when there is 1 feature. There were #{features.length}." if @line && features.length != 1
43
+ formatter.visit_features(features) if formatter.respond_to?(:visit_features)
44
+ features.accept(self)
45
+ formatter.dump
46
+ end
47
+
48
+ def visit_feature(feature)
49
+ formatter.visit_feature(feature) if formatter.respond_to?(:visit_feature)
50
+ feature.accept(self)
51
+ end
52
+
53
+ def visit_header(header)
54
+ formatter.header_executing(header) if formatter.respond_to?(:header_executing)
55
+ end
56
+
57
+ def visit_row_scenario(scenario)
58
+ visit_scenario(scenario)
59
+ end
60
+
61
+ def visit_regular_scenario(scenario)
62
+ visit_scenario(scenario)
63
+ end
64
+
65
+ def visit_scenario(scenario)
66
+ if accept?(scenario)
67
+ @error = nil
68
+ @pending = nil
69
+
70
+ @world = @world_proc.call
71
+ @world.extend(Spec::Matchers) if defined?(Spec::Matchers)
72
+ define_step_call_methods(@world)
73
+
74
+ formatter.scenario_executing(scenario) if formatter.respond_to?(:scenario_executing)
75
+ @before_scenario_procs.each{|p| p.call_in(@world, *[])}
76
+ scenario.accept(self)
77
+ @after_scenario_procs.each{|p| p.call_in(@world, *[])}
78
+ formatter.scenario_executed(scenario) if formatter.respond_to?(:scenario_executed)
79
+ end
80
+ end
81
+
82
+ def accept?(scenario)
83
+ @line.nil? || scenario.at_line?(@line)
84
+ end
85
+
86
+ def visit_row_step(step)
87
+ visit_step(step)
88
+ end
89
+
90
+ def visit_regular_step(step)
91
+ visit_step(step)
92
+ end
93
+
94
+ def visit_step(step)
95
+ unless @pending || @error
96
+ begin
97
+ regexp, args, proc = step.regexp_args_proc(@step_mother)
98
+ formatter.step_executing(step, regexp, args) if formatter.respond_to?(:step_executing)
99
+ step.execute_in(@world, regexp, args, proc)
100
+ @after_step_procs.each{|p| p.call_in(@world, *[])}
101
+ formatter.step_passed(step, regexp, args)
102
+ rescue Pending
103
+ record_pending_step(step, regexp, args)
104
+ rescue => e
105
+ @failed = true
106
+ @error = step.error = e
107
+ formatter.step_failed(step, regexp, args)
108
+ end
109
+ else
110
+ begin
111
+ regexp, args, proc = step.regexp_args_proc(@step_mother)
112
+ step.execute_in(@world, regexp, args, proc)
113
+ formatter.step_skipped(step, regexp, args)
114
+ rescue Pending
115
+ record_pending_step(step, regexp, args)
116
+ rescue Exception
117
+ formatter.step_skipped(step, regexp, args)
118
+ end
119
+ end
120
+ end
121
+
122
+ def record_pending_step(step, regexp, args)
123
+ @pending = true
124
+ formatter.step_pending(step, regexp, args)
125
+ end
126
+
127
+ def define_step_call_methods(world)
128
+ world.instance_variable_set('@__executor', self)
129
+ world.instance_eval do
130
+ class << self
131
+ def run_step(name)
132
+ _, args, proc = @__executor.instance_variable_get(:@step_mother).regexp_args_proc(name)
133
+ proc.call_in(self, *args)
134
+ end
135
+
136
+ %w{given when then and but}.each do |keyword|
137
+ alias_method Cucumber.language[keyword], :run_step
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end