cucumber 0.8.7 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +5 -0
  3. data/History.txt +16 -3
  4. data/Rakefile +4 -50
  5. data/cucumber.gemspec +36 -600
  6. data/features/cucumber_cli.feature +1 -1
  7. data/features/json_formatter.feature +1 -1
  8. data/features/junit_formatter.feature +10 -6
  9. data/features/post_configuration_hook.feature +15 -2
  10. data/features/step_definitions/cucumber_steps.rb +5 -1
  11. data/features/step_definitions/wire_steps.rb +1 -0
  12. data/features/support/env.rb +2 -5
  13. data/features/wire_protocol.feature +1 -1
  14. data/lib/cucumber.rb +8 -0
  15. data/lib/cucumber/ast/outline_table.rb +4 -4
  16. data/lib/cucumber/ast/step_invocation.rb +14 -13
  17. data/lib/cucumber/ast/table.rb +2 -1
  18. data/lib/cucumber/ast/tree_walker.rb +3 -3
  19. data/lib/cucumber/cli/configuration.rb +32 -7
  20. data/lib/cucumber/cli/main.rb +26 -30
  21. data/lib/cucumber/cli/options.rb +1 -3
  22. data/lib/cucumber/cli/profile_loader.rb +2 -0
  23. data/lib/cucumber/configuration.rb +37 -0
  24. data/lib/cucumber/errors.rb +40 -0
  25. data/lib/cucumber/feature_file.rb +5 -12
  26. data/lib/cucumber/formatter/junit.rb +2 -2
  27. data/lib/cucumber/formatter/tag_cloud.rb +1 -1
  28. data/lib/cucumber/js_support/js_dsl.js +4 -4
  29. data/lib/cucumber/js_support/js_language.rb +9 -5
  30. data/lib/cucumber/language_support.rb +2 -2
  31. data/lib/cucumber/parser/gherkin_builder.rb +19 -19
  32. data/lib/cucumber/platform.rb +3 -4
  33. data/lib/cucumber/rake/task.rb +1 -7
  34. data/lib/cucumber/rb_support/rb_dsl.rb +1 -0
  35. data/lib/cucumber/rb_support/rb_language.rb +1 -0
  36. data/lib/cucumber/rspec/doubles.rb +3 -3
  37. data/lib/cucumber/runtime.rb +192 -0
  38. data/lib/cucumber/runtime/features_loader.rb +62 -0
  39. data/lib/cucumber/runtime/results.rb +46 -0
  40. data/lib/cucumber/runtime/support_code.rb +174 -0
  41. data/lib/cucumber/runtime/user_interface.rb +80 -0
  42. data/lib/cucumber/step_mother.rb +6 -427
  43. data/lib/cucumber/wire_support/configuration.rb +2 -0
  44. data/lib/cucumber/wire_support/wire_language.rb +1 -8
  45. data/spec/cucumber/ast/background_spec.rb +3 -3
  46. data/spec/cucumber/ast/feature_spec.rb +2 -2
  47. data/spec/cucumber/ast/scenario_outline_spec.rb +1 -1
  48. data/spec/cucumber/ast/scenario_spec.rb +1 -2
  49. data/spec/cucumber/ast/tree_walker_spec.rb +1 -1
  50. data/spec/cucumber/cli/configuration_spec.rb +31 -5
  51. data/spec/cucumber/cli/drb_client_spec.rb +1 -1
  52. data/spec/cucumber/cli/main_spec.rb +8 -37
  53. data/spec/cucumber/cli/options_spec.rb +20 -0
  54. data/spec/cucumber/formatter/spec_helper.rb +5 -7
  55. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  56. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +1 -1
  57. data/spec/cucumber/runtime_spec.rb +294 -0
  58. data/spec/cucumber/step_match_spec.rb +10 -8
  59. data/spec/cucumber/world/pending_spec.rb +1 -1
  60. data/spec/spec_helper.rb +2 -21
  61. metadata +215 -84
  62. data/Caliper.yml +0 -4
  63. data/VERSION.yml +0 -5
  64. data/spec/cucumber/step_mother_spec.rb +0 -302
