cucumber 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. data/.rspec +1 -1
  2. data/Caliper.yml +4 -0
  3. data/History.txt +1557 -0
  4. data/LICENSE +1 -1
  5. data/README.rdoc +26 -0
  6. data/Rakefile +51 -5
  7. data/VERSION.yml +5 -0
  8. data/bin/cucumber +1 -7
  9. data/cucumber.gemspec +77 -3
  10. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +1 -1
  11. data/examples/i18n/he/features/step_definitons/calculator_steps.rb +1 -1
  12. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +7 -4
  13. data/examples/i18n/ro/features/suma.feature +11 -0
  14. data/examples/i18n/ru/features/division.feature +2 -2
  15. data/examples/i18n/tr/features/step_definitons/hesap_makinesi_adimlari.rb +3 -3
  16. data/examples/sinatra/features/support/env.rb +5 -2
  17. data/examples/v8/features/fibonacci.feature +1 -1
  18. data/examples/watir/features/step_definitions/search_steps.rb +1 -1
  19. data/features/announce.feature +164 -0
  20. data/features/around_hooks.feature +232 -0
  21. data/features/background.feature +95 -284
  22. data/features/bug_371.feature +32 -0
  23. data/features/bug_464.feature +16 -0
  24. data/features/bug_475.feature +42 -0
  25. data/features/bug_585_tab_indentation.feature +22 -0
  26. data/features/bug_600.feature +67 -0
  27. data/features/call_steps_from_stepdefs.feature +154 -0
  28. data/features/cucumber_cli.feature +591 -0
  29. data/features/cucumber_cli_outlines.feature +117 -0
  30. data/features/custom_formatter.feature +73 -3
  31. data/features/default_snippets.feature +42 -0
  32. data/features/diffing.feature +25 -0
  33. data/features/drb_server_integration.feature +174 -0
  34. data/features/exception_in_after_block.feature +127 -0
  35. data/features/exception_in_after_step_block.feature +104 -0
  36. data/features/exception_in_before_block.feature +98 -0
  37. data/features/exclude_files.feature +20 -0
  38. data/features/expand.feature +60 -0
  39. data/features/html_formatter.feature +8 -0
  40. data/features/html_formatter/a.html +582 -0
  41. data/features/json_formatter.feature +245 -160
  42. data/features/junit_formatter.feature +88 -0
  43. data/features/language_from_header.feature +30 -0
  44. data/features/language_help.feature +78 -0
  45. data/features/listener_debugger_formatter.feature +42 -0
  46. data/features/multiline_names.feature +44 -0
  47. data/features/negative_tagged_hooks.feature +60 -0
  48. data/features/post_configuration_hook.feature +37 -0
  49. data/features/profiles.feature +126 -0
  50. data/features/rake_task.feature +152 -0
  51. data/features/report_called_undefined_steps.feature +34 -0
  52. data/features/rerun_formatter.feature +45 -0
  53. data/features/simplest.feature +11 -0
  54. data/features/snippet.feature +23 -0
  55. data/features/snippets_when_using_star_keyword.feature +36 -0
  56. data/features/step_definitions/cucumber_steps.rb +153 -7
  57. data/features/step_definitions/extra_steps.rb +2 -0
  58. data/features/step_definitions/simplest_steps.rb +3 -0
  59. data/features/step_definitions/wire_steps.rb +32 -0
  60. data/features/support/env.rb +140 -18
  61. data/features/support/env.rb.simplest +7 -0
  62. data/features/support/fake_wire_server.rb +77 -0
  63. data/features/table_diffing.feature +45 -0
  64. data/features/table_mapping.feature +34 -0
  65. data/features/tag_logic.feature +258 -0
  66. data/features/transform.feature +245 -0
  67. data/features/unicode_table.feature +35 -0
  68. data/features/usage_and_stepdefs_formatter.feature +169 -0
  69. data/features/wire_protocol.feature +332 -0
  70. data/features/wire_protocol_table_diffing.feature +119 -0
  71. data/features/wire_protocol_tags.feature +87 -0
  72. data/features/wire_protocol_timeouts.feature +63 -0
  73. data/features/work_in_progress.feature +156 -0
  74. data/fixtures/json/features/pystring.feature +8 -0
  75. data/fixtures/junit/features/pending.feature +1 -3
  76. data/fixtures/self_test/features/background/background_tagged_before_on_outline.feature +12 -0
  77. data/fixtures/self_test/features/background/background_with_name.feature +7 -0
  78. data/fixtures/self_test/features/background/failing_background.feature +12 -0
  79. data/fixtures/self_test/features/background/failing_background_after_success.feature +11 -0
  80. data/fixtures/self_test/features/background/multiline_args_background.feature +32 -0
  81. data/fixtures/self_test/features/background/passing_background.feature +10 -0
  82. data/fixtures/self_test/features/background/pending_background.feature +10 -0
  83. data/fixtures/self_test/features/background/scenario_outline_failing_background.feature +16 -0
  84. data/fixtures/self_test/features/background/scenario_outline_passing_background.feature +16 -0
  85. data/fixtures/self_test/features/support/env.rb +0 -8
  86. data/fixtures/tickets/features.html +1 -1
  87. data/gem_tasks/examples.rake +1 -1
  88. data/gem_tasks/features.rake +14 -0
  89. data/gem_tasks/sdoc.rake +12 -0
  90. data/lib/cucumber.rb +0 -12
  91. data/lib/cucumber/ast.rb +1 -1
  92. data/lib/cucumber/ast/background.rb +5 -21
  93. data/lib/cucumber/ast/examples.rb +4 -12
  94. data/lib/cucumber/ast/feature.rb +5 -13
  95. data/lib/cucumber/ast/feature_element.rb +4 -9
  96. data/lib/cucumber/ast/outline_table.rb +4 -4
  97. data/lib/cucumber/ast/py_string.rb +80 -0
  98. data/lib/cucumber/ast/scenario.rb +5 -7
  99. data/lib/cucumber/ast/scenario_outline.rb +15 -23
  100. data/lib/cucumber/ast/step.rb +0 -5
  101. data/lib/cucumber/ast/step_invocation.rb +15 -21
  102. data/lib/cucumber/ast/table.rb +8 -14
  103. data/lib/cucumber/ast/tree_walker.rb +48 -10
  104. data/lib/cucumber/cli/configuration.rb +8 -33
  105. data/lib/cucumber/cli/main.rb +35 -20
  106. data/lib/cucumber/cli/options.rb +7 -8
  107. data/lib/cucumber/cli/profile_loader.rb +0 -2
  108. data/lib/cucumber/core_ext/proc.rb +1 -2
  109. data/lib/cucumber/feature_file.rb +15 -47
  110. data/lib/cucumber/formatter/ansicolor.rb +5 -3
  111. data/lib/cucumber/formatter/color_io.rb +23 -0
  112. data/lib/cucumber/formatter/console.rb +23 -27
  113. data/lib/cucumber/formatter/cucumber.css +17 -34
  114. data/lib/cucumber/formatter/cucumber.sass +182 -173
  115. data/lib/cucumber/formatter/html.rb +11 -46
  116. data/lib/cucumber/formatter/io.rb +4 -2
  117. data/lib/cucumber/formatter/json.rb +152 -15
  118. data/lib/cucumber/formatter/json_pretty.rb +6 -5
  119. data/lib/cucumber/formatter/junit.rb +22 -28
  120. data/lib/cucumber/formatter/pdf.rb +6 -6
  121. data/lib/cucumber/formatter/pretty.rb +5 -5
  122. data/lib/cucumber/formatter/rerun.rb +11 -22
  123. data/lib/cucumber/formatter/tag_cloud.rb +35 -0
  124. data/lib/cucumber/formatter/unicode.rb +20 -41
  125. data/lib/cucumber/js_support/js_dsl.js +4 -4
  126. data/lib/cucumber/js_support/js_language.rb +5 -9
  127. data/lib/cucumber/js_support/js_snippets.rb +2 -2
  128. data/lib/cucumber/language_support.rb +2 -2
  129. data/lib/cucumber/parser/gherkin_builder.rb +30 -35
  130. data/lib/cucumber/platform.rb +8 -8
  131. data/lib/cucumber/py_support/py_language.rb +2 -2
  132. data/lib/cucumber/rake/task.rb +31 -74
  133. data/lib/cucumber/rb_support/rb_dsl.rb +0 -1
  134. data/lib/cucumber/rb_support/rb_language.rb +8 -10
  135. data/lib/cucumber/rb_support/rb_step_definition.rb +0 -8
  136. data/lib/cucumber/rb_support/rb_transform.rb +0 -17
  137. data/lib/cucumber/rb_support/rb_world.rb +18 -26
  138. data/lib/cucumber/rspec/doubles.rb +3 -3
  139. data/lib/cucumber/step_match.rb +2 -6
  140. data/lib/cucumber/step_mother.rb +427 -6
  141. data/lib/cucumber/wire_support/configuration.rb +1 -4
  142. data/lib/cucumber/wire_support/wire_language.rb +10 -3
  143. data/spec/cucumber/ast/background_spec.rb +6 -68
  144. data/spec/cucumber/ast/feature_factory.rb +4 -5
  145. data/spec/cucumber/ast/feature_spec.rb +4 -4
  146. data/spec/cucumber/ast/outline_table_spec.rb +1 -1
  147. data/spec/cucumber/ast/py_string_spec.rb +40 -0
  148. data/spec/cucumber/ast/scenario_outline_spec.rb +11 -15
  149. data/spec/cucumber/ast/scenario_spec.rb +4 -4
  150. data/spec/cucumber/ast/step_spec.rb +3 -3
  151. data/spec/cucumber/ast/table_spec.rb +2 -38
  152. data/spec/cucumber/ast/tree_walker_spec.rb +2 -2
  153. data/spec/cucumber/broadcaster_spec.rb +1 -1
  154. data/spec/cucumber/cli/configuration_spec.rb +6 -32
  155. data/spec/cucumber/cli/drb_client_spec.rb +3 -2
  156. data/spec/cucumber/cli/main_spec.rb +43 -43
  157. data/spec/cucumber/cli/options_spec.rb +1 -28
  158. data/spec/cucumber/cli/profile_loader_spec.rb +1 -1
  159. data/spec/cucumber/core_ext/proc_spec.rb +1 -1
  160. data/spec/cucumber/formatter/ansicolor_spec.rb +1 -1
  161. data/spec/cucumber/formatter/color_io_spec.rb +29 -0
  162. data/spec/cucumber/formatter/duration_spec.rb +1 -1
  163. data/spec/cucumber/formatter/html_spec.rb +5 -3
  164. data/spec/cucumber/formatter/junit_spec.rb +2 -16
  165. data/spec/cucumber/formatter/progress_spec.rb +1 -1
  166. data/spec/cucumber/formatter/spec_helper.rb +12 -11
  167. data/spec/cucumber/rb_support/rb_language_spec.rb +28 -241
  168. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +28 -33
  169. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +1 -1
  170. data/spec/cucumber/step_match_spec.rb +9 -11
  171. data/spec/cucumber/step_mother_spec.rb +302 -0
  172. data/spec/cucumber/wire_support/configuration_spec.rb +1 -1
  173. data/spec/cucumber/wire_support/connection_spec.rb +1 -1
  174. data/spec/cucumber/wire_support/wire_exception_spec.rb +1 -1
  175. data/spec/cucumber/wire_support/wire_language_spec.rb +1 -1
  176. data/spec/cucumber/wire_support/wire_packet_spec.rb +1 -1
  177. data/spec/cucumber/wire_support/wire_step_definition_spec.rb +1 -1
  178. data/spec/cucumber/world/pending_spec.rb +2 -2
  179. data/spec/spec_helper.rb +20 -13
  180. metadata +78 -4
