cucumber 0.2.3 → 0.3.0

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