cucumber 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. data/.rspec +1 -1
  2. data/LICENSE +1 -1
  3. data/Rakefile +5 -51
  4. data/bin/cucumber +7 -1
  5. data/cucumber.gemspec +463 -679
  6. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +1 -1
  7. data/examples/i18n/he/features/step_definitons/calculator_steps.rb +1 -1
  8. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +4 -7
  9. data/examples/i18n/ru/features/division.feature +2 -2
  10. data/examples/i18n/tr/features/step_definitons/hesap_makinesi_adimlari.rb +3 -3
  11. data/examples/sinatra/features/support/env.rb +2 -5
  12. data/examples/v8/features/fibonacci.feature +1 -1
  13. data/examples/watir/features/step_definitions/search_steps.rb +1 -1
  14. data/features/background.feature +284 -95
  15. data/features/custom_formatter.feature +3 -73
  16. data/features/json_formatter.feature +160 -245
  17. data/features/step_definitions/cucumber_steps.rb +7 -153
  18. data/features/support/env.rb +18 -140
  19. data/fixtures/junit/features/pending.feature +3 -1
  20. data/fixtures/self_test/features/support/env.rb +8 -0
  21. data/fixtures/tickets/features.html +1 -1
  22. data/gem_tasks/examples.rake +1 -1
  23. data/lib/cucumber.rb +12 -0
  24. data/lib/cucumber/ast.rb +1 -1
  25. data/lib/cucumber/ast/background.rb +21 -5
  26. data/lib/cucumber/ast/examples.rb +12 -4
  27. data/lib/cucumber/ast/feature.rb +13 -5
  28. data/lib/cucumber/ast/feature_element.rb +9 -4
  29. data/lib/cucumber/ast/outline_table.rb +4 -4
  30. data/lib/cucumber/ast/scenario.rb +7 -5
  31. data/lib/cucumber/ast/scenario_outline.rb +23 -15
  32. data/lib/cucumber/ast/step.rb +5 -0
  33. data/lib/cucumber/ast/step_invocation.rb +21 -15
  34. data/lib/cucumber/ast/table.rb +14 -8
  35. data/lib/cucumber/ast/tree_walker.rb +10 -48
  36. data/lib/cucumber/cli/configuration.rb +33 -8
  37. data/lib/cucumber/cli/main.rb +20 -35
  38. data/lib/cucumber/cli/options.rb +8 -7
  39. data/lib/cucumber/cli/profile_loader.rb +2 -0
  40. data/lib/cucumber/core_ext/proc.rb +2 -1
  41. data/lib/cucumber/feature_file.rb +47 -15
  42. data/lib/cucumber/formatter/ansicolor.rb +3 -5
  43. data/lib/cucumber/formatter/console.rb +27 -23
  44. data/lib/cucumber/formatter/cucumber.css +34 -17
  45. data/lib/cucumber/formatter/cucumber.sass +173 -182
  46. data/lib/cucumber/formatter/html.rb +46 -11
  47. data/lib/cucumber/formatter/io.rb +2 -4
  48. data/lib/cucumber/formatter/json.rb +15 -152
  49. data/lib/cucumber/formatter/json_pretty.rb +5 -6
  50. data/lib/cucumber/formatter/junit.rb +28 -22
  51. data/lib/cucumber/formatter/pdf.rb +6 -6
  52. data/lib/cucumber/formatter/pretty.rb +5 -5
  53. data/lib/cucumber/formatter/rerun.rb +22 -11
  54. data/lib/cucumber/formatter/unicode.rb +41 -20
  55. data/lib/cucumber/js_support/js_dsl.js +4 -4
  56. data/lib/cucumber/js_support/js_language.rb +9 -5
  57. data/lib/cucumber/js_support/js_snippets.rb +2 -2
  58. data/lib/cucumber/language_support.rb +2 -2
  59. data/lib/cucumber/parser/gherkin_builder.rb +35 -30
  60. data/lib/cucumber/platform.rb +8 -8
  61. data/lib/cucumber/py_support/py_language.rb +2 -2
  62. data/lib/cucumber/rake/task.rb +80 -31
  63. data/lib/cucumber/rb_support/rb_dsl.rb +1 -0
  64. data/lib/cucumber/rb_support/rb_language.rb +10 -8
  65. data/lib/cucumber/rb_support/rb_step_definition.rb +8 -0
  66. data/lib/cucumber/rb_support/rb_transform.rb +17 -0
  67. data/lib/cucumber/rb_support/rb_world.rb +26 -18
  68. data/lib/cucumber/rspec/doubles.rb +3 -3
  69. data/lib/cucumber/step_match.rb +6 -2
  70. data/lib/cucumber/step_mother.rb +6 -427
  71. data/lib/cucumber/wire_support/configuration.rb +4 -1
  72. data/lib/cucumber/wire_support/wire_language.rb +3 -10
  73. data/spec/cucumber/ast/background_spec.rb +68 -6
  74. data/spec/cucumber/ast/feature_factory.rb +5 -4
  75. data/spec/cucumber/ast/feature_spec.rb +4 -4
  76. data/spec/cucumber/ast/outline_table_spec.rb +1 -1
  77. data/spec/cucumber/ast/scenario_outline_spec.rb +15 -11
  78. data/spec/cucumber/ast/scenario_spec.rb +4 -4
  79. data/spec/cucumber/ast/step_spec.rb +3 -3
  80. data/spec/cucumber/ast/table_spec.rb +38 -2
  81. data/spec/cucumber/ast/tree_walker_spec.rb +2 -2
  82. data/spec/cucumber/broadcaster_spec.rb +1 -1
  83. data/spec/cucumber/cli/configuration_spec.rb +32 -6
  84. data/spec/cucumber/cli/drb_client_spec.rb +2 -3
  85. data/spec/cucumber/cli/main_spec.rb +43 -43
  86. data/spec/cucumber/cli/options_spec.rb +28 -1
  87. data/spec/cucumber/cli/profile_loader_spec.rb +1 -1
  88. data/spec/cucumber/core_ext/proc_spec.rb +1 -1
  89. data/spec/cucumber/formatter/ansicolor_spec.rb +1 -1
  90. data/spec/cucumber/formatter/duration_spec.rb +1 -1
  91. data/spec/cucumber/formatter/html_spec.rb +3 -5
  92. data/spec/cucumber/formatter/junit_spec.rb +16 -2
  93. data/spec/cucumber/formatter/progress_spec.rb +1 -1
  94. data/spec/cucumber/formatter/spec_helper.rb +11 -12
  95. data/spec/cucumber/rb_support/rb_language_spec.rb +241 -28
  96. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +33 -28
  97. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +1 -1
  98. data/spec/cucumber/step_match_spec.rb +11 -9
  99. data/spec/cucumber/wire_support/configuration_spec.rb +1 -1
  100. data/spec/cucumber/wire_support/connection_spec.rb +1 -1
  101. data/spec/cucumber/wire_support/wire_exception_spec.rb +1 -1
  102. data/spec/cucumber/wire_support/wire_language_spec.rb +1 -1
  103. data/spec/cucumber/wire_support/wire_packet_spec.rb +1 -1
  104. data/spec/cucumber/wire_support/wire_step_definition_spec.rb +1 -1
  105. data/spec/cucumber/world/pending_spec.rb +2 -2
  106. data/spec/spec_helper.rb +13 -20
  107. metadata +11 -222
  108. data/.gitignore +0 -20
  109. data/Caliper.yml +0 -4
  110. data/History.txt +0 -1552
  111. data/README.rdoc +0 -26
  112. data/VERSION.yml +0 -5
  113. data/examples/i18n/ro/features/suma.feature +0 -11
  114. data/features/announce.feature +0 -164
  115. data/features/around_hooks.feature +0 -232
  116. data/features/bug_371.feature +0 -32
  117. data/features/bug_464.feature +0 -16
  118. data/features/bug_475.feature +0 -42
  119. data/features/bug_585_tab_indentation.feature +0 -22
  120. data/features/bug_600.feature +0 -67
  121. data/features/call_steps_from_stepdefs.feature +0 -154
  122. data/features/cucumber_cli.feature +0 -591
  123. data/features/cucumber_cli_outlines.feature +0 -117
  124. data/features/default_snippets.feature +0 -42
  125. data/features/diffing.feature +0 -25
  126. data/features/drb_server_integration.feature +0 -174
  127. data/features/exception_in_after_block.feature +0 -127
  128. data/features/exception_in_after_step_block.feature +0 -104
  129. data/features/exception_in_before_block.feature +0 -98
  130. data/features/exclude_files.feature +0 -20
  131. data/features/expand.feature +0 -60
  132. data/features/html_formatter.feature +0 -8
  133. data/features/html_formatter/a.html +0 -582
  134. data/features/junit_formatter.feature +0 -88
  135. data/features/language_from_header.feature +0 -30
  136. data/features/language_help.feature +0 -78
  137. data/features/listener_debugger_formatter.feature +0 -42
  138. data/features/multiline_names.feature +0 -44
  139. data/features/negative_tagged_hooks.feature +0 -60
  140. data/features/post_configuration_hook.feature +0 -37
  141. data/features/profiles.feature +0 -126
  142. data/features/rake_task.feature +0 -152
  143. data/features/report_called_undefined_steps.feature +0 -34
  144. data/features/rerun_formatter.feature +0 -45
  145. data/features/simplest.feature +0 -11
  146. data/features/snippet.feature +0 -23
  147. data/features/snippets_when_using_star_keyword.feature +0 -36
  148. data/features/step_definitions/extra_steps.rb +0 -2
  149. data/features/step_definitions/simplest_steps.rb +0 -3
  150. data/features/step_definitions/wire_steps.rb +0 -32
  151. data/features/support/env.rb.simplest +0 -7
  152. data/features/support/fake_wire_server.rb +0 -77
  153. data/features/table_diffing.feature +0 -45
  154. data/features/table_mapping.feature +0 -34
  155. data/features/tag_logic.feature +0 -258
  156. data/features/transform.feature +0 -245
  157. data/features/unicode_table.feature +0 -35
  158. data/features/usage_and_stepdefs_formatter.feature +0 -169
  159. data/features/wire_protocol.feature +0 -332
  160. data/features/wire_protocol_table_diffing.feature +0 -119
  161. data/features/wire_protocol_tags.feature +0 -87
  162. data/features/wire_protocol_timeouts.feature +0 -63
  163. data/features/work_in_progress.feature +0 -156
  164. data/fixtures/json/features/pystring.feature +0 -8
  165. data/fixtures/self_test/features/background/background_tagged_before_on_outline.feature +0 -12
  166. data/fixtures/self_test/features/background/background_with_name.feature +0 -7
  167. data/fixtures/self_test/features/background/failing_background.feature +0 -12
  168. data/fixtures/self_test/features/background/failing_background_after_success.feature +0 -11
  169. data/fixtures/self_test/features/background/multiline_args_background.feature +0 -32
  170. data/fixtures/self_test/features/background/passing_background.feature +0 -10
  171. data/fixtures/self_test/features/background/pending_background.feature +0 -10
  172. data/fixtures/self_test/features/background/scenario_outline_failing_background.feature +0 -16
  173. data/fixtures/self_test/features/background/scenario_outline_passing_background.feature +0 -16
  174. data/gem_tasks/features.rake +0 -14
  175. data/gem_tasks/sdoc.rake +0 -12
  176. data/lib/cucumber/ast/py_string.rb +0 -80
  177. data/lib/cucumber/formatter/color_io.rb +0 -23
  178. data/lib/cucumber/formatter/tag_cloud.rb +0 -35
  179. data/spec/cucumber/ast/py_string_spec.rb +0 -40
  180. data/spec/cucumber/formatter/color_io_spec.rb +0 -29
  181. data/spec/cucumber/step_mother_spec.rb +0 -302
