gherkin 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/History.txt +12 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +2 -2
  4. data/Rakefile +2 -2
  5. data/VERSION.yml +2 -2
  6. data/features/json_formatter.feature +3 -41
  7. data/features/step_definitions/gherkin_steps.rb +5 -6
  8. data/features/step_definitions/json_formatter_steps.rb +3 -2
  9. data/features/step_definitions/json_lexer_steps.rb +5 -5
  10. data/features/step_definitions/pretty_formatter_steps.rb +9 -13
  11. data/features/support/env.rb +1 -1
  12. data/lib/gherkin/formatter/argument.rb +1 -0
  13. data/lib/gherkin/formatter/filter_formatter.rb +149 -0
  14. data/lib/gherkin/formatter/json_formatter.rb +35 -45
  15. data/lib/gherkin/formatter/line_filter.rb +26 -0
  16. data/lib/gherkin/formatter/model.rb +85 -0
  17. data/lib/gherkin/formatter/pretty_formatter.rb +36 -39
  18. data/lib/gherkin/formatter/regexp_filter.rb +17 -0
  19. data/lib/gherkin/formatter/tag_count_formatter.rb +44 -0
  20. data/lib/gherkin/i18n.rb +5 -5
  21. data/lib/gherkin/i18n.yml +13 -0
  22. data/lib/gherkin/i18n_lexer.rb +2 -2
  23. data/lib/gherkin/{json_lexer.rb → json_parser.rb} +17 -5
  24. data/lib/gherkin/{parser → listener}/event.rb +1 -1
  25. data/lib/gherkin/{parser → listener}/formatter_listener.rb +30 -23
  26. data/lib/gherkin/native/java.rb +9 -1
  27. data/lib/gherkin/parser/parser.rb +27 -14
  28. data/lib/gherkin/rubify.rb +5 -1
  29. data/lib/gherkin/tag_expression.rb +62 -0
  30. data/lib/gherkin/tools/files.rb +3 -4
  31. data/lib/gherkin/tools/reformat.rb +2 -2
  32. data/lib/gherkin/tools/stats.rb +3 -4
  33. data/lib/gherkin/tools/stats_listener.rb +1 -1
  34. data/ragel/lexer.c.rl.erb +2 -3
  35. data/ragel/lexer.java.rl.erb +1 -2
  36. data/ragel/lexer.rb.rl.erb +1 -2
  37. data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
  38. data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
  39. data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
  40. data/spec/gherkin/formatter/filter_formatter_spec.rb +156 -0
  41. data/spec/gherkin/formatter/model_spec.rb +15 -0
  42. data/spec/gherkin/formatter/pretty_formatter_spec.rb +17 -16
  43. data/spec/gherkin/formatter/tag_count_formatter_spec.rb +31 -0
  44. data/spec/gherkin/i18n_lexer_spec.rb +3 -3
  45. data/spec/gherkin/i18n_spec.rb +2 -4
  46. data/spec/gherkin/{json_lexer_spec.rb → json_parser_spec.rb} +13 -8
  47. data/spec/gherkin/sexp_recorder.rb +10 -4
  48. data/spec/gherkin/shared/lexer_group.rb +0 -40
  49. data/spec/gherkin/shared/py_string_group.rb +0 -1
  50. data/spec/gherkin/shared/row_group.rb +1 -2
  51. data/spec/gherkin/tag_expression_spec.rb +137 -0
  52. data/spec/spec_helper.rb +5 -1
  53. data/tasks/bench.rake +5 -9
  54. metadata +35 -25
  55. data/lib/gherkin/parser/filter_listener.rb +0 -203
  56. data/lib/gherkin/parser/row.rb +0 -15
  57. data/lib/gherkin/parser/tag_expression.rb +0 -50
  58. data/spec/gherkin/parser/filter_listener_spec.rb +0 -397
  59. data/spec/gherkin/parser/formatter_listener_spec.rb +0 -134
  60. data/spec/gherkin/parser/parser_spec.rb +0 -50
  61. data/spec/gherkin/parser/tag_expression_spec.rb +0 -116
@@ -11,47 +11,33 @@ module Gherkin
11
11
  @io = io
12
12
  end
13
13
 
