gherkin 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +35 -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)
|