@@ -1,12 +1,10 @@
1
- require 'cucumber/ast/feature_element'
2
- require 'cucumber/ast/names'
3
-
4
1
  module Cucumber
5
2
  module Ast
6
3
  class ScenarioOutline #:nodoc:
7
4
  include FeatureElement
8
- include Names
9
5
 
6
+ attr_reader :name
7
+
10
8
  module ExamplesArray #:nodoc:
11
9
  def accept(visitor)
12
10
  return if Cucumber.wants_to_quit
@@ -22,12 +20,12 @@ module Cucumber
22
20
  # * Examples keyword
23
21
  # * Examples section name
24
22
  # * Raw matrix
25
- def initialize(background, comment, tags, line, keyword, title, description, raw_steps, example_sections)
26
- @background, @comment, @tags, @line, @keyword, @title, @description, @raw_steps, @example_sections = background, comment, tags, line, keyword, title, description, raw_steps, example_sections
23
+ def initialize(background, comment, tags, line, keyword, name, raw_steps, example_sections)
24
+ @background, @comment, @tags, @line, @keyword, @name, @raw_steps, @example_sections = background, comment, tags, line, keyword, name, raw_steps, example_sections
27
25
  end
28
26
 
29
- def add_examples(example_section, gherkin_examples)
30
- @example_sections << [example_section, gherkin_examples]
27
+ def add_examples(example_section)
28
+ @example_sections << example_section
31
29
  end
