gherkin 2.1.5 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/History.txt +16 -0
  2. data/README.rdoc +1 -0
  3. data/Rakefile +1 -1
  4. data/VERSION.yml +2 -2
  5. data/features/json_formatter.feature +3 -11
  6. data/features/json_parser.feature +2 -5
  7. data/features/step_definitions/json_lexer_steps.rb +1 -1
  8. data/features/step_definitions/pretty_formatter_steps.rb +1 -1
  9. data/features/support/env.rb +2 -1
  10. data/java/src/main/java/gherkin/lexer/{.gitignore → i18n/.gitignore} +0 -0
  11. data/json-simple-1.1.dll +0 -0
  12. data/lib/gherkin.rb +1 -1
  13. data/lib/gherkin/formatter/filter_formatter.rb +52 -61
  14. data/lib/gherkin/formatter/json_formatter.rb +26 -94
  15. data/lib/gherkin/formatter/line_filter.rb +3 -3
  16. data/lib/gherkin/formatter/model.rb +156 -19
  17. data/lib/gherkin/formatter/pretty_formatter.rb +25 -25
  18. data/lib/gherkin/formatter/regexp_filter.rb +5 -1
  19. data/lib/gherkin/formatter/tag_count_formatter.rb +15 -12
  20. data/lib/gherkin/formatter/tag_filter.rb +19 -0
  21. data/lib/gherkin/json_parser.rb +49 -65
  22. data/lib/gherkin/lexer/i18n_lexer.rb +40 -0
  23. data/lib/gherkin/listener/formatter_listener.rb +11 -18
  24. data/lib/gherkin/parser/parser.rb +4 -5
  25. data/lib/gherkin/tools/stats_listener.rb +1 -1
  26. data/ragel/lexer.c.rl.erb +3 -1
  27. data/ragel/lexer.java.rl.erb +4 -4
  28. data/ragel/lexer.rb.rl.erb +3 -1
  29. data/spec/gherkin/fixtures/complex.json +2 -3
  30. data/spec/gherkin/formatter/model_spec.rb +1 -1
  31. data/spec/gherkin/formatter/pretty_formatter_spec.rb +11 -8
  32. data/spec/gherkin/i18n_spec.rb +3 -3
  33. data/spec/gherkin/java_lexer_spec.rb +1 -1
  34. data/spec/gherkin/json.rb +5 -0
  35. data/spec/gherkin/json_parser_spec.rb +49 -73
  36. data/spec/gherkin/lexer/i18n_lexer_spec.rb +33 -0
  37. data/spec/gherkin/sexp_recorder.rb +0 -2
  38. data/spec/spec_helper.rb +1 -0
  39. data/tasks/bench.rake +2 -2
  40. data/tasks/compile.rake +1 -1
  41. data/tasks/ikvm.rake +3 -1
  42. data/tasks/ragel_task.rb +1 -1
  43. data/tasks/release.rake +13 -1
  44. data/tasks/rspec.rake +0 -1
  45. metadata +17 -13
  46. data/lib/gherkin/i18n_lexer.rb +0 -38
  47. data/spec/gherkin/i18n_lexer_spec.rb +0 -26
@@ -5,9 +5,9 @@ module Gherkin
5
5
  @lines = lines
6
6
  end
7
7
 
8
- def eval(ranges)
9
- @lines.detect do |line|
10
- ranges.detect do |range|
8
+ def eval(tags, names, ranges)
9
+ ranges.detect do |range|
10
+ @lines.detect do |line|
11
11
  range.include?(line)
12
12
  end
13
13
  end
@@ -3,7 +3,159 @@ require 'gherkin/native'
3
3
  module Gherkin
4
4
  module Formatter
5
5
  module Model