@@ -1,3 +1,5 @@
1
+ require 'yaml'
2
+
1
3
  module Cucumber
2
4
  module Cli
3
5
 
@@ -0,0 +1,37 @@
1
+ module Cucumber
2
+ # The base class for configuring settings for a Cucumber run.
3
+ class Configuration
4
+ def self.default
5
+ new
6
+ end
7
+
8
+ def self.parse(argument)
9
+ return new(argument) if argument.is_a?(Hash)
10
+ argument
11
+ end
12
+
13
+ def initialize(options = {})
14
+ @options = options
15
+ end
16
+
17
+ def dry_run?
18
+ @options[:dry_run]
19
+ end
20
+
21
+ def guess?
22
+ @options[:guess]
23
+ end
24
+
25
+ def strict?
26
+ @options[:strict]
27
+ end
28
+
29
+ def expand?
30
+ @options[:expand]
31
+ end
32
+
33
+ def paths
34
+ @options[:paths]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ module Cucumber
2
+ # Raised when there is no matching StepDefinition for a step.
3
+ class Undefined < StandardError
4
+ attr_reader :step_name
5
+
6
+ def initialize(step_name)
7
+ super %{Undefined step: "#{step_name}"}
8
+ @step_name = step_name
9
+ end
10
+
11
+ def nested!
12
+ @nested = true
13
+ end
14
+
15
+ def nested?
16
+ @nested
17
+ end
18
+ end
19
+
20
+ # Raised when a StepDefinition's block invokes World#pending
21
+ class Pending < StandardError
22
+ end
23
+
24
+ # Raised when a step matches 2 or more StepDefinitions
25
+ class Ambiguous < StandardError
26
+ def initialize(step_name, step_definitions, used_guess)
27
+ message = "Ambiguous match of \"#{step_name}\":\n\n"
28
+ message << step_definitions.map{|sd| sd.backtrace_line}.join("\n")
29
+ message << "\n\n"
30
+ message << "You can run again with --guess to make Cucumber be more smart about it\n" unless used_guess
31
+ super(message)
32
+ end
33
+ end
34
+
35
+ class TagExcess < StandardError
36
+ def initialize(messages)
37
+ super(messages.join("\n"))
38
+ end
39
+ end
40
+ end
@@ -2,14 +2,13 @@ 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
9
  LANGUAGE_PATTERN = /language:\s*(.*)/ #:nodoc:
11
10
 
12
- # The +uri+ argument is the location of the source. It can ba a path
11
+ # The +uri+ argument is the location of the source. It can be a path
13
12
  # or a path:line1:line2 etc. If +source+ is passed, +uri+ is ignored.
14
13
  def initialize(uri, source=nil)
15
14
  @source = source
@@ -22,10 +21,10 @@ module Cucumber
22
21
  end
23
22
 
24
23
  # Parses a file and returns a Cucumber::Ast
25
- # If +options+ contains tags, the result will
24
+ # If +configuration_filters+ contains any filters, the result will
26
25
  # be filtered.
27
- def parse(options, tag_counts)
28
- filters = @lines || options.filters
26
+ def parse(configuration_filters, tag_counts)
27
+ filters = @lines || configuration_filters
29
28
 
30
29
  builder = Cucumber::Parser::GherkinBuilder.new
31
30
  filter_formatter = filters.empty? ? builder : Gherkin::Formatter::FilterFormatter.new(builder, filters)
@@ -39,7 +38,7 @@ module Cucumber
39
38
  ast.language = parser.i18n_language
40
39
  ast.file = @path
41
40
  ast
42
- rescue Gherkin::LexingError, Gherkin::Parser::ParseError => e
41
+ rescue Gherkin::Lexer::LexingError, Gherkin::Parser::ParseError => e
43
42
  e.message.insert(0, "#{@path}: ")
44
43
  raise e
45
44
  end
@@ -59,11 +58,5 @@ module Cucumber
59
58
  end
60
59
  end
61
60
  end
62
-
63
- private
64
-
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
68
61
  end
69
62
  end
@@ -122,8 +122,8 @@ module Cucumber
122
122
  @builder.testcase(:classname => classname, :name => name, :time => "%.6f" % duration) do