32
30
 
33
31
  def init
@@ -35,21 +33,15 @@ module Cucumber
35
33
  attach_steps(@raw_steps)
36
34
  @steps = StepCollection.new(@raw_steps)
37
35
 
38
- @examples_array = @example_sections.map do |example_section_and_gherkin_examples|
39
- example_section = example_section_and_gherkin_examples[0]
40
- gherkin_examples = example_section_and_gherkin_examples[1]
41
-
42
- examples_comment = example_section[0]
43
- examples_line = example_section[1]
44
- examples_keyword = example_section[2]
45
- examples_title = example_section[3]
46
- examples_description = example_section[4]
47
- examples_matrix = example_section[5]
36
+ @examples_array = @example_sections.map do |example_section|
37
+ examples_comment = example_section[0]
38
+ examples_line = example_section[1]
39
+ examples_keyword = example_section[2]
40
+ examples_name = example_section[3]
41
+ examples_matrix = example_section[4]
48
42
 
49
43
  examples_table = OutlineTable.new(examples_matrix, self)
50
- ex = Examples.new(examples_comment, examples_line, examples_keyword, examples_title, examples_description, examples_table)
51
- ex.gherkin_statement(gherkin_examples)
52
- ex
44
+ Examples.new(examples_comment, examples_line, examples_keyword, examples_name, examples_table)
53
45
  end