@@ -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 :options #:nodoc:
5
+ attr_accessor :configuration #:nodoc:
6
6
  attr_reader :step_mother #:nodoc:
7
7
 
8
- def initialize(step_mother, listeners = [], options = {}, io = STDOUT)
9
- @step_mother, @listeners, @options, @io = step_mother, listeners, options, io
8
+ def initialize(step_mother, listeners = [], configuration = Cucumber::Configuration.default)
9
+ @step_mother, @listeners, @configuration = step_mother, listeners, configuration
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_py_string(string)
125
+ def visit_doc_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 +announcement+. This method can be called from within StepDefinitions.
146
- def announce(announcement)
147
- broadcast(announcement)
145
+ # Print +messages+. This method can be called from within StepDefinitions.
146
+ def puts(*messages)
147
+ broadcast(*messages)
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)
153
- broadcast(file, mime_type)
152
+ def embed(file, mime_type, label)
153
+ broadcast(file, mime_type, label)
154
154
  end
155
155
 
156
156
  private
@@ -171,48 +171,10 @@ module Cucumber
171
171
  def send_to_all(message, *args)
172
172
  @listeners.each do |listener|
173
173
  if listener.respond_to?(message)
174
- if legacy_listener?(listener)
175
- warn_legacy(listener)
176
- legacy_invoke(listener, message, *args)
177
- else
178
- listener.__send__(message, *args)
179
- end
174
+ listener.__send__(message, *args)
180
175
  end