6
- class Comment
6
+ class Hashable
7
+ def to_hash
8
+ instance_variables.inject({}) do |hash, ivar|
9
+ value = instance_variable_get(ivar)
10
+ value = value.to_hash if value.respond_to?(:to_hash)
11
+ if Array === value
12
+ value = value.map do |e|
13
+ e.respond_to?(:to_hash) ? e.to_hash : e
14
+ end
15
+ end
16
+ hash[ivar[1..-1]] = value unless [[], nil].index(value)
17
+ hash
18
+ end
19
+ end
20
+ end
21
+
22
+ class BasicStatement < Hashable
23
+ attr_reader :comments, :keyword, :name, :description, :line
24
+
25
+ def initialize(comments, keyword, name, description, line)
26
+ @comments, @keyword, @name, @description, @line = comments, keyword, name, description, line
27
+ end
28
+
29
+ def line_range
30
+ first = @comments.any? ? @comments[0].line : first_non_comment_line
31
+ first..line
32
+ end
33
+
34
+ def first_non_comment_line
35
+ @line
36
+ end
37
+ end
38
+
39
+ class TagStatement < BasicStatement
40
+ attr_reader :tags
41
+
42
+ def initialize(comments, tags, keyword, name, description, line)
43
+ super(comments, keyword, name, description, line)
44
+ @tags = tags
45
+ end
46
+
47
+ def first_non_comment_line
48
+ @tags.any? ? @tags[0].line : @line
49
+ end
50
+ end
51
+
52
+ class Feature < TagStatement
53
+ native_impl('gherkin')
54
+
55
+ def initialize(comments, tags, keyword, name, description, line)
56
+ super(comments, tags, keyword, name, description, line)
57
+ end
58
+
59
+ def replay(formatter)
60
+ formatter.feature(self)
61
+ end
62
+ end
63
+
64
+ class Background < BasicStatement
65
+ native_impl('gherkin')
66
+
67
+ def initialize(comments, keyword, name, description, line)
68
+ super(comments, keyword, name, description, line)
69
+ @type = "background"
70
+ end
71
+
72
+ def replay(formatter)
73
+ formatter.background(self)
74
+ end
75
+ end
76
+
77
+ class Scenario < TagStatement
78
+ native_impl('gherkin')
79
+
80
+ def initialize(comments, tags, keyword, name, description, line)
81
+ super(comments, tags, keyword, name, description, line)
82
+ @type = "scenario"
83
+ end
84
+
85
+ def replay(formatter)
86
+ formatter.scenario(self)
87
+ end
88
+ end
89
+
90
+ class ScenarioOutline < TagStatement
91
+ native_impl('gherkin')
92
+
93
+ def initialize(comments, tags, keyword, name, description, line)
94
+ super(comments, tags, keyword, name, description, line)
95
+ @type = "scenario_outline"
96
+ end
97
+
98
+ def replay(formatter)
99
+ formatter.scenario_outline(self)
100
+ end
101
+ end
102
+
103
+ class Examples < TagStatement
104
+ native_impl('gherkin')
105
+
106
+ attr_accessor :rows
107
+
108
+ def initialize(comments, tags, keyword, name, description, line, rows=nil)
109
+ super(comments, tags, keyword, name, description, line)
110
+ @rows = rows
111
+ end
112
+
113
+ def replay(formatter)
114
+ formatter.examples(self)
115
+ end
116
+ end
117
+
118
+ class Step < BasicStatement
119
+ native_impl('gherkin')
120
+
121
+ attr_accessor :multiline_arg, :result
122
+
123
+ def initialize(comments, keyword, name, description, line, multiline_arg=nil, result=nil)
124
+ super(comments, keyword, name, nil, line)
125
+ @multiline_arg = multiline_arg
126
+ @result = result
127
+ end
128
+
129
+ def line_range
130
+ range = super
131
+ case multiline_arg
132
+ when Array
133
+ range = range.first..multiline_arg[-1].line
134
+ when Model::PyString
135
+ range = range.first..multiline_arg.line_range.last
136
+ end
137
+ range
138
+ end
139
+
140
+ def replay(formatter)
141
+ formatter.step(self)
142
+ end
143
+
144
+ def to_hash
145
+ hash = super
146
+ if Array === @multiline_arg
147
+ hash['multiline_arg'] = {
148
+ 'type' => 'table',
149
+ 'value' => hash['multiline_arg']
150
+ }
151
+ elsif PyString === @multiline_arg
152
+ hash['multiline_arg']['type'] = 'py_string'
153
+ end
154
+ hash
155
+ end
156
+ end
157
+
158
+ class Comment < Hashable
7
159
  native_impl('gherkin')
8
160
 
9
161
  attr_reader :value, :line