54
46
 
55
47
  @examples_array.extend(ExamplesArray)
@@ -61,7 +53,7 @@ module Cucumber
61
53
  return if Cucumber.wants_to_quit
62
54
  visitor.visit_comment(@comment) unless @comment.empty?
63
55
  visitor.visit_tags(@tags)
64
- visitor.visit_scenario_name(@keyword, name, file_colon_line(@line), source_indent(first_line_length))
56
+ visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
65
57
  visitor.visit_steps(@steps)
66
58
 
67
59
  skip_invoke! if @background && @background.failed?
@@ -110,7 +102,7 @@ module Cucumber
110
102
 
111
103
  def to_sexp
112
104
  init
113
- sexp = [:scenario_outline, @keyword, name]
105
+ sexp = [:scenario_outline, @keyword, @name]
114
106
  comment = @comment.to_sexp
115
107
  sexp += [comment] if comment
116
108
  tags = @tags.to_sexp
@@ -14,11 +14,6 @@ module Cucumber
14
14
  @line, @keyword, @name, @multiline_arg = line, keyword, name, multiline_arg
15
15
  end
16
16
 
17
- attr_reader :gherkin_statement
18
- def gherkin_statement(statement=nil)
19
- @gherkin_statement ||= statement
20
- end
21
-
22
17
  def background?
23
18
  false
24
19
  end
@@ -1,4 +1,3 @@
1
- require 'cucumber/errors'
2
1
  require 'cucumber/step_match'
3
2
  require 'cucumber/ast/table'
4
3
  require 'gherkin/rubify'
@@ -39,7 +38,7 @@ module Cucumber
39
38
 
40
39
  def accept(visitor)
41
40
  return if Cucumber.wants_to_quit
42
- invoke(visitor.step_mother, visitor.configuration)
41
+ invoke(visitor.step_mother, visitor.options)
43
42
  visit_step_result(visitor)
