cucumber 0.3.103 → 0.3.104
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.
- data/History.txt +27 -2
- data/Manifest.txt +10 -4
- data/examples/ramaze/README.textile +7 -0
- data/examples/ramaze/Rakefile +6 -0
- data/examples/ramaze/app.rb +21 -0
- data/examples/ramaze/features/add.feature +11 -0
- data/examples/ramaze/features/step_definitions/add_steps.rb +15 -0
- data/examples/ramaze/features/support/env.rb +32 -0
- data/examples/ramaze/layout/default.html.erb +8 -0
- data/examples/ramaze/view/index.html.erb +5 -0
- data/examples/sinatra/features/support/env.rb +1 -1
- data/features/cucumber_cli.feature +5 -5
- data/features/usage_and_stepdefs_formatter.feature +169 -0
- data/lib/cucumber/ast/step_invocation.rb +7 -0
- data/lib/cucumber/ast/tags.rb +6 -1
- data/lib/cucumber/ast/tree_walker.rb +5 -11
- data/lib/cucumber/cli/options.rb +20 -11
- data/lib/cucumber/formatter/html.rb +0 -2
- data/lib/cucumber/formatter/stepdefs.rb +14 -0
- data/lib/cucumber/formatter/usage.rb +106 -50
- data/lib/cucumber/language_support/language_methods.rb +6 -9
- data/lib/cucumber/rb_support/rb_language.rb +16 -3
- data/lib/cucumber/rb_support/rb_step_definition.rb +7 -1
- data/lib/cucumber/step_match.rb +4 -0
- data/lib/cucumber/step_mother.rb +8 -37
- data/lib/cucumber/version.rb +1 -1
- data/spec/cucumber/ast/background_spec.rb +0 -6
- data/spec/cucumber/ast/tree_walker_spec.rb +0 -7
- data/spec/cucumber/cli/options_spec.rb +12 -0
- data/spec/cucumber/formatter/html_spec.rb +0 -1
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +0 -9
- data/spec/cucumber/step_mother_spec.rb +13 -34
- metadata +12 -6
- data/features/steps_formatter.feature +0 -26
- data/features/usage.feature +0 -126
- data/lib/cucumber/formatter/profile.rb +0 -78
- data/lib/cucumber/formatters/unicode.rb +0 -7
@@ -10,7 +10,6 @@ module Cucumber
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def visit_features(features)
|
13
|
-
warn "The listener(s) (#{deprecated_listeners.map{ |l| l.class }}) appear to support the legacy Ast::Visitor interface, which is no longer supported." if deprecated_listeners.any?
|
14
13
|
broadcast(features) do
|
15
14
|
features.accept(self)
|
16
15
|
end
|
@@ -154,14 +153,13 @@ module Cucumber
|
|
154
153
|
message = extract_method_name_from(caller)
|
155
154
|
message.gsub!('visit_', '')
|
156
155
|
|
157
|
-
|
156
|
+
if block_given?
|
157
|
+
send_to_all("before_#{message}", *args)
|
158
|
+
yield if block_given?
|
159
|
+
send_to_all("after_#{message}", *args)
|
160
|
+
else
|
158
161
|
send_to_all(message, *args)
|
159
|
-
return
|
160
162
|
end
|
161
|
-
|
162
|
-
send_to_all("before_#{message}", *args)
|
163
|
-
yield if block_given?
|
164
|
-
send_to_all("after_#{message}", *args)
|
165
163
|
end
|
166
164
|
|
167
165
|
def send_to_all(message, *args)
|
@@ -176,10 +174,6 @@ module Cucumber
|
|
176
174
|
call_stack[0].match(/in `(.*)'/).captures[0]
|
177
175
|
end
|
178
176
|
|
179
|
-
def deprecated_listeners
|
180
|
-
@listeners.select{ |l| l.respond_to?(:visit_features) }
|
181
|
-
end
|
182
|
-
|
183
177
|
end
|
184
178
|
end
|
185
179
|
end
|
data/lib/cucumber/cli/options.rb
CHANGED
@@ -9,13 +9,17 @@ module Cucumber
|
|
9
9
|
'pdf' => ['Cucumber::Formatter::Pdf', "Generates a PDF report. You need to have the\n" +
|
10
10
|
"#{' ' * 51}prawn gem installed. Will pick up logo from\n" +
|
11
11
|
"#{' ' * 51}features/support/logo.png if present."],
|
12
|
-
'profile' => ['Cucumber::Formatter::Profile', 'Prints the 10 slowest steps at the end.'],
|
13
12
|
'progress' => ['Cucumber::Formatter::Progress', 'Prints one character per scenario.'],
|
14
13
|
'rerun' => ['Cucumber::Formatter::Rerun', 'Prints failing files with line numbers.'],
|
15
|
-
'usage' => ['Cucumber::Formatter::Usage',
|
14
|
+
'usage' => ['Cucumber::Formatter::Usage', "Prints where step definitions are used.\n" +
|
15
|
+
"#{' ' * 51}The slowest step definitions (with duration) are\n" +
|
16
|
+
"#{' ' * 51}listed first. If --dry-run is used the duration\n" +
|
17
|
+
"#{' ' * 51}is not shown, and step definitions are sorted by\n" +
|
18
|
+
"#{' ' * 51}filename instead."],
|
19
|
+
'stepdefs' => ['Cucumber::Formatter::Stepdefs', "Prints All step definitions with their locations. Same as\n" +
|
20
|
+
"the usage formatter, except that steps are not printed."],
|
16
21
|
'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
|
17
|
-
'tag_cloud' => ['Cucumber::Formatter::TagCloud', 'Prints a tag cloud of tag usage.']
|
18
|
-
'steps' => ['Cucumber::Formatter::Steps', 'Prints location of step definitions.']
|
22
|
+
'tag_cloud' => ['Cucumber::Formatter::TagCloud', 'Prints a tag cloud of tag usage.']
|
19
23
|
}
|
20
24
|
max = BUILTIN_FORMATS.keys.map{|s| s.length}.max
|
21
25
|
FORMAT_HELP = (BUILTIN_FORMATS.keys.sort.map do |key|
|
@@ -171,9 +175,9 @@ module Cucumber
|
|
171
175
|
end
|
172
176
|
opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.",
|
173
177
|
"This also omits the loading of your support/env.rb file if it exists.",
|
174
|
-
"Implies --
|
178
|
+
"Implies --no-snippets.") do
|
175
179
|
@options[:dry_run] = true
|
176
|
-
@
|
180
|
+
@options[:snippets] = false
|
177
181
|
end
|
178
182
|
opts.on("-a", "--autoformat DIRECTORY",
|
179
183
|
"Reformats (pretty prints) feature files and write them to DIRECTORY.",
|
@@ -257,12 +261,16 @@ module Cucumber
|
|
257
261
|
attr_reader :options, :profiles, :expanded_args
|
258
262
|
protected :options, :profiles, :expanded_args
|
259
263
|
|
260
|
-
def non_stdout_formats
|
261
|
-
@options[:formats].select {|format, output| output != @out_stream }
|
262
|
-
end
|
263
|
-
|
264
264
|
private
|
265
265
|
|
266
|
+
def non_stdout_formats
|
267
|
+
@options[:formats].select {|format, output| output != @out_stream }
|
268
|
+
end
|
269
|
+
|
270
|
+
def stdout_formats
|
271
|
+
@options[:formats].select {|format, output| output == @out_stream }
|
272
|
+
end
|
273
|
+
|
266
274
|
def extract_environment_variables
|
267
275
|
@args.delete_if do |arg|
|
268
276
|
if arg =~ /^(\w+)=(.*)$/
|
@@ -337,7 +345,8 @@ module Cucumber
|
|
337
345
|
if @options[:formats].empty?
|
338
346
|
@options[:formats] = other_options[:formats]
|
339
347
|
else
|
340
|
-
@options[:formats] += other_options
|
348
|
+
@options[:formats] += other_options[:formats]
|
349
|
+
@options[:formats] = stdout_formats[0..0] + non_stdout_formats
|
341
350
|
end
|
342
351
|
|
343
352
|
self
|
@@ -2,82 +2,138 @@ require 'cucumber/formatter/progress'
|
|
2
2
|
|
3
3
|
module Cucumber
|
4
4
|
module Formatter
|
5
|
-
|
6
|
-
class Usage
|
5
|
+
class Usage < Progress
|
7
6
|
include Console
|
8
7
|
|
8
|
+
class StepDefKey
|
9
|
+
attr_reader :regexp_source, :file_colon_line
|
10
|
+
attr_accessor :mean_duration, :status
|
11
|
+
|
12
|
+
def initialize(regexp_source, file_colon_line)
|
13
|
+
@regexp_source, @file_colon_line = regexp_source, file_colon_line
|
14
|
+
end
|
15
|
+
|
16
|
+
def eql?(o)
|
17
|
+
regexp_source == o.regexp_source && file_colon_line == o.file_colon_line
|
18
|
+
end
|
19
|
+
|
20
|
+
def hash
|
21
|
+
regexp_source.hash + 17*file_colon_line.hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
9
25
|
def initialize(step_mother, io, options)
|
26
|
+
@step_mother = step_mother
|
10
27
|
@io = io
|
11
28
|
@options = options
|
12
|
-
@
|
13
|
-
@all_step_definitions = step_mother.step_definitions.dup
|
14
|
-
@locations = []
|
15
|
-
end
|
16
|
-
|
17
|
-
def after_features(features)
|
18
|
-
print_summary(features)
|
29
|
+
@stepdef_to_match = Hash.new{|h,stepdef_key| h[stepdef_key] = []}
|
19
30
|
end
|
20
31
|
|
21
32
|
def before_step(step)
|
22
33
|
@step = step
|
23
34
|
end
|
24
35
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@
|
36
|
+
def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
|
37
|
+
@step_duration = Time.now
|
38
|
+
end
|
39
|
+
|
40
|
+
def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
|
41
|
+
duration = Time.now - @step_duration
|
42
|
+
if step_match.name.nil? # nil if it's from a scenario outline
|
43
|
+
stepdef_key = StepDefKey.new(step_match.step_definition.regexp_source, step_match.step_definition.file_colon_line)
|
44
|
+
|
45
|
+
@stepdef_to_match[stepdef_key] << {
|
46
|
+
:keyword => keyword,
|
47
|
+
:step_match => step_match,
|
48
|
+
:status => status,
|
49
|
+
:file_colon_line => @step.file_colon_line,
|
50
|
+
:duration => duration
|
51
|
+
}
|
35
52
|
end
|
53
|
+
super
|
36
54
|
end
|
37
55
|
|
38
56
|
def print_summary(features)
|
39
|
-
|
40
|
-
|
41
|
-
sorted_defs.each do |step_definition|
|
42
|
-
step_matches_and_descriptions = @step_definitions[step_definition].sort_by do |step_match_and_description|
|
43
|
-
step_match = step_match_and_description[0]
|
44
|
-
step_match.step_definition.regexp_source
|
45
|
-
end
|
57
|
+
add_unused_stepdefs
|
58
|
+
aggregate_info
|
46
59
|
|
47
|
-
|
60
|
+
if @options[:dry_run]
|
61
|
+
keys = @stepdef_to_match.keys.sort {|a,b| a.regexp_source <=> b.regexp_source}
|
62
|
+
else
|
63
|
+
keys = @stepdef_to_match.keys.sort {|a,b| a.mean_duration <=> b.mean_duration}.reverse
|
64
|
+
end
|
65
|
+
|
66
|
+
keys.each do |stepdef_key|
|
67
|
+
print_step_definition(stepdef_key)
|
48
68
|
|
49
|
-
|
50
|
-
|
69
|
+
if @stepdef_to_match[stepdef_key].any?
|
70
|
+
print_steps(stepdef_key)
|
71
|
+
else
|
72
|
+
@io.puts(" " + format_string("NOT MATCHED BY ANY STEPS", :failed))
|
51
73
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
74
|
+
end
|
75
|
+
@io.puts
|
76
|
+
super
|
77
|
+
end
|
78
|
+
|
79
|
+
def print_step_definition(stepdef_key)
|
80
|
+
@io.print format_string(sprintf("%.7f", stepdef_key.mean_duration), :skipped) + " " unless @options[:dry_run]
|
81
|
+
@io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
|
82
|
+
if @options[:source]
|
83
|
+
indent = max_length - stepdef_key.regexp_source.jlength
|
84
|
+
line_comment = " # #{stepdef_key.file_colon_line}".indent(indent)
|
85
|
+
@io.print(format_string(line_comment, :comment))
|
86
|
+
end
|
87
|
+
@io.puts
|
88
|
+
end
|
89
|
+
|
90
|
+
def print_steps(stepdef_key)
|
91
|
+
@stepdef_to_match[stepdef_key].each do |step|
|
92
|
+
@io.print " "
|
93
|
+
@io.print format_string(sprintf("%.7f", step[:duration]), :skipped) + " " unless @options[:dry_run]
|
94
|
+
@io.print format_step(step[:keyword], step[:step_match], step[:status], nil)
|
95
|
+
if @options[:source]
|
96
|
+
indent = max_length - (step[:keyword].jlength + step[:step_match].format_args.jlength)
|
97
|
+
line_comment = " # #{step[:file_colon_line]}".indent(indent)
|
98
|
+
@io.print(format_string(line_comment, :comment))
|
63
99
|
end
|
64
|
-
|
100
|
+
@io.puts
|
65
101
|
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def max_length
|
105
|
+
[max_stepdef_length, max_step_length].compact.max
|
106
|
+
end
|
66
107
|
|
67
|
-
|
108
|
+
def max_stepdef_length
|
109
|
+
@stepdef_to_match.keys.flatten.map{|key| key.regexp_source.jlength}.max
|
68
110
|
end
|
69
111
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
112
|
+
def max_step_length
|
113
|
+
@stepdef_to_match.values.flatten.map do |step|
|
114
|
+
step[:keyword].jlength + step[:step_match].format_args.jlength
|
115
|
+
end.max
|
116
|
+
end
|
73
117
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
118
|
+
def aggregate_info
|
119
|
+
@stepdef_to_match.each do |key, steps|
|
120
|
+
if steps.empty?
|
121
|
+
key.status = :skipped
|
122
|
+
key.mean_duration = 0
|
123
|
+
else
|
124
|
+
key.status = Ast::StepInvocation.worst_status(steps.map{|step| step[:status]})
|
125
|
+
total_duration = steps.inject(0) {|sum, step| step[:duration] + sum}
|
126
|
+
key.mean_duration = total_duration / steps.length
|
78
127
|
end
|
79
128
|
end
|
80
129
|
end
|
130
|
+
|
131
|
+
def add_unused_stepdefs
|
132
|
+
@step_mother.unmatched_step_definitions.each do |step_definition|
|
133
|
+
stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
|
134
|
+
@stepdef_to_match[stepdef_key] = []
|
135
|
+
end
|
136
|
+
end
|
81
137
|
end
|
82
138
|
end
|
83
|
-
end
|
139
|
+
end
|
@@ -1,6 +1,12 @@
|
|
1
|
+
require 'cucumber/step_match'
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module LanguageSupport
|
3
5
|
module LanguageMethods
|
6
|
+
def create_step_match(step_definition, step_name, formatted_step_name, step_arguments)
|
7
|
+
StepMatch.new(step_definition, step_name, formatted_step_name, step_arguments)
|
8
|
+
end
|
9
|
+
|
4
10
|
def before(scenario)
|
5
11
|
begin_scenario
|
6
12
|
execute_before(scenario)
|
@@ -41,15 +47,6 @@ module Cucumber
|
|
41
47
|
transform
|
42
48
|
end
|
43
49
|
|
44
|
-
def add_step_definition(step_definition)
|
45
|
-
step_definitions << step_definition
|
46
|
-
step_definition
|
47
|
-
end
|
48
|
-
|
49
|
-
def step_definitions
|
50
|
-
@step_definitions ||= []
|
51
|
-
end
|
52
|
-
|
53
50
|
def hooks_for(phase, scenario) #:nodoc:
|
54
51
|
hooks[phase.to_sym].select{|hook| scenario.accept_hook?(hook)}
|
55
52
|
end
|
@@ -34,6 +34,7 @@ module Cucumber
|
|
34
34
|
|
35
35
|
def initialize(step_mother)
|
36
36
|
@step_mother = step_mother
|
37
|
+
@step_definitions = []
|
37
38
|
RbDsl.rb_language = self
|
38
39
|
end
|
39
40
|
|
@@ -56,10 +57,20 @@ module Cucumber
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
60
|
+
def step_matches(step_name, formatted_step_name)
|
61
|
+
@step_definitions.map do |step_definition|
|
62
|
+
step_definition.step_match(step_name, formatted_step_name)
|
63
|
+
end.compact
|
64
|
+
end
|
65
|
+
|
59
66
|
def arguments_from(regexp, step_name)
|
60
67
|
@regexp_argument_matcher.arguments_from(regexp, step_name)
|
61
68
|
end
|
62
69
|
|
70
|
+
def unmatched_step_definitions
|
71
|
+
@step_definitions.select{|step_definition| !step_definition.matched?}
|
72
|
+
end
|
73
|
+
|
63
74
|
def snippet_text(step_keyword, step_name, multiline_arg_class = nil)
|
64
75
|
escaped = Regexp.escape(step_name).gsub('\ ', ' ').gsub('/', '\/')
|
65
76
|
escaped = escaped.gsub(PARAM_PATTERN, ESCAPED_PARAM_PATTERN)
|
@@ -94,7 +105,9 @@ module Cucumber
|
|
94
105
|
end
|
95
106
|
|
96
107
|
def register_rb_step_definition(regexp, proc)
|
97
|
-
|
108
|
+
step_definition = RbStepDefinition.new(self, regexp, proc)
|
109
|
+
@step_definitions << step_definition
|
110
|
+
step_definition
|
98
111
|
end
|
99
112
|
|
100
113
|
def build_rb_world_factory(world_modules, proc)
|
@@ -106,12 +119,12 @@ module Cucumber
|
|
106
119
|
@world_modules += world_modules
|
107
120
|
end
|
108
121
|
|
109
|
-
protected
|
110
|
-
|
111
122
|
def load_code_file(code_file)
|
112
123
|
require code_file # This will cause self.add_step_definition, self.add_hook, and self.add_transform to be called from RbDsl
|
113
124
|
end
|
114
125
|
|
126
|
+
protected
|
127
|
+
|
115
128
|
def begin_scenario
|
116
129
|
begin_rb_scenario
|
117
130
|
end
|
@@ -42,7 +42,9 @@ module Cucumber
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def arguments_from(step_name)
|
45
|
-
RegexpArgumentMatcher.arguments_from(@regexp, step_name)
|
45
|
+
args = RegexpArgumentMatcher.arguments_from(@regexp, step_name)
|
46
|
+
@matched = true if args
|
47
|
+
args
|
46
48
|
end
|
47
49
|
|
48
50
|
def invoke(args)
|
@@ -56,6 +58,10 @@ module Cucumber
|
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
61
|
+
def matched?
|
62
|
+
@matched
|
63
|
+
end
|
64
|
+
|
59
65
|
def file_colon_line
|
60
66
|
@proc.file_colon_line
|
61
67
|
end
|
data/lib/cucumber/step_match.rb
CHANGED
data/lib/cucumber/step_mother.rb
CHANGED
@@ -38,16 +38,6 @@ module Cucumber
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
# Raised when 2 or more StepDefinition have the same Regexp
|
42
|
-
class Redundant < StandardError
|
43
|
-
def initialize(step_def_1, step_def_2)
|
44
|
-
message = "Multiple step definitions have the same Regexp:\n\n"
|
45
|
-
message << step_def_1.backtrace_line << "\n"
|
46
|
-
message << step_def_2.backtrace_line << "\n\n"
|
47
|
-
super(message)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
41
|
# This is the meaty part of Cucumber that ties everything together.
|
52
42
|
class StepMother
|
53
43
|
include Constantize
|
@@ -87,17 +77,12 @@ module Cucumber
|
|
87
77
|
def load_code_file(step_def_file)
|
88
78
|
if programming_language = programming_language_for(step_def_file)
|
89
79
|
log.debug(" * #{step_def_file}\n")
|
90
|
-
|
91
|
-
register_step_definitions(step_definitions)
|
80
|
+
programming_language.load_code_file(step_def_file)
|
92
81
|
else
|
93
82
|
log.debug(" * #{step_def_file} [NOT SUPPORTED]\n")
|
94
83
|
end
|
95
84
|
end
|
96
85
|
|
97
|
-
def register_step_definitions(step_definitions)
|
98
|
-
step_definitions.each{|step_definition| register_step_definition(step_definition)}
|
99
|
-
end
|
100
|
-
|
101
86
|
# Loads and registers programming language implementation.
|
102
87
|
# Instances are cached, so calling with the same argument
|
103
88
|
# twice will return the same instance.
|
@@ -152,7 +137,9 @@ module Cucumber
|
|
152
137
|
end
|
153
138
|
|
154
139
|
def step_match(step_name, formatted_step_name=nil) #:nodoc:
|
155
|
-
matches =
|
140
|
+
matches = @programming_languages.map do |programming_language|
|
141
|
+
programming_language.step_matches(step_name, formatted_step_name)
|
142
|
+
end.flatten
|
156
143
|
raise Undefined.new(step_name) if matches.empty?
|
157
144
|
matches = best_matches(step_name, matches) if matches.size > 1 && options[:guess]
|
158
145
|
raise Ambiguous.new(step_name, matches, options[:guess]) if matches.size > 1
|
@@ -174,16 +161,11 @@ module Cucumber
|
|
174
161
|
top_groups
|
175
162
|
end
|
176
163
|
end
|
177
|
-
|
178
|
-
def clear! #:nodoc:
|
179
|
-
step_definitions.clear
|
180
|
-
hooks.clear
|
181
|
-
steps.clear
|
182
|
-
scenarios.clear
|
183
|
-
end
|
184
164
|
|
185
|
-
def
|
186
|
-
@
|
165
|
+
def unmatched_step_definitions
|
166
|
+
@programming_languages.map do |programming_language|
|
167
|
+
programming_language.unmatched_step_definitions
|
168
|
+
end.flatten
|
187
169
|
end
|
188
170
|
|
189
171
|
def snippet_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
|
@@ -244,17 +226,6 @@ module Cucumber
|
|
244
226
|
|
245
227
|
private
|
246
228
|
|
247
|
-
# Registers a StepDefinition. This can be a Ruby StepDefintion,
|
248
|
-
# or any other kind of object that implements the StepDefintion
|
249
|
-
# contract (API).
|
250
|
-
def register_step_definition(step_definition)
|
251
|
-
step_definitions.each do |already|
|
252
|
-
raise Redundant.new(already, step_definition) if already == step_definition
|
253
|
-
end
|
254
|
-
step_definitions << step_definition
|
255
|
-
step_definition
|
256
|
-
end
|
257
|
-
|
258
229
|
def programming_language_for(step_def_file) #:nodoc:
|
259
230
|
if ext = File.extname(step_def_file)[1..-1]
|
260
231
|
return nil if @unsupported_programming_languages.index(ext)
|