gherkin 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitattributes +1 -0
  2. data/History.txt +18 -0
  3. data/README.rdoc +4 -1
  4. data/Rakefile +4 -2
  5. data/VERSION.yml +1 -1
  6. data/bin/gherkin +1 -1
  7. data/dotnet/.gitignore +13 -0
  8. data/features/feature_parser.feature +22 -2
  9. data/features/native_lexer.feature +1 -1
  10. data/features/parser_with_native_lexer.feature +1 -1
  11. data/features/step_definitions/gherkin_steps.rb +2 -6
  12. data/features/step_definitions/pretty_printer_steps.rb +2 -3
  13. data/features/steps_parser.feature +1 -1
  14. data/gherkin.gemspec +53 -24
  15. data/java/Gherkin.iml +2 -4
  16. data/java/build.xml +3 -0
  17. data/java/src/gherkin/FixJava.java +6 -3
  18. data/java/src/gherkin/I18nLexer.java +48 -0
  19. data/java/src/gherkin/Listener.java +3 -1
  20. data/java/src/gherkin/Main.java +17 -0
  21. data/java/src/gherkin/Parser.java +9 -3
  22. data/java/src/gherkin/formatter/Argument.java +39 -0
  23. data/java/src/gherkin/formatter/ArgumentFormat.java +17 -0
  24. data/java/src/gherkin/formatter/Colors.java +7 -0
  25. data/java/src/gherkin/formatter/Formatter.java +15 -0
  26. data/java/src/gherkin/formatter/PrettyFormatter.java +219 -0
  27. data/java/src/gherkin/parser/StateMachineReader.java +8 -3
  28. data/java/test/gherkin/formatter/ArgumentTest.java +17 -0
  29. data/lib/gherkin/csharp_lexer.rb +15 -0
  30. data/lib/gherkin/format/argument.rb +35 -0
  31. data/lib/gherkin/format/monochrome_format.rb +9 -0
  32. data/lib/gherkin/i18n.rb +22 -0
  33. data/lib/gherkin/i18n.yml +34 -20
  34. data/lib/gherkin/i18n_lexer.rb +57 -13
  35. data/lib/gherkin/lexer.rb +9 -18
  36. data/lib/gherkin/parser.rb +3 -3
  37. data/lib/gherkin/parser/meta.txt +5 -4
  38. data/lib/gherkin/parser/root.txt +11 -9
  39. data/lib/gherkin/parser/steps.txt +4 -3
  40. data/lib/gherkin/rb_parser.rb +13 -5
  41. data/lib/gherkin/tools/colors.rb +119 -0
  42. data/lib/gherkin/tools/files.rb +6 -1
  43. data/lib/gherkin/tools/pretty_listener.rb +115 -23
  44. data/ragel/lexer.c.rl.erb +67 -51
  45. data/ragel/lexer.csharp.rl.erb +240 -0
  46. data/ragel/lexer.java.rl.erb +27 -18
  47. data/ragel/lexer.rb.rl.erb +17 -17
  48. data/ragel/lexer_common.rl.erb +8 -8
  49. data/spec/gherkin/c_lexer_spec.rb +4 -4
  50. data/spec/gherkin/csharp_lexer_spec.rb +20 -0
  51. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  52. data/spec/gherkin/fixtures/complex.feature +2 -0
  53. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  54. data/spec/gherkin/fixtures/i18n_fr.feature +1 -0
  55. data/spec/gherkin/fixtures/i18n_no.feature +1 -0
  56. data/spec/gherkin/fixtures/i18n_zh-CN.feature +1 -0
  57. data/spec/gherkin/format/argument_spec.rb +28 -0
  58. data/spec/gherkin/i18n_lexer_spec.rb +4 -4
  59. data/spec/gherkin/i18n_spec.rb +31 -23
  60. data/spec/gherkin/java_lexer_spec.rb +4 -3
  61. data/spec/gherkin/parser_spec.rb +5 -0
  62. data/spec/gherkin/rb_lexer_spec.rb +4 -2
  63. data/spec/gherkin/sexp_recorder.rb +1 -1
  64. data/spec/gherkin/shared/lexer_spec.rb +169 -60
  65. data/spec/gherkin/shared/py_string_spec.rb +6 -0
  66. data/spec/gherkin/shared/row_spec.rb +107 -0
  67. data/spec/gherkin/shared/tags_spec.rb +1 -1
  68. data/spec/gherkin/tools/colors_spec.rb +19 -0
  69. data/spec/gherkin/tools/pretty_listener_spec.rb +147 -0
  70. data/spec/spec_helper.rb +31 -7
  71. data/tasks/compile.rake +81 -7
  72. data/tasks/ragel_task.rb +6 -4
  73. data/tasks/rspec.rake +2 -2
  74. metadata +104 -41
  75. data/lib/gherkin/java_lexer.rb +0 -10
  76. data/spec/gherkin/shared/table_spec.rb +0 -97