@@ -13,7 +165,7 @@ module Gherkin
13
165
  end
14
166
  end
15
167
 
16
- class Tag
168
+ class Tag < Hashable
17
169
  native_impl('gherkin')
18
170
 
19
171
  attr_reader :name, :line
@@ -31,7 +183,7 @@ module Gherkin
31
183
  end
32
184
  end
33
185
 
34
- class PyString
186
+ class PyString < Hashable
35
187
  native_impl('gherkin')
36
188
 
37
189
  attr_reader :value, :line
@@ -46,7 +198,7 @@ module Gherkin
46
198
  end
47
199
  end
48
200
 
49
- class Row
201
+ class Row < Hashable
50
202
  native_impl('gherkin')
51
203
 
52
204
  attr_reader :comments, :cells, :line
@@ -56,21 +208,6 @@ module Gherkin
56
208
  end
57
209
  end
58
210
 
59
- class Statement
60
- native_impl('gherkin')
61
-
62
- attr_reader :comments, :tags, :keyword, :name, :description, :line
63
-
64
- def initialize(comments, tags, keyword, name, description, line)
65
- @comments, @tags, @keyword, @name, @description, @line = comments, tags, keyword, name, description, line
66
- end
67
-
68
- def line_range
69
- first = @comments[0] ? @comments[0].line : (@tags[0] ? @tags[0].line : line)
70
- first..line
71
- end
72
- end
73
-
74
211
  class Result
75
212
  native_impl('gherkin')
76
213
 
@@ -20,12 +20,15 @@ module Gherkin
20
20
  @format = MonochromeFormat.new #@monochrome ? MonochromeFormat.new : AnsiColorFormat.new
21
21
  end
22
22
 
23
- def feature(statement, uri)
23
+ def uri(uri)
24
24
  @uri = uri
25
- print_comments(statement.comments, '')
26
- print_tags(statement.tags, '')
27
- @io.puts "#{statement.keyword}: #{statement.name}"
28
- print_description(statement.description, ' ', false)
25
+ end
26
+
27
+ def feature(feature)
28
+ print_comments(feature.comments, '')
29
+ print_tags(feature.tags, '')
30
+ @io.puts "#{feature.keyword}: #{feature.name}"
31
+ print_description(feature.description, ' ', false)
29
32
  end
30
33
 
31
34
  def background(statement)
@@ -43,35 +46,32 @@ module Gherkin
43
46
  print_description(statement.description, ' ')
44
47
  end
45
48
 
46
- def scenario_outline(statement)
47
- scenario(statement)
49
+ def scenario_outline(scenario_outline)
50
+ scenario(scenario_outline)
48
51
  end
49
52
 
50
- def examples(statement, examples_rows)
53
+ def examples(examples)
51
54
  @io.puts
52
- print_comments(statement.comments, ' ')
53
- print_tags(statement.tags, ' ')
54
- @io.puts " #{statement.keyword}: #{statement.name}"
55
- print_description(statement.description, ' ')
56
- table(examples_rows)
55
+ print_comments(examples.comments, ' ')
56
+ print_tags(examples.tags, ' ')
57
+ @io.puts " #{examples.keyword}: #{examples.name}"
58
+ print_description(examples.description, ' ')
59
+ table(examples.rows)
57
60
  end
58
61
 
59
- def step(statement, multiline_arg, result)
60
- name = Gherkin::Formatter::Argument.format(statement.name, @format, (result ? result.arguments : []))
62
+ def step(step)
63
+ name = Gherkin::Formatter::Argument.format(step.name, @format, (step.result ? step.result.arguments : []))
61
64
 
62
- step = "#{statement.keyword}#{statement.name}"
63
- step = self.__send__(result.status, step, @monochrome) if result
65
+ step_text = "#{step.keyword}#{step.name}"
66
+ step_text = self.__send__(step.result.status, step_text, @monochrome) if step.result
64
67
 
65
- print_comments(statement.comments, ' ')
66
- @io.puts(" #{step}#{indented_step_location!(result ? result.stepdef_location : nil)}")
67
- case multiline_arg
68
+ print_comments(step.comments, ' ')
69
+ @io.puts(" #{step_text}#{indented_step_location!(step.result ? step.result.stepdef_location : nil)}")
70
+ case step.multiline_arg
68
71
  when Model::PyString