123
123
  if failed
124
124
  @builder.failure(:message => "#{status.to_s} #{name}", :type => status.to_s) do
125
- @builder.text! @output
126
- @builder.text!(format_exception(exception)) if exception
125
+ @builder.cdata! @output
126
+ @builder.cdata!(format_exception(exception)) if exception
127
127
  end
128
128
  @failures += 1
129
129
  end
@@ -28,7 +28,7 @@ module Cucumber
28
28
  matrix = @counts.to_a.sort{|paira, pairb| paira[0] <=> pairb[0]}.transpose
29
29
  table = Cucumber::Ast::Table.new(matrix)
30
30
  formatter = Cucumber::Formatter::Pretty.new(@step_mother, @io, {})
31
- Cucumber::Ast::TreeWalker.new(@step_mother, [formatter], {}).visit_multiline_arg(table)
31
+ Cucumber::Ast::TreeWalker.new(@step_mother, [formatter]).visit_multiline_arg(table)
32
32
  end
33
33
  end
34
34
  end
@@ -1,15 +1,15 @@
1
1
  var CucumberJsDsl = {
2
2
  registerStepDefinition: function(regexp, func) {
3
3
  if(func == null) {
4
- jsLanguage.executeStepDefinition(regexp);
4
+ jsLanguage.execute_step_definition(regexp);
5
5
  }
6
6
  else{
7
- jsLanguage.addStepDefinition(regexp, func);
7
+ jsLanguage.add_step_definition(regexp, func);
8
8
  }
9
9
  },
10
10
 
11
11
  registerTransform: function(regexp, func) {
12
- jsLanguage.registerJsTransform(regexp, func);
12
+ jsLanguage.register_js_transform(regexp, func);
13
13
  },
14
14
 
15
15
  beforeHook: function(tag_expressions_or_func, func) {
@@ -40,7 +40,7 @@ var CucumberJsDsl = {
40
40
  var hook_func = tag_expressions_or_func;
41
41
  var tag_expressions = [];
42
42
  }
43
- jsLanguage.registerJsHook(label, tag_expressions, hook_func);
43
+ jsLanguage.register_js_hook(label, tag_expressions, hook_func);
44
44
  }
45
45
  }
46
46
 
@@ -39,6 +39,10 @@ module Cucumber
39
39
  @js_language.current_world.execute(@js_function, args)
40
40
  end
41
41
 
42
+ def regexp_source
43
+ @regexp.inspect
44
+ end
45
+
42
46
  def arguments_from(step_name)
43
47
  matches = eval_js "#{@regexp}.exec('#{step_name}')"
44
48
  if matches
@@ -101,10 +105,10 @@ module Cucumber
101
105
  include LanguageSupport::LanguageMethods
102
106
  include JsSnippets
103
107
 
104
- def initialize(step_mother)
108
+ def initialize(runtime)
105
109
  @step_definitions = []
106
110
  @world = JsWorld.new
107
- @step_mother = step_mother
111
+ @runtime = runtime
108
112
 
109
113
  @world["jsLanguage"] = self
110
114
  @world.load(File.dirname(__FILE__) + '/js_dsl.js')
@@ -146,7 +150,7 @@ module Cucumber
146
150
 
147
151
  #TODO: support multiline arguments when calling steps from within steps
148
152
  def execute_step_definition(name, multiline_argument = nil)
149
- @step_mother.step_match(name).invoke(multiline_argument)
153
+ @runtime.step_match(name).invoke(multiline_argument)
150
154
  end
151
155
 
152
156
  def register_js_hook(phase, tag_expressions, js_function)
@@ -162,12 +166,12 @@ module Cucumber
162
166
  end
163
167
 
164
168
  def steps(steps_text, file_colon_line)
165
- @step_mother.invoke_steps(steps_text, @language, file_colon_line)
169
+ @runtime.invoke_steps(steps_text, @language, file_colon_line)
166
170
  end
167
171
 
168
172
  private
169
173
  def path_to_load_js_from
170
- paths = @step_mother.options[:paths]
174
+ paths = @runtime.features_paths
171
175
  if paths.empty?