14
- def feature(comments, tags, keyword, name, description, uri)
15
- @json_hash = {
16
- 'comments' => comments.to_a,
17
- 'tags' => tags.to_a,
18
- 'keyword' => keyword,
19
- 'name' => name,
20
- 'description' => description,
21
- 'uri' => uri
22
- }
14
+ def feature(statement, uri)
15
+ @json_hash = statement_hash(nil, statement)
16
+ @json_hash['uri'] = uri
23
17
  end
24
18
 
25
- def background(comments, keyword, name, description, line)
26
- background = {
27
- 'comments' => comments.to_a,
28
- 'keyword' => keyword,
29
- 'name' => name,
30
- 'description' => description,
31
- 'line' => line,
32
- 'steps' => [],
33
- }
34
- @json_hash['background'] = background
19
+ def background(statement)
20
+ @json_hash['background'] = statement_hash(nil, statement)
35
21
  @in_background = true
36
22
  end
37
23
 
38
- def scenario(comments, tags, keyword, name, description, line)
24
+ def scenario(statement)
39
25
  @in_background = false
40
- add_step_container(comments, tags, keyword, name, description, line, 'scenario')
26
+ add_step_container('scenario', statement)
41
27
  end
42
28
 
43
- def scenario_outline(comments, tags, keyword, name, description, line)
29
+ def scenario_outline(statement)
44
30
  @in_background = false
45
- add_step_container(comments, tags, keyword, name, description, line, 'scenario_outline')
31
+ add_step_container('scenario_outline', statement)
46
32
  end
47
33
 
48
- def examples(comments, tags, keyword, name, description, line, table)
49
- @table_container = add_examples(comments, tags, keyword, name, description, line)
50
- @table_container['table'] = to_hash_array(table)
34
+ def examples(statement, examples_rows)
35
+ @table_container = add_examples(statement)
36
+ @table_container['table'] = to_hash_array(examples_rows)
51
37
  end
52
38
 
53
- def step(comments, keyword, name, line, multiline_arg, status, exception, arguments, stepdef_location)
54
- @table_container = {'comments' => comments.to_a, 'keyword' => keyword, 'name' => name, 'line' => line}.merge(step_arg_to_hash(multiline_arg))
39
+ def step(statement, multiline_arg, result)
40
+ @table_container = statement_hash(nil, statement).merge(step_arg_to_hash(multiline_arg))
55
41
  last_element['steps'] ||= []
56
42
  last_element['steps'] << @table_container
57
43
  end
@@ -62,35 +48,35 @@ module Gherkin
62
48
 
63
49
  private
64
50
 
65
- def element_hash(comments, tags, keyword, name, description, line, type=nil)
51
+ def statement_hash(type, statement)
66
52
  element = {
67
- 'comments' => comments.to_a,
68
- 'tags' => tags.to_a,
69
- 'keyword' => keyword,
70
- 'name' => name,
71
- 'description' => description,
72
- 'line' => line,
53
+ 'comments' => statement.comments.map{|comment| comment.value},
54
+ 'tags' => statement.tags.map{|tag| tag.name},
55
+ 'keyword' => statement.keyword,
56
+ 'name' => statement.name,
57
+ 'description' => statement.description,
58
+ 'line' => statement.line,
73
59
  }
74
- element['type'] = type if type
75
- element
60
+ element['type'] = type
61
+ compact(element)
76
62
  end
77
63
 
78
- def add_element(comments, tags, keyword, name, description, line, type)
79
- element = element_hash(comments, tags, keyword, name, description, line, type)
64
+ def add_element(type, statement)
65
+ element = statement_hash(type, statement)
80
66
  @json_hash['elements'] ||= []
81
67
  @json_hash['elements'] << element
82
68
  element
83
69
  end
84
70
 
85
- def add_examples(comments, tags, keyword, name, description, line)
86
- element = element_hash(comments, tags, keyword, name, description, line)
71
+ def add_examples(statement)
72
+ element = statement_hash(nil, statement)
87
73
  last_element['examples'] ||= []
88
74
  last_element['examples'] << element
89
75
  element
90
76
  end
91
77
 
92
- def add_step_container(type, comments, tags, keyword, name, description, line)
93
- add_element(type, comments, tags, keyword, name, description, line)
78
+ def add_step_container(type, statement)
79
+ add_element(type, statement)
94
80
  last_element['steps'] = []
95
81
  end
96
82
 
@@ -104,14 +90,18 @@ module Gherkin
104
90
 
