gherkin 5.1.0 → 6.0.10

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -4
  3. data/bin/gherkin +43 -16
  4. data/gherkin-go/gherkin-go-darwin-386 +0 -0
  5. data/gherkin-go/gherkin-go-darwin-amd64 +0 -0
  6. data/gherkin-go/gherkin-go-freebsd-386 +0 -0
  7. data/gherkin-go/gherkin-go-freebsd-amd64 +0 -0
  8. data/gherkin-go/gherkin-go-freebsd-arm +0 -0
  9. data/gherkin-go/gherkin-go-linux-386 +0 -0
  10. data/gherkin-go/gherkin-go-linux-amd64 +0 -0
  11. data/gherkin-go/gherkin-go-linux-arm +0 -0
  12. data/gherkin-go/gherkin-go-linux-mips +2 -0
  13. data/gherkin-go/gherkin-go-linux-mips64 +2 -0
  14. data/gherkin-go/gherkin-go-linux-mips64le +2 -0
  15. data/gherkin-go/gherkin-go-linux-mipsle +2 -0
  16. data/gherkin-go/gherkin-go-linux-s390x +2 -0
  17. data/gherkin-go/gherkin-go-netbsd-386 +0 -0
  18. data/gherkin-go/gherkin-go-netbsd-amd64 +0 -0
  19. data/gherkin-go/gherkin-go-netbsd-arm +0 -0
  20. data/gherkin-go/gherkin-go-openbsd-386 +0 -0
  21. data/gherkin-go/gherkin-go-openbsd-amd64 +0 -0
  22. data/gherkin-go/gherkin-go-windows-386.exe +0 -0
  23. data/gherkin-go/gherkin-go-windows-amd64.exe +0 -0
  24. data/lib/gherkin/dialect.rb +16 -2
  25. data/lib/gherkin/exe_file_path.rb +3 -0
  26. data/lib/gherkin/gherkin.rb +75 -0
  27. data/lib/gherkin/protobuf_cucumber_messages.rb +30 -0
  28. data/spec/capture_warnings.rb +11 -5
  29. data/spec/coverage.rb +3 -6
  30. data/spec/gherkin/dialect_spec.rb +13 -0
  31. data/spec/gherkin/gherkin_spec.rb +354 -0
  32. metadata +49 -27
  33. data/lib/gherkin/ast_builder.rb +0 -257
  34. data/lib/gherkin/ast_node.rb +0 -30
  35. data/lib/gherkin/errors.rb +0 -45
  36. data/lib/gherkin/gherkin-languages.json +0 -3239
  37. data/lib/gherkin/gherkin_line.rb +0 -95
  38. data/lib/gherkin/parser.rb +0 -2310
  39. data/lib/gherkin/pickles/compiler.rb +0 -163
  40. data/lib/gherkin/stream/gherkin_events.rb +0 -71
  41. data/lib/gherkin/stream/source_events.rb +0 -26
  42. data/lib/gherkin/token.rb +0 -18
  43. data/lib/gherkin/token_formatter_builder.rb +0 -39
  44. data/lib/gherkin/token_matcher.rb +0 -169
  45. data/lib/gherkin/token_scanner.rb +0 -40
  46. data/spec/gherkin/parser_spec.rb +0 -280
  47. data/spec/gherkin/stream/gherkin_events_spec.rb +0 -27
  48. data/spec/gherkin/stream/test_fr.feature +0 -3
