cucumber 2.0.2 → 2.1.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -6
  3. data/CONTRIBUTING.md +3 -1
  4. data/Gemfile +1 -1
  5. data/History.md +17 -0
  6. data/README.md +3 -3
  7. data/bin/cucumber +1 -2
  8. data/cucumber.gemspec +2 -2
  9. data/examples/i18n/ht/features/adisyon.feature +7 -7
  10. data/features/docs/api/listen_for_events.feature +58 -0
  11. data/features/docs/cli/fail_fast.feature +46 -0
  12. data/features/docs/defining_steps/nested_steps_with_second_arg.feature +3 -22
  13. data/features/docs/extending_cucumber/custom_formatter.feature +40 -4
  14. data/features/docs/gherkin/doc_strings.feature +5 -5
  15. data/features/docs/gherkin/language_help.feature +15 -15
  16. data/features/docs/gherkin/using_descriptions.feature +0 -5
  17. data/lib/cucumber/cli/configuration.rb +10 -92
  18. data/lib/cucumber/cli/main.rb +1 -7
  19. data/lib/cucumber/cli/options.rb +47 -12
  20. data/lib/cucumber/configuration.rb +195 -7
  21. data/lib/cucumber/events.rb +20 -0
  22. data/lib/cucumber/events/after_test_case.rb +25 -0
  23. data/lib/cucumber/events/after_test_step.rb +30 -0
  24. data/lib/cucumber/events/before_test_case.rb +18 -0
  25. data/lib/cucumber/events/before_test_step.rb +23 -0
  26. data/lib/cucumber/events/bus.rb +86 -0
  27. data/lib/cucumber/events/step_match.rb +23 -0
  28. data/lib/cucumber/filters/prepare_world.rb +2 -2
  29. data/lib/cucumber/formatter/backtrace_filter.rb +9 -8
  30. data/lib/cucumber/formatter/console.rb +1 -1
  31. data/lib/cucumber/formatter/event_bus_report.rb +37 -0
  32. data/lib/cucumber/formatter/fail_fast.rb +18 -0
  33. data/lib/cucumber/formatter/html.rb +1 -1
  34. data/lib/cucumber/formatter/io.rb +3 -1
  35. data/lib/cucumber/formatter/json.rb +19 -1
  36. data/lib/cucumber/formatter/legacy_api/adapter.rb +5 -13
  37. data/lib/cucumber/formatter/legacy_api/ast.rb +2 -2
  38. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +3 -1
  39. data/lib/cucumber/formatter/pretty.rb +5 -7
  40. data/lib/cucumber/formatter/progress.rb +1 -1
  41. data/lib/cucumber/formatter/rerun.rb +1 -1
  42. data/lib/cucumber/formatter/steps.rb +1 -1
  43. data/lib/cucumber/formatter/usage.rb +12 -8
  44. data/lib/cucumber/gherkin/data_table_parser.rb +23 -0
  45. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +99 -0
  46. data/lib/cucumber/gherkin/formatter/argument.rb +17 -0
  47. data/lib/cucumber/gherkin/formatter/escaping.rb +17 -0
  48. data/lib/cucumber/gherkin/formatter/hashable.rb +27 -0
  49. data/lib/cucumber/gherkin/i18n.rb +15 -0
  50. data/lib/cucumber/gherkin/steps_parser.rb +41 -0
  51. data/lib/cucumber/language_support/language_methods.rb +6 -5
  52. data/lib/cucumber/multiline_argument.rb +0 -3
  53. data/lib/cucumber/multiline_argument/data_table.rb +6 -5
  54. data/lib/cucumber/multiline_argument/doc_string.rb +1 -2
  55. data/lib/cucumber/platform.rb +1 -1
  56. data/lib/cucumber/rake/task.rb +2 -2
  57. data/lib/cucumber/rb_support/rb_hook.rb +1 -6
  58. data/lib/cucumber/rb_support/rb_language.rb +15 -5
  59. data/lib/cucumber/rb_support/rb_step_definition.rb +11 -17
  60. data/lib/cucumber/rb_support/rb_world.rb +6 -4
  61. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +2 -2
  62. data/lib/cucumber/runtime.rb +36 -16
  63. data/lib/cucumber/runtime/support_code.rb +19 -15
  64. data/lib/cucumber/step_definition_light.rb +5 -5
  65. data/lib/cucumber/step_definitions.rb +2 -2
  66. data/lib/cucumber/step_match.rb +11 -2
  67. data/lib/cucumber/wire_support/wire_protocol/requests.rb +2 -2
  68. data/lib/cucumber/wire_support/wire_step_definition.rb +4 -2
  69. data/{spec → lib}/simplecov_setup.rb +0 -0
  70. data/spec/cucumber/cli/configuration_spec.rb +2 -104
  71. data/spec/cucumber/cli/main_spec.rb +0 -22
  72. data/spec/cucumber/cli/options_spec.rb +3 -1
  73. data/spec/cucumber/configuration_spec.rb +123 -0
  74. data/spec/cucumber/events/bus_spec.rb +94 -0
  75. data/spec/cucumber/formatter/event_bus_report_spec.rb +79 -0
  76. data/spec/cucumber/formatter/fail_fast_spec.rb +88 -0
  77. data/spec/cucumber/formatter/json_spec.rb +43 -1
  78. data/spec/cucumber/formatter/rerun_spec.rb +4 -20
  79. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +29 -0
  80. data/spec/cucumber/runtime_spec.rb +2 -28
  81. data/spec/spec_helper.rb +1 -1
  82. data/spec/support/standard_step_actions.rb +18 -0
  83. metadata +37 -13
  84. data/lib/cucumber/core_ext/proc.rb +0 -36
  85. data/spec/cucumber/core_ext/proc_spec.rb +0 -69
