cucumber-gherkin 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e29214ad6a0eae41b18a082346911c0bae2fdd0297e8b878549c2d8c8cd241ac
4
+ data.tar.gz: 1a3dd2275a2bf3e4999f360135b7f86342e84a30d146668ecf83ad111b103faa
5
+ SHA512:
6
+ metadata.gz: 3889715de4087bae76cc68de729ec3d4fd613ad7fc07f815d6f47ec94d517fa364cc38a93620f132c3db5aeb2cafe25261f52328f90022ad1631f0271b18631b
7
+ data.tar.gz: 529b1867c7dfcfca824ee6a8a35bcfe7542bf42a5f6ed1c067d66c5f79ea26430c7ab7e82f27ce426c210684aee72802c951ffc2714189538b01987cfb4b6847
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Cucumber Ltd, Gaspar Nagy, Björn Rasmusson, Peter Sergeant
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,10 @@
1
+ [![Build Status](https://secure.travis-ci.org/cucumber/gherkin-ruby.svg)](http://travis-ci.org/cucumber/gherkin-ruby)
2
+
3
+ Gherkin parser/compiler for Ruby. Please see [Gherkin](https://github.com/cucumber/gherkin) for details.
4
+
5
+ ## To build
6
+
7
+ ~~~bash
8
+ cd <project_root>/ruby
9
+ make
10
+ ~~~
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE=nil # Shut up JRuby warnings on Travis
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"../lib"))
4
+
5
+ require 'optparse'
6
+ require 'json'
7
+ require 'cucumber/messages'
8
+ require 'gherkin'
9
+ require 'gherkin/stream/subprocess_message_stream'
10
+
11
+ options = {
12
+ include_source: true,
13
+ include_gherkin_document: true,
14
+ include_pickles: true,
15
+ format: 'protobuf',
16
+ predictable_ids: false
17
+ }
18
+
19
+ OptionParser.new do |opts|
20
+ opts.on("--[no-]source", "Don't print source messages") do |v|
21
+ options[:include_source] = v
22
+ end
23
+ opts.on("--[no-]ast", "Don't print ast messages") do |v|
24
+ options[:include_gherkin_document] = v
25
+ end
26
+ opts.on("--[no-]pickles", "Don't print pickle messages") do |v|
27
+ options[:include_pickles] = v
28
+ end
29
+ opts.on("--format ndjson|protobuf", "Output format") do |v|
30
+ options[:format] = v
31
+ end
32
+ opts.on("--predictable-ids", "Generate incrementing ids rather than UUIDs") do |v|
33
+ options[:id_generator] = Cucumber::Messages::IdGenerator::Incrementing.new if v
34
+ end
35
+ end.parse!
36
+
37
+ def process_messages(messages, options)
38
+ messages.each do |message|
39
+ if options[:format] == 'ndjson'
40
+ message.write_ndjson_to(STDOUT)
41
+ elsif options[:format] == 'protobuf'
42
+ message.write_delimited_to(STDOUT)
43
+ else
44
+ raise "Unsupported format: #{options[:format]}"
45
+ end
46
+ end
47
+ end
48
+
49
+ gherkin_executable = ENV['GHERKIN_EXECUTABLE']
50
+ if ARGV.empty?
51
+ # Read protobuf from STDIN
52
+ messages = Cucumber::Messages::BinaryToMessageEnumerator.new(STDIN)
53
+ elsif gherkin_executable
54
+ # Read protobuf from STDIN
55
+ messages = Gherkin::Stream::SubprocessMessageStream.new(
56
+ gherkin_executable,
57
+ ARGV,
58
+ options[:include_source],
59
+ options[:include_gherkin_document],
60
+ options[:include_pickles]
61
+ ).messages
62
+ else
63
+ messages = Gherkin.from_paths(
64
+ ARGV,
65
+ options
66
+ )
67
+ end
68
+ process_messages(messages, options)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ load(File.dirname(__FILE__) + '/gherkin')
@@ -0,0 +1,39 @@
1
+ require 'gherkin/stream/parser_message_stream'
2
+
3
+ module Gherkin
4
+ DEFAULT_OPTIONS = {
5
+ include_source: true,
6
+ include_gherkin_document: true,
7
+ include_pickles: true
8
+ }.freeze
9
+
10
+ def self.from_paths(paths, options={})
11
+ Stream::ParserMessageStream.new(
12
+ paths,
13
+ [],
14
+ options
15
+ ).messages
16
+ end
17
+
18
+ def self.from_sources(sources, options={})
19
+ Stream::ParserMessageStream.new(
20
+ [],
21
+ sources,
22
+ options
23
+ ).messages
24
+ end
25
+
26
+ def self.from_source(uri, data, options={})
27
+ from_sources([encode_source_message(uri, data)], options)
28
+ end
29
+
30
+ private
31
+
32
+ def self.encode_source_message(uri, data)
33
+ Cucumber::Messages::Source.new({
34
+ uri: uri,
35
+ data: data,
36
+ media_type: 'text/x.cucumber.gherkin+plain'
37
+ })
38
+ end
39
+ end
@@ -0,0 +1,257 @@
1
+ require 'cucumber/messages'
2
+ require 'gherkin/ast_node'
3
+
4
+ module Gherkin
5
+ class AstBuilder
6
+ def initialize(id_generator)
7
+ @id_generator = id_generator
8
+ reset
9
+ end
10
+
11
+ def reset
12
+ @stack = [AstNode.new(:None)]
13
+ @comments = []
14
+ end
15
+
16
+ def start_rule(rule_type)
17
+ @stack.push AstNode.new(rule_type)
18
+ end
19
+
20
+ def end_rule(rule_type)
21
+ node = @stack.pop
22
+ current_node.add(node.rule_type, transform_node(node))
23
+ end
24
+
25
+ def build(token)
26
+ if token.matched_type == :Comment
27
+ @comments.push(Cucumber::Messages::GherkinDocument::Comment.new(
28
+ location: get_location(token, 0),
29
+ text: token.matched_text
30
+ ))
31
+ else
32
+ current_node.add(token.matched_type, token)
33
+ end
34
+ end
35
+
36
+ def get_result
37
+ current_node.get_single(:GherkinDocument)
38
+ end
39
+
40
+ def current_node
41
+ @stack.last
42
+ end
43
+
44
+ def get_location(token, column)
45
+ column = column == 0 ? token.location[:column] : column
46
+ Cucumber::Messages::Location.new(
47
+ line: token.location[:line],
48
+ column: column
49
+ )
50
+ end
51
+
52
+ def get_tags(node)
53
+ tags = []
54
+ tags_node = node.get_single(:Tags)
55
+ return tags unless tags_node
56
+
57
+ tags_node.get_tokens(:TagLine).each do |token|
58
+ token.matched_items.each do |tag_item|
59
+ tags.push(Cucumber::Messages::GherkinDocument::Feature::Tag.new(
60
+ location: get_location(token, tag_item.column),
61
+ name: tag_item.text,
62
+ id: @id_generator.new_id
63
+ ))
64
+ end
65
+ end
66
+
67
+ tags
68
+ end
69
+
70
+ def get_table_rows(node)
71
+ rows = node.get_tokens(:TableRow).map do |token|
72
+ Cucumber::Messages::GherkinDocument::Feature::TableRow.new(
73
+ id: @id_generator.new_id,
74
+ location: get_location(token, 0),
75
+ cells: get_cells(token)
76
+ )
77
+ end
78
+ ensure_cell_count(rows)
79
+ rows
80
+ end
81
+
82
+ def ensure_cell_count(rows)
83
+ return if rows.empty?
84
+ cell_count = rows[0].cells.length
85
+ rows.each do |row|
86
+ if row.cells.length != cell_count
87
+ location = {line: row.location.line, column: row.location.column}
88
+ raise AstBuilderException.new("inconsistent cell count within the table", location)
89
+ end
90
+ end
91
+ end
92
+
93
+ def get_cells(table_row_token)
94
+ table_row_token.matched_items.map do |cell_item|
95
+ Cucumber::Messages::GherkinDocument::Feature::TableRow::TableCell.new(
96
+ location: get_location(table_row_token, cell_item.column),
97
+ value: cell_item.text
98
+ )
99
+ end
100
+ end
101
+
102
+ def get_description(node)
103
+ node.get_single(:Description)
104
+ end
105
+
106
+ def get_steps(node)
107
+ node.get_items(:Step)
108
+ end
109
+
110
+ def transform_node(node)
111
+ case node.rule_type
112
+ when :Step
113
+ step_line = node.get_token(:StepLine)
114
+ data_table = node.get_single(:DataTable)
115
+ doc_string = node.get_single(:DocString)
116
+
117
+ Cucumber::Messages::GherkinDocument::Feature::Step.new(
118
+ location: get_location(step_line, 0),
119
+ keyword: step_line.matched_keyword,
120
+ text: step_line.matched_text,
121
+ data_table: data_table,
122
+ doc_string: doc_string,
123
+ id: @id_generator.new_id
124
+ )
125
+ when :DocString
126
+ separator_token = node.get_tokens(:DocStringSeparator)[0]
127
+ media_type = separator_token.matched_text == '' ? nil : separator_token.matched_text
128
+ line_tokens = node.get_tokens(:Other)
129
+ content = line_tokens.map { |t| t.matched_text }.join("\n")
130
+
131
+ Cucumber::Messages::GherkinDocument::Feature::Step::DocString.new(
132
+ location: get_location(separator_token, 0),
133
+ content: content,
134
+ delimiter: separator_token.matched_keyword,
135
+ media_type: media_type,
136
+ )
137
+ when :DataTable
138
+ rows = get_table_rows(node)
139
+ Cucumber::Messages::GherkinDocument::Feature::Step::DataTable.new(
140
+ location: rows[0].location,
141
+ rows: rows,
142
+ )
143
+ when :Background
144
+ background_line = node.get_token(:BackgroundLine)
145
+ description = get_description(node)
146
+ steps = get_steps(node)
147
+
148
+ Cucumber::Messages::GherkinDocument::Feature::Background.new(
149
+ location: get_location(background_line, 0),
150
+ keyword: background_line.matched_keyword,
151
+ name: background_line.matched_text,
152
+ description: description,
153
+ steps: steps
154
+ )
155
+ when :ScenarioDefinition
156
+ tags = get_tags(node)
157
+ scenario_node = node.get_single(:Scenario)
158
+ scenario_line = scenario_node.get_token(:ScenarioLine)
159
+ description = get_description(scenario_node)
160
+ steps = get_steps(scenario_node)
161
+ examples = scenario_node.get_items(:ExamplesDefinition)
162
+ Cucumber::Messages::GherkinDocument::Feature::Scenario.new(
163
+ id: @id_generator.new_id,
164
+ tags: tags,
165
+ location: get_location(scenario_line, 0),
166
+ keyword: scenario_line.matched_keyword,
167
+ name: scenario_line.matched_text,
168
+ description: description,
169
+ steps: steps,
170
+ examples: examples
171
+ )
172
+ when :ExamplesDefinition
173
+ tags = get_tags(node)
174
+ examples_node = node.get_single(:Examples)
175
+ examples_line = examples_node.get_token(:ExamplesLine)
176
+ description = get_description(examples_node)
177
+ rows = examples_node.get_single(:ExamplesTable)
178
+
179
+ table_header = rows.nil? ? nil : rows.first
180
+ table_body = rows.nil? ? nil : rows[1..-1]
181
+
182
+ Cucumber::Messages::GherkinDocument::Feature::Scenario::Examples.new(
183
+ tags: tags,
184
+ location: get_location(examples_line, 0),
185
+ keyword: examples_line.matched_keyword,
186
+ name: examples_line.matched_text,
187
+ description: description,
188
+ table_header: table_header,
189
+ table_body: table_body,
190
+ )
191
+ when :ExamplesTable
192
+ get_table_rows(node)
193
+ when :Description
194
+ line_tokens = node.get_tokens(:Other)
195
+ # Trim trailing empty lines
196
+ last_non_empty = line_tokens.rindex { |token| !token.line.trimmed_line_text.empty? }
197
+ description = line_tokens[0..last_non_empty].map { |token| token.matched_text }.join("\n")
198
+ return description
199
+ when :Feature
200
+ header = node.get_single(:FeatureHeader)
201
+ return unless header
202
+ tags = get_tags(header)
203
+ feature_line = header.get_token(:FeatureLine)
204
+ return unless feature_line
205
+ children = []
206
+ background = node.get_single(:Background)
207
+ children.push(Cucumber::Messages::GherkinDocument::Feature::FeatureChild.new(background: background)) if background
208
+ node.get_items(:ScenarioDefinition).each do |scenario|
209
+ children.push(Cucumber::Messages::GherkinDocument::Feature::FeatureChild.new(scenario: scenario))
210
+ end
211
+ node.get_items(:Rule).each do |rule|
212
+ children.push(Cucumber::Messages::GherkinDocument::Feature::FeatureChild.new(rule: rule))
213
+ end
214
+ description = get_description(header)
215
+ language = feature_line.matched_gherkin_dialect
216
+
217
+ Cucumber::Messages::GherkinDocument::Feature.new(
218
+ tags: tags,
219
+ location: get_location(feature_line, 0),
220
+ language: language,
221
+ keyword: feature_line.matched_keyword,
222
+ name: feature_line.matched_text,
223
+ description: description,
224
+ children: children,
225
+ )
226
+ when :Rule
227
+ header = node.get_single(:RuleHeader)
228
+ return unless header
229
+ rule_line = header.get_token(:RuleLine)
230
+ return unless rule_line
231
+ children = []
232
+ background = node.get_single(:Background)
233
+ children.push(Cucumber::Messages::GherkinDocument::Feature::FeatureChild::RuleChild.new(background: background)) if background
234
+ node.get_items(:ScenarioDefinition).each do |scenario|
235
+ children.push(Cucumber::Messages::GherkinDocument::Feature::FeatureChild::RuleChild.new(scenario: scenario))
236
+ end
237
+ description = get_description(header)
238
+
239
+ Cucumber::Messages::GherkinDocument::Feature::FeatureChild::Rule.new(
240
+ location: get_location(rule_line, 0),
241
+ keyword: rule_line.matched_keyword,
242
+ name: rule_line.matched_text,
243
+ description: description,
244
+ children: children,
245
+ )
246
+ when :GherkinDocument
247
+ feature = node.get_single(:Feature)
248
+ {
249
+ feature: feature,
250
+ comments: @comments
251
+ }
252
+ else
253
+ return node
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,30 @@
1
+ module Gherkin
2
+ class AstNode
3
+ attr_reader :rule_type
4
+
5
+ def initialize(rule_type)
6
+ @rule_type = rule_type
7
+ @_sub_items = Hash.new { |hash, key| hash[key] = [] } # returns [] for unknown key
8
+ end
9
+
10
+ def add(rule_type, obj)
11
+ @_sub_items[rule_type].push(obj)
12
+ end
13
+
14
+ def get_single(rule_type)
15
+ @_sub_items[rule_type].first
16
+ end
17
+
18
+ def get_items(rule_type)
19
+ @_sub_items[rule_type]
20
+ end
21
+
22
+ def get_token(token_type)
23
+ get_single(token_type)
24
+ end
25
+
26
+ def get_tokens(token_type)
27
+ @_sub_items[token_type]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+
3
+ module Gherkin
4
+ DIALECT_FILE_PATH = File.expand_path("gherkin-languages.json", File.dirname(__FILE__))
5
+ DIALECTS = JSON.parse File.open(DIALECT_FILE_PATH, 'r:UTF-8').read
6
+
7
+ class Dialect
8
+ def self.for(name)
9
+ spec = DIALECTS[name]
10
+ return nil unless spec
11
+ new(spec)
12
+ end
13
+
14
+ def initialize(spec)
15
+ @spec = spec
16
+ end
17
+
18
+ def feature_keywords
19
+ @spec.fetch('feature')
20
+ end
21
+
22
+ def rule_keywords
23
+ @spec.fetch('rule')
24
+ end
25
+
26
+ def scenario_keywords
27
+ @spec.fetch('scenario')
28
+ end
29
+
30
+ def scenario_outline_keywords
31
+ @spec.fetch('scenarioOutline')
32
+ end
33
+
34
+ def examples_keywords
35
+ @spec.fetch('examples')
36
+ end
37
+
38
+ def background_keywords
39
+ @spec.fetch('background')
40
+ end
41
+
42
+ def given_keywords
43
+ @spec.fetch('given')
44
+ end
45
+
46
+ def when_keywords
47
+ @spec.fetch('when')
48
+ end
49
+
50
+ def then_keywords
51
+ @spec.fetch('then')
52
+ end
53
+
54
+ def and_keywords
55
+ @spec.fetch('and')
56
+ end
57
+
58
+ def but_keywords
59
+ @spec.fetch('but')
60
+ end
61
+ end
62
+ end