gherkin 2.0.2-i386-mswin32 → 2.1.0-i386-mswin32
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.
- 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 +33 -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
data/lib/gherkin/i18n.yml
CHANGED
@@ -144,6 +144,19 @@
|
|
144
144
|
then: "*|DEN"
|
145
145
|
and: "*|AN"
|
146
146
|
but: "*|BUT"
|
147
|
+
"en-pirate":
|
148
|
+
name: Pirate
|
149
|
+
native: Pirate
|
150
|
+
feature: Ahoy matey!
|
151
|
+
background: Yo-ho-ho
|
152
|
+
scenario: Heave to
|
153
|
+
scenario_outline: Shiver me timbers
|
154
|
+
examples: Dead men tell no tales
|
155
|
+
given: "*|Gangway!"
|
156
|
+
when: "*|Blimey!"
|
157
|
+
then: "*|Let go and haul"
|
158
|
+
and: "*|Aye"
|
159
|
+
but: "*|Avast!"
|
147
160
|
"en-Scouse":
|
148
161
|
name: Scouse
|
149
162
|
native: Scouse
|
data/lib/gherkin/i18n_lexer.rb
CHANGED
@@ -1,13 +1,27 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'gherkin/listener/formatter_listener'
|
2
3
|
|
3
4
|
module Gherkin
|
4
|
-
class
|
5
|
+
class JSONParser
|
5
6
|
|
6
|
-
def initialize(
|
7
|
+
def initialize(formatter)
|
8
|
+
@formatter = formatter
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(src, feature_uri='unknown.json', line_offset=0)
|
12
|
+
@listener = Listener::FormatterListener.new(@formatter)
|
13
|
+
_parse(src, feature_uri, line_offset)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_with_listener(src, listener)
|
7
17
|
@listener = listener
|
18
|
+
_parse(src, 'unknown.json', 0)
|
8
19
|
end
|
9
20
|
|
10
|
-
|
21
|
+
private
|
22
|
+
|
23
|
+
def _parse(src, feature_uri, line_offset)
|
24
|
+
@listener.location(feature_uri)
|
11
25
|
feature = JSON.parse(src)
|
12
26
|
|
13
27
|
comments_for(feature)
|
@@ -27,8 +41,6 @@ module Gherkin
|
|
27
41
|
@listener.eof
|
28
42
|
end
|
29
43
|
|
30
|
-
private
|
31
|
-
|
32
44
|
def parse_element(feature_element)
|
33
45
|
comments_for(feature_element)
|
34
46
|
tags_for(feature_element)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'gherkin/native'
|
2
|
-
require 'gherkin/
|
2
|
+
require 'gherkin/formatter/model'
|
3
3
|
|
4
4
|
module Gherkin
|
5
|
-
module
|
5
|
+
module Listener
|
6
6
|
# Adapter from the "raw" Gherkin <tt>Listener</tt> API
|
7
7
|
# to the slightly more high-level <tt>Formatter</tt> API,
|
8
8
|
# which is easier to implement (less state to keep track of).
|
@@ -16,54 +16,53 @@ module Gherkin
|
|
16
16
|
@table = nil
|
17
17
|
end
|
18
18
|
|
19
|
-
def location(
|
20
|
-
@
|
21
|
-
@offset = offset
|
19
|
+
def location(feature_uri)
|
20
|
+
@feature_uri = feature_uri
|
22
21
|
end
|
23
22
|
|
24
|
-
def comment(
|
25
|
-
@comments <<
|
23
|
+
def comment(value, line)
|
24
|
+
@comments << Formatter::Model::Comment.new(value, line)
|
26
25
|
end
|
27
26
|
|
28
27
|
def tag(name, line)
|
29
|
-
@tags << name
|
28
|
+
@tags << Formatter::Model::Tag.new(name, line)
|
30
29
|
end
|
31
30
|
|
32
31
|
def feature(keyword, name, description, line)
|
33
|
-
@formatter.feature(grab_comments!, grab_tags!, keyword, name, description, @
|
32
|
+
@formatter.feature(statement(grab_comments!, grab_tags!, keyword, name, description, line), @feature_uri)
|
34
33
|
end
|
35
34
|
|
36
35
|
def background(keyword, name, description, line)
|
37
|
-
@formatter.background(grab_comments!, keyword, name, description, line)
|
36
|
+
@formatter.background(statement(grab_comments!, [], keyword, name, description, line))
|
38
37
|
end
|
39
38
|
|
40
39
|
def scenario(keyword, name, description, line)
|
41
40
|
replay_step_or_examples
|
42
|
-
@formatter.scenario(grab_comments!, grab_tags!, keyword, name, description, line)
|
41
|
+
@formatter.scenario(statement(grab_comments!, grab_tags!, keyword, name, description, line))
|
43
42
|
end
|
44
43
|
|
45
44
|
def scenario_outline(keyword, name, description, line)
|
46
45
|
replay_step_or_examples
|
47
|
-
@formatter.scenario_outline(grab_comments!, grab_tags!, keyword, name, description, line)
|
46
|
+
@formatter.scenario_outline(statement(grab_comments!, grab_tags!, keyword, name, description, line))
|
48
47
|
end
|
49
48
|
|
50
49
|
def examples(keyword, name, description, line)
|
51
50
|
replay_step_or_examples
|
52
|
-
@
|
51
|
+
@examples_statement = statement(grab_comments!, grab_tags!, keyword, name, description, line)
|
53
52
|
end
|
54
53
|
|
55
54
|
def step(keyword, name, line)
|
56
55
|
replay_step_or_examples
|
57
|
-
@
|
56
|
+
@step_statement = statement(grab_comments!, [], keyword, name, nil, line)
|
58
57
|
end
|
59
58
|
|
60
59
|
def row(cells, line)
|
61
60
|
@table ||= []
|
62
|
-
@table << Row.new(cells,
|
61
|
+
@table << Formatter::Model::Row.new(grab_comments!, cells, line)
|
63
62
|
end
|
64
63
|
|
65
|
-
def py_string(
|
66
|
-
@py_string =
|
64
|
+
def py_string(string, line)
|
65
|
+
@py_string = Formatter::Model::PyString.new(string, line)
|
67
66
|
end
|
68
67
|
|
69
68
|
def eof
|
@@ -71,8 +70,16 @@ module Gherkin
|
|
71
70
|
@formatter.eof
|
72
71
|
end
|
73
72
|
|
73
|
+
def syntax_error(state, ev, legal_events, uri, line)
|
74
|
+
@formatter.syntax_error(state, ev, legal_events, uri, line)
|
75
|
+
end
|
76
|
+
|
74
77
|
private
|
75
78
|
|
79
|
+
def statement(comments, tags, keyword, name, description, line)
|
80
|
+
Formatter::Model::Statement.new(comments, tags, keyword, name, description, line)
|
81
|
+
end
|
82
|
+
|
76
83
|
def grab_comments!
|
77
84
|
comments = @comments
|
78
85
|
@comments = []
|
@@ -98,14 +105,14 @@ module Gherkin
|
|
98
105
|
end
|
99
106
|
|
100
107
|
def replay_step_or_examples
|
101
|
-
if(@
|
108
|
+
if(@step_statement)
|
102
109
|
multiline_arg = grab_py_string! || grab_table!
|
103
|
-
@formatter.step(
|
104
|
-
@
|
110
|
+
@formatter.step(@step_statement, multiline_arg, nil)
|
111
|
+
@step_statement = nil
|
105
112
|
end
|
106
|
-
if(@
|
107
|
-
@formatter.examples(
|
108
|
-
@
|
113
|
+
if(@examples_statement)
|
114
|
+
@formatter.examples(@examples_statement, grab_table!)
|
115
|
+
@examples_statement = nil
|
109
116
|
end
|
110
117
|
end
|
111
118
|
end
|
data/lib/gherkin/native/java.rb
CHANGED
@@ -26,7 +26,15 @@ class Class
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def new(*args)
|
29
|
-
|
29
|
+
begin
|
30
|
+
java_class.new(*javaify(args))
|
31
|
+
rescue ArgumentError => e
|
32
|
+
e.message << "\n#{java_class.name}"
|
33
|
+
raise e
|
34
|
+
rescue NameError => e
|
35
|
+
e.message << "\n args: #{args.inspect}"
|
36
|
+
raise e
|
37
|
+
end
|
30
38
|
end
|
31
39
|
|
32
40
|
def ===(object)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'gherkin/native'
|
2
|
+
require 'gherkin/listener/formatter_listener'
|
2
3
|
|
3
4
|
module Gherkin
|
4
5
|
module Parser
|
@@ -12,24 +13,36 @@ module Gherkin
|
|
12
13
|
native_impl('gherkin')
|
13
14
|
|
14
15
|
# Initialize the parser. +machine_name+ refers to a state machine table.
|
15
|
-
def initialize(
|
16
|
-
@
|
16
|
+
def initialize(formatter, raise_on_error=true, machine_name='root', force_ruby=false)
|
17
|
+
@formatter = formatter
|
18
|
+
@listener = Listener::FormatterListener.new(@formatter)
|
17
19
|
@raise_on_error = raise_on_error
|
18
|
-
@machines = []
|
19
20
|
@machine_name = machine_name
|
21
|
+
@machines = []
|
20
22
|
push_machine(@machine_name)
|
23
|
+
@lexer = I18nLexer.new(self, force_ruby)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(gherkin, feature_uri, line_offset)
|
27
|
+
@feature_uri = feature_uri
|
28
|
+
@line_offset = line_offset
|
29
|
+
@listener.location(feature_uri)
|
30
|
+
@lexer.scan(gherkin)
|
21
31
|
end
|
22
32
|
|
23
|
-
def
|
24
|
-
@
|
33
|
+
def i18n_language
|
34
|
+
@lexer.i18n_language
|
35
|
+
end
|
36
|
+
|
37
|
+
def errors
|
38
|
+
@lexer.errors
|
25
39
|
end
|
26
40
|
|
27
41
|
# Doesn't yet fall back to super
|
28
42
|
def method_missing(method, *args)
|
29
43
|
# TODO: Catch exception and call super
|
30
|
-
|
31
|
-
|
32
|
-
end
|
44
|
+
event(method.to_s, args[-1])
|
45
|
+
@listener.__send__(method, *args)
|
33
46
|
if method == :eof
|
34
47
|
pop_machine
|
35
48
|
push_machine(@machine_name)
|
@@ -37,15 +50,15 @@ module Gherkin
|
|
37
50
|
end
|
38
51
|
|
39
52
|
def event(ev, line)
|
40
|
-
|
53
|
+
l = line ? @line_offset+line : nil
|
54
|
+
machine.event(ev, l) do |state, legal_events|
|
41
55
|
if @raise_on_error
|
42
|
-
raise ParseError.new(state, ev,
|
56
|
+
raise ParseError.new(state, ev, legal_events, @feature_uri, l)
|
43
57
|
else
|
44
|
-
|
45
|
-
|
58
|
+
# Only used for testing
|
59
|
+
@listener.syntax_error(state, ev, legal_events, @feature_uri, l)
|
46
60
|
end
|
47
61
|
end
|
48
|
-
true
|
49
62
|
end
|
50
63
|
|
51
64
|
def push_machine(name)
|
@@ -122,7 +135,7 @@ module Gherkin
|
|
122
135
|
state_machine_reader = StateMachineReader.new
|
123
136
|
lexer = Gherkin::I18n.new('en').lexer(state_machine_reader)
|
124
137
|
machine = File.dirname(__FILE__) + "/#{name}.txt"
|
125
|
-
lexer.scan(File.read(machine)
|
138
|
+
lexer.scan(File.read(machine))
|
126
139
|
state_machine_reader.rows
|
127
140
|
end
|
128
141
|
|
data/lib/gherkin/rubify.rb
CHANGED
@@ -5,8 +5,12 @@ module Gherkin
|
|
5
5
|
# This is especially important to convert java.util.List coming
|
6
6
|
# from Java and back to a Ruby Array.
|
7
7
|
def rubify(o)
|
8
|
-
|
8
|
+
case(o)
|
9
|
+
when Java.java.util.Collection, Array
|
9
10
|
o.map{|e| rubify(e)}
|
11
|
+
when Java.gherkin.formatter.model.PyString
|
12
|
+
require 'gherkin/formatter/model'
|
13
|
+
Formatter::Model::PyString.new(o.value, o.line)
|
10
14
|
else
|
11
15
|
o
|
12
16
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'gherkin/native'
|
2
|
+
|
3
|
+
module Gherkin
|
4
|
+
class TagExpression
|
5
|
+
native_impl('gherkin')
|
6
|
+
|
7
|
+
attr_reader :limits
|
8
|
+
|
9
|
+
def initialize(tag_expressions)
|
10
|
+
@ands = []
|
11
|
+
@limits = {}
|
12
|
+
tag_expressions.each do |expr|
|
13
|
+
add(expr.strip.split(/\s*,\s*/))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
@ands.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def eval(tags)
|
22
|
+
return true if @ands.flatten.empty?
|
23
|
+
vars = Hash[*tags.map{|tag| [tag, true]}.flatten]
|
24
|
+
!!Kernel.eval(ruby_expression)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def add(tags_with_negation_and_limits)
|
30
|
+
negatives, positives = tags_with_negation_and_limits.partition{|tag| tag =~ /^~/}
|
31
|
+
@ands << (store_and_extract_limits(negatives, true) + store_and_extract_limits(positives, false))
|
32
|
+
end
|
33
|
+
|
34
|
+
def store_and_extract_limits(tags_with_negation_and_limits, negated)
|
35
|
+
tags_with_negation = []
|
36
|
+
tags_with_negation_and_limits.each do |tag_with_negation_and_limit|
|
37
|
+
tag_with_negation, limit = tag_with_negation_and_limit.split(':')
|
38
|
+
tags_with_negation << tag_with_negation
|
39
|
+
if limit
|
40
|
+
tag_without_negation = negated ? tag_with_negation[1..-1] : tag_with_negation
|
41
|
+
if @limits[tag_without_negation] && @limits[tag_without_negation] != limit.to_i
|
42
|
+
raise "Inconsistent tag limits for #{tag_without_negation}: #{@limits[tag_without_negation]} and #{limit.to_i}"
|
43
|
+
end
|
44
|
+
@limits[tag_without_negation] = limit.to_i
|
45
|
+
end
|
46
|
+
end
|
47
|
+
tags_with_negation
|
48
|
+
end
|
49
|
+
|
50
|
+
def ruby_expression
|
51
|
+
"(" + @ands.map do |ors|
|
52
|
+
ors.map do |tag|
|
53
|
+
if tag =~ /^~(.*)/
|
54
|
+
"!vars['#{$1}']"
|
55
|
+
else
|
56
|
+
"vars['#{tag}']"
|
57
|
+
end
|
58
|
+
end.join("||")
|
59
|
+
end.join(")&&(") + ")"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/gherkin/tools/files.rb
CHANGED
@@ -20,11 +20,10 @@ module Gherkin
|
|
20
20
|
Dir[*globs].uniq.sort.each(&proc)
|
21
21
|
end
|
22
22
|
|
23
|
-
def scan(file,
|
24
|
-
parser = Gherkin::Parser::Parser.new(
|
25
|
-
lexer = Gherkin::I18nLexer.new(parser, false)
|
23
|
+
def scan(file, formatter)
|
24
|
+
parser = Gherkin::Parser::Parser.new(formatter, true, "root")
|
26
25
|
begin
|
27
|
-
|
26
|
+
parser.parse(IO.read(file), file, 0)
|
28
27
|
rescue => e
|
29
28
|
e.message << " (#{file})"
|
30
29
|
raise e
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'stringio'
|
2
2
|
require 'gherkin/tools/files'
|
3
3
|
require 'gherkin/formatter/pretty_formatter'
|
4
|
-
require 'gherkin/
|
4
|
+
require 'gherkin/listener/formatter_listener'
|
5
5
|
|
6
6
|
module Gherkin
|
7
7
|
module Tools
|
@@ -10,7 +10,7 @@ module Gherkin
|
|
10
10
|
each do |file|
|
11
11
|
io = defined?(JRUBY_VERSION) ? Java.java.io.StringWriter.new : StringIO.new
|
12
12
|
formatter = Formatter::PrettyFormatter.new(io, true)
|
13
|
-
listener =
|
13
|
+
listener = Listener::FormatterListener.new(formatter)
|
14
14
|
scan(file, listener)
|
15
15
|
string = defined?(JRUBY_VERSION) ? io.getBuffer.toString : io.string
|
16
16
|
File.open(file, 'w') {|io| io.write(string)}
|
data/lib/gherkin/tools/stats.rb
CHANGED
@@ -6,11 +6,10 @@ module Gherkin
|
|
6
6
|
module Tools
|
7
7
|
class Stats < Files
|
8
8
|
def run
|
9
|
-
|
9
|
+
formatter = StatsFormatter.new
|
10
10
|
each do |f|
|
11
|
-
parser = Gherkin::Parser::Parser.new(
|
12
|
-
|
13
|
-
lexer.scan(IO.read(f), f, 0)
|
11
|
+
parser = Gherkin::Parser::Parser.new(formatter, true)
|
12
|
+
parser.parse(IO.read(f), f, 0)
|
14
13
|
end
|
15
14
|
puts "Features: #{listener.features}"
|
16
15
|
puts "Scenarios: #{listener.scenarios}"
|
data/ragel/lexer.c.rl.erb
CHANGED
@@ -389,10 +389,9 @@ static VALUE CLexer_init(VALUE self, VALUE listener)
|
|
389
389
|
return self;
|
390
390
|
}
|
391
391
|
|
392
|
-
static VALUE CLexer_scan(VALUE self, VALUE input
|
392
|
+
static VALUE CLexer_scan(VALUE self, VALUE input)
|
393
393
|
{
|
394
394
|
VALUE listener = rb_iv_get(self, "@listener");
|
395
|
-
rb_funcall(listener, rb_intern("location"), 2, uri, offset);
|
396
395
|
|
397
396
|
lexer_state *lexer = NULL;
|
398
397
|
DATA_GET(self, lexer_state, lexer);
|
@@ -449,6 +448,6 @@ void Init_gherkin_lexer_<%= @i18n.underscored_iso_code %>()
|
|
449
448
|
cI18nLexer = rb_define_class_under(mCLexer, "<%= @i18n.underscored_iso_code.capitalize %>", rb_cObject);
|
450
449
|
rb_define_alloc_func(cI18nLexer, CLexer_alloc);
|
451
450
|
rb_define_method(cI18nLexer, "initialize", CLexer_init, 1);
|
452
|
-
rb_define_method(cI18nLexer, "scan", CLexer_scan,
|
451
|
+
rb_define_method(cI18nLexer, "scan", CLexer_scan, 1);
|
453
452
|
}
|
454
453
|
|