@@ -2,7 +2,7 @@ require 'logger'
2
2
  require 'cucumber/cli/options'
3
3
  require 'cucumber/cli/rerun_file'
4
4
  require 'cucumber/constantize'
5
- require 'gherkin/tag_expression'
5
+ require 'cucumber/core/gherkin/tag_expression'
6
6
 
7
7
  module Cucumber
8
8
  module Cli
@@ -27,7 +27,7 @@ module Cucumber
27
27
  arrange_formats
28
28
  raise("You can't use both --strict and --wip") if strict? && wip?
29
29
  # todo: remove
30
- @options[:tag_expression] = Gherkin::TagExpression.new(@options[:tag_expressions])
30
+ @options[:tag_expression] = Cucumber::Core::Gherkin::TagExpression.new(@options[:tag_expressions])
31
31
  set_environment_variables
32
32
  end
33
33
 
@@ -63,63 +63,12 @@ module Cucumber
63
63
  @options[:expand]
64
64
  end
65
65
 
66
- def snippet_type
67
- @options[:snippet_type] || :regexp
68
- end
69
-
70
- def formatter_class(format)
71
- if(builtin = Options::BUILTIN_FORMATS[format])
72
- constantize(builtin[0])
73
- else
74
- constantize(format)
75
- end
76
- end
77
-
78
- def all_files_to_load
79
- files = require_dirs.map do |path|
80
- path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
81
- path = path.gsub(/\/$/, '') # Strip trailing slash.
82
- File.directory?(path) ? Dir["#{path}/**/*"] : path
83
- end.flatten.uniq
84
- remove_excluded_files_from(files)
85
- files.reject! {|f| !File.file?(f)}
86
- files.reject! {|f| File.extname(f) == '.feature' }
87
- files.reject! {|f| f =~ /^http/}
88
- files.sort
89
- end
90
-
91
- def step_defs_to_load
92
- all_files_to_load.reject {|f| f =~ %r{/support/} }
93
- end
94
-
95
- def support_to_load
96
- support_files = all_files_to_load.select {|f| f =~ %r{/support/} }
97
- env_files = support_files.select {|f| f =~ %r{/support/env\..*} }
98
- other_files = support_files - env_files
99
- @options[:dry_run] ? other_files : env_files + other_files
100
- end
101
-
102
- def feature_files
103
- potential_feature_files = with_default_features_path(paths).map do |path|
104
- path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
105
- path = path.chomp('/')
106
- if File.directory?(path)
107
- Dir["#{path}/**/*.feature"].sort
108
- elsif RerunFile.can_read?(path)
109
- RerunFile.new(path).features
110
- else
111
- path
112
- end
113
- end.flatten.uniq
114
- remove_excluded_files_from(potential_feature_files)
115
- potential_feature_files
66
+ def fail_fast?
67
+ !!@options[:fail_fast]
116
68
  end