172
176
  '' # Using rake
173
177
  else
@@ -1,5 +1,5 @@
1
1
  module Cucumber
2
- # This module defines the API for programming panguage support in Cucumber.
2
+ # This module defines the API for programming language support in Cucumber.
3
3
  # While Cucumber itself is written in Ruby, any programming language can
4
4
  # be supported by implementing this API.
5
5
  #
@@ -27,4 +27,4 @@ module Cucumber
27
27
  #
28
28
  module LanguageSupport
29
29
  end
30
- end
30
+ end
@@ -13,23 +13,23 @@ module Cucumber
13
13
  @feature || @multiline_arg
14
14
  end
15
15
 
16
- def feature(statement, uri)
16
+ def feature(feature)
17
17
  @feature = Ast::Feature.new(
18
18
  nil,
19
- Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
20
- Ast::Tags.new(nil, statement.tags.map{|tag| tag.name}),
21
- statement.keyword,
22
- legacy_name_for(statement.name, statement.description),
19
+ Ast::Comment.new(feature.comments.map{|comment| comment.value}.join("\n")),
20
+ Ast::Tags.new(nil, feature.tags.map{|tag| tag.name}),
21
+ feature.keyword,
22
+ legacy_name_for(feature.name, feature.description),
23
23
  []
24
24
  )
25
25
  end
26
26
 
27
- def background(statement)
27
+ def background(background)
28
28
  @background = Ast::Background.new(
29
- Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
30
- statement.line,
31
- statement.keyword,
32
- legacy_name_for(statement.name, statement.description),
29
+ Ast::Comment.new(background.comments.map{|comment| comment.value}.join("\n")),
30
+ background.line,
31
+ background.keyword,
32
+ legacy_name_for(background.name, background.description),
33
33
  steps=[]
34
34
  )
35
35
  @feature.background = @background
@@ -71,20 +71,20 @@ module Cucumber
71
71
  @step_container = scenario_outline
72
72
  end
73
73
 
74
- def examples(statement, examples_rows)
74
+ def examples(examples)
75
75
  examples_fields = [
76
- Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
77
- statement.line,
78
- statement.keyword,
79
- legacy_name_for(statement.name, statement.description),
80
- matrix(examples_rows)
76
+ Ast::Comment.new(examples.comments.map{|comment| comment.value}.join("\n")),
77
+ examples.line,
78
+ examples.keyword,
79
+ legacy_name_for(examples.name, examples.description),
80
+ matrix(examples.rows)
81
81
  ]
82
82
  @step_container.add_examples(examples_fields)
83
83
  end
84
84
 
85
- def step(statement, multiline_arg, result)
86
- @table_owner = Ast::Step.new(statement.line, statement.keyword, statement.name)
87
- multiline_arg = rubify(multiline_arg)
85
+ def step(step)
86
+ @table_owner = Ast::Step.new(step.line, step.keyword, step.name)
87
+ multiline_arg = rubify(step.multiline_arg)
88
88
  case(multiline_arg)
89
89
  when Gherkin::Formatter::Model::PyString
90
90
  @table_owner.multiline_arg = Ast::PyString.new(multiline_arg.value)
@@ -1,11 +1,9 @@
1
1
  # Detect the platform we're running on so we can tweak behaviour
2
2
  # in various places.
3
- require 'rbconfig'
4
- require 'yaml'
5
3
 
6
4
  module Cucumber
7
- version = YAML.load_file(File.dirname(__FILE__) + '/../../VERSION.yml')
8
- VERSION = [version[:major], version[:minor], version[:patch], version[:build]].compact.join('.')
5
+ unless defined?(Cucumber::VERSION)
6
+ VERSION = '0.9.0'
9
7
  BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
10
8
  LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
11
9
  JRUBY = defined?(JRUBY_VERSION)
@@ -27,3 +25,4 @@ module Cucumber
27
25
  end
28
26
  self.use_full_backtrace = false
29
27
  end
28
+ end
@@ -1,11 +1,5 @@
1
1
  require 'cucumber/platform'
2
2
 