69
- py_string(multiline_arg)
72
+ py_string(step.multiline_arg)
70
73
  when Array
71
- table(multiline_arg)
72
- when NilClass
73
- else
74
- raise "Bad multiline_arg: #{multiline_arg.inspect}"
74
+ table(step.multiline_arg)
75
75
  end
76
76
  end
77
77
 
@@ -5,13 +5,17 @@ module Gherkin
5
5
  @regexen = regexen
6
6
  end
7
7
 
8
- def eval(names)
8
+ def eval(tags, names, ranges)
9
9
  @regexen.detect do |regexp|
10
10
  names.detect do |name|
11
11
  name =~ regexp
12
12
  end
13
13
  end
14
14
  end
15
+
16
+ def filter_table_body_rows(rows)
17
+ rows
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -6,25 +6,28 @@ module Gherkin
6
6
  @tag_counts = tag_counts
7
7
  end
8
8
 
9
- def feature(statement, uri)
10
- @feature_tags = statement.tags
9
+ def uri(uri)
11
10
  @uri = uri
12
- @formatter.feature(statement, uri)
13
11
  end
14
12
 
15
- def scenario(statement)
16
- record_tags((@feature_tags.to_a + statement.tags.to_a).uniq, statement.line)
17
- @formatter.scenario(statement)
13
+ def feature(feature)
14
+ @feature_tags = feature.tags
15
+ @formatter.feature(feature)
18
16
  end
19
17
 
20
- def scenario_outline(statement)
21
- @scenario_outline_tags = statement.tags
22
- @formatter.scenario_outline(statement)
18
+ def scenario(scenario)
19
+ record_tags((@feature_tags.to_a + scenario.tags.to_a).uniq, scenario.line)
20
+ @formatter.scenario(scenario)
23
21
  end
24
22
 
25
- def examples(statement, examples_rows)
26
- record_tags((@feature_tags.to_a + @scenario_outline_tags.to_a + statement.tags.to_a).uniq, statement.line)
27
- @formatter.examples(statement, examples_rows)
23
+ def scenario_outline(scenario_outline)
24
+ @scenario_outline_tags = scenario_outline.tags
25
+ @formatter.scenario_outline(scenario_outline)
26
+ end
27
+
28
+ def examples(examples)
29
+ record_tags((@feature_tags.to_a + @scenario_outline_tags.to_a + examples.tags.to_a).uniq, examples.line)
30
+ @formatter.examples(examples)
28
31
  end
29
32
 
30
33
  private
@@ -0,0 +1,19 @@
1
+ require 'gherkin/tag_expression'
2
+
3
+ module Gherkin
4
+ module Formatter
5
+ class TagFilter
6
+ def initialize(tags)
7
+ @tag_expression = TagExpression.new(tags)
8
+ end
9
+
10
+ def eval(tags, names, ranges)
11
+ @tag_expression.eval(tags.uniq.map{|tag| tag.name})
12
+ end
13
+
14
+ def filter_table_body_rows(rows)
15
+ rows
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,102 +1,86 @@
1
1
  require 'json'
2
- require 'gherkin/listener/formatter_listener'
2
+ require 'gherkin/formatter/model'
3
+ require 'gherkin/native'
3
4
 
4
5
  module Gherkin
5
6
  class JSONParser
7
+ native_impl('gherkin')
6
8
 
7
9
  def initialize(formatter)
8
10
  @formatter = formatter
9
11
  end
10
12
 
11
13
  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
14
+ @formatter.uri(feature_uri)
15
+ o = JSON.parse(src)
16
+
17
+ Formatter::Model::Feature.new(comments(o), tags(o), keyword(o), name(o), description(o), line(o)).replay(@formatter)
18
+ (o["elements"] || []).each do |feature_element|
19
+ feature_element(feature_element).replay(@formatter)
20
+ (feature_element["steps"] || []).each do |step|
21
+ step(step).replay(@formatter)
22
+ end
23
+ (feature_element["examples"] || []).each do |eo|
24
+ Formatter::Model::Examples.new(comments(eo), tags(eo), keyword(eo), name(eo), description(eo), line(eo), rows(eo['rows'])).replay(@formatter)
25
+ end
26
+ end
15
27
 