117
69
 
118
-
119
- def feature_dirs
120
- dirs = paths.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
121
- dirs.delete('.') unless paths.include?('.')
122
- with_default_features_path(dirs)
70
+ def snippet_type
71
+ @options[:snippet_type] || :regexp
123
72
  end
124
73
 
125
74
  def log
@@ -132,7 +81,7 @@ module Cucumber
132
81
 
133
82
  # todo: remove
134
83
  def tag_expression
135
- Gherkin::TagExpression.new(@options[:tag_expressions])
84
+ Cucumber::Core::Gherkin::TagExpression.new(@options[:tag_expressions])
136
85
  end
137
86
 
138
87
  def tag_limits
@@ -164,31 +113,12 @@ module Cucumber
164
113
  @options[:paths]
165
114
  end
166
115
 
167
- def formatter_factories
168
- @options[:formats].map do |format_and_out|
169
- format = format_and_out[0]
170
- path_or_io = format_and_out[1]
171
- begin
172
- factory = formatter_class(format)
173
- yield factory, path_or_io, @options
174
- rescue Exception => e
175
- e.message << "\nError creating formatter: #{format}"
176
- raise e
177
- end
178
- end
116
+ def to_hash
117
+ Hash.try_convert(@options).merge(out_stream: @out_stream, error_stream: @error_stream)
179
118
  end
180
119
 
181
120
  private
182
121
 
183
- def default_features_paths
184
- ["features"]
185
- end
186
-
187
- def with_default_features_path(paths)
188
- return default_features_paths if paths.empty?
189
- paths
190
- end
191
-
192
122
  class LogFormatter < ::Logger::Formatter
193
123
  def call(severity, time, progname, msg)
194
124
  msg
@@ -207,18 +137,6 @@ module Cucumber
207
137
  @options[:formats].uniq!
208
138
  @options.check_formatter_stream_conflicts()
209
139
  end
210
-
211
- def remove_excluded_files_from(files)
212
- files.reject! {|path| @options[:excludes].detect {|pattern| path =~ pattern } }
213
- end
214
-
215
- def require_dirs
216
- if @options[:require].empty?
217
- default_features_paths + Dir['vendor/{gems,plugins}/*/cucumber']
218
- else
219
- @options[:require]
220
- end
221
- end
222
140
  end
223
141
  end
224
- end
142
+ end
@@ -1,9 +1,3 @@
1
- begin
2
- require 'gherkin'
3
- rescue LoadError
4
- require 'rubygems'
5
- require 'gherkin'
6
- end
7
1
  require 'optparse'
8
2
  require 'cucumber'
9
3
  require 'logger'
@@ -102,4 +96,4 @@ module Cucumber
102
96
  end
103
97
  end
104
98
  end
105
- end
99
+ end
@@ -43,6 +43,7 @@ module Cucumber
43
43
  NO_PROFILE_SHORT_FLAG = '-P'
44
44
  PROFILE_LONG_FLAG = '--profile'
45
45
  NO_PROFILE_LONG_FLAG = '--no-profile'