3
- begin
4
- # Support Rake > 0.8.7
5
- require 'rake/dsl_definition'
6
- include Rake::DSL
7
- rescue LoadError
8
- end
9
3
  module Cucumber
10
4
  module Rake
11
5
  # Defines a Rake task for running features.
@@ -71,7 +65,7 @@ module Cucumber
71
65
  end
72
66
 
73
67
  def runner
74
- File.exist?("./Gemfile") ? ["bundle", "exec", RUBY] : [RUBY]
68
+ File.exist?("./Gemfile") && Gem.available?("bundler") ? ["bundle", "exec", RUBY] : [RUBY]
75
69
  end
76
70
 
77
71
  def run
@@ -88,6 +88,7 @@ module Cucumber
88
88
 
89
89
  # Registers a proc that will run after Cucumber is configured. You can register as
90
90
  # as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
91
+ # TODO: Deprecate this
91
92
  def AfterConfiguration(&proc)
92
93
  RbDsl.register_rb_hook('after_configuration', [], proc)
93
94
  end
@@ -1,3 +1,4 @@
1
+ require 'cucumber/core_ext/instance_exec'
1
2
  require 'cucumber/rb_support/rb_dsl'
2
3
  require 'cucumber/rb_support/rb_world'
3
4
  require 'cucumber/rb_support/rb_step_definition'
@@ -4,13 +4,13 @@ RSpec.configuration.configure_mock_framework
4
4
  World(RSpec::Core::MockFrameworkAdapter)
5
5
 
6
6
  Before do
7
- _setup_mocks
7
+ RSpec::Mocks::setup(self)
8
8
  end
9
9
 
10
10
  After do
11
11
  begin
12
- _verify_mocks
12
+ RSpec::Mocks::verify
13
13
  ensure
14
- _teardown_mocks
14
+ RSpec::Mocks::teardown
15
15
  end
16
16
  end