44
43
  end
45
44
 
@@ -55,64 +54,63 @@ module Cucumber
55
54
  )
56
55
  end
57
56
 
58
- def invoke(step_mother, configuration)
59
- find_step_match!(step_mother, configuration)
60
- unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
57
+ def invoke(step_mother, options)
58
+ find_step_match!(step_mother)
59
+ unless @skip_invoke || options[:dry_run] || @exception || @step_collection.exception
61
60
  @skip_invoke = true
62
61
  begin
63
62
  @step_match.invoke(@multiline_arg)
64
63
  step_mother.after_step
65
64
  status!(:passed)
66
65
  rescue Pending => e
67
- failed(configuration, e, false)
66
+ failed(options, e, false)
68
67
  status!(:pending)
69
68
  rescue Undefined => e
70
- failed(configuration, e, false)
69
+ failed(options, e, false)
71
70
  status!(:undefined)
72
71
  rescue Cucumber::Ast::Table::Different => e
73
72
  @different_table = e.table
74
- failed(configuration, e, false)
73
+ failed(options, e, false)
75
74
  status!(:failed)
76
75
  rescue Exception => e
77
- failed(configuration, e, false)
76
+ failed(options, e, false)
78
77
  status!(:failed)
79
78
  end
80
79
  end
81
80
  end
82
81
 
83
- def find_step_match!(step_mother, configuration)
82
+ def find_step_match!(step_mother)
84
83
  return if @step_match
85
84
  begin
86
85
  @step_match = step_mother.step_match(@name)
87
86
  rescue Undefined => e
88
- failed(configuration, e, true)
87
+ failed(step_mother.options, e, true)
89
88
  status!(:undefined)
90
89
  @step_match = NoStepMatch.new(@step, @name)
91
90
  rescue Ambiguous => e
92
- failed(configuration, e, false)
91
+ failed(step_mother.options, e, false)
93
92
  status!(:failed)
94
93
  @step_match = NoStepMatch.new(@step, @name)
95
94
  end
96
95
  step_mother.step_visited(self)
97
96
  end
98
97
 
99
- def failed(configuration, e, clear_backtrace)
98
+ def failed(options, e, clear_backtrace)
100
99
  e = filter_backtrace(e)
101
100
  e.set_backtrace([]) if clear_backtrace
102
101
  e.backtrace << @step.backtrace_line unless @step.backtrace_line.nil?
103
102
  @exception = e
104
- if(configuration.strict? || !(Undefined === e) || e.nested?)
103
+ if(options[:strict] || !(Undefined === e) || e.nested?)
105
104
  @reported_exception = e
106
105
  else
107
106
  @reported_exception = nil
108
107
  end
109
108
  end
110
109
 
111
- PWD_PATTERN = /#{Regexp.escape(Dir.pwd)}\//m
112
-
113
110
  def filter_backtrace(e)
114
111
  return e if Cucumber.use_full_backtrace
115
- (e.backtrace || []).each{|line| line.gsub!(PWD_PATTERN, "./")}
112
+ pwd = /#{Regexp.escape(Dir.pwd)}\//m
113
+ (e.backtrace || []).each{|line| line.gsub!(pwd, "./")}
116
114
 
117
115
  filtered = (e.backtrace || []).reject do |line|
118
116
  BACKTRACE_FILTER_PATTERNS.detect { |p| line =~ p }
@@ -187,10 +185,6 @@ module Cucumber
187
185
  @step.language
188
186
  end
189
187
 
190
- def gherkin_statement
191
- @step.gherkin_statement
192
- end
193
-
194
188
  def to_sexp