@@ -0,0 +1,17 @@
1
+ package gherkin.formatter;
2
+
3
+ import org.junit.Test;
4
+
5
+ import java.io.UnsupportedEncodingException;
6
+
7
+ import static org.junit.Assert.assertEquals;
8
+
9
+ public class ArgumentTest {
10
+ @Test
11
+ public void shouldFormatAscii() throws UnsupportedEncodingException {
12
+ assertEquals("I have [[[[åtte] cukes i [[[[bøtta]", Argument.format("I have åtte cukes i bøtta", new ArgumentFormat("[[[[", "]"),
13
+ new Argument(7, "åtte"),
14
+ new Argument(21, "bøtta")
15
+ ));
16
+ }
17
+ }
@@ -0,0 +1,15 @@
1
+ require 'Gherkin.dll'
2
+
3
+ module Gherkin
4
+ module CSharpLexer
5
+ def self.[](i18n_language)
6
+ i18n_lexer_class_name = i18n_language.gsub(/[\s-]/, '').capitalize
7
+ puts "In C# lexer: #{i18n_lexer_class_name}"
8
+ Gherkin::ILexer
9
+ puts "OK1"
10
+ l = Gherkin::Lexer.__send__(i18n_lexer_class_name)
11
+ puts "OK2"
12
+ l
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ module Gherkin
2
+ module Format
3
+ class Argument
4
+ attr_reader :byte_offset, :val
5
+
6
+ class << self
7
+ def new(byte_offset, val)
8
+ if defined?(JRUBY_VERSION)
9
+ require 'gherkin.jar'
10
+ Java::GherkinFormatter::Argument.new(byte_offset, val)
11
+ else
12
+ super
13
+ end
14
+ end
15
+ end
16
+
17
+ def initialize(byte_offset, val)
18
+ @byte_offset, @val = byte_offset, val
19
+ end
20
+
21
+ def self.format(string, argument_format, arguments)
22
+ s = string.dup
23
+ offset = past_offset = 0
24
+ arguments.each do |arg|
25
+ next if arg.byte_offset.nil? || arg.byte_offset < past_offset
26
+ replacement = argument_format.format_argument(arg.val)
27
+ s[arg.byte_offset + offset, arg.val.length] = replacement
28
+ offset += replacement.unpack("U*").length - arg.val.unpack("U*").length
29
+ past_offset = arg.byte_offset + arg.val.length
30
+ end
31
+ s
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ module Gherkin
2
+ module Format
3
+ class MonochromeFormat
4
+ def format_argument(arg)
5
+ arg
6
+ end
7
+ end
8
+ end
9
+ end
@@ -18,6 +18,23 @@ module Gherkin
18
18
  def languages
19
19
  @languages ||= {}
20
20
  end
