gherkin 2.0.2-universal-dotnet → 2.1.0-universal-dotnet
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 +12 -0
- data/LICENSE +1 -1
- data/README.rdoc +2 -2
- data/Rakefile +2 -2
- data/VERSION.yml +2 -2
- data/features/json_formatter.feature +3 -41
- data/features/step_definitions/gherkin_steps.rb +5 -6
- data/features/step_definitions/json_formatter_steps.rb +3 -2
- data/features/step_definitions/json_lexer_steps.rb +5 -5
- data/features/step_definitions/pretty_formatter_steps.rb +9 -13
- data/features/support/env.rb +1 -1
- data/lib/gherkin/formatter/argument.rb +1 -0
- data/lib/gherkin/formatter/filter_formatter.rb +149 -0
- data/lib/gherkin/formatter/json_formatter.rb +35 -45
- data/lib/gherkin/formatter/line_filter.rb +26 -0
- data/lib/gherkin/formatter/model.rb +85 -0
- data/lib/gherkin/formatter/pretty_formatter.rb +36 -39
- data/lib/gherkin/formatter/regexp_filter.rb +17 -0
- data/lib/gherkin/formatter/tag_count_formatter.rb +44 -0
- data/lib/gherkin/i18n.rb +5 -5
- data/lib/gherkin/i18n.yml +13 -0
- data/lib/gherkin/i18n_lexer.rb +2 -2
- data/lib/gherkin/{json_lexer.rb → json_parser.rb} +17 -5
- data/lib/gherkin/{parser → listener}/event.rb +1 -1
- data/lib/gherkin/{parser → listener}/formatter_listener.rb +30 -23
- data/lib/gherkin/native/java.rb +9 -1
- data/lib/gherkin/parser/parser.rb +27 -14
- data/lib/gherkin/rubify.rb +5 -1
- data/lib/gherkin/tag_expression.rb +62 -0
- data/lib/gherkin/tools/files.rb +3 -4
- data/lib/gherkin/tools/reformat.rb +2 -2
- data/lib/gherkin/tools/stats.rb +3 -4
- data/lib/gherkin/tools/stats_listener.rb +1 -1
- data/ragel/lexer.c.rl.erb +2 -3
- data/ragel/lexer.java.rl.erb +1 -2
- data/ragel/lexer.rb.rl.erb +1 -2
- data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
- data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
- data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
- data/spec/gherkin/formatter/filter_formatter_spec.rb +156 -0
- data/spec/gherkin/formatter/model_spec.rb +15 -0
- data/spec/gherkin/formatter/pretty_formatter_spec.rb +17 -16
- data/spec/gherkin/formatter/tag_count_formatter_spec.rb +31 -0
- data/spec/gherkin/i18n_lexer_spec.rb +3 -3
- data/spec/gherkin/i18n_spec.rb +2 -4
- data/spec/gherkin/{json_lexer_spec.rb → json_parser_spec.rb} +13 -8
- data/spec/gherkin/sexp_recorder.rb +10 -4
- data/spec/gherkin/shared/lexer_group.rb +0 -40
- data/spec/gherkin/shared/py_string_group.rb +0 -1
- data/spec/gherkin/shared/row_group.rb +1 -2
- data/spec/gherkin/tag_expression_spec.rb +137 -0
- data/spec/spec_helper.rb +5 -1
- data/tasks/bench.rake +5 -9
- metadata +31 -25
- data/lib/gherkin/parser/filter_listener.rb +0 -203
- data/lib/gherkin/parser/row.rb +0 -15
- data/lib/gherkin/parser/tag_expression.rb +0 -50
- data/spec/gherkin/parser/filter_listener_spec.rb +0 -397
- data/spec/gherkin/parser/formatter_listener_spec.rb +0 -134
- data/spec/gherkin/parser/parser_spec.rb +0 -50
- data/spec/gherkin/parser/tag_expression_spec.rb +0 -116
@@ -11,47 +11,33 @@ module Gherkin
|
|
11
11
|
@io = io
|
12
12
|
end
|
13
13
|
|
14
|
-
def feature(
|
15
|
-
@json_hash =
|
16
|
-
|
17
|
-
'tags' => tags.to_a,
|
18
|
-
'keyword' => keyword,
|
19
|
-
'name' => name,
|
20
|
-
'description' => description,
|
21
|
-
'uri' => uri
|
22
|
-
}
|
14
|
+
def feature(statement, uri)
|
15
|
+
@json_hash = statement_hash(nil, statement)
|
16
|
+
@json_hash['uri'] = uri
|
23
17
|
end
|
24
18
|
|
25
|
-
def background(
|
26
|
-
background =
|
27
|
-
'comments' => comments.to_a,
|
28
|
-
'keyword' => keyword,
|
29
|
-
'name' => name,
|
30
|
-
'description' => description,
|
31
|
-
'line' => line,
|
32
|
-
'steps' => [],
|
33
|
-
}
|
34
|
-
@json_hash['background'] = background
|
19
|
+
def background(statement)
|
20
|
+
@json_hash['background'] = statement_hash(nil, statement)
|
35
21
|
@in_background = true
|
36
22
|
end
|
37
23
|
|
38
|
-
def scenario(
|
24
|
+
def scenario(statement)
|
39
25
|
@in_background = false
|
40
|
-
add_step_container(
|
26
|
+
add_step_container('scenario', statement)
|
41
27
|
end
|
42
28
|
|
43
|
-
def scenario_outline(
|
29
|
+
def scenario_outline(statement)
|
44
30
|
@in_background = false
|
45
|
-
add_step_container(
|
31
|
+
add_step_container('scenario_outline', statement)
|
46
32
|
end
|
47
33
|
|
48
|
-
def examples(
|
49
|
-
@table_container = add_examples(
|
50
|
-
@table_container['table'] = to_hash_array(
|
34
|
+
def examples(statement, examples_rows)
|
35
|
+
@table_container = add_examples(statement)
|
36
|
+
@table_container['table'] = to_hash_array(examples_rows)
|
51
37
|
end
|
52
38
|
|
53
|
-
def step(
|
54
|
-
@table_container =
|
39
|
+
def step(statement, multiline_arg, result)
|
40
|
+
@table_container = statement_hash(nil, statement).merge(step_arg_to_hash(multiline_arg))
|
55
41
|
last_element['steps'] ||= []
|
56
42
|
last_element['steps'] << @table_container
|
57
43
|
end
|
@@ -62,35 +48,35 @@ module Gherkin
|
|
62
48
|
|
63
49
|
private
|
64
50
|
|
65
|
-
def
|
51
|
+
def statement_hash(type, statement)
|
66
52
|
element = {
|
67
|
-
'comments' => comments.
|
68
|
-
'tags' => tags.
|
69
|
-
'keyword' => keyword,
|
70
|
-
'name' => name,
|
71
|
-
'description' => description,
|
72
|
-
'line' => line,
|
53
|
+
'comments' => statement.comments.map{|comment| comment.value},
|
54
|
+
'tags' => statement.tags.map{|tag| tag.name},
|
55
|
+
'keyword' => statement.keyword,
|
56
|
+
'name' => statement.name,
|
57
|
+
'description' => statement.description,
|
58
|
+
'line' => statement.line,
|
73
59
|
}
|
74
|
-
element['type'] = type
|
75
|
-
element
|
60
|
+
element['type'] = type
|
61
|
+
compact(element)
|
76
62
|
end
|
77
63
|
|
78
|
-
def add_element(
|
79
|
-
element =
|
64
|
+
def add_element(type, statement)
|
65
|
+
element = statement_hash(type, statement)
|
80
66
|
@json_hash['elements'] ||= []
|
81
67
|
@json_hash['elements'] << element
|
82
68
|
element
|
83
69
|
end
|
84
70
|
|
85
|
-
def add_examples(
|
86
|
-
element =
|
71
|
+
def add_examples(statement)
|
72
|
+
element = statement_hash(nil, statement)
|
87
73
|
last_element['examples'] ||= []
|
88
74
|
last_element['examples'] << element
|
89
75
|
element
|
90
76
|
end
|
91
77
|
|
92
|
-
def add_step_container(type,
|
93
|
-
add_element(type,
|
78
|
+
def add_step_container(type, statement)
|
79
|
+
add_element(type, statement)
|
94
80
|
last_element['steps'] = []
|
95
81
|
end
|
96
82
|
|
@@ -104,14 +90,18 @@ module Gherkin
|
|
104
90
|
|
105
91
|
def to_hash_array(rows)
|
106
92
|
rows.map do |row|
|
107
|
-
{"cells" => row.cells.to_a, "comments" => row.comments.
|
93
|
+
compact({"cells" => row.cells.to_a, "comments" => row.comments.map{|comment| comment.value}, "line" => row.line})
|
108
94
|
end
|
109
95
|
end
|
110
96
|
|
111
97
|
def step_arg_to_hash(multiline_arg)
|
112
98
|
return {} if multiline_arg.nil?
|
113
99
|
multiline_arg = rubify(multiline_arg)
|
114
|
-
Array === multiline_arg ? {"table" => to_hash_array(multiline_arg) } : { "py_string" => multiline_arg }
|
100
|
+
Array === multiline_arg ? {"table" => to_hash_array(multiline_arg) } : { "py_string" => multiline_arg.value }
|
101
|
+
end
|
102
|
+
|
103
|
+
def compact(hash)
|
104
|
+
hash.reject{|k,v| [[], "", nil].index(v)}
|
115
105
|
end
|
116
106
|
end
|
117
107
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Gherkin
|
2
|
+
module Formatter
|
3
|
+
class LineFilter
|
4
|
+
def initialize(lines)
|
5
|
+
@lines = lines
|
6
|
+
end
|
7
|
+
|
8
|
+
def eval(ranges)
|
9
|
+
@lines.detect do |line|
|
10
|
+
ranges.detect do |range|
|
11
|
+
range.include?(line)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def filter_table_body_rows(rows)
|
17
|
+
body = rows.to_a[1..-1].select do |row|
|
18
|
+
@lines.detect do |line|
|
19
|
+
row.line == line
|
20
|
+
end
|
21
|
+
end
|
22
|
+
[rows[0]] + body
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'gherkin/native'
|
2
|
+
|
3
|
+
module Gherkin
|
4
|
+
module Formatter
|
5
|
+
module Model
|
6
|
+
class Comment
|
7
|
+
native_impl('gherkin')
|
8
|
+
|
9
|
+
attr_reader :value, :line
|
10
|
+
|
11
|
+
def initialize(value, line)
|
12
|
+
@value, @line = value, line
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Tag
|
17
|
+
native_impl('gherkin')
|
18
|
+
|
19
|
+
attr_reader :name, :line
|
20
|
+
|
21
|
+
def initialize(name, line)
|
22
|
+
@name, @line = name, line
|
23
|
+
end
|
24
|
+
|
25
|
+
def eql?(tag)
|
26
|
+
@name.eql?(tag.name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def hash
|
30
|
+
@name.hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class PyString
|
35
|
+
native_impl('gherkin')
|
36
|
+
|
37
|
+
attr_reader :value, :line
|
38
|
+
|
39
|
+
def initialize(value, line)
|
40
|
+
@value, @line = value, line
|
41
|
+
end
|
42
|
+
|
43
|
+
def line_range
|
44
|
+
line_count = value.split(/\r?\n/).length
|
45
|
+
line..(line+line_count+1)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Row
|
50
|
+
native_impl('gherkin')
|
51
|
+
|
52
|
+
attr_reader :comments, :cells, :line
|
53
|
+
|
54
|
+
def initialize(comments, cells, line)
|
55
|
+
@comments, @cells, @line = comments, cells, line
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Statement
|
60
|
+
native_impl('gherkin')
|
61
|
+
|
62
|
+
attr_reader :comments, :tags, :keyword, :name, :description, :line
|
63
|
+
|
64
|
+
def initialize(comments, tags, keyword, name, description, line)
|
65
|
+
@comments, @tags, @keyword, @name, @description, @line = comments, tags, keyword, name, description, line
|
66
|
+
end
|
67
|
+
|
68
|
+
def line_range
|
69
|
+
first = @comments[0] ? @comments[0].line : (@tags[0] ? @tags[0].line : line)
|
70
|
+
first..line
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Result
|
75
|
+
native_impl('gherkin')
|
76
|
+
|
77
|
+
attr_reader :status, :error_message, :arguments, :stepdef_location
|
78
|
+
|
79
|
+
def initialize(status, error_message, arguments, stepdef_location)
|
80
|
+
@status, @error_message, @arguments, @stepdef_location = status, error_message, arguments, stepdef_location
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -3,6 +3,7 @@ require 'gherkin/formatter/colors'
|
|
3
3
|
require 'gherkin/formatter/monochrome_format'
|
4
4
|
require 'gherkin/formatter/argument'
|
5
5
|
require 'gherkin/formatter/escaping'
|
6
|
+
require 'gherkin/formatter/model'
|
6
7
|
require 'gherkin/native'
|
7
8
|
|
8
9
|
module Gherkin
|
@@ -19,53 +20,52 @@ module Gherkin
|
|
19
20
|
@format = MonochromeFormat.new #@monochrome ? MonochromeFormat.new : AnsiColorFormat.new
|
20
21
|
end
|
21
22
|
|
22
|
-
def feature(
|
23
|
+
def feature(statement, uri)
|
23
24
|
@uri = uri
|
24
|
-
print_comments(comments, '')
|
25
|
-
print_tags(tags, '')
|
26
|
-
@io.puts "#{keyword}: #{name}"
|
27
|
-
print_description(description, ' ', false)
|
25
|
+
print_comments(statement.comments, '')
|
26
|
+
print_tags(statement.tags, '')
|
27
|
+
@io.puts "#{statement.keyword}: #{statement.name}"
|
28
|
+
print_description(statement.description, ' ', false)
|
28
29
|
end
|
29
30
|
|
30
|
-
def background(
|
31
|
+
def background(statement)
|
31
32
|
@io.puts
|
32
|
-
print_comments(comments, ' ')
|
33
|
-
@io.puts " #{keyword}: #{name}#{indented_element_uri!(keyword, name, line)}"
|
34
|
-
print_description(description, ' ')
|
33
|
+
print_comments(statement.comments, ' ')
|
34
|
+
@io.puts " #{statement.keyword}: #{statement.name}#{indented_element_uri!(statement.keyword, statement.name, statement.line)}"
|
35
|
+
print_description(statement.description, ' ')
|
35
36
|
end
|
36
37
|
|
37
|
-
def scenario(
|
38
|
+
def scenario(statement)
|
38
39
|
@io.puts
|
39
|
-
print_comments(comments, ' ')
|
40
|
-
print_tags(tags, ' ')
|
41
|
-
@io.puts " #{keyword}: #{name}#{indented_element_uri!(keyword, name, line)}"
|
42
|
-
print_description(description, ' ')
|
40
|
+
print_comments(statement.comments, ' ')
|
41
|
+
print_tags(statement.tags, ' ')
|
42
|
+
@io.puts " #{statement.keyword}: #{statement.name}#{indented_element_uri!(statement.keyword, statement.name, statement.line)}"
|
43
|
+
print_description(statement.description, ' ')
|
43
44
|
end
|
44
45
|
|
45
|
-
def scenario_outline(
|
46
|
-
scenario(
|
46
|
+
def scenario_outline(statement)
|
47
|
+
scenario(statement)
|
47
48
|
end
|
48
49
|
|
49
|
-
def examples(
|
50
|
+
def examples(statement, examples_rows)
|
50
51
|
@io.puts
|
51
|
-
print_comments(comments, ' ')
|
52
|
-
print_tags(tags, ' ')
|
53
|
-
@io.puts " #{keyword}: #{name}"
|
54
|
-
print_description(description, ' ')
|
55
|
-
table(
|
52
|
+
print_comments(statement.comments, ' ')
|
53
|
+
print_tags(statement.tags, ' ')
|
54
|
+
@io.puts " #{statement.keyword}: #{statement.name}"
|
55
|
+
print_description(statement.description, ' ')
|
56
|
+
table(examples_rows)
|
56
57
|
end
|
57
58
|
|
58
|
-
def step(
|
59
|
-
|
60
|
-
name = Gherkin::Formatter::Argument.format(name, @format, (arguments || []))
|
59
|
+
def step(statement, multiline_arg, result)
|
60
|
+
name = Gherkin::Formatter::Argument.format(statement.name, @format, (result ? result.arguments : []))
|
61
61
|
|
62
|
-
step = "#{keyword}#{name}"
|
63
|
-
step = self.__send__(status, step, @monochrome) if
|
62
|
+
step = "#{statement.keyword}#{statement.name}"
|
63
|
+
step = self.__send__(result.status, step, @monochrome) if result
|
64
64
|
|
65
|
-
print_comments(comments, ' ')
|
66
|
-
@io.puts(" #{step}#{indented_step_location!(stepdef_location)}")
|
65
|
+
print_comments(statement.comments, ' ')
|
66
|
+
@io.puts(" #{step}#{indented_step_location!(result ? result.stepdef_location : nil)}")
|
67
67
|
case multiline_arg
|
68
|
-
when
|
68
|
+
when Model::PyString
|
69
69
|
py_string(multiline_arg)
|
70
70
|
when Array
|
71
71
|
table(multiline_arg)
|
@@ -75,11 +75,8 @@ module Gherkin
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def syntax_error(state, event, legal_events, line)
|
79
|
-
raise "SYNTAX ERROR"
|
80
|
-
end
|
81
|
-
|
82
78
|
def eof
|
79
|
+
# NO-OP
|
83
80
|
end
|
84
81
|
|
85
82
|
# This method can be invoked before a #scenario, to ensure location arguments are aligned
|
@@ -99,7 +96,7 @@ module Gherkin
|
|
99
96
|
|
100
97
|
rows.each_with_index do |row, i|
|
101
98
|
row.comments.each do |comment|
|
102
|
-
@io.puts " #{comment}"
|
99
|
+
@io.puts " #{comment.value}"
|
103
100
|
end
|
104
101
|
j = -1
|
105
102
|
@io.puts ' | ' + row.cells.zip(max_lengths).map { |cell, max_length|
|
@@ -111,8 +108,8 @@ module Gherkin
|
|
111
108
|
|
112
109
|
private
|
113
110
|
|
114
|
-
def py_string(
|
115
|
-
@io.puts " \"\"\"\n" + escape_triple_quotes(indent(
|
111
|
+
def py_string(py_string)
|
112
|
+
@io.puts " \"\"\"\n" + escape_triple_quotes(indent(py_string.value, ' ')) + "\n \"\"\""
|
116
113
|
end
|
117
114
|
|
118
115
|
def exception(exception)
|
@@ -145,11 +142,11 @@ module Gherkin
|
|
145
142
|
end
|
146
143
|
|
147
144
|
def print_tags(tags, indent)
|
148
|
-
@io.write(tags.empty? ? '' : indent + tags.join(' ') + "\n")
|
145
|
+
@io.write(tags.empty? ? '' : indent + tags.map{|tag| tag.name}.join(' ') + "\n")
|
149
146
|
end
|
150
147
|
|
151
148
|
def print_comments(comments, indent)
|
152
|
-
@io.write(comments.empty? ? '' : indent + comments.join("\n#{indent}") + "\n")
|
149
|
+
@io.write(comments.empty? ? '' : indent + comments.map{|comment| comment.value}.join("\n#{indent}") + "\n")
|
153
150
|
end
|
154
151
|
|
155
152
|
def print_description(description, indent, newline=true)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Gherkin
|
2
|
+
module Formatter
|
3
|
+
class TagCountFormatter
|
4
|
+
def initialize(formatter, tag_counts)
|
5
|
+
@formatter = formatter
|
6
|
+
@tag_counts = tag_counts
|
7
|
+
end
|
8
|
+
|
9
|
+
def feature(statement, uri)
|
10
|
+
@feature_tags = statement.tags
|
11
|
+
@uri = uri
|
12
|
+
@formatter.feature(statement, uri)
|
13
|
+
end
|
14
|
+
|
15
|
+
def scenario(statement)
|
16
|
+
record_tags((@feature_tags.to_a + statement.tags.to_a).uniq, statement.line)
|
17
|
+
@formatter.scenario(statement)
|
18
|
+
end
|
19
|
+
|
20
|
+
def scenario_outline(statement)
|
21
|
+
@scenario_outline_tags = statement.tags
|
22
|
+
@formatter.scenario_outline(statement)
|
23
|
+
end
|
24
|
+
|
25
|
+
def examples(statement, examples_rows)
|
26
|
+
record_tags((@feature_tags.to_a + @scenario_outline_tags.to_a + statement.tags.to_a).uniq, statement.line)
|
27
|
+
@formatter.examples(statement, examples_rows)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def record_tags(tags, line)
|
33
|
+
tags.each do |tag|
|
34
|
+
@tag_counts[tag.name] ||= []
|
35
|
+
@tag_counts[tag.name] << "#{@uri}:#{line}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(*args)
|
40
|
+
@formatter.__send__(*args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/gherkin/i18n.rb
CHANGED
@@ -55,11 +55,11 @@ module Gherkin
|
|
55
55
|
def language_table
|
56
56
|
require 'stringio'
|
57
57
|
require 'gherkin/formatter/pretty_formatter'
|
58
|
-
require 'gherkin/
|
58
|
+
require 'gherkin/formatter/model'
|
59
59
|
io = defined?(JRUBY_VERSION) ? Java.java.io.StringWriter.new : StringIO.new
|
60
60
|
pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
|
61
61
|
table = all.map do |i18n|
|
62
|
-
|
62
|
+
Formatter::Model::Row.new([], [i18n.iso_code, i18n.keywords('name')[0], i18n.keywords('native')[0]], nil)
|
63
63
|
end
|
64
64
|
pf.table(table)
|
65
65
|
if defined?(JRUBY_VERSION)
|
@@ -147,19 +147,19 @@ module Gherkin
|
|
147
147
|
def keyword_table
|
148
148
|
require 'stringio'
|
149
149
|
require 'gherkin/formatter/pretty_formatter'
|
150
|
-
require 'gherkin/
|
150
|
+
require 'gherkin/formatter/model'
|
151
151
|
io = StringIO.new
|
152
152
|
pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
|
153
153
|
|
154
154
|
gherkin_keyword_table = KEYWORD_KEYS.map do |key|
|
155
|
-
|
155
|
+
Formatter::Model::Row.new([], [key, keywords(key).map{|keyword| %{"#{keyword}"}}.join(', ')], nil)
|
156
156
|
end
|
157
157
|
|
158
158
|
code_keyword_table = STEP_KEYWORD_KEYS.map do |key|
|
159
159
|
code_keywords = keywords(key).reject{|keyword| keyword == '* '}.map do |keyword|
|
160
160
|
%{"#{self.class.code_keyword_for(keyword)}"}
|
161
161
|
end.join(', ')
|
162
|
-
|
162
|
+
Formatter::Model::Row.new([], ["#{key} (code)", code_keywords], nil)
|
163
163
|
end
|
164
164
|
|
165
165
|
pf.table(gherkin_keyword_table + code_keyword_table)
|