195
189
  [:step_invocation, @step.line, @step.keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
196
190
  end
@@ -1,5 +1,4 @@
1
1
  require 'gherkin/rubify'
2
- require 'gherkin/lexer/i18n_lexer'
3
2
  require 'gherkin/formatter/escaping'
4
3
 
5
4
  module Cucumber
@@ -61,7 +60,7 @@ module Cucumber
61
60
 
62
61
  def self.parse(text, uri, offset)
63
62
  builder = Builder.new
64
- lexer = Gherkin::Lexer::I18nLexer.new(builder)
63
+ lexer = Gherkin::I18nLexer.new(builder)
65
64
  lexer.scan(text)
66
65
  new(builder.rows)
67
66
  end
@@ -74,6 +73,7 @@ module Cucumber
74
73
  def initialize(raw, conversion_procs = NULL_CONVERSIONS.dup)
75
74
  @cells_class = Cells
76
75
  @cell_class = Cell
76
+
77
77
  raw = ensure_array_of_array(rubify(raw))
78
78
  # Verify that it's square
79
79
  transposed = raw.transpose
@@ -153,7 +153,7 @@ module Cucumber
153
153
  #
154
154
  # gets converted into the following:
155
155
  #
156
- # [['a', 'b'], ['c', 'd']]
156
+ # [['a', 'b], ['c', 'd']]
157
157
  #
158
158
  def raw
159
159
  cell_matrix.map do |row|
@@ -163,14 +163,9 @@ module Cucumber
163
163
  end
164
164
  end
165
165
 
166
- def column_names #:nodoc:
167
- @col_names ||= cell_matrix[0].map { |cell| cell.value }
168
- end
169
-
166
+ # Same as #raw, but skips the first (header) row
170
167
  def rows
171
- hashes.map do |hash|
172
- hash.values_at *headers
173
- end
168
+ raw[1..-1]
174
169
  end
175
170
 
176
171
  def each_cells_row(&proc) #:nodoc:
@@ -276,9 +271,8 @@ module Cucumber
276
271
  # end
277
272
  #
278
273
  def map_column!(column_name, strict=true, &conversion_proc)
279
- verify_column(column_name.to_s) if strict
280
- @conversion_procs[column_name.to_s] = conversion_proc
281
- self
274
+ verify_column(column_name) if strict
275
+ @conversion_procs[column_name] = conversion_proc
282
276
  end
283
277
 
284
278
  # Compares +other_table+ to self. If +other_table+ contains columns
@@ -385,7 +379,7 @@ module Cucumber
385
379
  hash = Hash.new do |hash, key|
386
380
  hash[key.to_s] if key.is_a?(Symbol)
387
381
  end
388
- column_names.each_with_index do |column_name, column_index|
382
+ raw[0].each_with_index do |column_name, column_index|
389
383
  value = @conversion_procs[column_name].call(cells.value(column_index))
390
384
  hash[column_name] = value
391
385
  end
@@ -2,11 +2,11 @@ module Cucumber
2
2
  module Ast
3
3
  # Walks the AST, executing steps and notifying listeners
4
4
  class TreeWalker
5
- attr_accessor :configuration #:nodoc:
5
+ attr_accessor :options #:nodoc:
6
6
  attr_reader :step_mother #:nodoc:
7
7
 
8
- def initialize(step_mother, listeners = [], configuration = Cucumber::Configuration.default)
9
- @step_mother, @listeners, @configuration = step_mother, listeners, configuration
8
+ def initialize(step_mother, listeners = [], options = {}, io = STDOUT)
9
+ @step_mother, @listeners, @options, @io = step_mother, listeners, options, io
10
10
  end
11
11
 
12
12
  def visit_features(features)
@@ -122,7 +122,7 @@ module Cucumber
122
122
  broadcast(exception, status)
123
123
  end
124
124
 
125
- def visit_doc_string(string)
125
+ def visit_py_string(string)
126
126
  broadcast(string)
127
127
  end
128
128
 
@@ -142,15 +142,15 @@ module Cucumber
142
142
  broadcast(value, status)
143
143
  end
144
144
 
145
- # Print +messages+. This method can be called from within StepDefinitions.
146
- def puts(*messages)
147
- broadcast(*messages)
145
+ # Print +announcement+. This method can be called from within StepDefinitions.
146
+ def announce(announcement)
147
+ broadcast(announcement)
148
148
  end
149
149
 
150
150
  # Embed +file+ of +mime_type+ in the formatter. This method can be called from within StepDefinitions.
151
151
  # For most formatters this is a no-op.
152
- def embed(file, mime_type, label)
153
- broadcast(file, mime_type, label)
152
+ def embed(file, mime_type)
153
+ broadcast(file, mime_type)
154
154
  end
155
155
 
156
156
  private
@@ -171,10 +171,48 @@ module Cucumber
171
171
  def send_to_all(message, *args)
172
172
  @listeners.each do |listener|
173
173
  if listener.respond_to?(message)
174
- listener.__send__(message, *args)
174
+ if legacy_listener?(listener)
175
+ warn_legacy(listener)
176
+ legacy_invoke(listener, message, *args)
177
+ else
178
+ listener.__send__(message, *args)
179
+ end
175
180
  end
176
181
  end
177
182
  end
183
+
184
+ def legacy_listener?(listener)
185
+ listener.respond_to?(:feature_name) &&
186
+ (listener.method(:feature_name) rescue false) &&
187
+ listener.method(:feature_name).arity == 1
188
+ end
189
+
190
+ def warn_legacy(listener)
191
+ @warned_listeners ||= []
192
+ unless @warned_listeners.index(listener)
193
+ warn("#{listener.class} is using a deprecated formatter API. Starting with Cucumber 0.7.0 the signatures\n" +
194
+ "that have changed are:\n" +
195
+ " feature_name(keyword, name) # Two arguments. The keyword argument will not contain a colon.\n" +
196
+ " scenario_name(keyword, name, file_colon_line, source_indent) # The keyword argument will not contain a colon.\n" +
197
+ " examples_name(keyword, name) # The keyword argument will not contain a colon.\n"
198
+ )
199
+ end
200
+ @warned_listeners << listener
201
+ end
202
+
203
+ def legacy_invoke(listener, message, *args)
204
+ case message.to_sym
205
+ when :feature_name
206
+ listener.feature_name("#{args[0]}: #{args[1]}")
207
+ when :scenario_name, :examples_name
208
+ args_with_colon = args.dup
209
+ args_with_colon[0] += ':'
210
+ listener.__send__(message, *args_with_colon)
211
+ else
212
+ listener.__send__(message, *args)
213
+ end
214
+ end
215
+
178
216
  def extract_method_name_from(call_stack)
179
217
  call_stack[0].match(/in `(.*)'/).captures[0]
180
218
  end
@@ -12,7 +12,7 @@ module Cucumber
12
12
  class Configuration
13
13
  include Constantize
14
14
 
15
- attr_reader :out_stream
15
+ attr_reader :options, :out_stream
16
16
 
17
17
  def initialize(out_stream = STDOUT, error_stream = STDERR)
18
18
  @out_stream = out_stream
@@ -56,16 +56,8 @@ module Cucumber
56
56
  @options[:drb_port].to_i if @options[:drb_port]
57
57
  end
58
58
 
59
- def dry_run?
60
- @options[:dry_run]
61
- end
62
-
63
- def expand?
64
- @options[:expand]
65
- end
66
-
67
- def build_tree_walker(step_mother)
68
- Ast::TreeWalker.new(step_mother, formatters(step_mother), self)
59
+ def build_runner(step_mother, io)
60
+ Ast::TreeWalker.new(step_mother, formatters(step_mother), @options, io)
69
61
  end
70
62
 
71
63
  def formatter_class(format)
@@ -106,7 +98,7 @@ module Cucumber
106
98
  path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
107
99
  path = path.chomp('/')
108
100
  if File.directory?(path)
109
- Dir["#{path}/**/*.feature"].sort
101
+ Dir["#{path}/**/*.feature"]
110
102
  elsif path[0..0] == '@' and # @listfile.txt
111
103
  File.file?(path[1..-1]) # listfile.txt is a file
112
104
  IO.read(path[1..-1]).split
@@ -129,27 +121,7 @@ module Cucumber
129
121
  logger.level = Logger::DEBUG if self.verbose?
130
122
  logger
131
123
  end
132
-
133
- def tag_expression
134
- Gherkin::TagExpression.new(@options[:tag_expressions])
135
- end
136
-
137
- def filters
138
- @options.filters
139
- end
140
-
141
- def formats
142
- @options[:formats]
143
- end
144
-
145
- def options
146
- warn("Deprecated: Configuration#options will be removed from the next release of Cucumber. Please use the configuration object directly instead.")
147
- @options
148
- end
149
-
150
- def paths
151
- @options[:paths].empty? ? ['features'] : @options[:paths]
152
- end
124
+
153
125
  private
154
126
 
155
127
  def formatters(step_mother)
@@ -179,6 +151,9 @@ module Cucumber
179
151
  end
180
152
  end
181
153
 
154
+ def paths
155
+ @options[:paths].empty? ? ['features'] : @options[:paths]
156
+ end
182
157
 
183
158
  def set_environment_variables
184
159
  @options[:env_vars].each do |var, value|
@@ -9,6 +9,7 @@ require 'cucumber'
9
9
  require 'logger'
10
10
  require 'cucumber/parser'
11
11
  require 'cucumber/feature_file'
12
+ require 'cucumber/formatter/color_io'
12
13
  require 'cucumber/cli/configuration'
13
14
  require 'cucumber/cli/drb_client'
14
15
 
@@ -16,32 +17,55 @@ module Cucumber
16
17
  module Cli
17
18
  class Main
18
19
  class << self
20
+ def step_mother
21
+ @step_mother ||= StepMother.new
22
+ end
23
+
19
24
  def execute(args)
20
- new(args).execute!
25
+ new(args).execute!(step_mother)
21
26
  end
22
27
  end
23
28
 
24
29
  def initialize(args, out_stream = STDOUT, error_stream = STDERR)
25
30
  @args = args
26
- @out_stream = out_stream
31
+ if Cucumber::WINDOWS_MRI
32
+ @out_stream = out_stream == STDOUT ? Formatter::ColorIO.new(Kernel, STDOUT) : out_stream
33
+ else
34
+ @out_stream = out_stream
35
+ end
27
36
 
28
37
  @error_stream = error_stream
29
38
  @configuration = nil
30
39
  end
31
40
 
32
- def execute!(existing_runtime = nil)
41
+ def execute!(step_mother)
33
42
  trap_interrupt
34
- return @drb_output if run_drb_client
43
+ if configuration.drb?
44
+ begin
45
+ return DRbClient.run(@args, @error_stream, @out_stream, configuration.drb_port)
46
+ rescue DRbClientError => e
47
+ @error_stream.puts "WARNING: #{e.message} Running features locally:"
48
+ end
49
+ end
50
+ step_mother.options = configuration.options
51
+ step_mother.log = configuration.log
52
+
53
+ step_mother.load_code_files(configuration.support_to_load)
54
+ step_mother.after_configuration(configuration)
55
+ features = step_mother.load_plain_text_features(configuration.feature_files)
56
+ step_mother.load_code_files(configuration.step_defs_to_load)
57
+
58
+ runner = configuration.build_runner(step_mother, @out_stream)
59
+ step_mother.visitor = runner # Needed to support World#announce
35
60
 
36
- runtime = if existing_runtime
37
- existing_runtime.configure(configuration)
38
- existing_runtime
61
+ runner.visit_features(features)
62
+
63
+ failure = if configuration.wip?
64
+ step_mother.scenarios(:passed).any?
39
65
  else
40
- Runtime.new(configuration)
66
+ step_mother.scenarios(:failed).any? ||
67
+ (configuration.strict? && (step_mother.steps(:undefined).any? || step_mother.steps(:pending).any?))
41
68
  end
42
-
43
- runtime.run!
44
- runtime.results.failure?
45
69
  rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
46
70
  @error_stream.puts e.message
47
71
  true
@@ -52,19 +76,10 @@ module Cucumber
52
76
 
53
77
  @configuration = Configuration.new(@out_stream, @error_stream)
54
78
  @configuration.parse!(@args)
55
- Cucumber.logger = @configuration.log
56
79
  @configuration
57
80
  end
58
81
 
59
82
  private
60
-
61
- def run_drb_client
62
- return false unless configuration.drb?
63
- @drb_output = DRbClient.run(@args, @error_stream, @out_stream, configuration.drb_port)
64
- true
65
- rescue DRbClientError => e
66
- @error_stream.puts "WARNING: #{e.message} Running features locally:"
67
- end
68
83
 
69
84
  def trap_interrupt
70
85
  trap('INT') do