21
+
22
+ # Returns all keyword translations and aliases of +keywords+, escaped and joined with <tt>|</tt>.
23
+ # This method is convenient for editor support and syntax highlighting engines for Gherkin, where
24
+ # there is typically a code generation tool to generate regular expressions for recognising the
25
+ # various I18n translations of Gherkin's keywords.
26
+ #
27
+ # The +keywords+ arguments can be one of <tt>:feature</tt>, <tt>:background</tt>, <tt>:scenario</tt>,
28
+ # <tt>:scenario_outline</tt>, <tt>:examples</tt>, <tt>:step</tt>.
29
+ def keyword_regexp(*keywords)
30
+ unique_keywords = all.map do |lang|
31
+ keywords.map do |keyword|
32
+ lang.__send__("#{keyword}_keywords".to_sym)
33
+ end
34
+ end
35
+
36
+ unique_keywords.flatten.compact.sort.reverse.uniq.join('|').gsub(/\*/, '\*')
37
+ end
21
38
  end
22
39
 
23
40
  attr_reader :key
@@ -69,12 +86,17 @@ module Gherkin
69
86
  %w{given when then and but}.map{|key| keywords(key, true)}.flatten.uniq
70
87
  end
71
88
 
89
+ def gwt_keywords
90
+ %w{given when then}.map{|key| keywords(key, true)}.flatten.uniq
91
+ end
92
+
72
93
  def keywords(key, space=false)
73
94
  raise "No #{key} in #{@keywords.inspect}" if @keywords[key].nil?
74
95
  @keywords[key].split('|').map{|kw| space ? keyword_space(kw) : kw}
75
96
  end
76
97
 
77
98
  def adverbs
