cucumber 0.3.95 → 0.3.96
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -0
- data/Manifest.txt +9 -3
- data/examples/sinatra/features/support/env.rb +1 -3
- data/features/cucumber_cli.feature +1 -0
- data/features/drb_server_integration.feature +56 -3
- data/features/junit_formatter.feature +23 -12
- data/features/step_definitions/cucumber_steps.rb +13 -2
- data/features/support/env.rb +19 -3
- data/lib/cucumber/ast/feature_element.rb +1 -1
- data/lib/cucumber/ast/step.rb +1 -1
- data/lib/cucumber/ast/step_invocation.rb +3 -2
- data/lib/cucumber/cli/configuration.rb +9 -25
- data/lib/cucumber/cli/drb_client.rb +7 -3
- data/lib/cucumber/cli/language_help_formatter.rb +4 -4
- data/lib/cucumber/cli/main.rb +26 -46
- data/lib/cucumber/cli/options.rb +3 -0
- data/lib/cucumber/constantize.rb +28 -0
- data/lib/cucumber/feature_file.rb +3 -3
- data/lib/cucumber/formatter/junit.rb +13 -9
- data/lib/cucumber/formatter/pretty.rb +2 -2
- data/lib/cucumber/language_support/hook_methods.rb +9 -0
- data/lib/cucumber/language_support/language_methods.rb +47 -0
- data/lib/cucumber/language_support/step_definition_methods.rb +44 -0
- data/lib/cucumber/parser/natural_language.rb +72 -0
- data/lib/cucumber/rb_support/rb_dsl.rb +73 -0
- data/lib/cucumber/rb_support/rb_hook.rb +19 -0
- data/lib/cucumber/rb_support/rb_language.rb +129 -0
- data/lib/cucumber/rb_support/rb_step_definition.rb +56 -0
- data/lib/cucumber/step_match.rb +2 -2
- data/lib/cucumber/step_mother.rb +87 -206
- data/lib/cucumber/version.rb +1 -1
- data/lib/cucumber/webrat/element_locator.rb +7 -7
- data/lib/cucumber/world.rb +28 -8
- data/rails_generators/cucumber/templates/cucumber_environment.rb +2 -2
- data/rails_generators/cucumber/templates/spork_env.rb +0 -2
- data/rails_generators/cucumber/templates/webrat_steps.rb +17 -0
- data/spec/cucumber/ast/background_spec.rb +8 -5
- data/spec/cucumber/ast/feature_factory.rb +4 -5
- data/spec/cucumber/ast/feature_spec.rb +7 -1
- data/spec/cucumber/ast/scenario_outline_spec.rb +10 -6
- data/spec/cucumber/ast/scenario_spec.rb +8 -3
- data/spec/cucumber/ast/step_collection_spec.rb +2 -2
- data/spec/cucumber/cli/configuration_spec.rb +15 -0
- data/spec/cucumber/cli/drb_client_spec.rb +35 -1
- data/spec/cucumber/cli/main_spec.rb +5 -4
- data/spec/cucumber/cli/options_spec.rb +6 -0
- data/spec/cucumber/parser/feature_parser_spec.rb +6 -5
- data/spec/cucumber/parser/table_parser_spec.rb +1 -1
- data/spec/cucumber/step_definition_spec.rb +26 -25
- data/spec/cucumber/step_mother_spec.rb +46 -41
- data/spec/cucumber/world/pending_spec.rb +4 -5
- metadata +11 -5
- data/lib/cucumber/cli/rb_step_def_loader.rb +0 -14
- data/lib/cucumber/parser/i18n/language.rb +0 -87
- data/lib/cucumber/step_definition.rb +0 -122
@@ -7,14 +7,18 @@ module Cucumber
|
|
7
7
|
end
|
8
8
|
# Runs features on a DRB server, originally created with Spork compatibility in mind.
|
9
9
|
class DRbClient
|
10
|
-
|
10
|
+
DEFAULT_PORT = 8990
|
11
|
+
|
12
|
+
def self.run(args, error_stream, out_stream, port = nil)
|
13
|
+
port ||= ENV["CUCUMBER_DRB"] || DEFAULT_PORT
|
14
|
+
|
11
15
|
# See http://redmine.ruby-lang.org/issues/show/496 as to why we specify localhost:0
|
12
16
|
DRb.start_service("druby://localhost:0")
|
13
|
-
feature_server = DRbObject.new_with_uri("druby://127.0.0.1
|
17
|
+
feature_server = DRbObject.new_with_uri("druby://127.0.0.1:#{port}")
|
14
18
|
cloned_args = [] # I have no idea why this is needed, but if the regular args are sent then DRb magically transforms it into a DRb object - not an array
|
15
19
|
args.each { |arg| cloned_args << arg }
|
16
20
|
feature_server.run(cloned_args, error_stream, out_stream)
|
17
|
-
rescue DRb::DRbConnError
|
21
|
+
rescue DRb::DRbConnError => e
|
18
22
|
raise DRbClientError, "No DRb server is running."
|
19
23
|
end
|
20
24
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'cucumber/formatter/pretty'
|
2
|
-
require 'cucumber/parser/
|
2
|
+
require 'cucumber/parser/natural_language'
|
3
3
|
|
4
4
|
module Cucumber
|
5
5
|
module Cli
|
@@ -23,8 +23,8 @@ http://wiki.github.com/aslakhellesoy/cucumber/spoken-languages
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def self.list_keywords(io, lang)
|
26
|
-
language = Parser::
|
27
|
-
raw = Parser::
|
26
|
+
language = Parser::NaturalLanguage[lang]
|
27
|
+
raw = Parser::NaturalLanguage::KEYWORD_KEYS.map do |key|
|
28
28
|
[key, language.keywords(key)]
|
29
29
|
end
|
30
30
|
table = Ast::Table.new(raw)
|
@@ -46,7 +46,7 @@ http://wiki.github.com/aslakhellesoy/cucumber/spoken-languages
|
|
46
46
|
def visit_table_cell_value(value, status)
|
47
47
|
if @col == 1
|
48
48
|
if(@options[:check_lang])
|
49
|
-
@incomplete = Parser::
|
49
|
+
@incomplete = Parser::NaturalLanguage.get(nil, value).incomplete?
|
50
50
|
end
|
51
51
|
status = :comment
|
52
52
|
elsif @incomplete
|
data/lib/cucumber/cli/main.rb
CHANGED
@@ -15,17 +15,11 @@ module Cucumber
|
|
15
15
|
|
16
16
|
class << self
|
17
17
|
def step_mother
|
18
|
-
@step_mother
|
19
|
-
end
|
20
|
-
|
21
|
-
def step_mother=(step_mother)
|
22
|
-
@step_mother = step_mother
|
23
|
-
@step_mother.extend(StepMother)
|
24
|
-
@step_mother.snippet_generator = StepDefinition
|
18
|
+
@step_mother ||= StepMother.new
|
25
19
|
end
|
26
20
|
|
27
21
|
def execute(args)
|
28
|
-
new(args).execute!(
|
22
|
+
new(args).execute!(step_mother)
|
29
23
|
end
|
30
24
|
end
|
31
25
|
|
@@ -33,13 +27,15 @@ module Cucumber
|
|
33
27
|
@args = args
|
34
28
|
@out_stream = out_stream == STDOUT ? Formatter::ColorIO.new : out_stream
|
35
29
|
@error_stream = error_stream
|
30
|
+
$err = error_stream
|
31
|
+
@unsupported_programming_languages = []
|
36
32
|
end
|
37
33
|
|
38
34
|
def execute!(step_mother)
|
39
35
|
trap_interrupt
|
40
36
|
if configuration.drb?
|
41
37
|
begin
|
42
|
-
return DRbClient.run(@args, @error_stream, @out_stream)
|
38
|
+
return DRbClient.run(@args, @error_stream, @out_stream, configuration.drb_port)
|
43
39
|
rescue DRbClientError => e
|
44
40
|
@error_stream.puts "WARNING: #{e.message} Running features locally:"
|
45
41
|
end
|
@@ -50,8 +46,8 @@ module Cucumber
|
|
50
46
|
# This is because i18n step methods are only aliased when
|
51
47
|
# features are loaded. If we swap the order, the requires
|
52
48
|
# will fail.
|
53
|
-
features = load_plain_text_features
|
54
|
-
load_step_defs
|
49
|
+
features = load_plain_text_features(step_mother)
|
50
|
+
load_step_defs(step_mother)
|
55
51
|
enable_diffing
|
56
52
|
|
57
53
|
visitor = configuration.build_formatter_broadcaster(step_mother)
|
@@ -64,7 +60,7 @@ module Cucumber
|
|
64
60
|
step_mother.scenarios(:passed).any?
|
65
61
|
else
|
66
62
|
step_mother.scenarios(:failed).any? ||
|
67
|
-
(configuration.strict? && step_mother.steps(:undefined).any?)
|
63
|
+
(configuration.strict? && (step_mother.steps(:undefined).any? || step_mother.steps(:pending).any?))
|
68
64
|
end
|
69
65
|
rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
|
70
66
|
@error_stream.puts e.message
|
@@ -84,19 +80,19 @@ module Cucumber
|
|
84
80
|
exceeded
|
85
81
|
end
|
86
82
|
|
87
|
-
def load_plain_text_features
|
83
|
+
def load_plain_text_features(step_mother)
|
88
84
|
features = Ast::Features.new
|
89
85
|
|
90
86
|
verbose_log("Features:")
|
91
87
|
configuration.feature_files.each do |f|
|
92
88
|
feature_file = FeatureFile.new(f)
|
93
|
-
feature = feature_file.parse(configuration.options)
|
89
|
+
feature = feature_file.parse(step_mother, configuration.options)
|
94
90
|
if feature
|
95
91
|
features.add_feature(feature)
|
96
92
|
verbose_log(" * #{f}")
|
97
93
|
end
|
98
94
|
end
|
99
|
-
verbose_log("\n"
|
95
|
+
verbose_log("\n")
|
100
96
|
features
|
101
97
|
end
|
102
98
|
|
@@ -114,50 +110,36 @@ module Cucumber
|
|
114
110
|
|
115
111
|
private
|
116
112
|
|
117
|
-
def load_step_defs
|
113
|
+
def load_step_defs(step_mother)
|
118
114
|
step_def_files = configuration.step_defs_to_load
|
119
|
-
verbose_log("Step Definitions
|
115
|
+
verbose_log("Step Definitions:")
|
120
116
|
step_def_files.each do |step_def_file|
|
121
|
-
load_step_def(step_def_file)
|
117
|
+
load_step_def(step_mother, step_def_file)
|
122
118
|
end
|
119
|
+
verbose_log("\n")
|
123
120
|
end
|
124
121
|
|
125
|
-
def load_step_def(step_def_file)
|
126
|
-
if
|
122
|
+
def load_step_def(step_mother, step_def_file)
|
123
|
+
if programming_language = programming_language_for(step_mother, step_def_file)
|
127
124
|
verbose_log(" * #{step_def_file}")
|
128
|
-
|
125
|
+
programming_language.load_step_def_file(step_def_file)
|
126
|
+
else
|
127
|
+
verbose_log(" * #{step_def_file} [NOT SUPPORTED]")
|
129
128
|
end
|
130
129
|
end
|
131
130
|
|
132
|
-
def
|
133
|
-
@sted_def_loaders ||= {}
|
131
|
+
def programming_language_for(step_mother, step_def_file) # :nodoc:
|
134
132
|
if ext = File.extname(step_def_file)[1..-1]
|
135
|
-
|
136
|
-
return nil if loader == :missing
|
137
|
-
return loader if loader
|
133
|
+
return nil if @unsupported_programming_languages.index(ext)
|
138
134
|
begin
|
139
|
-
|
140
|
-
return @sted_def_loaders[ext] = loader_class.new
|
135
|
+
step_mother.load_programming_language(ext)
|
141
136
|
rescue LoadError
|
142
|
-
@
|
137
|
+
@unsupported_programming_languages << ext
|
143
138
|
nil
|
144
139
|
end
|
140
|
+
else
|
141
|
+
nil
|
145
142
|
end
|
146
|
-
nil
|
147
|
-
end
|
148
|
-
|
149
|
-
def step_def_files
|
150
|
-
main.verbose_log("Ruby files required:")
|
151
|
-
main.verbose_log(requires.map{|lib| " * #{lib}"}.join("\n"))
|
152
|
-
requires.each do |lib|
|
153
|
-
begin
|
154
|
-
require lib
|
155
|
-
rescue LoadError => e
|
156
|
-
e.message << "\nFailed to load #{lib}"
|
157
|
-
raise e
|
158
|
-
end
|
159
|
-
end
|
160
|
-
main.verbose_log("\n")
|
161
143
|
end
|
162
144
|
|
163
145
|
def enable_diffing
|
@@ -186,5 +168,3 @@ module Cucumber
|
|
186
168
|
end
|
187
169
|
end
|
188
170
|
end
|
189
|
-
|
190
|
-
Cucumber::Cli::Main.step_mother = self
|
data/lib/cucumber/cli/options.rb
CHANGED
@@ -218,6 +218,9 @@ module Cucumber
|
|
218
218
|
opts.on(DRB_FLAG, "Run features against a DRb server. (i.e. with the spork gem)") do
|
219
219
|
@options[:drb] = true
|
220
220
|
end
|
221
|
+
opts.on("--port PORT", "Specify DRb port. Ignored without --drb") do |port|
|
222
|
+
@options[:drb_port] = port
|
223
|
+
end
|
221
224
|
opts.on_tail("--version", "Show version.") do
|
222
225
|
@out_stream.puts VERSION::STRING
|
223
226
|
Kernel.exit
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Constantize
|
3
|
+
def constantize(camel_cased_word)
|
4
|
+
begin
|
5
|
+
names = camel_cased_word.split('::')
|
6
|
+
names.shift if names.empty? || names.first.empty?
|
7
|
+
|
8
|
+
constant = Object
|
9
|
+
names.each do |name|
|
10
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
11
|
+
end
|
12
|
+
constant
|
13
|
+
rescue NameError
|
14
|
+
require underscore(camel_cased_word)
|
15
|
+
retry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Snagged from active_support
|
20
|
+
def underscore(camel_cased_word)
|
21
|
+
camel_cased_word.to_s.gsub(/::/, '/').
|
22
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
23
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
24
|
+
tr("-", "_").
|
25
|
+
downcase
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'cucumber/parser/
|
1
|
+
require 'cucumber/parser/natural_language'
|
2
2
|
require 'cucumber/filter'
|
3
3
|
|
4
4
|
module Cucumber
|
@@ -20,9 +20,9 @@ module Cucumber
|
|
20
20
|
# Parses a file and returns a Cucumber::Ast
|
21
21
|
# If +options+ contains tags, the result will
|
22
22
|
# be filtered.
|
23
|
-
def parse(options
|
23
|
+
def parse(step_mother, options)
|
24
24
|
filter = Filter.new(@lines, options)
|
25
|
-
language = Parser::
|
25
|
+
language = Parser::NaturalLanguage.get(step_mother, (lang || options[:lang] || 'en'))
|
26
26
|
language.parse(source, @path, filter)
|
27
27
|
end
|
28
28
|
|
@@ -45,8 +45,8 @@ module Cucumber
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def visit_scenario_name(keyword, name, file_colon_line, source_indent)
|
48
|
-
scenario_name = name.strip
|
49
|
-
scenario_name = "Unnamed scenario" if name
|
48
|
+
scenario_name = name.strip.delete(".\r\n")
|
49
|
+
scenario_name = "Unnamed scenario" if name.blank?
|
50
50
|
@scenario = scenario_name
|
51
51
|
@outline = keyword.include?('Scenario Outline')
|
52
52
|
@output = "Scenario#{ " outline" if @outline}: #{@scenario}\n\n"
|
@@ -96,16 +96,20 @@ module Cucumber
|
|
96
96
|
@time += duration
|
97
97
|
classname = "#{@feature_name}.#{@scenario}"
|
98
98
|
name = "#{@scenario}#{suffix}"
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
99
|
+
failed = (status == :failed || (status == :pending && @options[:strict]))
|
100
|
+
#puts "FAILED:!!#{failed}"
|
101
|
+
if status == :passed || failed
|
102
|
+
@builder.testcase(:classname => classname, :name => name, :time => "%.6f" % duration) do
|
103
|
+
if failed
|
104
|
+
@builder.failure(:message => "#{status.to_s} #{name}", :type => status.to_s) do
|
105
|
+
@builder.text! @output
|
106
|
+
@builder.text!(format_exception(exception)) if exception
|
107
|
+
end
|
108
|
+
@failures += 1
|
104
109
|
end
|
105
|
-
@failures += 1
|
106
110
|
end
|
111
|
+
@tests += 1
|
107
112
|
end
|
108
|
-
@tests += 1
|
109
113
|
end
|
110
114
|
|
111
115
|
def format_exception(exception)
|
@@ -97,9 +97,9 @@ module Cucumber
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def visit_examples_name(keyword, name)
|
100
|
-
names = name.empty? ? [name] : name.split("\n")
|
100
|
+
names = name.strip.empty? ? [name.strip] : name.split("\n")
|
101
101
|
@io.puts("\n #{keyword} #{names[0]}")
|
102
|
-
names[1..-1].each {|s| @io.puts " #{s}" }
|
102
|
+
names[1..-1].each {|s| @io.puts " #{s}" } unless names.empty?
|
103
103
|
@io.flush
|
104
104
|
@indent = 6
|
105
105
|
@scenario_indent = 6
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module LanguageSupport
|
3
|
+
module LanguageMethods
|
4
|
+
def before(scenario)
|
5
|
+
step_mother.begin_scenario
|
6
|
+
execute_before(scenario)
|
7
|
+
end
|
8
|
+
|
9
|
+
def after(scenario)
|
10
|
+
execute_after(scenario)
|
11
|
+
step_mother.end_scenario
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute_before(scenario)
|
15
|
+
step_mother.hooks_for(:before, scenario).each do |hook|
|
16
|
+
invoke(hook, 'Before', scenario, true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute_after(scenario)
|
21
|
+
step_mother.hooks_for(:after, scenario).each do |hook|
|
22
|
+
invoke(hook, 'After', scenario, true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute_after_step(scenario)
|
27
|
+
step_mother.hooks_for(:after_step, scenario).each do |hook|
|
28
|
+
invoke(hook, 'AfterStep', scenario, false)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def invoke(hook, location, scenario, exception_fails_scenario)
|
35
|
+
begin
|
36
|
+
hook.invoke(location, scenario)
|
37
|
+
rescue Exception => exception
|
38
|
+
if exception_fails_scenario
|
39
|
+
scenario.fail!(exception)
|
40
|
+
else
|
41
|
+
raise
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module LanguageSupport
|
3
|
+
module StepDefinitionMethods
|
4
|
+
def step_match(name_to_match, name_to_report)
|
5
|
+
if(match = regexp.match(name_to_match))
|
6
|
+
StepMatch.new(self, name_to_match, name_to_report, match.captures)
|
7
|
+
else
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Formats the matched arguments of the associated Step. This method
|
13
|
+
# is usually called from visitors, which render output.
|
14
|
+
#
|
15
|
+
# The +format+ can either be a String or a Proc.
|
16
|
+
#
|
17
|
+
# If it is a String it should be a format string according to
|
18
|
+
# <tt>Kernel#sprinf</tt>, for example:
|
19
|
+
#
|
20
|
+
# '<span class="param">%s</span></tt>'
|
21
|
+
#
|
22
|
+
# If it is a Proc, it should take one argument and return the formatted
|
23
|
+
# argument, for example:
|
24
|
+
#
|
25
|
+
# lambda { |param| "[#{param}]" }
|
26
|
+
#
|
27
|
+
def format_args(step_name, format)
|
28
|
+
step_name.gzub(regexp, format)
|
29
|
+
end
|
30
|
+
|
31
|
+
def same_regexp?(regexp)
|
32
|
+
self.regexp == regexp
|
33
|
+
end
|
34
|
+
|
35
|
+
def backtrace_line
|
36
|
+
"#{file_colon_line}:in `#{regexp.inspect}'"
|
37
|
+
end
|
38
|
+
|
39
|
+
def text_length
|
40
|
+
regexp.inspect.jlength
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Parser
|
3
|
+
class NaturalLanguage
|
4
|
+
KEYWORD_KEYS = %w{name native encoding feature background scenario scenario_outline examples given when then but}
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def get(step_mother, lang)
|
8
|
+
languages[lang] ||= new(step_mother, lang)
|
9
|
+
end
|
10
|
+
|
11
|
+
def languages
|
12
|
+
@languages ||= {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_mother, lang)
|
17
|
+
@keywords = Cucumber::LANGUAGES[lang]
|
18
|
+
raise "Language not supported: #{lang.inspect}" if @keywords.nil?
|
19
|
+
@keywords['grammar_name'] = @keywords['name'].gsub(/\s/, '')
|
20
|
+
register_adverbs(step_mother) if step_mother
|
21
|
+
end
|
22
|
+
|
23
|
+
def register_adverbs(step_mother)
|
24
|
+
adverbs = %w{given when then and but}.map{|keyword| @keywords[keyword].split('|').map{|w| w.gsub(/\s/, '')}}.flatten
|
25
|
+
step_mother.register_adverbs(adverbs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def parser
|
29
|
+
return @parser if @parser
|
30
|
+
i18n_tt = File.expand_path(File.dirname(__FILE__) + '/i18n.tt')
|
31
|
+
template = File.open(i18n_tt, Cucumber.file_mode('r')).read
|
32
|
+
erb = ERB.new(template)
|
33
|
+
grammar = erb.result(binding)
|
34
|
+
Treetop.load_from_string(grammar)
|
35
|
+
@parser = Parser::I18n.const_get("#{@keywords['grammar_name']}Parser").new
|
36
|
+
def @parser.inspect
|
37
|
+
"#<#{self.class.name}>"
|
38
|
+
end
|
39
|
+
@parser
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse(source, path, filter)
|
43
|
+
feature = parser.parse_or_fail(source, path, filter)
|
44
|
+
feature.language = self if feature
|
45
|
+
feature
|
46
|
+
end
|
47
|
+
|
48
|
+
def keywords(key, raw=false)
|
49
|
+
return @keywords[key] if raw
|
50
|
+
return nil unless @keywords[key]
|
51
|
+
values = @keywords[key].split('|')
|
52
|
+
values.map{|value| "'#{value}'"}.join(" / ")
|
53
|
+
end
|
54
|
+
|
55
|
+
def incomplete?
|
56
|
+
KEYWORD_KEYS.detect{|key| @keywords[key].nil?}
|
57
|
+
end
|
58
|
+
|
59
|
+
def scenario_keyword
|
60
|
+
@keywords['scenario'].split('|')[0] + ':'
|
61
|
+
end
|
62
|
+
|
63
|
+
def but_keywords
|
64
|
+
@keywords['but'].split('|')
|
65
|
+
end
|
66
|
+
|
67
|
+
def and_keywords
|
68
|
+
@keywords['and'].split('|')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|