@@ -1,163 +0,0 @@
1
- module Gherkin
2
- module Pickles
3
- class Compiler
4
- def compile(gherkin_document)
5
- pickles = []
6
-
7
- return pickles unless gherkin_document[:feature]
8
- feature = gherkin_document[:feature]
9
- feature_tags = feature[:tags]
10
- background_steps = []
11
-
12
- feature[:children].each do |scenario_definition|
13
- if(scenario_definition[:type] == :Background)
14
- background_steps = pickle_steps(scenario_definition)
15
- elsif(scenario_definition[:type] == :Scenario)
16
- compile_scenario(feature_tags, background_steps, scenario_definition, feature[:language], pickles)
17
- else
18
- compile_scenario_outline(feature_tags, background_steps, scenario_definition, feature[:language], pickles)
19
- end
20
- end
21
- return pickles
22
- end
23
-
24
- private
25
-
26
- def compile_scenario(feature_tags, background_steps, scenario, language, pickles)
27
- steps = scenario[:steps].empty? ? [] : [].concat(background_steps)
28
-
29
- tags = [].concat(feature_tags).concat(scenario[:tags])
30
-
31
- scenario[:steps].each do |step|
32
- steps.push(pickle_step(step))
33
- end
34
-
35
- pickle = {
36
- tags: pickle_tags(tags),
37
- name: scenario[:name],
38
- language: language,
39
- locations: [pickle_location(scenario[:location])],
40
- steps: steps
41
- }
42
- pickles.push(pickle)
43
- end
44
-
45
- def compile_scenario_outline(feature_tags, background_steps, scenario_outline, language, pickles)
46
- scenario_outline[:examples].reject { |examples| examples[:tableHeader].nil? }.each do |examples|
47
- variable_cells = examples[:tableHeader][:cells]
48
- examples[:tableBody].each do |values|
49
- value_cells = values[:cells]
50
- steps = scenario_outline[:steps].empty? ? [] : [].concat(background_steps)
51
- tags = [].concat(feature_tags).concat(scenario_outline[:tags]).concat(examples[:tags])
52
-
53
- scenario_outline[:steps].each do |scenario_outline_step|
54
- step_text = interpolate(scenario_outline_step[:text], variable_cells, value_cells);
55
- arguments = create_pickle_arguments(scenario_outline_step[:argument], variable_cells, value_cells)
56
- pickle_step = {
57
- text: step_text,
58
- arguments: arguments,
59
- locations: [
60
- pickle_location(values[:location]),
61
- pickle_step_location(scenario_outline_step)
62
- ]
63
- }
64
- steps.push(pickle_step)
65
- end
66
-
67
- pickle = {
68
- name: interpolate(scenario_outline[:name], variable_cells, value_cells),
69
- language: language,
70
- steps: steps,
71
- tags: pickle_tags(tags),
72
- locations: [
73
- pickle_location(values[:location]),
74
- pickle_location(scenario_outline[:location])
75
- ]
76
- }
77
- pickles.push(pickle);
78
-
79
- end
80
- end
81
- end
82
-
83
- def create_pickle_arguments(argument, variable_cells, value_cells)
84
- result = []
85
- return result if argument.nil?
86
- if (argument[:type] == :DataTable)
87
- table = {
88
- rows: argument[:rows].map do |row|
89
- {
90
- cells: row[:cells].map do |cell|
91
- {
92
- location: pickle_location(cell[:location]),
93
- value: interpolate(cell[:value], variable_cells, value_cells)
94
- }
95
- end
96
- }
97
- end
98
- }
99
- result.push(table)
100
- elsif (argument[:type] == :DocString)
101
- doc_string = {
102
- location: pickle_location(argument[:location]),
103
- content: interpolate(argument[:content], variable_cells, value_cells)
104
- }
105
- if argument.key?(:contentType)
106
- doc_string[:contentType] = interpolate(argument[:contentType], variable_cells, value_cells)
107
- end
108
- result.push(doc_string)
109
- else
110
- raise 'Internal error'
111
- end
112
- result
113
- end
114
-
115
- def interpolate(name, variable_cells, value_cells)
116
- variable_cells.each_with_index do |variable_cell, n|
117
- value_cell = value_cells[n]
118
- name = name.gsub('<' + variable_cell[:value] + '>', value_cell[:value])
119
- end
120
- name
121
- end
122
-
123
- def pickle_steps(scenario_definition)
124
- scenario_definition[:steps].map do |step|
125
- pickle_step(step)
126
- end
127
- end
128
-
129
- def pickle_step(step)
130
- {
131
- text: step[:text],
132
- arguments: create_pickle_arguments(step[:argument], [], []),
133
- locations: [pickle_step_location(step)]
134
- }
135
- end
136
-
137
- def pickle_step_location(step)
138
- {
139
- line: step[:location][:line],
140
- column: step[:location][:column] + (step[:keyword] ? step[:keyword].length : 0)
141
- }
142
- end
143
-
144
- def pickle_location(location)
145
- {
146
- line: location[:line],
147
- column: location[:column]
148
- }
149
- end
150
-
151
- def pickle_tags(tags)
152
- tags.map {|tag| pickle_tag(tag)}
153
- end
154
-
155
- def pickle_tag(tag)
156
- {
157
- name: tag[:name],
158
- location: pickle_location(tag[:location])
159
- }
160
- end
161
- end
162
- end
163
- end
@@ -1,71 +0,0 @@
1
- require 'gherkin/parser'
2
- require 'gherkin/token_matcher'
3
- require 'gherkin/pickles/compiler'
4
-
5
- module Gherkin
6
- module Stream
7
- class GherkinEvents
8
- def initialize(options, language='en')
9
- @options = options
10
- @parser = Gherkin::Parser.new
11
- @compiler = Gherkin::Pickles::Compiler.new
12
- @language = language
13
- end
14
-
15
- def enum(source_event)
16
- Enumerator.new do |y|
17
- uri = source_event[:uri]
18
- source = source_event[:data]
19
- begin
20
- gherkin_document = @parser.parse(source, TokenMatcher.new(@language))
21
-
22
- if (@options[:print_source])
23
- y.yield source_event
24
- end
25
- if (@options[:print_ast])
26
- y.yield({
27
- type: 'gherkin-document',
28
- uri: uri,
29
- document: gherkin_document
30
- })
31
- end
32
- if (@options[:print_pickles])
33
- pickles = @compiler.compile(gherkin_document)
34
- pickles.each do |pickle|
35
- y.yield({
36
- type: 'pickle',
37
- uri: uri,
38
- pickle: pickle
39
- })
40
- end
41
- end
42
- rescue Gherkin::CompositeParserException => e
43
- yield_errors(y, e.errors, uri)
44
- rescue Gherkin::ParserError => e
45
- yield_errors(y, [e], uri)
46
- end
47
- end
48
- end
49
-
50
- def yield_errors(y, errors, uri)
51
- errors.each do |error|
52
- y.yield({
53
- type: 'attachment',
54
- source: {
55
- uri: uri,
56
- start: {
57
- line: error.location[:line],
58
- column: error.location[:column]
59
- }
60
- },
61
- data: error.message,
62
- media: {
63
- encoding: 'utf-8',
64
- type: 'text/x.cucumber.stacktrace+plain'
65
- }
66
- })
67
- end
68
- end
69
- end
70
- end
71
- end
@@ -1,26 +0,0 @@
1
- module Gherkin
2
- module Stream
3
- class SourceEvents
4
- def initialize(paths)
5
- @paths = paths
6
- end
7
-
8
- def enum
9
- Enumerator.new do |y|
10
- @paths.each do |path|
11
- event = {
12
- type: 'source',
13
- uri: path,
14
- data: File.open(path, 'r:UTF-8', &:read),
15
- media: {
16
- encoding: 'utf-8',
17
- type: 'text/x.cucumber.gherkin+plain'
18
- }
19
- }
20
- y.yield(event)
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,18 +0,0 @@
1
- module Gherkin
2
- class Token < Struct.new(:line, :location)
3
- attr_accessor :matched_type, :matched_text, :matched_keyword, :matched_indent,
4
- :matched_items, :matched_gherkin_dialect
5
-
6
- def eof?
7
- line.nil?
8
- end
9
-
10
- def detach
11
- # TODO: detach line - is this needed?
12
- end
13
-
14
- def token_value
15
- eof? ? "EOF" : line.get_line_text(-1)
16
- end
17
- end
18
- end
@@ -1,39 +0,0 @@
1
- module Gherkin
2
- class TokenFormatterBuilder
3
- def initialize
4
- reset
5
- end
6
-
7
- def reset
8
- @tokens_text = ""
9
- end
10
-
11
- def build(token)
12
- @tokens_text << "#{format_token(token)}\n"
13
- end
14
-
15
- def start_rule(rule_type)
16
- end
17
-
18
- def end_rule(rule_type)
19
- end
20
-
21
- def get_result
22
- @tokens_text
23
- end
24
-
25
- private
26
- def format_token(token)
27
- return "EOF" if token.eof?
28
-
29
- sprintf "(%s:%s)%s:%s/%s/%s",
30
- token.location[:line],
31
- token.location[:column],
32
- token.matched_type,
33
- token.matched_keyword,
34
- token.matched_text,
35
- Array(token.matched_items).map { |i| "#{i.column}:#{i.text}"}.join(',')
36
- end
37
-
38
- end
39
- end
@@ -1,169 +0,0 @@
1
- require 'gherkin/dialect'
2
- require 'gherkin/errors'
3
-
4
- module Gherkin
5
- class TokenMatcher
6
- LANGUAGE_PATTERN = /^\s*#\s*language\s*:\s*([a-zA-Z\-_]+)\s*$/
7
-
8
- def initialize(dialect_name = 'en')
9
- @default_dialect_name = dialect_name
10
- change_dialect(dialect_name, nil)
11
- reset
12
- end
13
-
14
- def reset
15
- change_dialect(@default_dialect_name, nil) unless @dialect_name == @default_dialect_name
16
- @active_doc_string_separator = nil
17
- @indent_to_remove = 0
18
- end
19
-
20
- def match_TagLine(token)
21
- return false unless token.line.start_with?('@')
22
-
23
- set_token_matched(token, :TagLine, nil, nil, nil, token.line.tags)
24
- true
25
- end
26
-
27
- def match_FeatureLine(token)
28
- match_title_line(token, :FeatureLine, @dialect.feature_keywords)
29
- end
30
-
31
- def match_ScenarioLine(token)
32
- match_title_line(token, :ScenarioLine, @dialect.scenario_keywords)
33
- end
34
-
35
- def match_ScenarioOutlineLine(token)
36
- match_title_line(token, :ScenarioOutlineLine, @dialect.scenario_outline_keywords)
37
- end
38
-
39
- def match_BackgroundLine(token)
40
- match_title_line(token, :BackgroundLine, @dialect.background_keywords)
41
- end
42
-
43
- def match_ExamplesLine(token)
44
- match_title_line(token, :ExamplesLine, @dialect.examples_keywords)
45
- end
46
-
47
- def match_TableRow(token)
48
- return false unless token.line.start_with?('|')
49
- # TODO: indent
50
- set_token_matched(token, :TableRow, nil, nil, nil, token.line.table_cells)
51
- true
52
- end
53
-
54
- def match_Empty(token)
55
- return false unless token.line.empty?
56
- set_token_matched(token, :Empty, nil, nil, 0)
57
- true
58
- end
59
-
60
- def match_Comment(token)
61
- return false unless token.line.start_with?('#')
62
- text = token.line.get_line_text(0) #take the entire line, including leading space
63
- set_token_matched(token, :Comment, text, nil, 0)
64
- true
65
- end
66
-
67
- def match_Language(token)
68
- return false unless token.line.trimmed_line_text =~ LANGUAGE_PATTERN
69
-
70
- dialect_name = $1
71
- set_token_matched(token, :Language, dialect_name)
72
-
73
- change_dialect(dialect_name, token.location)
74
-
75
- true
76
- end
77
-
78
- def match_DocStringSeparator(token)
79
- if @active_doc_string_separator.nil?
80
- # open
81
- _match_DocStringSeparator(token, '"""', true) ||
82
- _match_DocStringSeparator(token, '```', true)
83
- else
84
- # close
85
- _match_DocStringSeparator(token, @active_doc_string_separator, false)
86
- end
87
- end
88
-
89
- def _match_DocStringSeparator(token, separator, is_open)
90
- return false unless token.line.start_with?(separator)
91
-
92
- content_type = nil
93
- if is_open
94
- content_type = token.line.get_rest_trimmed(separator.length)
95
- @active_doc_string_separator = separator
96
- @indent_to_remove = token.line.indent
97
- else
98
- @active_doc_string_separator = nil
99
- @indent_to_remove = 0
100
- end
101
-
102
- # TODO: Use the separator as keyword. That's needed for pretty printing.
103
- set_token_matched(token, :DocStringSeparator, content_type)
104
- true
105
- end
106
-
107
- def match_EOF(token)
108
- return false unless token.eof?
109
- set_token_matched(token, :EOF)
110
- true
111
- end
112
-
113
- def match_Other(token)
114
- text = token.line.get_line_text(@indent_to_remove) # take the entire line, except removing DocString indents
115
- set_token_matched(token, :Other, unescape_docstring(text), nil, 0)
116
- true
117
- end
118
-
119
- def match_StepLine(token)
120
- keywords = @dialect.given_keywords +
121
- @dialect.when_keywords +
122
- @dialect.then_keywords +
123
- @dialect.and_keywords +
124
- @dialect.but_keywords
125
-
126
- keyword = keywords.detect { |k| token.line.start_with?(k) }
127
-
128
- return false unless keyword
129
-
130
- title = token.line.get_rest_trimmed(keyword.length)
131
- set_token_matched(token, :StepLine, title, keyword)
132
- return true
133
- end
134
-
135
- private
136
-
137
- def change_dialect(dialect_name, location)
138
- dialect = Dialect.for(dialect_name)
139
- raise NoSuchLanguageException.new(dialect_name, location) if dialect.nil?
140
-
141
- @dialect_name = dialect_name
142
- @dialect = dialect
143
- end
144
-
145
- def match_title_line(token, token_type, keywords)
146
- keyword = keywords.detect { |k| token.line.start_with_title_keyword?(k) }
147
-
148
- return false unless keyword
149
-
150
- title = token.line.get_rest_trimmed(keyword.length + ':'.length)
151
- set_token_matched(token, token_type, title, keyword)
152
- true
153
- end
154
-
155
- def set_token_matched(token, matched_type, text=nil, keyword=nil, indent=nil, items=[])
156
- token.matched_type = matched_type
157
- token.matched_text = text && text.chomp
158
- token.matched_keyword = keyword
159
- token.matched_indent = indent || (token.line && token.line.indent) || 0
160
- token.matched_items = items
161
- token.location[:column] = token.matched_indent + 1
162
- token.matched_gherkin_dialect = @dialect_name
163
- end
164
-
165
- def unescape_docstring(text)
166
- @active_doc_string_separator ? text.gsub("\\\"\\\"\\\"", "\"\"\"") : text
167
- end
168
- end
169
- end