99
+ # TODO: looks very similar to #step_keywords. Lose this? Where is it used from?
78
100
  %w{given when then and but}.map{|keyword| @keywords[keyword].split('|').map{|w| w.gsub(/[\s<']/, '')}}.flatten
79
101
  end
80
102
 
@@ -1,11 +1,16 @@
1
1
  # encoding: UTF-8
2
- # We use the codes here (prefer 2 letters when possible)
3
- # http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
2
+ #
3
+ # We use ISO 639-1 (language) and ISO 3166 alpha-2 (region - if appliccable):
4
+ # http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
5
+ # http://en.wikipedia.org/wiki/ISO_3166-1
4
6
  #
5
7
  # If you want several aliases for a keyword, just separate them
6
8
  # with a | character. Make sure there are no ambiguities in the
7
9
  # keywords.
8
10
  #
11
+ # If you do *not* want a trailing space after a keyword, end it with a < character.
12
+ # (See Chinese for examples).
13
+ #
9
14
  "en":
10
15
  name: English
11
16
  native: English
@@ -20,10 +25,6 @@
20
25
  and: "*|And"
21
26
  but: "*|But"
22
27
 
23
- # Please help us keeping the languages below uptodate. The parsers for a language
24
- # that is missing a keyword will expect the English word until the missing word(s)
25
- # are added.
26
- #
27
28
  # Please keep the grammars in alphabetical order by name from here and down.
28
29
 
29
30
  "ar":
@@ -52,20 +53,20 @@
52
53
  then: "*|То"
53
54
  and: "*|И"
54
55
  but: "*|Но"
55
- "cat":
56
+ "ca":
56
57
  name: Catalan
57
58
  native: català
58
59
  background: Rerefons|Antecedents
59
- feature: Característica
60
+ feature: Característica|Funcionalitat
60
61
  scenario: Escenari
61
62
  scenario_outline: Esquema de l'escenari
62
63
  examples: Exemples
63
- given: "*|Donat|Donada"
64
+ given: "*|Donat|Donada|Atès|Atesa"
64
65
  when: "*|Quan"
65
- then: "*|Aleshores"
66
+ then: "*|Aleshores|Cal"
66
67
  and: "*|I"
67
68
  but: "*|Però"
68
- "cy":
69
+ "cy-GB":
69
70
  name: Welsh
70
71
  native: Cymraeg
71
72
  background: Cefndir
@@ -112,7 +113,7 @@
112
113
  scenario: Szenario
113
114
  scenario_outline: Szenariogrundriss
114
115
  examples: Beispiele
115
- given: "*|Gegeben sei"
116
+ given: "*|Angenommen|Gegeben sei"
116
117
  when: "*|Wenn"
117
118
  then: "*|Dann"
118
119
  and: "*|Und"
@@ -143,6 +144,19 @@
143
144
  then: "*|DEN"
144
145
  and: "*|AN"
145
146
  but: "*|BUT"
147
+ "en-Scouse":
148
+ name: Scouse
149
+ native: Scouse
150
+ feature: Feature
151
+ background: "Dis is what went down"
152
+ scenario: "The thing of it is"
153
+ scenario_outline: "Wharrimean is"
154
+ examples: Examples
155
+ given: "*|Givun|Youse know when youse got"
156
+ when: "*|Wun|Youse know like when"
157
+ then: "*|Dun|Den youse gotta"
158
+ and: "*|An"
159
+ but: "*|Buh"
146
160
  "en-tx":
147
161
  name: Texan
148
162
  native: Texan
@@ -294,11 +308,11 @@
294
308
  scenario: 시나리오
295
309
  scenario_outline: 시나리오 개요
296
310
  examples: 예
297
- given: "*|조건<"
298
- when: "*|만일<"
311
+ given: "*|조건<|먼저<"
312
+ when: "*|만일<|만약<"
299
313
  then: "*|그러면<"
300
314
  and: "*|그리고<"
301
- but: "*|하지만<"
315
+ but: "*|하지만<|단<"
302
316
  "lt":
303
317
  name: Lithuanian
304
318
  native: lietuvių kalba
@@ -390,7 +404,7 @@
390
404
  then: "*|Atunci"
391
405
  and: "*|Si"
392
406
  but: "*|Dar"
393
- "ro2":
407
+ "ro-RO":
394
408
  name: Romanian (diacritical)
395
409
  native: română (diacritical)
396
410
  background: Condiţii
@@ -416,7 +430,7 @@
416
430
  then: "*|То"
417
431
  and: "*|И|К тому же"
418
432
  but: "*|Но|А"
419
- "se":
433
+ "sv":
420
434
  name: Swedish
421
435
  native: Svenska
422
436
  feature: Egenskap
@@ -443,8 +457,8 @@
443
457
  and: "*|A"
444
458
  but: "*|Ale"
445
459
  "sr-Latn":
446
- name: Serbian_latin
447
- native: Srpski_latinica
460
+ name: Serbian (Latin)
461
+ native: Srpski (Latinica)
448
462
  feature: Funkcionalnost|Mogućnost|Mogucnost|Osobina
449
463
  background: Kontekst|Osnova|Pozadina
450
464
  scenario: Scenario|Primer
@@ -455,7 +469,7 @@
455
469
  then: "*|Onda"
456
470
  and: "*|I"
457
471
  but: "*|Ali"
458
- "sr":
472
+ "sr-Cyrl":
459
473
  name: Serbian
460
474
  native: Српски
461
475
  feature: Функционалност|Могућност|Особина
@@ -1,29 +1,73 @@
1
- require 'gherkin/lexer'
2
1
  require 'gherkin/i18n'
3
2
 
4
3
  module Gherkin
4
+ I18nLexerNotFound = Class.new(LoadError)
5
+ LexingError = Class.new(StandardError)
6
+
5
7
  # The main entry point to lexing Gherkin source.
6
8
  class I18nLexer
7
9
  LANGUAGE_PATTERN = /language\s*:\s*(.*)/ #:nodoc:
8
10
 
9
- attr_reader :language
11
+ attr_reader :i18n_language
12
+
13
+ class << self
14
+ def new(parser, force_ruby)
15
+ if !force_ruby && defined?(JRUBY_VERSION)
16
+ require 'gherkin.jar'
17
+ Java::Gherkin::I18nLexer.new(parser)
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ def lexer_class(i18n_lang, force_ruby)
24
+ begin
25
+ if force_ruby
26
+ rb[i18n_lang]
27
+ else
28
+ begin
29
+ c[i18n_lang]
30
+ rescue NameError, LoadError => e
31
+ warn("WARNING: #{e.message}. Reverting to Ruby lexer.")
32
+ rb[i18n_lang]
33
+ end
34
+ end
35
+ rescue LoadError => e
36
+ raise I18nLexerNotFound, "No lexer was found for #{i18n_lang} (#{e.message}). Supported languages are listed in gherkin/i18n.yml."
37
+ end
38
+ end
39
+
40
+ def i18n_language(source)
41
+ line_one = source.split(/\n/)[0]
42
+ match = LANGUAGE_PATTERN.match(line_one)
43
+ I18n.get(match ? match[1] : 'en').key
44
+ end
45
+
46
+ def c
47
+ require 'gherkin/c_lexer'
48
+ CLexer
49
+ end
50
+
51
+ def csharp
52
+ require 'gherkin/csharp_lexer'
53
+ CSharpLexer
54
+ end
10
55
 
11
- def initialize(parser)
56
+ def rb
57
+ require 'gherkin/rb_lexer'
58
+ RbLexer
59
+ end
60
+ end
61
+
62
+ def initialize(parser, force_ruby)
12
63
  @parser = parser
64
+ @force_ruby = force_ruby
13
65
  end
14
66
 
15
67
  def scan(source)
16
- @language = lang(source)
17
- delegate = Lexer[@language.key].new(@parser)
68
+ @i18n_language = self.class.i18n_language(source)
69
+ delegate = self.class.lexer_class(@i18n_language, @force_ruby).new(@parser)
18
70
  delegate.scan(source)
19
71
  end
20
-
21
- private
22
-
23
- def lang(source)
24
- line_one = source.split(/\n/)[0]
25
- match = LANGUAGE_PATTERN.match(line_one)
26
- I18n.get(match ? match[1] : 'en')
27
- end
28
72
  end
29
73
  end
@@ -1,24 +1,15 @@
1
1
  module Gherkin
2
2
  module Lexer
3
- I18nLexerNotFound = Class.new(LoadError)
4
- LexingError = Class.new(StandardError)
5
3
 
6
4
  class << self
7
5
  def [](i18n_lang)
8
6
  begin
9
- # Uncomment the line below (during development) to force use of Ruby lexer
10
- # return rb[i18n_lang]
11
-
12
- if defined?(JRUBY_VERSION)
13
- java[i18n_lang]
14
- else
15
- begin
16
- c[i18n_lang]
17
- rescue NameError, LoadError => e
18
- warn("WARNING: #{e.message}. Reverting to Ruby lexer.") unless defined?(@warned)
19
- @warned = true
20
- rb[i18n_lang]
21
- end
7
+ begin
8
+ c[i18n_lang]
9
+ rescue NameError, LoadError => e
10
+ raise("WARNING: #{e.message}. Reverting to Ruby lexer.") unless defined?(@warned)
11
+ @warned = true
12
+ rb[i18n_lang]
22
13
  end
23
14
  rescue LoadError => e
24
15
  raise I18nLexerNotFound, "No lexer was found for #{i18n_lang} (#{e.message}). Supported languages are listed in gherkin/i18n.yml."
@@ -30,9 +21,9 @@ module Gherkin
30
21
  CLexer
31
22
  end
32
23
 
33
- def java
34
- require 'gherkin/java_lexer'
35
- JavaLexer
24
+ def csharp
25
+ require 'gherkin/csharp_lexer'
26
+ CSharpLexer
36
27
  end
37
28
 
38
29
  def rb
@@ -6,13 +6,13 @@ module Gherkin
6
6
  end
7
7
 
8
8
  class Parser
9
- def self.new(listener, raise_on_error=false, machine_names='root')
9
+ def self.new(listener, raise_on_error=false, machine_name='root')
10
10
  if defined?(JRUBY_VERSION)
11
11
  require 'gherkin.jar'
12
- Java::Gherkin::Parser.new(listener, raise_on_error, machine_names)
12
+ Java::Gherkin::Parser.new(listener, raise_on_error, machine_name)
13
13
  else
14
14
  require 'gherkin/rb_parser'
15
- Gherkin::RbParser.new(listener, raise_on_error, machine_names)
15
+ Gherkin::RbParser.new(listener, raise_on_error, machine_name)
16
16
  end
17
17
  end
18
18
  end
@@ -1,4 +1,5 @@
1
- | | feature | background | scenario | scenario_outline | examples | step | table | py_string | comment | tag |
2
- | meta | E | E | E | E | E | E | E | E | comment | tag |
3
- | comment | pop() | pop() | pop() | pop() | pop() | pop() | pop() | pop() | pop() | tag |
4
- | tag | pop() | E | pop() | pop() | pop() | E | E | E | E | tag |
1
+ | | feature | background | scenario | scenario_outline | examples | step | row | py_string | eof | comment | tag |
2
+ | meta | E | E | E | E | E | E | E | E | eof | comment | tag |
3
+ | comment | pop() | pop() | pop() | pop() | pop() | pop() | pop() | pop() | eof | pop() | tag |
4
+ | tag | pop() | E | pop() | pop() | pop() | E | E | E | E | E | tag |
5
+ | eof | E | E | E | E | E | E | E | E | E | E | E |
@@ -1,9 +1,11 @@
1
- | | feature | background | scenario | scenario_outline | examples | step | table | py_string | comment | tag |
2
- | root | feature | E | E | E | E | E | E | E | push(meta) | push(meta) |
3
- | feature | E | background | scenario | scenario_outline | E | E | E | E | push(meta) | push(meta) |
4
- | step | E | E | scenario | scenario_outline | examples | step | step | step | push(meta) | push(meta) |
5
- | background | E | E | scenario | scenario_outline | E | step | E | E | push(meta) | push(meta) |
6
- | scenario | E | E | scenario | scenario_outline | E | step | E | E | push(meta) | push(meta) |
7
- | scenario_outline | E | E | E | E | E | step | E | E | push(meta) | push(meta) |
8
- | examples | E | E | E | E | E | E | examples_table | E | push(meta) | push(meta) |
9
- | examples_table | E | E | scenario | scenario_outline | examples | E | E | E | push(meta) | push(meta) |
1
+ | | feature | background | scenario | scenario_outline | examples | step | row | py_string | eof | comment | tag |
2
+ | root | feature | E | E | E | E | E | E | E | eof | push(meta) | push(meta) |
3
+ | feature | E | background | scenario | scenario_outline | E | E | E | E | eof | push(meta) | push(meta) |
4
+ | step | E | E | scenario | scenario_outline | E | step | step | step | eof | push(meta) | push(meta) |
5
+ | outline_step | E | E | scenario | scenario_outline | examples | outline_step | outline_step | outline_step | eof | push(meta) | push(meta) |
6
+ | background | E | E | scenario | scenario_outline | E | step | E | E | eof | push(meta) | push(meta) |
7
+ | scenario | E | E | scenario | scenario_outline | E | step | E | E | eof | push(meta) | push(meta) |
8
+ | scenario_outline | E | E | E | E | E | outline_step | E | E | eof | push(meta) | push(meta) |
9
+ | examples | E | E | E | E | E | E | examples_table | E | eof | push(meta) | push(meta) |
10
+ | examples_table | E | E | scenario | scenario_outline | examples | E | examples_table | E | eof | push(meta) | push(meta) |
11
+ | eof | E | E | E | E | E | E | E | E | E | E | E |
@@ -1,3 +1,4 @@
1
- | | feature | background | scenario | scenario_outline | examples | step | table | py_string | comment | tag |
2
- | steps | E | E | E | E | E | step | E | E | E | E |
3
- | step | E | E | E | E | E | step | steps | steps | E | E |
1
+ | | feature | background | scenario | scenario_outline | examples | step | row | py_string | eof | comment | tag |
2
+ | steps | E | E | E | E | E | step | E | E | eof | E | E |
3
+ | step | E | E | E | E | E | step | step | steps | eof | E | E |
4
+ | eof | E | E | E | E | E | E | E | E | E | E | E |