gherkin 2.1.5 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +16 -0
- data/README.rdoc +1 -0
- data/Rakefile +1 -1
- data/VERSION.yml +2 -2
- data/features/json_formatter.feature +3 -11
- data/features/json_parser.feature +2 -5
- data/features/step_definitions/json_lexer_steps.rb +1 -1
- data/features/step_definitions/pretty_formatter_steps.rb +1 -1
- data/features/support/env.rb +2 -1
- data/java/src/main/java/gherkin/lexer/{.gitignore → i18n/.gitignore} +0 -0
- data/json-simple-1.1.dll +0 -0
- data/lib/gherkin.rb +1 -1
- data/lib/gherkin/formatter/filter_formatter.rb +52 -61
- data/lib/gherkin/formatter/json_formatter.rb +26 -94
- data/lib/gherkin/formatter/line_filter.rb +3 -3
- data/lib/gherkin/formatter/model.rb +156 -19
- data/lib/gherkin/formatter/pretty_formatter.rb +25 -25
- data/lib/gherkin/formatter/regexp_filter.rb +5 -1
- data/lib/gherkin/formatter/tag_count_formatter.rb +15 -12
- data/lib/gherkin/formatter/tag_filter.rb +19 -0
- data/lib/gherkin/json_parser.rb +49 -65
- data/lib/gherkin/lexer/i18n_lexer.rb +40 -0
- data/lib/gherkin/listener/formatter_listener.rb +11 -18
- data/lib/gherkin/parser/parser.rb +4 -5
- data/lib/gherkin/tools/stats_listener.rb +1 -1
- data/ragel/lexer.c.rl.erb +3 -1
- data/ragel/lexer.java.rl.erb +4 -4
- data/ragel/lexer.rb.rl.erb +3 -1
- data/spec/gherkin/fixtures/complex.json +2 -3
- data/spec/gherkin/formatter/model_spec.rb +1 -1
- data/spec/gherkin/formatter/pretty_formatter_spec.rb +11 -8
- data/spec/gherkin/i18n_spec.rb +3 -3
- data/spec/gherkin/java_lexer_spec.rb +1 -1
- data/spec/gherkin/json.rb +5 -0
- data/spec/gherkin/json_parser_spec.rb +49 -73
- data/spec/gherkin/lexer/i18n_lexer_spec.rb +33 -0
- data/spec/gherkin/sexp_recorder.rb +0 -2
- data/spec/spec_helper.rb +1 -0
- data/tasks/bench.rake +2 -2
- data/tasks/compile.rake +1 -1
- data/tasks/ikvm.rake +3 -1
- data/tasks/ragel_task.rb +1 -1
- data/tasks/release.rake +13 -1
- data/tasks/rspec.rake +0 -1
- metadata +17 -13
- data/lib/gherkin/i18n_lexer.rb +0 -38
- data/spec/gherkin/i18n_lexer_spec.rb +0 -26
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'gherkin/i18n'
|
2
|
+
require 'gherkin/native'
|
3
|
+
|
4
|
+
module Gherkin
|
5
|
+
module Lexer
|
6
|
+
I18nLexerNotFound = Class.new(LoadError)
|
7
|
+
LexingError = Class.new(StandardError)
|
8
|
+
|
9
|
+
# The main entry point to lexing Gherkin source.
|
10
|
+
class I18nLexer
|
11
|
+
native_impl('gherkin')
|
12
|
+
|
13
|
+
LANGUAGE_PATTERN = /^\s*#\s*language\s*:\s*([a-zA-Z\-]+)/ #:nodoc:
|
14
|
+
attr_reader :i18n_language
|
15
|
+
|
16
|
+
def initialize(listener, force_ruby=false)
|
17
|
+
@listener = listener
|
18
|
+
@force_ruby = force_ruby
|
19
|
+
end
|
20
|
+
|
21
|
+
def scan(source)
|
22
|
+
create_delegate(source).scan(source)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def create_delegate(source)
|
28
|
+
@i18n_language = lang(source)
|
29
|
+
@i18n_language.lexer(@listener, @force_ruby)
|
30
|
+
end
|
31
|
+
|
32
|
+
def lang(source)
|
33
|
+
line_one = source.split(/\n/)[0]
|
34
|
+
match = LANGUAGE_PATTERN.match(line_one)
|
35
|
+
I18n.get(match ? match[1] : 'en')
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -16,10 +16,6 @@ module Gherkin
|
|
16
16
|
@table = nil
|
17
17
|
end
|
18
18
|
|
19
|
-
def location(feature_uri)
|
20
|
-
@feature_uri = feature_uri
|
21
|
-
end
|
22
|
-
|
23
19
|
def comment(value, line)
|
24
20
|
@comments << Formatter::Model::Comment.new(value, line)
|
25
21
|
end
|
@@ -29,31 +25,31 @@ module Gherkin
|
|
29
25
|
end
|
30
26
|
|
31
27
|
def feature(keyword, name, description, line)
|
32
|
-
@formatter.feature(
|
28
|
+
@formatter.feature(Formatter::Model::Feature.new(grab_comments!, grab_tags!, keyword, name, description, line))
|
33
29
|
end
|
34
30
|
|
35
31
|
def background(keyword, name, description, line)
|
36
|
-
@formatter.background(
|
32
|
+
@formatter.background(Formatter::Model::Background.new(grab_comments!, keyword, name, description, line))
|
37
33
|
end
|
38
34
|
|
39
35
|
def scenario(keyword, name, description, line)
|
40
36
|
replay_step_or_examples
|
41
|
-
@formatter.scenario(
|
37
|
+
@formatter.scenario(Formatter::Model::Scenario.new(grab_comments!, grab_tags!, keyword, name, description, line))
|
42
38
|
end
|
43
39
|
|
44
40
|
def scenario_outline(keyword, name, description, line)
|
45
41
|
replay_step_or_examples
|
46
|
-
@formatter.scenario_outline(
|
42
|
+
@formatter.scenario_outline(Formatter::Model::ScenarioOutline.new(grab_comments!, grab_tags!, keyword, name, description, line))
|
47
43
|
end
|
48
44
|
|
49
45
|
def examples(keyword, name, description, line)
|
50
46
|
replay_step_or_examples
|
51
|
-
@examples_statement =
|
47
|
+
@examples_statement = Formatter::Model::Examples.new(grab_comments!, grab_tags!, keyword, name, description, line)
|
52
48
|
end
|
53
49
|
|
54
50
|
def step(keyword, name, line)
|
55
51
|
replay_step_or_examples
|
56
|
-
@step_statement =
|
52
|
+
@step_statement = Formatter::Model::Step.new(grab_comments!, keyword, name, nil, line)
|
57
53
|
end
|
58
54
|
|
59
55
|
def row(cells, line)
|
@@ -76,10 +72,6 @@ module Gherkin
|
|
76
72
|
|
77
73
|
private
|
78
74
|
|
79
|
-
def statement(comments, tags, keyword, name, description, line)
|
80
|
-
Formatter::Model::Statement.new(comments, tags, keyword, name, description, line)
|
81
|
-
end
|
82
|
-
|
83
75
|
def grab_comments!
|
84
76
|
comments = @comments
|
85
77
|
@comments = []
|
@@ -92,7 +84,7 @@ module Gherkin
|
|
92
84
|
tags
|
93
85
|
end
|
94
86
|
|
95
|
-
def
|
87
|
+
def grab_rows!
|
96
88
|
table = @table
|
97
89
|
@table = nil
|
98
90
|
table
|
@@ -106,12 +98,13 @@ module Gherkin
|
|
106
98
|
|
107
99
|
def replay_step_or_examples
|
108
100
|
if(@step_statement)
|
109
|
-
multiline_arg = grab_py_string! ||
|
110
|
-
@formatter.step(@step_statement
|
101
|
+
@step_statement.multiline_arg = grab_py_string! || grab_rows!
|
102
|
+
@formatter.step(@step_statement)
|
111
103
|
@step_statement = nil
|
112
104
|
end
|
113
105
|
if(@examples_statement)
|
114
|
-
@
|
106
|
+
@examples_statement.rows = grab_rows!
|
107
|
+
@formatter.examples(@examples_statement)
|
115
108
|
@examples_statement = nil
|
116
109
|
end
|
117
110
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'gherkin/i18n'
|
2
|
-
require 'gherkin/i18n_lexer'
|
2
|
+
require 'gherkin/lexer/i18n_lexer'
|
3
3
|
require 'gherkin/native'
|
4
4
|
require 'gherkin/listener/formatter_listener'
|
5
5
|
|
@@ -22,13 +22,12 @@ module Gherkin
|
|
22
22
|
@machine_name = machine_name
|
23
23
|
@machines = []
|
24
24
|
push_machine(@machine_name)
|
25
|
-
@lexer = I18nLexer.new(self, force_ruby)
|
25
|
+
@lexer = Gherkin::Lexer::I18nLexer.new(self, force_ruby)
|
26
26
|
end
|
27
27
|
|
28
28
|
def parse(gherkin, feature_uri, line_offset)
|
29
|
-
@feature_uri
|
29
|
+
@formatter.uri(feature_uri)
|
30
30
|
@line_offset = line_offset
|
31
|
-
@listener.location(feature_uri)
|
32
31
|
@lexer.scan(gherkin)
|
33
32
|
end
|
34
33
|
|
@@ -148,7 +147,7 @@ module Gherkin
|
|
148
147
|
@rows = []
|
149
148
|
end
|
150
149
|
|
151
|
-
def
|
150
|
+
def uri(uri)
|
152
151
|
end
|
153
152
|
|
154
153
|
def row(row, line_number)
|
data/ragel/lexer.c.rl.erb
CHANGED
@@ -57,6 +57,7 @@ typedef struct lexer_state {
|
|
57
57
|
} lexer_state;
|
58
58
|
|
59
59
|
static VALUE mGherkin;
|
60
|
+
static VALUE mGherkinLexer;
|
60
61
|
static VALUE mCLexer;
|
61
62
|
static VALUE cI18nLexer;
|
62
63
|
static VALUE rb_eGherkinLexingError;
|
@@ -442,7 +443,8 @@ static VALUE CLexer_scan(VALUE self, VALUE input)
|
|
442
443
|
void Init_gherkin_lexer_<%= @i18n.underscored_iso_code %>()
|
443
444
|
{
|
444
445
|
mGherkin = rb_define_module("Gherkin");
|
445
|
-
|
446
|
+
mGherkinLexer = rb_define_module_under(mGherkin, "Lexer");
|
447
|
+
rb_eGherkinLexingError = rb_const_get(mGherkinLexer, rb_intern("LexingError"));
|
446
448
|
|
447
449
|
mCLexer = rb_define_module_under(mGherkin, "CLexer");
|
448
450
|
cI18nLexer = rb_define_class_under(mCLexer, "<%= @i18n.underscored_iso_code.capitalize %>", rb_cObject);
|
data/ragel/lexer.java.rl.erb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
package gherkin.lexer;
|
1
|
+
package gherkin.lexer.i18n;
|
2
2
|
|
3
3
|
import java.io.UnsupportedEncodingException;
|
4
4
|
import java.util.List;
|
5
5
|
import java.util.ArrayList;
|
6
6
|
import java.util.regex.Pattern;
|
7
7
|
import java.util.regex.Matcher;
|
8
|
-
import gherkin.Lexer;
|
9
|
-
import gherkin.Listener;
|
10
|
-
import gherkin.LexingError;
|
8
|
+
import gherkin.lexer.Lexer;
|
9
|
+
import gherkin.lexer.Listener;
|
10
|
+
import gherkin.lexer.LexingError;
|
11
11
|
|
12
12
|
public class <%= @i18n.underscored_iso_code.upcase %> implements Lexer {
|
13
13
|
%%{
|
data/ragel/lexer.rb.rl.erb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'gherkin/lexer/i18n_lexer'
|
2
|
+
|
1
3
|
module Gherkin
|
2
4
|
module RbLexer
|
3
5
|
class <%= @i18n.underscored_iso_code.capitalize %> #:nodoc:
|
@@ -113,7 +115,7 @@ module Gherkin
|
|
113
115
|
action end_feature {
|
114
116
|
if cs < lexer_first_final
|
115
117
|
content = current_line_content(data, p)
|
116
|
-
raise LexingError.new("Lexing error on line %d: '%s'. See http://wiki.github.com/aslakhellesoy/gherkin/lexingerror for more information." % [@line_number, content])
|
118
|
+
raise Gherkin::Lexer::LexingError.new("Lexing error on line %d: '%s'. See http://wiki.github.com/aslakhellesoy/gherkin/lexingerror for more information." % [@line_number, content])
|
117
119
|
else
|
118
120
|
@listener.eof
|
119
121
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
{
|
2
|
-
"type": "feature",
|
3
2
|
"name": "Feature Text",
|
4
3
|
"keyword": "Feature",
|
5
4
|
"description": "In order to test multiline forms",
|
@@ -41,11 +40,11 @@
|
|
41
40
|
}
|
42
41
|
],
|
43
42
|
"examples": [
|
44
|
-
{
|
43
|
+
{
|
45
44
|
"name": "Sweet Example",
|
46
45
|
"keyword": "Examples",
|
47
46
|
"description": "",
|
48
|
-
"
|
47
|
+
"rows" : [
|
49
48
|
{"cells" :
|
50
49
|
[ "Fill","In" ]
|
51
50
|
},
|
@@ -35,14 +35,15 @@ module Gherkin
|
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should print comments when scenario is longer" do
|
38
|
-
@l.
|
38
|
+
@l.uri("features/foo.feature")
|
39
|
+
@l.feature(Model::Feature.new([], [], "Feature", "Hello", "World", 1))
|
39
40
|
@l.steps([
|
40
41
|
['Given ', 'some stuff'],
|
41
42
|
['When ', 'foo']
|
42
43
|
])
|
43
|
-
@l.scenario(Model::
|
44
|
-
@l.step(Model::
|
45
|
-
@l.step(Model::
|
44
|
+
@l.scenario(Model::Scenario.new([], [], "Scenario", "The scenario", "", 4))
|
45
|
+
@l.step(Model::Step.new([], "Given ", "some stuff", "", 5, nil, result('passed', nil, nil, "features/step_definitions/bar.rb:56")))
|
46
|
+
@l.step(Model::Step.new([], "When ", "foo", "", 6, nil, result('passed', nil, nil, "features/step_definitions/bar.rb:96")))
|
46
47
|
|
47
48
|
assert_io(%{Feature: Hello
|
48
49
|
World
|
@@ -54,12 +55,13 @@ module Gherkin
|
|
54
55
|
end
|
55
56
|
|
56
57
|
it "should print comments when step is longer" do
|
57
|
-
@l.
|
58
|
+
@l.uri("features/foo.feature")
|
59
|
+
@l.feature(Model::Feature.new([], [], "Feature", "Hello", "World", 1))
|
58
60
|
@l.steps([
|
59
61
|
['Given ', 'some stuff that is longer']
|
60
62
|
])
|
61
|
-
@l.scenario(Model::
|
62
|
-
@l.step(Model::
|
63
|
+
@l.scenario(Model::Scenario.new([], [], "Scenario", "The scenario", "", 4))
|
64
|
+
@l.step(Model::Step.new([], "Given ", "some stuff that is longer", "", 5, nil, result('passed', nil, nil, "features/step_definitions/bar.rb:56")))
|
63
65
|
|
64
66
|
assert_io(%{Feature: Hello
|
65
67
|
World
|
@@ -70,7 +72,8 @@ module Gherkin
|
|
70
72
|
end
|
71
73
|
|
72
74
|
it "should highlight arguments for regular steps" do
|
73
|
-
|
75
|
+
step = Model::Step.new([], "Given ", "I have 999 cukes in my belly", "", 3, nil, result('passed', nil, [Gherkin::Formatter::Argument.new(7, '999')], nil))
|
76
|
+
@l.step(step)
|
74
77
|
assert_io(" Given I have 999 cukes in my belly\n")
|
75
78
|
end
|
76
79
|
|
data/spec/gherkin/i18n_spec.rb
CHANGED
@@ -13,7 +13,7 @@ module Gherkin
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should recognize keywords in the language of the lexer" do
|
16
|
-
lexer = Gherkin::I18nLexer.new(@listener, false)
|
16
|
+
lexer = Gherkin::Lexer::I18nLexer.new(@listener, false)
|
17
17
|
scan_file(lexer, "i18n_no.feature")
|
18
18
|
@listener.to_sexp.should == [
|
19
19
|
[:comment, "#language:no", 1],
|
@@ -27,7 +27,7 @@ module Gherkin
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should parse languages without a space after keywords" do
|
30
|
-
lexer = Gherkin::I18nLexer.new(@listener, false)
|
30
|
+
lexer = Gherkin::Lexer::I18nLexer.new(@listener, false)
|
31
31
|
scan_file(lexer, "i18n_zh-CN.feature")
|
32
32
|
@listener.to_sexp.should == [
|
33
33
|
[:comment, "#language:zh-CN", 1],
|
@@ -42,7 +42,7 @@ module Gherkin
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should parse languages with spaces after some keywords but not others" do
|
45
|
-
lexer = Gherkin::I18nLexer.new(@listener, false)
|
45
|
+
lexer = Gherkin::Lexer::I18nLexer.new(@listener, false)
|
46
46
|
scan_file(lexer, "i18n_fr.feature")
|
47
47
|
@listener.to_sexp.should == [
|
48
48
|
[:comment, "#language:fr", 1],
|
@@ -1,91 +1,67 @@
|
|
1
1
|
#encoding: utf-8
|
2
|
+
require 'ap'
|
2
3
|
require 'spec_helper'
|
3
4
|
require 'gherkin/json_parser'
|
5
|
+
require 'gherkin/formatter/json_formatter'
|
4
6
|
|
5
7
|
module Gherkin
|
6
8
|
describe JSONParser do
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def check_json(json)
|
11
|
+
io = StringIO.new
|
12
|
+
f = Formatter::JSONFormatter.new(io)
|
13
|
+
p = JSONParser.new(f)
|
14
|
+
p.parse(json, 'unknown.json')
|
15
|
+
expected = JSON.parse(json)
|
16
|
+
actual = JSON.parse(io.string)
|
12
17
|
|
13
|
-
|
14
|
-
it "should scan empty features" do
|
15
|
-
@parser.parse_with_listener('{}', @listener)
|
16
|
-
@listener.to_sexp.should == [
|
17
|
-
[:location, "unknown.json"],
|
18
|
-
[:eof]
|
19
|
-
]
|
20
|
-
end
|
18
|
+
actual.should == expected
|
21
19
|
end
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
]
|
31
|
-
end
|
21
|
+
it "should parse a barely empty feature" do
|
22
|
+
check_json(%{{
|
23
|
+
"keyword": "Feature",
|
24
|
+
"name": "One",
|
25
|
+
"description": "",
|
26
|
+
"line" : 3
|
27
|
+
}})
|
32
28
|
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
it "should parse feature with tags and one scenario" do
|
31
|
+
check_json(%{{
|
32
|
+
"tags": [
|
33
|
+
{
|
34
|
+
"name": "@foo",
|
35
|
+
"line": 22
|
36
|
+
}
|
37
|
+
],
|
38
|
+
"keyword": "Feature",
|
39
|
+
"name": "One",
|
40
|
+
"description": "",
|
41
|
+
"line": 3,
|
42
|
+
"elements": [
|
43
|
+
{
|
44
|
+
"type": "scenario",
|
45
|
+
"steps": [
|
46
|
+
{
|
47
|
+
"name": "Hello",
|
48
|
+
"multiline_arg": {
|
49
|
+
"type": "table",
|
50
|
+
"value": [
|
51
|
+
{
|
52
|
+
"cells": ["foo", "bar"]
|
53
|
+
}
|
54
|
+
]
|
55
|
+
}
|
56
|
+
}
|
57
|
+
]
|
58
|
+
}
|
41
59
|
]
|
42
|
-
|
60
|
+
}})
|
43
61
|
end
|
44
62
|
|
45
|
-
|
46
|
-
|
47
|
-
@parser.parse_with_listener(fixture("complex.json"), @listener)
|
48
|
-
@listener.to_sexp.should == [
|
49
|
-
[:location, "unknown.json"],
|
50
|
-
[:tag, "@tag1", nil],
|
51
|
-
[:tag, "@tag2", nil],
|
52
|
-
[:feature, "Feature", "Feature Text","In order to test multiline forms", nil],
|
53
|
-
[:background, "Background", "", "", nil],
|
54
|
-
[:step, "Given ", "this is a background step", nil],
|
55
|
-
[:step, "When ", "this is another one", 412],
|
56
|
-
[:tag, "@foo", nil],
|
57
|
-
[:scenario_outline, "Scenario Outline", "An Scenario Outline","", nil],
|
58
|
-
[:step, "Given ", "A step with a table", nil],
|
59
|
-
[:row, %w{a row for a step}, nil],
|
60
|
-
[:tag, "@exampletag", nil],
|
61
|
-
[:examples, "Examples", "Sweet Example", "", nil],
|
62
|
-
[:row, %w{Fill In}, nil],
|
63
|
-
[:row, %w{The Blanks}, nil],
|
64
|
-
[:tag, "@tag3", nil],
|
65
|
-
[:tag, "@tag4", nil],
|
66
|
-
[:scenario, "Scenario", "Reading a Scenario", "", nil],
|
67
|
-
[:step, "Given ", "there is a step", nil],
|
68
|
-
[:step, "But ", "not another step", nil],
|
69
|
-
[:tag, "@tag3", nil],
|
70
|
-
[:scenario, "Scenario", "Reading a second scenario", "With two lines of text", nil],
|
71
|
-
[:step, "Given ", "a third step with a table", nil],
|
72
|
-
[:row, %w{a b}, 987],
|
73
|
-
[:row, %w{c d}, nil],
|
74
|
-
[:row, %w{e f}, nil],
|
75
|
-
[:step, "Given ", "I am still testing things", nil],
|
76
|
-
[:row, %w{g h}, nil],
|
77
|
-
[:row, %w{e r}, nil],
|
78
|
-
[:row, %w{k i}, nil],
|
79
|
-
[:row, ['n', ''], nil],
|
80
|
-
[:step, "Given ", "I am done testing these tables", nil],
|
81
|
-
[:step, "Given ", "I am happy", nil],
|
82
|
-
[:scenario, "Scenario", "Hammerzeit", "", nil],
|
83
|
-
[:step, "Given ", "All work and no play", nil],
|
84
|
-
[:py_string, "Makes Homer something something\nAnd something else", 777],
|
85
|
-
[:step, "Given ", "crazy", nil],
|
86
|
-
[:eof]
|
87
|
-
]
|
88
|
-
end
|
63
|
+
it "shoud parse a complex feature" do
|
64
|
+
check_json(fixture("complex.json"))
|
89
65
|
end
|
90
66
|
end
|
91
67
|
end
|