@@ -0,0 +1,192 @@
1
+ require 'cucumber/configuration'
2
+ require 'cucumber/language_support/language_methods'
3
+ require 'cucumber/formatter/duration'
4
+ require 'gherkin/rubify'
5
+ require 'cucumber/runtime/user_interface'
6
+ require 'cucumber/runtime/features_loader'
7
+ require 'cucumber/runtime/results'
8
+ require 'cucumber/runtime/support_code'
9
+
10
+ module Cucumber
11
+ # This is the meaty part of Cucumber that ties everything together.
12
+ class Runtime
13
+ attr_reader :results
14
+
15
+ include Formatter::Duration
16
+ include Runtime::UserInterface
17
+
18
+ def initialize(configuration = Configuration.default)
19
+ @current_scenario = nil
20
+ @configuration = Configuration.parse(configuration)
21
+ @support_code = SupportCode.new(self, @configuration.guess?)
22
+ @results = Results.new(@configuration)
23
+ end
24
+
25
+ def run!
26
+ load_step_definitions
27
+ fire_after_configuration_hook
28
+
29
+ tree_walker = @configuration.build_tree_walker(self)
30
+ self.visitor = tree_walker # Ugly circular dependency, but needed to support World#announce
31
+
32
+ tree_walker.visit_features(features)
33
+ end
34
+
35
+ def features_paths
36
+ @configuration.paths
37
+ end
38
+
39
+ def step_visited(step) #:nodoc:
40
+ @results.step_visited(step)
41
+ end
42
+
43
+ def scenarios(status = nil)
44
+ @results.scenarios(status)
45
+ end
46
+
47
+ def steps(status = nil)
48
+ @results.steps(status)
49
+ end
50
+
51
+ # Loads and registers programming language implementation.
52
+ # Instances are cached, so calling with the same argument
53
+ # twice will return the same instance.
54
+ #
55
+ def load_programming_language(ext)
56
+ @support_code.load_programming_language!(ext)
57
+ end
58
+
59
+ def invoke(step_name, multiline_argument)
60
+ @support_code.invoke(step_name, multiline_argument)
61
+ end
62
+
63
+ # Invokes a series of steps +steps_text+. Example:
64
+ #
65
+ # invoke(%Q{
66
+ # Given I have 8 cukes in my belly
67
+ # Then I should not be thirsty
68
+ # })
69
+ def invoke_steps(steps_text, i18n, file_colon_line)
70
+ @support_code.invoke_steps(steps_text, i18n, file_colon_line)
71
+ end
72
+
73
+ # Returns a Cucumber::Ast::Table for +text_or_table+, which can either
74
+ # be a String:
75
+ #
76
+ # table(%{
77
+ # | account | description | amount |
78
+ # | INT-100 | Taxi | 114 |
79
+ # | CUC-101 | Peeler | 22 |
80
+ # })
81
+ #
82
+ # or a 2D Array:
83
+ #
84
+ # table([
85
+ # %w{ account description amount },
86
+ # %w{ INT-100 Taxi 114 },
87
+ # %w{ CUC-101 Peeler 22 }
88
+ # ])
89
+ #
90
+ def table(text_or_table, file=nil, line_offset=0)
91
+ if Array === text_or_table
92
+ Ast::Table.new(text_or_table)
93
+ else
94
+ Ast::Table.parse(text_or_table, file, line_offset)
95
+ end
96
+ end
97
+
98
+ # Returns a regular String for +string_with_triple_quotes+. Example:
99
+ #
100
+ # """
101
+ # hello
102
+ # world
103
+ # """
104
+ #
105
+ # Is retured as: " hello\nworld"
106
+ #
107
+ def py_string(string_with_triple_quotes, file=nil, line_offset=0)
108
+ Ast::PyString.parse(string_with_triple_quotes)
109
+ end
110
+
111
+ def step_match(step_name, name_to_report=nil) #:nodoc:
112
+ @support_code.step_match(step_name, name_to_report)
113
+ end
114
+
115
+ def unmatched_step_definitions
116
+ @support_code.unmatched_step_definitions
117
+ end
118
+
119
+ def snippet_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
120
+ @support_code.snippet_text(step_keyword, step_name, multiline_arg_class)
121
+ end
122
+
123
+ def with_hooks(scenario, skip_hooks=false)
124
+ around(scenario, skip_hooks) do
125
+ before_and_after(scenario, skip_hooks) do
126
+ yield scenario
127
+ end
128
+ end
129
+ end
130
+
131
+ def around(scenario, skip_hooks=false, &block) #:nodoc:
132
+ if skip_hooks
133
+ yield
134
+ return
135
+ end
136
+
137
+ @support_code.around(scenario, block)
138
+ end
139
+
140
+ def before_and_after(scenario, skip_hooks=false) #:nodoc:
141
+ before(scenario) unless skip_hooks
142
+ yield scenario
143
+ after(scenario) unless skip_hooks
144
+ @results.scenario_visited(scenario)
145
+ end
146
+
147
+ def before(scenario) #:nodoc:
148
+ return if @configuration.dry_run? || @current_scenario
149
+ @current_scenario = scenario
150
+ @support_code.fire_hook(:before, scenario)
151
+ end
152
+
153
+ def after(scenario) #:nodoc:
154
+ @current_scenario = nil
155
+ return if @configuration.dry_run?
156
+ @support_code.fire_hook(:after, scenario)
157
+ end
158
+
159
+ def after_step #:nodoc:
160
+ return if @configuration.dry_run?
161
+ @support_code.fire_hook(:execute_after_step, @current_scenario)
162
+ end
163
+
164
+ def unknown_programming_language?
165
+ @support_code.unknown_programming_language?
166
+ end
167
+
168
+ private
169
+
170
+ def fire_after_configuration_hook #:nodoc
171
+ @support_code.fire_hook(:after_configuration, @configuration)
172
+ end
173
+
174
+ def features
175
+ loader = Runtime::FeaturesLoader.new(
176
+ @configuration.feature_files,
177
+ @configuration.filters,
178
+ @configuration.tag_expression)
179
+ loader.features
180
+ end
181
+
182
+ def load_step_definitions
183
+ files = @configuration.support_to_load + @configuration.step_defs_to_load
184
+ @support_code.load_files!(files)
185
+ end
186
+
187
+ def log
188
+ Cucumber.logger
189
+ end
190
+ end
191
+
192
+ end