cucumber 0.2.3 → 0.3.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.
Files changed (128) hide show
  1. data/History.txt +56 -1
  2. data/Manifest.txt +70 -49
  3. data/config/hoe.rb +1 -1
  4. data/cucumber.yml +1 -1
  5. data/examples/i18n/bg/Rakefile +6 -0
  6. data/examples/i18n/bg/features/addition.feature +11 -0
  7. data/examples/i18n/bg/features/consecutive_calculations.feature +18 -0
  8. data/examples/i18n/bg/features/division.feature +16 -0
  9. data/examples/i18n/bg/features/step_definitons/calculator_steps.rb +24 -0
  10. data/examples/i18n/bg/features/support/env.rb +6 -0
  11. data/examples/i18n/bg/features/support/world.rb +8 -0
  12. data/examples/i18n/bg/lib/calculator.rb +24 -0
  13. data/examples/i18n/ru/features/support/world.rb +4 -3
  14. data/examples/i18n/sk/Rakefile +6 -0
  15. data/examples/i18n/sk/features/addition.feature +16 -0
  16. data/examples/i18n/sk/features/division.feature +9 -0
  17. data/examples/i18n/sk/features/step_definitons/calculator_steps.rb +24 -0
  18. data/examples/i18n/sk/lib/calculator.rb +14 -0
  19. data/examples/self_test/features/background/background_with_name.feature +7 -0
  20. data/examples/self_test/features/background/passing_background.feature +2 -2
  21. data/examples/self_test/features/step_definitions/sample_steps.rb +18 -2
  22. data/examples/self_test/features/undefined_multiline_args.feature +12 -0
  23. data/examples/sinatra/features/support/env.rb +2 -6
  24. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +1 -4
  25. data/examples/tickets/Rakefile +1 -1
  26. data/examples/tickets/features/229/tagged_hooks.feature +8 -0
  27. data/examples/tickets/features/229/tagged_hooks.rb +14 -0
  28. data/examples/tickets/features/270/back.feature +14 -0
  29. data/examples/tickets/features/270/back.steps.rb +14 -0
  30. data/examples/tickets/features/279/py_string_indent.feature +25 -0
  31. data/examples/tickets/features/279/py_string_indent.steps.rb +12 -0
  32. data/examples/tickets/features/279/wrong.feature_ +11 -0
  33. data/examples/tickets/features/step_definitons/tickets_steps.rb +0 -7
  34. data/features/background.feature +21 -3
  35. data/features/cucumber_cli.feature +18 -5
  36. data/features/cucumber_cli_outlines.feature +4 -1
  37. data/features/rake_task.feature +132 -0
  38. data/features/snippet.feature +23 -0
  39. data/features/step_definitions/cucumber_steps.rb +46 -15
  40. data/features/support/env.rb +61 -4
  41. data/features/usage.feature +5 -0
  42. data/gem_tasks/deployment.rake +1 -1
  43. data/lib/cucumber/ast/background.rb +14 -4
  44. data/lib/cucumber/ast/examples.rb +0 -12
  45. data/lib/cucumber/ast/feature.rb +2 -12
  46. data/lib/cucumber/ast/feature_element.rb +4 -8
  47. data/lib/cucumber/ast/features.rb +1 -1
  48. data/lib/cucumber/ast/outline_table.rb +20 -20
  49. data/lib/cucumber/ast/py_string.rb +6 -11
  50. data/lib/cucumber/ast/scenario.rb +1 -8
  51. data/lib/cucumber/ast/scenario_outline.rb +1 -11
  52. data/lib/cucumber/ast/step.rb +3 -9
  53. data/lib/cucumber/ast/step_collection.rb +0 -4
  54. data/lib/cucumber/ast/step_invocation.rb +5 -6
  55. data/lib/cucumber/ast/table.rb +5 -22
  56. data/lib/cucumber/ast/tags.rb +9 -9
  57. data/lib/cucumber/ast/visitor.rb +12 -25
  58. data/lib/cucumber/cli/configuration.rb +4 -4
  59. data/lib/cucumber/cli/main.rb +10 -3
  60. data/lib/cucumber/core_ext/instance_exec.rb +17 -4
  61. data/lib/cucumber/formatter/ansicolor.rb +1 -1
  62. data/lib/cucumber/formatter/console.rb +2 -1
  63. data/lib/cucumber/formatter/html.rb +21 -7
  64. data/lib/cucumber/formatter/pretty.rb +27 -20
  65. data/lib/cucumber/formatter/usage.rb +16 -0
  66. data/lib/cucumber/languages.yml +23 -5
  67. data/lib/cucumber/parser/feature.rb +231 -114
  68. data/lib/cucumber/parser/feature.tt +120 -25
  69. data/lib/cucumber/parser/table.rb +37 -25
  70. data/lib/cucumber/parser/table.tt +15 -3
  71. data/lib/cucumber/parser/treetop_ext.rb +48 -9
  72. data/lib/cucumber/rake/task.rb +29 -6
  73. data/lib/cucumber/step_definition.rb +4 -2
  74. data/lib/cucumber/step_mother.rb +143 -26
  75. data/lib/cucumber/version.rb +2 -2
  76. data/rails_generators/cucumber/templates/paths.rb +13 -4
  77. data/rails_generators/cucumber/templates/webrat_steps.rb +16 -0
  78. data/{specs → spec}/cucumber/ast/background_spec.rb +1 -0
  79. data/{specs → spec}/cucumber/ast/feature_factory.rb +1 -1
  80. data/{specs → spec}/cucumber/ast/feature_spec.rb +2 -2
  81. data/{specs → spec}/cucumber/ast/py_string_spec.rb +0 -0
  82. data/{specs → spec}/cucumber/ast/scenario_outline_spec.rb +0 -0
  83. data/{specs → spec}/cucumber/ast/scenario_spec.rb +0 -27
  84. data/{specs → spec}/cucumber/ast/step_collection_spec.rb +0 -0
  85. data/{specs → spec}/cucumber/ast/step_spec.rb +0 -0
  86. data/{specs → spec}/cucumber/ast/table_spec.rb +2 -2
  87. data/{specs → spec}/cucumber/broadcaster_spec.rb +0 -0
  88. data/{specs → spec}/cucumber/cli/configuration_spec.rb +0 -0
  89. data/{specs → spec}/cucumber/cli/main_spec.rb +5 -1
  90. data/spec/cucumber/core_ext/proc_spec.rb +54 -0
  91. data/{specs → spec}/cucumber/core_ext/string_spec.rb +0 -0
  92. data/{specs → spec}/cucumber/formatter/ansicolor_spec.rb +0 -0
  93. data/{specs → spec}/cucumber/formatter/color_io_spec.rb +0 -0
  94. data/{specs → spec}/cucumber/formatter/html/cucumber.css +0 -0
  95. data/{specs → spec}/cucumber/formatter/html/cucumber.js +0 -0
  96. data/{specs → spec}/cucumber/formatter/html/index.html +0 -0
  97. data/{specs → spec}/cucumber/formatter/html/jquery-1.3.min.js +0 -0
  98. data/{specs → spec}/cucumber/formatter/html/jquery.uitableedit.js +0 -0
  99. data/{specs → spec}/cucumber/formatters/profile_formatter_spec.rb +0 -0
  100. data/{specs → spec}/cucumber/parser/feature_parser_spec.rb +43 -41
  101. data/{specs → spec}/cucumber/parser/table_parser_spec.rb +0 -0
  102. data/{specs → spec}/cucumber/rails/stubs/mini_rails.rb +0 -0
  103. data/{specs → spec}/cucumber/rails/stubs/test_help.rb +0 -0
  104. data/{specs → spec}/cucumber/rails/world_spec.rb +0 -0
  105. data/{specs → spec}/cucumber/sell_cucumbers.feature +0 -0
  106. data/{specs → spec}/cucumber/step_definition_spec.rb +0 -0
  107. data/{specs → spec}/cucumber/step_mother_spec.rb +63 -4
  108. data/{specs → spec}/cucumber/treetop_parser/empty_feature.feature +0 -0
  109. data/{specs → spec}/cucumber/treetop_parser/empty_scenario.feature +0 -0
  110. data/{specs → spec}/cucumber/treetop_parser/empty_scenario_outline.feature +0 -0
  111. data/{specs → spec}/cucumber/treetop_parser/fit_scenario.feature +0 -0
  112. data/{specs → spec}/cucumber/treetop_parser/given_scenario.feature +0 -0
  113. data/{specs → spec}/cucumber/treetop_parser/invalid_scenario_outlines.feature +0 -0
  114. data/{specs → spec}/cucumber/treetop_parser/multiline_steps.feature +0 -0
  115. data/{specs → spec}/cucumber/treetop_parser/multiple_tables.feature +0 -0
  116. data/{specs → spec}/cucumber/treetop_parser/scenario_outline.feature +0 -0
  117. data/{specs → spec}/cucumber/treetop_parser/spaces.feature +0 -0
  118. data/{specs → spec}/cucumber/treetop_parser/test_dos.feature +0 -0
  119. data/{specs → spec}/cucumber/treetop_parser/with_comments.feature +0 -0
  120. data/{specs → spec}/cucumber/treetop_parser/with_tags.feature +0 -0
  121. data/{specs → spec}/cucumber/world/pending_spec.rb +0 -0
  122. data/{specs → spec}/spec.opts +0 -0
  123. data/{specs → spec}/spec_helper.rb +2 -11
  124. metadata +72 -51
  125. data/examples/tickets/cucumber.yml +0 -3
  126. data/lib/cucumber/parser/basic.rb +0 -0
  127. data/specs/cucumber/ast/tags_spec.rb +0 -19
  128. data/specs/cucumber/core_ext/proc_spec.rb +0 -37