46
+ FAIL_FAST_FLAG = '--fail-fast'
46
47
  OPTIONS_WITH_ARGS = ['-r', '--require', '--i18n', '-f', '--format', '-o', '--out',
47
48
  '-t', '--tags', '-n', '--name', '-e', '--exclude',
48
49
  PROFILE_SHORT_FLAG, PROFILE_LONG_FLAG,
@@ -59,9 +60,9 @@ module Cucumber
59
60
  @error_stream = error_stream
60
61
 
61
62
  @default_profile = options[:default_profile]
62
- @profiles = []
63
+ @profiles = options[:profiles] || []
63
64
  @overridden_paths = []
64
- @options = default_options
65
+ @options = default_options.merge(options)
65
66
  @profile_loader = options[:profile_loader]
66
67
  @options[:skip_profile_information] = options[:skip_profile_information]
67
68
 
@@ -116,16 +117,19 @@ module Cucumber
116
117
  opts.on("--i18n LANG",
117
118
  "List keywords for in a particular language",
118
119
  %{Run with "--i18n help" to see all languages}) do |lang|
119
- require 'gherkin/i18n'
120
+ require 'gherkin3/dialect'
120
121
 
121
122
  if lang == 'help'
122
123
  list_languages_and_exit
123
- elsif !Gherkin::I18n::LANGUAGES.keys.include? lang
124
+ elsif !::Gherkin3::DIALECTS.keys.include? lang
124
125
  indicate_invalid_language_and_exit(lang)
125
126
  else
126
127
  list_keywords_and_exit(lang)
127
128
  end
128
129
  end
130
+ opts.on(FAIL_FAST_FLAG, "Exit immediately following the first failing scenario") do |v|
131
+ options[:fail_fast] = true
132
+ end
129
133
  opts.on("-f FORMAT", "--format FORMAT",
130
134
  "How to format features (Default: pretty). Available formats:",
131
135
  *FORMAT_HELP) do |v|
@@ -289,6 +293,10 @@ TEXT
289
293
  end
290
294
  end
291
295
 
296
+ def to_hash
297
+ Hash.try_convert(@options)
298
+ end
299
+
292
300
  protected
293
301
 
294
302
  attr_reader :options, :profiles, :expanded_args
@@ -384,24 +392,51 @@ TEXT
384
392
  end
385
393
 
386
394
  def indicate_invalid_language_and_exit(lang)
387
- require 'gherkin/i18n'
388
395
  @out_stream.write("Invalid language '#{lang}'. Available languages are:\n")
389
- @out_stream.write(Gherkin::I18n.language_table)
390
- Kernel.exit(0)
396
+ list_languages_and_exit
391
397
  end
392
398
 
393
399
  def list_keywords_and_exit(lang)
394
- require 'gherkin/i18n'
395
- @out_stream.write(Gherkin::I18n.get(lang).keyword_table)
400
+ require 'gherkin3/dialect'
401
+ language = ::Gherkin3::Dialect.for(lang)
402
+ data = Cucumber::MultilineArgument::DataTable.from(
403
+ [["feature", to_keywords_string(language.feature_keywords)],
404
+ ["background", to_keywords_string(language.background_keywords)],
405
+ ["scenario", to_keywords_string(language.scenario_keywords)],
406
+ ["scenario_outline", to_keywords_string(language.scenario_outline_keywords)],
407
+ ["examples", to_keywords_string(language.examples_keywords)],
408
+ ["given", to_keywords_string(language.given_keywords)],
409
+ ["when", to_keywords_string(language.when_keywords)],
410
+ ["then", to_keywords_string(language.then_keywords)],
411
+ ["and", to_keywords_string(language.and_keywords)],
412
+ ["but", to_keywords_string(language.but_keywords)],
413
+ ["given (code)", to_code_keywords_string(language.given_keywords)],
414
+ ["when (code)", to_code_keywords_string(language.when_keywords)],
415
+ ["then (code)", to_code_keywords_string(language.then_keywords)],
416
+ ["and (code)", to_code_keywords_string(language.and_keywords)],
417
+ ["but (code)", to_code_keywords_string(language.but_keywords)]])
418
+ @out_stream.write(data.to_s({ color: false, prefixes: Hash.new('') }))
396
419
  Kernel.exit(0)
397
420
  end
398
421
 
399
422
  def list_languages_and_exit
400
- require 'gherkin/i18n'
401
- @out_stream.write(Gherkin::I18n.language_table)
423
+ require 'gherkin3/dialect'
424
+ data = Cucumber::MultilineArgument::DataTable.from(
425
+ ::Gherkin3::DIALECTS.keys.map do |key|
426
+ [key, ::Gherkin3::DIALECTS[key].fetch('name'), ::Gherkin3::DIALECTS[key].fetch('native')]
427
+ end)
428
+ @out_stream.write(data.to_s({ color: false, prefixes: Hash.new('') }))
402
429
  Kernel.exit(0)
403
430
  end
404
431
 
432
+ def to_keywords_string(list)
433
+ list.map { |item| "\"#{item}\"" }.join(', ')
434
+ end
435
+
436
+ def to_code_keywords_string(list)
437
+ to_keywords_string(Cucumber::Gherkin::I18n.code_keywords_for(list))
438
+ end
439
+
405
440
  def default_options
406
441
  {
407
442
  :strict => false,
@@ -421,4 +456,4 @@ TEXT
421
456
  end
422
457
 
423
458
  end
424
- end
459
+ end
@@ -1,27 +1,70 @@
1
+ require 'cucumber/constantize'
2
+ require 'cucumber/cli/rerun_file'
3
+ require 'cucumber/events'
4
+ require 'forwardable'
5
+ require 'cucumber/core/gherkin/tag_expression'
6
+
1
7
  module Cucumber
2
8
  # The base class for configuring settings for a Cucumber run.
3
9
  class Configuration
10
+ include Constantize
11
+ extend Forwardable
12
+
4
13
  def self.default
5
14
  new
6
15
  end
7
16
 
8
- def self.parse(argument)
9
- return new(argument) if argument.is_a?(Hash)
10
- argument
11
- end
17
+ # Subscribe to an event.
18
+ #
19
+ # See {Cucumber::Events} for the list of possible events.
20
+ #
21
+ # @param event_id [Symbol, Class, String] Identifier for the type of event to subscribe to
22
+ # @param handler_object [Object optional] an object to be called when the event occurs
23
+ # @yield [Object] Block to be called when th event occurs
24
+ # @method on_event
25
+ def_instance_delegator :event_bus, :register, :on_event
26
+
27
+ # @private
28
+ def_instance_delegator :event_bus, :notify
12
29
 
13
30
  def initialize(user_options = {})
14
- @options = default_options.merge(user_options)
31
+ @options = default_options.merge(Hash.try_convert(user_options))
32
+ end
33
+
34
+ def with_options(new_options)
35
+ self.class.new(new_options.merge(@options))
36
+ end
37
+
38
+ # TODO: Actually Deprecate???
39
+ def options
40
+ warn("Deprecated: Configuration#options will be removed from the next release of Cucumber. Please use the configuration object directly instead.")
41
+ Marshal.load(Marhal.dump(@options))
42
+ end
43
+
44
+ def out_stream
45
+ @options[:out_stream]
46
+ end
47
+
48
+ def error_stream
49
+ @options[:error_stream]
15
50
  end
16
51
 
17
52
  def randomize?
18
- @options[:randomize]
53
+ @options[:order] == 'random'
54
+ end
55
+
56
+ def seed
57
+ Integer(@options[:seed] || rand(0xFFFF))
19
58
  end
20
59
 
21
60
  def dry_run?
22
61
  @options[:dry_run]
23
62
  end
24
63
 
64
+ def fail_fast?
65
+ @options[:fail_fast]
66
+ end
67
+
25
68
  def guess?
26
69
  @options[:guess]
27
70
  end
@@ -30,6 +73,10 @@ module Cucumber
30
73
  @options[:strict]
31
74
  end
32
75
 
76
+ def wip?
77
+ @options[:wip]
78
+ end
79
+
33
80
  def expand?
34
81
  @options[:expand]
35
82
  end
@@ -38,6 +85,10 @@ module Cucumber
38
85
  @options[:paths]
39
86
  end
40
87
 
88
+ def formats
89
+ @options[:formats]
90
+ end
91
+
41
92
  def autoload_code_paths
42
93
  @options[:autoload_code_paths]
43
94
  end
@@ -46,12 +97,149 @@ module Cucumber
46
97
  @options[:snippet_type]
47
98
  end
48
99
 
100
+ def feature_dirs
101
+ dirs = paths.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
102
+ dirs.delete('.') unless paths.include?('.')
103
+ with_default_features_path(dirs)
104
+ end
105
+
106
+ # todo: remove
107
+ def tag_expression
108
+ Cucumber::Core::Gherkin::TagExpression.new(@options[:tag_expressions])
109
+ end
110
+
111
+ def tag_limits
112
+ tag_expression.limits.to_hash
113
+ end
114
+
115
+ def tag_expressions
116
+ @options[:tag_expressions]
117
+ end
118
+
119
+ def name_regexps
120
+ @options[:name_regexps]
121
+ end
122
+
123
+ def filters
124
+ @options[:filters]
125
+ end
126
+
127
+ def feature_files
128
+ potential_feature_files = with_default_features_path(paths).map do |path|
129
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
130
+ path = path.chomp('/')
131
+
132
+ # TODO: Move to using feature loading strategies stored in
133
+ # options[:feature_loaders]
134
+ if File.directory?(path)
135
+ Dir["#{path}/**/*.feature"].sort
136
+ elsif Cli::RerunFile.can_read?(path)
137
+ Cli::RerunFile.new(path).features
138
+ else
139
+ path
140
+ end
141
+ end.flatten.uniq
142
+ remove_excluded_files_from(potential_feature_files)
143
+ potential_feature_files
144
+ end
145
+
146
+ def support_to_load
147
+ support_files = all_files_to_load.select {|f| f =~ %r{/support/} }
148
+ env_files = support_files.select {|f| f =~ %r{/support/env\..*} }
149
+ other_files = support_files - env_files
150
+ @options[:dry_run] ? other_files : env_files + other_files
151
+ end
152
+
153
+ def all_files_to_load
154
+ files = require_dirs.map do |path|
155
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
156
+ path = path.gsub(/\/$/, '') # Strip trailing slash.
157
+ File.directory?(path) ? Dir["#{path}/**/*"] : path
158
+ end.flatten.uniq
159
+ remove_excluded_files_from(files)
160
+ files.reject! {|f| !File.file?(f)}
161
+ files.reject! {|f| File.extname(f) == '.feature' }
162
+ files.reject! {|f| f =~ /^http/}
163
+ files.sort
164
+ end
165
+
166
+ def step_defs_to_load
167
+ all_files_to_load.reject {|f| f =~ %r{/support/} }
168
+ end
169
+
170
+ def formatter_factories
171
+ @options[:formats].map do |format_and_out|
172
+ format = format_and_out[0]
173
+ path_or_io = format_and_out[1]
174
+ begin
175
+ factory = formatter_class(format)
176
+ yield factory, path_or_io, Cli::Options.new(STDOUT, STDERR, @options)
177
+ rescue Exception => e
178
+ e.message << "\nError creating formatter: #{format}"
179
+ raise e
180
+ end
181
+ end
182
+ end
183
+
184
+ def formatter_class(format)
185
+ if(builtin = Cli::Options::BUILTIN_FORMATS[format])
186
+ constantize(builtin[0])
187
+ else
188
+ constantize(format)
189
+ end
190
+ end
191
+
192
+ def to_hash
193
+ @options
194
+ end
195
+
49
196
  private
50
197
 
51
198
  def default_options
52
199
  {
53
- :autoload_code_paths => ['features/support', 'features/step_definitions']
200
+ :autoload_code_paths => ['features/support', 'features/step_definitions'],
201
+ :filters => [],
202
+ :strict => false,
203
+ :require => [],
204
+ :dry_run => false,
205
+ :fail_fast => false,
206
+ :formats => [],
207
+ :excludes => [],
208
+ :tag_expressions => [],
209
+ :name_regexps => [],
210
+ :env_vars => {},
211
+ :diff_enabled => true,
212
+ :snippets => true,
213
+ :source => true,
214
+ :duration => true,
215
+ :event_bus => Events::Bus.new(Cucumber::Events)
54
216
  }
55
217
  end
218
+
219
+ def event_bus
220
+ @options[:event_bus]
221
+ end
222
+
223
+
224
+ def default_features_paths
225
+ ["features"]
226
+ end
227
+
228
+ def with_default_features_path(paths)
229
+ return default_features_paths if paths.empty?
230
+ paths
231
+ end
232
+
233
+ def remove_excluded_files_from(files)
234
+ files.reject! {|path| @options[:excludes].detect {|pattern| path =~ pattern } }
235
+ end
236
+
237
+ def require_dirs
238
+ if @options[:require].empty?
239
+ default_features_paths + Dir['vendor/{gems,plugins}/*/cucumber']
240
+ else
241
+ @options[:require]
242
+ end
243
+ end
56
244
  end
57
245
  end