105
91
  def to_hash_array(rows)
106
92
  rows.map do |row|
107
- {"cells" => row.cells.to_a, "comments" => row.comments.to_a, "line" => row.line}
93
+ compact({"cells" => row.cells.to_a, "comments" => row.comments.map{|comment| comment.value}, "line" => row.line})
108
94
  end
109
95
  end
110
96
 
111
97
  def step_arg_to_hash(multiline_arg)
112
98
  return {} if multiline_arg.nil?
113
99
  multiline_arg = rubify(multiline_arg)
114
- Array === multiline_arg ? {"table" => to_hash_array(multiline_arg) } : { "py_string" => multiline_arg }
100
+ Array === multiline_arg ? {"table" => to_hash_array(multiline_arg) } : { "py_string" => multiline_arg.value }
101
+ end
102
+
103
+ def compact(hash)
104
+ hash.reject{|k,v| [[], "", nil].index(v)}
115
105
  end
116
106
  end
117
107
  end
@@ -0,0 +1,26 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class LineFilter
4
+ def initialize(lines)
5
+ @lines = lines
6
+ end
7
+
8
+ def eval(ranges)
9
+ @lines.detect do |line|
10
+ ranges.detect do |range|
11
+ range.include?(line)
12
+ end
13
+ end
14
+ end
15
+
16
+ def filter_table_body_rows(rows)
17
+ body = rows.to_a[1..-1].select do |row|
18
+ @lines.detect do |line|
19
+ row.line == line
20
+ end
21
+ end
22
+ [rows[0]] + body
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,85 @@
1
+ require 'gherkin/native'
2
+
3
+ module Gherkin
4
+ module Formatter
5
+ module Model
6
+ class Comment
7
+ native_impl('gherkin')
8
+
9
+ attr_reader :value, :line
10
+
11
+ def initialize(value, line)
12
+ @value, @line = value, line
13
+ end
14
+ end
15
+
16
+ class Tag
17
+ native_impl('gherkin')
18
+
19
+ attr_reader :name, :line
20
+
21
+ def initialize(name, line)
22
+ @name, @line = name, line
23
+ end
24
+
25
+ def eql?(tag)
26
+ @name.eql?(tag.name)
27
+ end
28
+
29
+ def hash
30
+ @name.hash
31
+ end
32
+ end
33
+
34
+ class PyString
35
+ native_impl('gherkin')
36
+
37
+ attr_reader :value, :line
38
+
39
+ def initialize(value, line)
40
+ @value, @line = value, line
41
+ end
42
+
43
+ def line_range
44
+ line_count = value.split(/\r?\n/).length
45
+ line..(line+line_count+1)
46
+ end
47
+ end
48
+
49
+ class Row
50
+ native_impl('gherkin')
51
+
52
+ attr_reader :comments, :cells, :line
53
+
54
+ def initialize(comments, cells, line)
55
+ @comments, @cells, @line = comments, cells, line
56
+ end
57
+ end
58
+
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
+ class Result
75
+ native_impl('gherkin')
76
+
77
+ attr_reader :status, :error_message, :arguments, :stepdef_location
78
+
79
+ def initialize(status, error_message, arguments, stepdef_location)
80
+ @status, @error_message, @arguments, @stepdef_location = status, error_message, arguments, stepdef_location
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -3,6 +3,7 @@ require 'gherkin/formatter/colors'
3
3
  require 'gherkin/formatter/monochrome_format'
4
4
  require 'gherkin/formatter/argument'
5
5
  require 'gherkin/formatter/escaping'
6
+ require 'gherkin/formatter/model'
6
7
  require 'gherkin/native'
7
8
 
8
9
  module Gherkin
@@ -19,53 +20,52 @@ module Gherkin
19
20
  @format = MonochromeFormat.new #@monochrome ? MonochromeFormat.new : AnsiColorFormat.new
20
21
  end
21
22
 
22
- def feature(comments, tags, keyword, name, description, uri)
23
+ def feature(statement, uri)
23
24
  @uri = uri
24
- print_comments(comments, '')
25
- print_tags(tags, '')
26
- @io.puts "#{keyword}: #{name}"
27
- print_description(description, ' ', false)
25
+ print_comments(statement.comments, '')
26
+ print_tags(statement.tags, '')
27
+ @io.puts "#{statement.keyword}: #{statement.name}"
28
+ print_description(statement.description, ' ', false)
28
29
  end