181
176
  end
182
177
  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
-
216
178
  def extract_method_name_from(call_stack)
217
179
  call_stack[0].match(/in `(.*)'/).captures[0]
218
180
  end
@@ -12,7 +12,7 @@ module Cucumber
12
12
  class Configuration
13
13
  include Constantize
14
14
 
15
- attr_reader :options, :out_stream
15
+ attr_reader :out_stream
16
16
 
17
17
  def initialize(out_stream = STDOUT, error_stream = STDERR)
18
18
  @out_stream = out_stream
@@ -56,8 +56,16 @@ module Cucumber
56
56
  @options[:drb_port].to_i if @options[:drb_port]
57
57
  end
58
58
 
59
- def build_runner(step_mother, io)
60
- Ast::TreeWalker.new(step_mother, formatters(step_mother), @options, io)
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)
61
69
  end
62
70
 
63
71
  def formatter_class(format)
@@ -98,7 +106,7 @@ module Cucumber
98
106
  path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
99
107
  path = path.chomp('/')
100
108
  if File.directory?(path)
101
- Dir["#{path}/**/*.feature"]
109
+ Dir["#{path}/**/*.feature"].sort
102
110
  elsif path[0..0] == '@' and # @listfile.txt
103
111
  File.file?(path[1..-1]) # listfile.txt is a file
104
112
  IO.read(path[1..-1]).split
@@ -121,7 +129,27 @@ module Cucumber
121
129
  logger.level = Logger::DEBUG if self.verbose?
122
130
  logger
123
131
  end
124
-
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
125
153
  private
126
154
 
127
155
  def formatters(step_mother)
@@ -151,9 +179,6 @@ module Cucumber
151
179
  end
152
180
  end
153
181
 
154
- def paths
155
- @options[:paths].empty? ? ['features'] : @options[:paths]
156
- end
157
182
 
158
183
  def set_environment_variables
159
184
  @options[:env_vars].each do |var, value|
@@ -9,7 +9,6 @@ require 'cucumber'
9
9
  require 'logger'
10
10
  require 'cucumber/parser'
11
11
  require 'cucumber/feature_file'
12
- require 'cucumber/formatter/color_io'
13
12
  require 'cucumber/cli/configuration'
14
13
  require 'cucumber/cli/drb_client'
15
14
 
@@ -17,55 +16,32 @@ module Cucumber
17
16
  module Cli
18
17
  class Main
19
18
  class << self
20
- def step_mother
21
- @step_mother ||= StepMother.new
22
- end
23
-
24
19
  def execute(args)
25
- new(args).execute!(step_mother)
20
+ new(args).execute!
26
21
  end
27
22
  end
28
23
 
29
24
  def initialize(args, out_stream = STDOUT, error_stream = STDERR)
30
25
  @args = args
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
26
+ @out_stream = out_stream
36
27
 
37
28
  @error_stream = error_stream
38
29
  @configuration = nil
39
30
  end
40
31
 
41
- def execute!(step_mother)
32
+ def execute!(existing_runtime = nil)
42
33
  trap_interrupt
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
34
+ return @drb_output if run_drb_client
60
35
 
61
- runner.visit_features(features)
62
-
63
- failure = if configuration.wip?
64
- step_mother.scenarios(:passed).any?
36
+ runtime = if existing_runtime
37
+ existing_runtime.configure(configuration)
38
+ existing_runtime
65
39
  else
66
- step_mother.scenarios(:failed).any? ||
67
- (configuration.strict? && (step_mother.steps(:undefined).any? || step_mother.steps(:pending).any?))
40
+ Runtime.new(configuration)
68
41
  end
42
+
43
+ runtime.run!
44
+ runtime.results.failure?
69
45
  rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
70
46
  @error_stream.puts e.message
71
47
  true
@@ -76,10 +52,19 @@ module Cucumber
76
52
 
77
53
  @configuration = Configuration.new(@out_stream, @error_stream)
78
54
  @configuration.parse!(@args)
55
+ Cucumber.logger = @configuration.log
79
56
  @configuration
80
57
  end
81
58
 
82
59
  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
83
68
 
84
69
  def trap_interrupt
85
70
  trap('INT') do
@@ -24,8 +24,7 @@ module Cucumber
24
24
  "#{INDENT}the usage formatter, except that steps are not printed."],
25
25
  'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
26
26
  'json' => ['Cucumber::Formatter::Json', 'Prints the feature as JSON'],
27
- 'json_pretty' => ['Cucumber::Formatter::JsonPretty', 'Prints the feature as pretty JSON'],
28
- 'tag_cloud' => ['Cucumber::Formatter::TagCloud', 'Prints a tag cloud of tag usage.'],
27
+ 'json_pretty' => ['Cucumber::Formatter::JsonPretty', 'Prints the feature as prettified JSON'],
29
28
  'debug' => ['Cucumber::Formatter::Debug', 'For developing formatters - prints the calls made to the listeners.']
30
29
  }
31
30
  max = BUILTIN_FORMATS.keys.map{|s| s.length}.max
@@ -165,7 +164,7 @@ module Cucumber
165
164
  "This represents the boolean expression (@foo || !@bar) && @zap.",
166
165
  "\n",
167
166
  "Beware that if you want to use several negative tags to exclude several tags",
168
- "you have to use logical AND: --tags ~@fixme --tags @buggy.",
167
+ "you have to use logical AND: --tags ~@fixme --tags ~@buggy.",
169
168
  "\n",
170
169
  "Positive tags can be given a threshold to limit the number of occurrences.",
171
170
  "Example: --tags @qa:3 will fail if there are more than 3 occurrences of the @qa tag.",
@@ -199,10 +198,8 @@ module Cucumber
199
198
  Term::ANSIColor.coloring = v
200
199
  end
201
200
  opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.",
202
- "This also omits the loading of your support/env.rb file if it exists.",
203
- "Implies --no-snippets.") do
201
+ "This also omits the loading of your support/env.rb file if it exists.") do
204
202
  @options[:dry_run] = true
205
- @options[:snippets] = false
206
203
  end
207
204
  opts.on("-a", "--autoformat DIR",
208
205
  "Reformats (pretty prints) feature files and write them to DIRECTORY.",
@@ -231,7 +228,7 @@ module Cucumber
231
228
  opts.on("-b", "--backtrace", "Show full backtrace for all errors.") do
232
229
  Cucumber.use_full_backtrace = true
233
230
  end
234
- opts.on("-S", "--strict", "Fail if there are any undefined steps.") do
231
+ opts.on("-S", "--strict", "Fail if there are any undefined or pending steps.") do
235
232
  @options[:strict] = true
236
233
  end
237
234
  opts.on("-w", "--wip", "Fail if there are any passing scenarios.") do
@@ -243,6 +240,9 @@ module Cucumber
243
240
  opts.on("-g", "--guess", "Guess best match for Ambiguous steps.") do
244
241
  @options[:guess] = true
245
242
  end
243
+ opts.on("-l", "--lines LINES", "Run given line numbers. Equivalent to FILE:LINE syntax") do |lines|
244
+ @options[:lines] = lines
245
+ end
246
246
  opts.on("-x", "--expand", "Expand Scenario Outline Tables in output.") do
247
247
  @options[:expand] = true
248
248
  end
@@ -268,6 +268,7 @@ module Cucumber
268
268
  @options[:snippets] = true if @options[:snippets].nil?
269
269
  @options[:source] = true if @options[:source].nil?
270
270
  end
271
+ @args.map! { |a| "#{a}:#{@options[:lines]}" } if @options[:lines]
271
272
 
272
273
  extract_environment_variables
273
274
  @options[:paths] = @args.dup #whatver is left over
@@ -1,3 +1,5 @@
1
+ require 'yaml'
2
+
1
3
  module Cucumber
2
4
  module Cli
3
5
 
@@ -1,6 +1,7 @@
1
1
  # Proc extension to get more location info out of a proc
2
2
  class Proc #:nodoc:
3
3
  PROC_PATTERN = /[\d\w]+@(.+):(\d+).*>/
4
+ PWD = Dir.pwd
4
5
 
5
6
  def to_comment_line
6
7
  "# #{file_colon_line}"
@@ -14,7 +15,7 @@ class Proc #:nodoc:
14
15
  def file_colon_line
15
16
  path, line = *to_s.match(PROC_PATTERN)[1..2]
16
17
  path = File.expand_path(path)
17
- pwd = File.expand_path(Dir.pwd)
18
+ pwd = File.expand_path(PWD)
18
19
  if path.index(pwd)
19
20
  path = path[pwd.length+1..-1]
20
21
  elsif path =~ /.*\/gems\/(.*\.rb)$/
@@ -2,14 +2,15 @@ require 'cucumber/parser/gherkin_builder'
2
2
  require 'gherkin/formatter/filter_formatter'
3
3
  require 'gherkin/formatter/tag_count_formatter'
4
4
  require 'gherkin/parser/parser'
5
- require 'gherkin/i18n_lexer'
6
5
 
7
6
  module Cucumber
8
7
  class FeatureFile
9
8
  FILE_COLON_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/ #:nodoc:
10
- LANGUAGE_PATTERN = /language:\s*(.*)/ #:nodoc:
9
+ DEFAULT_ENCODING = "UTF-8" #:nodoc:
10
+ COMMENT_OR_EMPTY_LINE_PATTERN = /^\s*#|^\s*$/ #:nodoc:
11
+ ENCODING_PATTERN = /^\s*#\s*encoding\s*:\s*([^\s]+)/ #:nodoc:
11
12
 
12
- # The +uri+ argument is the location of the source. It can ba a path
13
+ # The +uri+ argument is the location of the source. It can be a path
13
14
  # or a path:line1:line2 etc. If +source+ is passed, +uri+ is ignored.
14
15
  def initialize(uri, source=nil)
15
16
  @source = source
@@ -20,12 +21,12 @@ module Cucumber
20
21
  @path = uri
21
22
  end
22
23
  end
23
-
24
+
24
25
  # Parses a file and returns a Cucumber::Ast
25
- # If +options+ contains tags, the result will
26
+ # If +configuration_filters+ contains any filters, the result will
26
27
  # be filtered.
27
- def parse(options, tag_counts)
28
- filters = @lines || options.filters
28
+ def parse(configuration_filters, tag_counts)
29
+ filters = @lines || configuration_filters
29
30
 
30
31
  builder = Cucumber::Parser::GherkinBuilder.new
31
32
  filter_formatter = filters.empty? ? builder : Gherkin::Formatter::FilterFormatter.new(builder, filters)
@@ -39,7 +40,7 @@ module Cucumber
39
40
  ast.language = parser.i18n_language
40
41
  ast.file = @path
41
42
  ast
42
- rescue Gherkin::LexingError, Gherkin::Parser::ParseError => e
43
+ rescue Gherkin::Lexer::LexingError, Gherkin::Parser::ParseError => e
43
44
  e.message.insert(0, "#{@path}: ")
44
45
  raise e
45
46
  end
@@ -51,19 +52,50 @@ module Cucumber
51
52
  open(@path).read
52
53
  else
53
54
  begin
54
- File.open(@path, Cucumber.file_mode('r')).read
55
+ source = File.open(@path, Cucumber.file_mode('r', DEFAULT_ENCODING)).read
56
+ encoding = encoding_for(source)
57
+ if(DEFAULT_ENCODING.downcase != encoding.downcase)
58
+ # Read the file again - it's explicitly declaring a different encoding
59
+ source = File.open(@path, Cucumber.file_mode('r', encoding)).read
60
+ source = to_default_encoding(source, encoding)
61
+ end
62
+ source
55
63
  rescue Errno::EACCES => e
56
- p = File.expand_path(@path)
57
- e.message << "\nCouldn't open #{p}"
64
+ e.message << "\nCouldn't open #{File.expand_path(@path)}"
65
+ raise e
66
+ rescue Errno::ENOENT => e
67
+ # special-case opening features, because this could be a new user:
68
+ if(@path == 'features')
69
+ STDERR.puts("You don't have a 'features' directory. Please create one to get started.",
70
+ "See http://cukes.info/ for more information.")
71
+ exit 1
72
+ end
58
73
  raise e
59
74
  end
60
75
  end
61
76
  end
62
-
77
+
63
78
  private
64
79
 
65
- # Special PML markup that we want to filter out.
66
- CO = %{\\s*<(label|callout)\s+id=".*?"\s*/>\\s*}
67
- C_CALLOUT = %r{/\*#{CO}\*/|//#{CO}}o
80
+ def encoding_for(source)
81
+ encoding = DEFAULT_ENCODING
82
+ source.each_line do |line|
83
+ break unless COMMENT_OR_EMPTY_LINE_PATTERN =~ line
84
+ if ENCODING_PATTERN =~ line
85
+ encoding = $1
86
+ break
87
+ end
88
+ end
89
+ encoding
90
+ end
91
+
92
+ def to_default_encoding(string, encoding)
93
+ if string.respond_to?(:encode)
94
+ string.encode(DEFAULT_ENCODING)
95
+ else
96
+ require 'iconv'
97
+ Iconv.new(DEFAULT_ENCODING, encoding).iconv(string)
98
+ end
99
+ end
68
100
  end
69
101
  end
@@ -15,15 +15,13 @@ if Cucumber::IRONRUBY
15
15
  end
16
16
 
17
17
  if Cucumber::WINDOWS_MRI
18
- begin
19
- require 'Win32/Console/ANSI'
20
- rescue LoadError
21
- STDERR.puts %{*** WARNING: You must "gem install win32console" (1.2.0 or higher) to get coloured output on MRI/Windows}
18
+ unless ENV['ANSICON']
19
+ STDERR.puts %{*** WARNING: You must use ANSICON 1.31 or higher (http://adoxa.110mb.com/ansicon) to get coloured output on Windows}
22
20
  Term::ANSIColor.coloring = false
23
21
  end
24
22
  end
25
23
 
26
- Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.has_key?("AUTOTEST")
24
+ Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.has_key?('AUTOTEST')
27
25
 
28
26
  module Cucumber
29
27
  module Formatter