16
- def parse_with_listener(src, listener)
17
- @listener = listener
18
- _parse(src, 'unknown.json', 0)
28
+ @formatter.eof
19
29
  end
20
30
 
21
- private
22
-
23
- def _parse(src, feature_uri, line_offset)
24
- @listener.location(feature_uri)
25
- feature = JSON.parse(src)
26
-
27
- comments_for(feature)
28
- tags_for(feature)
29
- multiline_event(feature)
30
-
31
- (feature["elements"] || []).each do |feature_element|
32
- parse_element(feature_element)
31
+ def feature_element(o)
32
+ case o['type']
33
+ when 'background'
34
+ Formatter::Model::Background.new(comments(o), keyword(o), name(o), description(o), line(o))
35
+ when 'scenario'
36
+ Formatter::Model::Scenario.new(comments(o), tags(o), keyword(o), name(o), description(o), line(o))
37
+ when 'scenario_outline'
38
+ Formatter::Model::ScenarioOutline.new(comments(o), tags(o), keyword(o), name(o), description(o), line(o))
33
39
  end
34
-
35
- @listener.eof
36
40
  end
37
41
 
38
- def parse_element(feature_element)
39
- comments_for(feature_element)
40
- tags_for(feature_element)
41
- multiline_event(feature_element)
42
- steps_for(feature_element)
43
-
44
- if feature_element["type"] == "scenario_outline"
45
- (feature_element["examples"] || []).each do |examples|
46
- comments_for(examples)
47
- tags_for(examples)
48
- multiline_event(examples)
49
- rows_for(examples['table'])
42
+ def step(o)
43
+ multiline_arg = nil
44
+ if(ma = o['multiline_arg'])
45
+ if(ma['type'] == 'table')
46
+ multiline_arg = rows(ma['value'])
47
+ else
48
+ multiline_arg = Formatter::Model::PyString.new(ma['value'], ma['line'])
50
49
  end
51
50
  end
51
+ Formatter::Model::Step.new(comments(o), keyword(o), name(o), nil, line(o), multiline_arg)
52
52
  end
53
53
 
54
- def comments_for(element)
55
- (element["comments"] || []).each do |comment|
56
- @listener.comment(comment['value'], comment['line'])
57
- end
54
+ def rows(o)
55
+ o.map{|row| Formatter::Model::Row.new(comments(row), row['cells'], row['line'])}
58
56
  end
59
57
 
60
- def tags_for(element)
61
- (element["tags"] || []).each do |tag|
62
- @listener.tag(tag['name'], tag['line'])
58
+ def comments(o)
59
+ (o['comments'] || []).map do |comment|
60
+ Formatter::Model::Comment.new(comment['value'], comment['line'])
63
61
  end
64
62
  end
65
63
 
66
- def steps_for(element)
67
- element["steps"].each do |step|
68
- comments_for(step)
69
- @listener.step(step["keyword"], step["name"], step['line'])
70
- multiline_arg_for(step)
64
+ def tags(o)
65
+ (o['tags'] || []).map do |tag|
66
+ Formatter::Model::Tag.new(tag['name'], tag['line'])
71
67
  end
72
68
  end
73
69
 
74
- def multiline_arg_for(element)
75
- if ma = element["multiline_arg"]
76
- case ma["type"]
77
- when "py_string"
78
- @listener.py_string(ma["value"], ma["line"])
79
- when "table"
80
- rows_for(ma["value"])
81
- end
82
- end
70
+ def keyword(o)
71
+ o['keyword']
83
72
  end
84
73
 
85
- def rows_for(rows)
86
- (rows || []).each do |row|
87
- comments_for(row)
88
- @listener.row(cells_for(row), row['line'])
89
- end
74
+ def name(o)
75
+ o['name']
90
76
  end
91
77
 
92
- def cells_for(row)
93
- row["cells"]
78
+ def description(o)
79
+ o['description']
94
80
  end
95
81
 
96
- def multiline_event(element)
97
- if element["keyword"]
98
- @listener.__send__(element['type'].to_sym, element["keyword"], element["name"] || "", element["description"] || "", element['line'])
99
- end
82
+ def line(o)
83
+ o['line']
100
84
  end
101
85
  end
102
86
  end