29
30
 
30
- def background(comments, keyword, name, description, line)
31
+ def background(statement)
31
32
  @io.puts
32
- print_comments(comments, ' ')
33
- @io.puts " #{keyword}: #{name}#{indented_element_uri!(keyword, name, line)}"
34
- print_description(description, ' ')
33
+ print_comments(statement.comments, ' ')
34
+ @io.puts " #{statement.keyword}: #{statement.name}#{indented_element_uri!(statement.keyword, statement.name, statement.line)}"
35
+ print_description(statement.description, ' ')
35
36
  end
36
37
 
37
- def scenario(comments, tags, keyword, name, description, line)
38
+ def scenario(statement)
38
39
  @io.puts
39
- print_comments(comments, ' ')
40
- print_tags(tags, ' ')
41
- @io.puts " #{keyword}: #{name}#{indented_element_uri!(keyword, name, line)}"
42
- print_description(description, ' ')
40
+ print_comments(statement.comments, ' ')
41
+ print_tags(statement.tags, ' ')
42
+ @io.puts " #{statement.keyword}: #{statement.name}#{indented_element_uri!(statement.keyword, statement.name, statement.line)}"
43
+ print_description(statement.description, ' ')
43
44
  end
44
45
 
45
- def scenario_outline(comments, tags, keyword, name, description, line)
46
- scenario(comments, tags, keyword, name, description, line)
46
+ def scenario_outline(statement)
47
+ scenario(statement)
47
48
  end
48
49
 
49
- def examples(comments, tags, keyword, name, description, line, examples_table)
50
+ def examples(statement, examples_rows)
50
51
  @io.puts
51
- print_comments(comments, ' ')
52
- print_tags(tags, ' ')
53
- @io.puts " #{keyword}: #{name}"
54
- print_description(description, ' ')
55
- table(examples_table)
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)
56
57
  end
57
58
 
58
- def step(comments, keyword, name, line, multiline_arg, status, exception, arguments, stepdef_location)
59
- status_param = "#{status}_param" if status
60
- name = Gherkin::Formatter::Argument.format(name, @format, (arguments || []))
59
+ def step(statement, multiline_arg, result)
60
+ name = Gherkin::Formatter::Argument.format(statement.name, @format, (result ? result.arguments : []))
61
61
 
62
- step = "#{keyword}#{name}"
63
- step = self.__send__(status, step, @monochrome) if status
62
+ step = "#{statement.keyword}#{statement.name}"
63
+ step = self.__send__(result.status, step, @monochrome) if result
64
64
 
65
- print_comments(comments, ' ')
66
- @io.puts(" #{step}#{indented_step_location!(stepdef_location)}")
65
+ print_comments(statement.comments, ' ')
66
+ @io.puts(" #{step}#{indented_step_location!(result ? result.stepdef_location : nil)}")
67
67
  case multiline_arg
68
- when String
68
+ when Model::PyString
69
69
  py_string(multiline_arg)
70
70
  when Array
71
71
  table(multiline_arg)
@@ -75,11 +75,8 @@ module Gherkin
75
75
  end
76
76
  end
77
77
 
78
- def syntax_error(state, event, legal_events, line)
79
- raise "SYNTAX ERROR"
80
- end
81
-
82
78
  def eof
79
+ # NO-OP
83
80
  end
84
81
 
85
82
  # This method can be invoked before a #scenario, to ensure location arguments are aligned
@@ -99,7 +96,7 @@ module Gherkin
99
96
 
100
97
  rows.each_with_index do |row, i|
101
98
  row.comments.each do |comment|
102
- @io.puts " #{comment}"
99
+ @io.puts " #{comment.value}"
103
100
  end
104
101
  j = -1
