gherkin 5.1.0 → 6.0.10

Sign up to get free protection for your applications and to get access to all the features.
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