@@ -10,18 +10,30 @@ module Cucumber
10
10
 
11
11
  rule table
12
12
  table_row+ {
13
- def build
13
+ def at_line?(line)
14
+ elements.detect{|table_row| table_row.at_line?(line)}
15
+ end
16
+
17
+ def build(filter=nil)
14
18
  Ast::Table.new(raw)
15
19
  end
16
20
 
17
- def raw
18
- elements.map{|e| e.build}
21
+ def raw(filter=nil, scenario_outline=nil)
22
+ elements.map do |table_row|
23
+ if(filter.nil? || table_row == elements[0] || filter.at_line?(table_row) || (scenario_outline && filter.outline_at_line?(scenario_outline)))
24
+ table_row.build
25
+ end
26
+ end.compact
19
27
  end
20
28
  }
21
29
  end
22
30
 
23
31
  rule table_row
24
32
  space* '|' cells:(cell '|')+ space* (eol+ / eof) {
33
+ def at_line?(line)
34
+ cells.line == line
35
+ end
36
+
25
37
  def build
26
38
  row = cells.elements.map do |elt|
27
39
  value = elt.cell.text_value.strip
@@ -12,37 +12,76 @@ end
12
12
 
13
13
  module Cucumber
14
14
  module Parser
15
- module TreetopExt
15
+ class Filter
16
+ def initialize(lines, options)
17
+ @lines = lines
18
+ @include_tags = options[:include_tags] || []
19
+ @exclude_tags = options[:exclude_tags] || []
20
+ @names = options[:scenario_names] || []
21
+ end
22
+
23
+ def accept?(syntax_node)
24
+ at_line?(syntax_node) &&
25
+ matches_tags?(syntax_node) &&
26
+ matches_names?(syntax_node)
27
+ end
28
+
29
+ def at_line?(syntax_node)
30
+ @lines.nil? || @lines.empty? || @lines.detect{|line| syntax_node.at_line?(line)}
31
+ end
32
+
33
+ def outline_at_line?(syntax_node)
34
+ @lines.nil? || @lines.empty? || @lines.detect{|line| syntax_node.outline_at_line?(line)}
35
+ end
36
+
37
+ def matches_tags?(syntax_node)
38
+ !excluded_by_tags?(syntax_node) &&
39
+ included_by_tags?(syntax_node)
40
+ end
41
+
42
+ def included_by_tags?(syntax_node)
43
+ @include_tags.empty? || syntax_node.has_tags?(@include_tags)
44
+ end
45
+
46
+ def excluded_by_tags?(syntax_node)
47
+ @exclude_tags.any? && syntax_node.has_tags?(@exclude_tags)
48
+ end
49
+
50
+ def matches_names?(syntax_node)
51
+ @names.nil? || @names.empty? || @names.detect{|name| syntax_node.matches_name?(name)}
52
+ end
53
+ end
54
+
55
+ module TreetopExt
16
56
  FILE_COLON_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/
17
57
 
18
58
  # Parses a file and returns a Cucumber::Ast
19
- def parse_file(file)
59
+ def parse_file(file, options)
20
60
  _, path, lines = *FILE_COLON_LINE_PATTERN.match(file)
21
61
  if path
22
62
  lines = lines.split(':').map { |line| line.to_i }
23
63
  else
24
64
  path = file
25
- lines = []
26
65
  end
66
+ filter = Filter.new(lines, options)
27
67
 
28
- loader = lambda { |io| parse_or_fail(io.read, path) }
68
+ loader = lambda { |io| parse_or_fail(io.read, filter, path) }
29
69
  feature = if path =~ /^http/
30
70
  require 'open-uri'
31
71
  open(path, &loader)
32
72
  else
33
73
  File.open(path, Cucumber.file_mode('r'), &loader)
34
74
  end
35
- feature.lines = lines
36
75
  feature
37
76
  end
38
77
 
39
- def parse_or_fail(s, file=nil, line_offset=0)
40
- parse_tree = parse(s)
78
+ def parse_or_fail(string, filter=nil, file=nil, line_offset=0)
79
+ parse_tree = parse(string)
41
80
  if parse_tree.nil?
42
81
  raise Cucumber::Parser::SyntaxError.new(self, file, line_offset)
43
82
  else
44
- ast = parse_tree.build
45
- ast.file = file
83
+ ast = parse_tree.build(filter) # may return nil if it doesn't match filter.
84
+ ast.file = file unless ast.nil?
46
85
  ast
47
86
  end
48
87
  end
@@ -27,26 +27,45 @@ module Cucumber
27
27
  class Task
28
28
  LIB = File.expand_path(File.dirname(__FILE__) + '/../..') # :nodoc:
29
29
 
30
+ # TODO: remove depreated accessors for 0.4.0
31
+ def self.deprecate_accessor(attribute) # :nodoc:
32
+ attr_reader attribute
33
+ class_eval <<-EOF, __FILE__, __LINE__ + 1
34
+ def #{attribute}=(value)
35
+ @#{attribute} = value
36
+ warn("Cucumber::Rake::Task##{attribute} is deprecated and will be removed in 0.4.0. Please use profiles for complex settings: http://wiki.github.com/aslakhellesoy/cucumber/using-rake#profiles")
37
+ end
38
+ EOF
39
+ end
40
+
30
41
  # Directories to add to the Ruby $LOAD_PATH
31
42
  attr_accessor :libs
32
43
  # Name of the cucumber binary to use for running features. Defaults to Cucumber::BINARY
33
44
  attr_accessor :binary
34
45
  # Array of paths to specific step definition files to use
35
- attr_accessor :step_list
46
+ deprecate_accessor :step_list
36
47
  # File pattern for finding step definitions. Defaults to
37
48
  # 'features/**/*.rb'.
38
- attr_accessor :step_pattern
49
+ deprecate_accessor :step_pattern
39
50
  # Array of paths to specific features to run.
40
- attr_accessor :feature_list
51
+ deprecate_accessor :feature_list
41
52
  # File pattern for finding features to run. Defaults to
42
- # 'features/**/*.feature'. Can be overriden by the FEATURE environment variable.
43
- attr_accessor :feature_pattern
53
+ # 'features/**/*.feature'. Can be overridden by the FEATURE environment variable.
54
+ deprecate_accessor :feature_pattern
44
55
  # Extra options to pass to the cucumber binary. Can be overridden by the CUCUMBER_OPTS environment variable.
45
56
  attr_accessor :cucumber_opts
46
57
  # Run cucumber with RCov?
47
58
  attr_accessor :rcov
48
59
  # Extra options to pass to rcov
49
60
  attr_accessor :rcov_opts
61
+ # Define what profile to be used. When used with cucumber_opts it is simply appended to it. Will be ignored when CUCUMBER_OPTS is used.
62
+ def profile=(profile)
63
+ @profile = profile
64
+ unless feature_list
65
+ @feature_list = [] # Don't use accessor to avoid deprecation warning.
66
+ end
67
+ end
68
+ attr_reader :profile
50
69
 
51
70
  # Define a Rake
52
71
  def initialize(task_name = "features", desc = "Run Features with Cucumber")
@@ -75,7 +94,7 @@ module Cucumber
75
94
  def arguments_for_ruby_execution(task_args = nil) # :nodoc:
76
95
  lib_args = ['"%s"' % libs.join(File::PATH_SEPARATOR)]
77
96
  cucumber_bin = ['"%s"' % binary]
78
- cuc_opts = [(ENV['CUCUMBER_OPTS'] || cucumber_opts)]
97
+ cuc_opts = [(ENV['CUCUMBER_OPTS'] || cucumber_opts_with_profile)]
79
98
 
80
99
  step_files(task_args).each do |step_file|
81
100
  cuc_opts << '--require'
@@ -92,6 +111,10 @@ module Cucumber
92
111
  args
93
112
  end
94
113
 
114
+ def cucumber_opts_with_profile # :nodoc:
115
+ @profile ? "#{cucumber_opts} --profile #{@profile}" : cucumber_opts
116
+ end
117
+
95
118
  def feature_files(task_args = nil) # :nodoc:
96
119
  if ENV['FEATURE']
97
120
  FileList[ ENV['FEATURE'] ]
@@ -59,7 +59,7 @@ module Cucumber
59
59
  PARAM_PATTERN = /"([^\"]*)"/
60
60
  ESCAPED_PARAM_PATTERN = '"([^\\"]*)"'
61
61
 
62
- def self.snippet_text(step_keyword, step_name)
62
+ def self.snippet_text(step_keyword, step_name, multiline_arg_class = nil)
63
63
  escaped = Regexp.escape(step_name).gsub('\ ', ' ').gsub('/', '\/')
64
64
  escaped = escaped.gsub(PARAM_PATTERN, ESCAPED_PARAM_PATTERN)
65
65
 
@@ -68,9 +68,11 @@ module Cucumber
68
68
  n += 1
69
69
  "arg#{n}"
70
70
  end
71
+ block_args << multiline_arg_class.default_arg_name unless multiline_arg_class.nil?
71
72
  block_arg_string = block_args.empty? ? "" : " |#{block_args.join(", ")}|"
73
+ multiline_class_string = multiline_arg_class ? "# #{multiline_arg_class.default_arg_name} is a #{multiline_arg_class.to_s}\n " : ""
72
74
 
73
- "#{step_keyword} /^#{escaped}$/ do#{block_arg_string}\n pending\nend"
75
+ "#{step_keyword} /^#{escaped}$/ do#{block_arg_string}\n #{multiline_class_string}pending\nend"
74
76
  end
75
77
 
76
78
  class MissingProc < StandardError
@@ -45,11 +45,43 @@ module Cucumber
45
45
  end
46
46
  end
47
47
 
48
+ class NilWorld < StandardError
49
+ def initialize
50
+ super("World procs should never return nil")
51
+ end
52
+ end
53
+
54
+ class MultipleWorld < StandardError
55
+ def initialize(first_proc, second_proc)
56
+ message = "You can only pass a proc to #World once, but it's happening\n"
57
+ message << "in 2 places:\n\n"
58
+ message << first_proc.backtrace_line('World') << "\n"
59
+ message << second_proc.backtrace_line('World') << "\n\n"
60
+ message << "Use Ruby modules instead to extend your worlds. See the #World RDoc.\n\n"
61
+ super(message)
62
+ end
63
+ end
64
+
48
65
  # This is the main interface for registering step definitions, which is done
49
66
  # from <tt>*_steps.rb</tt> files. This module is included right at the top-level
50
67
  # so #register_step_definition (and more interestingly - its aliases) are
51
68
  # available from the top-level.
52
69
  module StepMother
70
+ class Hook
71
+ def initialize(tag_names, proc)
72
+ @tag_names = tag_names.map{|tag| Ast::Tags.strip_prefix(tag)}
73
+ @proc = proc
74
+ end
75
+
76
+ def matches_tag_names?(tag_names)
77
+ @tag_names.empty? || (@tag_names & tag_names).any?
78
+ end
79
+
80
+ def execute_in(world, scenario, location)
81
+ world.cucumber_instance_exec(false, location, scenario, &@proc)
82
+ end
83
+ end
84
+
53
85
  class << self
54
86
  def alias_adverb(adverb)
55
87
  adverb = adverb.gsub(/\s/, '')
@@ -97,18 +129,68 @@ module Cucumber
97
129
 
98
130
  # Registers a Before proc. You can call this method as many times as you
99
131
  # want (typically from ruby scripts under <tt>support</tt>).
100
- def Before(&proc)
101
- (@before_procs ||= []) << proc
132
+ def Before(*tag_names, &proc)
133
+ register_hook(:before, tag_names, proc)
102
134
  end
103
135
 
104
- def After(&proc)
105
- (@after_procs ||= []).unshift(proc)
136
+ def After(*tag_names, &proc)
137
+ register_hook(:after, tag_names, proc)
106
138
  end
107
139
 
108
- # Registers a World proc. You can call this method as many times as you
109
- # want (typically from ruby scripts under <tt>support</tt>).
110
- def World(&proc)
111
- (@world_procs ||= []) << proc
140
+ def register_hook(phase, tags, proc)
141
+ hook = Hook.new(tags, proc)
142
+ hooks[phase] << hook
143
+ hook
144
+ end
145
+
146
+ def hooks
147
+ @hooks ||= Hash.new {|hash, phase| hash[phase] = []}
148
+ end
149
+
150
+ def hooks_for(phase, scenario)
151
+ hooks[phase].select{|hook| scenario.accept_hook?(hook)}
152
+ end
153
+
154
+ # Registers any number of +world_modules+ (Ruby Modules) and/or a Proc.
155
+ # The +proc+ will be executed once before each scenario to create an
156
+ # Object that the scenario's steps will run within. Any +world_modules+
157
+ # will be mixed into this Object (via Object#extend).
158
+ #
159
+ # This method is typically called from one or more Ruby scripts under
160
+ # <tt>features/support</tt>. You can call this method as many times as you
161
+ # like (to register more modules), but if you try to register more than
162
+ # one Proc you will get an error.
163
+ #
164
+ # Cucumber will not yield anything to the +proc+ (like it used to do before v0.3).
165
+ #
166
+ # In earlier versions of Cucumber (before 0.3) you could not register
167
+ # any +world_modules+. Instead you would register several Proc objects (by
168
+ # calling the method several times). The result of each +proc+ would be yielded
169
+ # to the next +proc+. Example:
170
+ #
171
+ # World do |world| # NOT SUPPORTED FROM 0.3
172
+ # MyClass.new
173
+ # end
174
+ #
175
+ # World do |world| # NOT SUPPORTED FROM 0.3
176
+ # world.extend(MyModule)
177
+ # end
178
+ #
179
+ # From Cucumber 0.3 the recommended way to do this is:
180
+ #
181
+ # World do
182
+ # MyClass.new
183
+ # end
184
+ #
185
+ # World(MyModule)
186
+ #
187
+ def World(*world_modules, &proc)
188
+ if(proc)
189
+ raise MultipleWorld.new(@world_proc, proc) if @world_proc
190
+ @world_proc = proc
191
+ end
192
+ @world_modules ||= []
193
+ @world_modules += world_modules
112
194
  end
113
195
 
114
196
  def current_world
@@ -139,21 +221,27 @@ module Cucumber
139
221
  @step_definitions ||= []
140
222
  end
141
223
 
142
- def snippet_text(step_keyword, step_name)
143
- @snippet_generator.snippet_text(step_keyword, step_name)
224
+ def snippet_text(step_keyword, step_name, multiline_arg_class)
225
+ @snippet_generator.snippet_text(step_keyword, step_name, multiline_arg_class)
144
226
  end
145
227
 
146
228
  def before_and_after(scenario, skip=false)
147
- unless current_world || skip
229
+ before(scenario) unless skip
230
+ yield
231
+ after(scenario) unless skip
232
+ scenario_visited(scenario)
233
+ end
234
+
235
+ def before(scenario)
236
+ unless current_world
148
237
  new_world!
149
238
  execute_before(scenario)
150
239
  end
151
- if block_given?
152
- yield
153
- execute_after(scenario) unless skip
154
- nil_world!
155
- scenario_visited(scenario)
156
- end
240
+ end
241
+
242
+ def after(scenario)
243
+ execute_after(scenario)
244
+ nil_world!
157
245
  end
158
246
 
159
247
  private
@@ -168,17 +256,46 @@ module Cucumber
168
256
 
169
257
  # Creates a new world instance
170
258
  def new_world!
171
- @current_world = Object.new
172
- (@world_procs ||= []).each do |proc|
173
- @current_world = proc.call(@current_world)
259
+ create_world!
260
+ extend_world
261
+ connect_world
262
+ @current_world
263
+ end
264
+
265
+ def create_world!
266
+ if(@world_proc)
267
+ @current_world = @world_proc.call
268
+ check_nil(@current_world, @world_proc)
269
+ else
270
+ @current_world = Object.new
174
271
  end
272
+ end
175
273
 
274
+ def extend_world
176
275
  @current_world.extend(World)
276
+ @current_world.extend(::Spec::Matchers) if defined?(::Spec::Matchers)
277
+ (@world_modules || []).each do |mod|
278
+ @current_world.extend(mod)
279
+ end
280
+ end
281
+
282
+ def connect_world
177
283
  @current_world.__cucumber_step_mother = self
178
284
  @current_world.__cucumber_visitor = @visitor
285
+ end
179
286
 
180
- @current_world.extend(::Spec::Matchers) if defined?(::Spec::Matchers)
181
- @current_world
287
+ def check_nil(o, proc)
288
+ if o.nil?
289
+ begin
290
+ raise NilWorld.new
291
+ rescue NilWorld => e
292
+ e.backtrace.clear
293
+ e.backtrace.push(proc.backtrace_line("World"))
294
+ raise e
295
+ end
296
+ else
297
+ o
298
+ end
182
299
  end
183
300
 
184
301
  def nil_world!
@@ -186,14 +303,14 @@ module Cucumber
186
303
  end
187
304
 
188
305
  def execute_before(scenario)
189
- (@before_procs ||= []).each do |proc|
190
- @current_world.cucumber_instance_exec(false, 'Before', scenario, &proc)
306
+ hooks_for(:before, scenario).each do |hook|
307
+ hook.execute_in(@current_world, scenario, 'Before')
191
308
  end
192
309
  end
193
310
 
194
311
  def execute_after(scenario)
195
- (@after_procs ||= []).each do |proc|
196
- @current_world.cucumber_instance_exec(false, 'After', scenario, &proc)
312
+ hooks_for(:after, scenario).each do |hook|
313
+ hook.execute_in(@current_world, scenario, 'After')
197
314
  end
198
315
  end
199
316
 
@@ -1,8 +1,8 @@
1
1
  module Cucumber #:nodoc:
2
2
  class VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
5
- TINY = 3
4
+ MINOR = 3
5
+ TINY = 0
6
6
  PATCH = nil # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')