105
102
  @io.puts ' | ' + row.cells.zip(max_lengths).map { |cell, max_length|
@@ -111,8 +108,8 @@ module Gherkin
111
108
 
112
109
  private
113
110
 
114
- def py_string(string)
115
- @io.puts " \"\"\"\n" + escape_triple_quotes(indent(string, ' ')) + "\n \"\"\""
111
+ def py_string(py_string)
112
+ @io.puts " \"\"\"\n" + escape_triple_quotes(indent(py_string.value, ' ')) + "\n \"\"\""
116
113
  end
117
114
 
118
115
  def exception(exception)
@@ -145,11 +142,11 @@ module Gherkin
145
142
  end
146
143
 
147
144
  def print_tags(tags, indent)
148
- @io.write(tags.empty? ? '' : indent + tags.join(' ') + "\n")
145
+ @io.write(tags.empty? ? '' : indent + tags.map{|tag| tag.name}.join(' ') + "\n")
149
146
  end
150
147
 
151
148
  def print_comments(comments, indent)
152
- @io.write(comments.empty? ? '' : indent + comments.join("\n#{indent}") + "\n")
149
+ @io.write(comments.empty? ? '' : indent + comments.map{|comment| comment.value}.join("\n#{indent}") + "\n")
153
150
  end
154
151
 
155
152
  def print_description(description, indent, newline=true)
@@ -0,0 +1,17 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class RegexpFilter
4
+ def initialize(regexen)
5
+ @regexen = regexen
6
+ end
7
+
8
+ def eval(names)
9
+ @regexen.detect do |regexp|
10
+ names.detect do |name|
11
+ name =~ regexp
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class TagCountFormatter
4
+ def initialize(formatter, tag_counts)
5
+ @formatter = formatter
6
+ @tag_counts = tag_counts
7
+ end
8
+
9
+ def feature(statement, uri)
10
+ @feature_tags = statement.tags
11
+ @uri = uri
12
+ @formatter.feature(statement, uri)
13
+ end
14
+
15
+ def scenario(statement)
16
+ record_tags((@feature_tags.to_a + statement.tags.to_a).uniq, statement.line)
17
+ @formatter.scenario(statement)
18
+ end
19
+
20
+ def scenario_outline(statement)
21
+ @scenario_outline_tags = statement.tags
22
+ @formatter.scenario_outline(statement)
23
+ end
24
+
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)
28
+ end
29
+
30
+ private
31
+
32
+ def record_tags(tags, line)
33
+ tags.each do |tag|
34
+ @tag_counts[tag.name] ||= []
35
+ @tag_counts[tag.name] << "#{@uri}:#{line}"
36
+ end
37
+ end
38
+
39
+ def method_missing(*args)
40
+ @formatter.__send__(*args)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -55,11 +55,11 @@ module Gherkin
55
55
  def language_table
56
56
  require 'stringio'
57
57
  require 'gherkin/formatter/pretty_formatter'
58
- require 'gherkin/parser/row'
58
+ require 'gherkin/formatter/model'
59
59
  io = defined?(JRUBY_VERSION) ? Java.java.io.StringWriter.new : StringIO.new
60
60
  pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
61
61
  table = all.map do |i18n|
62
- Parser::Row.new([i18n.iso_code, i18n.keywords('name')[0], i18n.keywords('native')[0]], [], nil)
62
+ Formatter::Model::Row.new([], [i18n.iso_code, i18n.keywords('name')[0], i18n.keywords('native')[0]], nil)
63
63
  end
64
64
  pf.table(table)
65
65
  if defined?(JRUBY_VERSION)
@@ -147,19 +147,19 @@ module Gherkin
147
147
  def keyword_table
148
148
  require 'stringio'
149
149
  require 'gherkin/formatter/pretty_formatter'
150
- require 'gherkin/parser/row'
150
+ require 'gherkin/formatter/model'
151
151
  io = StringIO.new
152
152
  pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
153
153
 
154
154
  gherkin_keyword_table = KEYWORD_KEYS.map do |key|
155
- Parser::Row.new([key, keywords(key).map{|keyword| %{"#{keyword}"}}.join(', ')], [], nil)
155
+ Formatter::Model::Row.new([], [key, keywords(key).map{|keyword| %{"#{keyword}"}}.join(', ')], nil)
156
156
  end
157
157
 
158
158
  code_keyword_table = STEP_KEYWORD_KEYS.map do |key|
159
159
  code_keywords = keywords(key).reject{|keyword| keyword == '* '}.map do |keyword|
160
160
  %{"#{self.class.code_keyword_for(keyword)}"}
161
161
  end.join(', ')
162
- Parser::Row.new(["#{key} (code)", code_keywords], [], nil)
162
+ Formatter::Model::Row.new([], ["#{key} (code)", code_keywords], nil)
163
163
  end
164
164
 
165
165
  pf.table(gherkin_keyword_table + code_keyword_table)