gherkin 1.0.30-universal-dotnet

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/.gitattributes +2 -0
  2. data/.gitignore +9 -0
  3. data/.mailmap +2 -0
  4. data/History.txt +187 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +59 -0
  7. data/Rakefile +58 -0
  8. data/VERSION.yml +5 -0
  9. data/bin/gherkin +5 -0
  10. data/cucumber.yml +3 -0
  11. data/features/escaped_pipes.feature +8 -0
  12. data/features/feature_parser.feature +226 -0
  13. data/features/native_lexer.feature +19 -0
  14. data/features/parser_with_native_lexer.feature +205 -0
  15. data/features/pretty_printer.feature +14 -0
  16. data/features/step_definitions/eyeball_steps.rb +3 -0
  17. data/features/step_definitions/gherkin_steps.rb +30 -0
  18. data/features/step_definitions/pretty_formatter_steps.rb +55 -0
  19. data/features/steps_parser.feature +46 -0
  20. data/features/support/env.rb +33 -0
  21. data/ikvm/.gitignore +3 -0
  22. data/java/.gitignore +2 -0
  23. data/java/src/main/java/gherkin/lexer/.gitignore +1 -0
  24. data/java/src/main/resources/gherkin/.gitignore +1 -0
  25. data/lib/.gitignore +4 -0
  26. data/lib/gherkin.rb +2 -0
  27. data/lib/gherkin/c_lexer.rb +17 -0
  28. data/lib/gherkin/cli/main.rb +33 -0
  29. data/lib/gherkin/formatter/argument.rb +27 -0
  30. data/lib/gherkin/formatter/colors.rb +119 -0
  31. data/lib/gherkin/formatter/escaping.rb +15 -0
  32. data/lib/gherkin/formatter/monochrome_format.rb +9 -0
  33. data/lib/gherkin/formatter/pretty_formatter.rb +168 -0
  34. data/lib/gherkin/i18n.rb +176 -0
  35. data/lib/gherkin/i18n.yml +588 -0
  36. data/lib/gherkin/i18n_lexer.rb +38 -0
  37. data/lib/gherkin/native.rb +7 -0
  38. data/lib/gherkin/native/ikvm.rb +55 -0
  39. data/lib/gherkin/native/java.rb +47 -0
  40. data/lib/gherkin/native/null.rb +9 -0
  41. data/lib/gherkin/parser/event.rb +45 -0
  42. data/lib/gherkin/parser/filter_listener.rb +199 -0
  43. data/lib/gherkin/parser/meta.txt +5 -0
  44. data/lib/gherkin/parser/parser.rb +142 -0
  45. data/lib/gherkin/parser/root.txt +11 -0
  46. data/lib/gherkin/parser/steps.txt +4 -0
  47. data/lib/gherkin/parser/tag_expression.rb +50 -0
  48. data/lib/gherkin/rb_lexer.rb +8 -0
  49. data/lib/gherkin/rb_lexer/.gitignore +1 -0
  50. data/lib/gherkin/rb_lexer/README.rdoc +8 -0
  51. data/lib/gherkin/rubify.rb +18 -0
  52. data/lib/gherkin/tools.rb +8 -0
  53. data/lib/gherkin/tools/files.rb +35 -0
  54. data/lib/gherkin/tools/reformat.rb +19 -0
  55. data/lib/gherkin/tools/stats.rb +21 -0
  56. data/lib/gherkin/tools/stats_listener.rb +57 -0
  57. data/ragel/i18n/.gitignore +1 -0
  58. data/ragel/lexer.c.rl.erb +425 -0
  59. data/ragel/lexer.java.rl.erb +216 -0
  60. data/ragel/lexer.rb.rl.erb +173 -0
  61. data/ragel/lexer_common.rl.erb +50 -0
  62. data/spec/gherkin/c_lexer_spec.rb +21 -0
  63. data/spec/gherkin/csharp_lexer_spec.rb +20 -0
  64. data/spec/gherkin/fixtures/1.feature +8 -0
  65. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  66. data/spec/gherkin/fixtures/complex.feature +45 -0
  67. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  68. data/spec/gherkin/fixtures/i18n_fr.feature +14 -0
  69. data/spec/gherkin/fixtures/i18n_no.feature +7 -0
  70. data/spec/gherkin/fixtures/i18n_zh-CN.feature +9 -0
  71. data/spec/gherkin/fixtures/simple_with_comments.feature +7 -0
  72. data/spec/gherkin/fixtures/simple_with_tags.feature +11 -0
  73. data/spec/gherkin/fixtures/with_bom.feature +3 -0
  74. data/spec/gherkin/formatter/argument_spec.rb +28 -0
  75. data/spec/gherkin/formatter/colors_spec.rb +19 -0
  76. data/spec/gherkin/formatter/pretty_formatter_spec.rb +162 -0
  77. data/spec/gherkin/formatter/spaces.feature +9 -0
  78. data/spec/gherkin/formatter/tabs.feature +9 -0
  79. data/spec/gherkin/i18n_lexer_spec.rb +26 -0
  80. data/spec/gherkin/i18n_spec.rb +144 -0
  81. data/spec/gherkin/java_lexer_spec.rb +21 -0
  82. data/spec/gherkin/parser/filter_listener_spec.rb +390 -0
  83. data/spec/gherkin/parser/parser_spec.rb +50 -0
  84. data/spec/gherkin/parser/tag_expression_spec.rb +116 -0
  85. data/spec/gherkin/rb_lexer_spec.rb +19 -0
  86. data/spec/gherkin/sexp_recorder.rb +32 -0
  87. data/spec/gherkin/shared/lexer_spec.rb +550 -0
  88. data/spec/gherkin/shared/py_string_spec.rb +150 -0
  89. data/spec/gherkin/shared/row_spec.rb +104 -0
  90. data/spec/gherkin/shared/tags_spec.rb +50 -0
  91. data/spec/spec_helper.rb +87 -0
  92. data/tasks/bench.rake +188 -0
  93. data/tasks/bench/feature_builder.rb +49 -0
  94. data/tasks/bench/generated/.gitignore +1 -0
  95. data/tasks/bench/null_listener.rb +4 -0
  96. data/tasks/compile.rake +89 -0
  97. data/tasks/cucumber.rake +26 -0
  98. data/tasks/gems.rake +45 -0
  99. data/tasks/ikvm.rake +47 -0
  100. data/tasks/ragel_task.rb +70 -0
  101. data/tasks/rdoc.rake +12 -0
  102. data/tasks/release.rake +26 -0
  103. data/tasks/rspec.rake +15 -0
  104. metadata +257 -0
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'trollop'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'trollop'
6
+ end
7
+ require 'gherkin/tools'
8
+
9
+ module Gherkin
10
+ module Cli
11
+ class Main
12
+ def self.run(args)
13
+ Trollop::options(args) do
14
+ banner "Super fast gherkin parser"
15
+ stop_on Tools::SUB_COMMANDS
16
+ end
17
+
18
+ cmd_name = args.shift
19
+ die("Missing command") if cmd_name.nil?
20
+ begin
21
+ cmd = Tools.const_get(cmd_name.capitalize.to_sym).new(args)
22
+ cmd.run
23
+ rescue => e
24
+ Trollop::die(e.message + "\nCommand: #{cmd_name}")
25
+ end
26
+ end
27
+
28
+ def self.die(msg)
29
+ Trollop::die("#{msg}\nusage: gherkin COMMAND [ARGS]\nAvailable commands: #{Tools::SUB_COMMANDS.join(' ')}")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ require 'gherkin/native'
2
+
3
+ module Gherkin
4
+ module Formatter
5
+ class Argument
6
+ native_impl('gherkin')
7
+ attr_reader :byte_offset, :val
8
+
9
+ def initialize(byte_offset, val)
10
+ @byte_offset, @val = byte_offset, val
11
+ end
12
+
13
+ def self.format(string, argument_format, arguments)
14
+ s = string.dup
15
+ offset = past_offset = 0
16
+ arguments.each do |arg|
17
+ next if arg.byte_offset.nil? || arg.byte_offset < past_offset
18
+ replacement = argument_format.format_argument(arg.val)
19
+ s[arg.byte_offset + offset, arg.val.length] = replacement
20
+ offset += replacement.unpack("U*").length - arg.val.unpack("U*").length
21
+ past_offset = arg.byte_offset + arg.val.length
22
+ end
23
+ s
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,119 @@
1
+ require 'term/ansicolor'
2
+
3
+ module Gherkin
4
+ module Formatter
5
+ # Defines aliases for coloured output. You don't invoke any methods from this
6
+ # module directly, but you can change the output colours by defining
7
+ # a <tt>GHERKIN_COLORS</tt> variable in your shell, very much like how you can
8
+ # tweak the familiar POSIX command <tt>ls</tt> with
9
+ # <a href="http://mipsisrisc.com/rambling/2008/06/27/lscolorsls_colors-now-with-linux-support/">$LSCOLORS/$LS_COLORS</a>
10
+ #
11
+ # The colours that you can change are:
12
+ #
13
+ # * <tt>undefined</tt> - defaults to <tt>yellow</tt>
14
+ # * <tt>pending</tt> - defaults to <tt>yellow</tt>
15
+ # * <tt>pending_param</tt> - defaults to <tt>yellow,bold</tt>
16
+ # * <tt>failed</tt> - defaults to <tt>red</tt>
17
+ # * <tt>failed_param</tt> - defaults to <tt>red,bold</tt>
18
+ # * <tt>passed</tt> - defaults to <tt>green</tt>
19
+ # * <tt>passed_param</tt> - defaults to <tt>green,bold</tt>
20
+ # * <tt>outline</tt> - defaults to <tt>cyan</tt>
21
+ # * <tt>outline_param</tt> - defaults to <tt>cyan,bold</tt>
22
+ # * <tt>skipped</tt> - defaults to <tt>cyan</tt>
23
+ # * <tt>skipped_param</tt> - defaults to <tt>cyan,bold</tt>
24
+ # * <tt>comment</tt> - defaults to <tt>grey</tt>
25
+ # * <tt>tag</tt> - defaults to <tt>cyan</tt>
26
+ #
27
+ # For instance, if your shell has a black background and a green font (like the
28
+ # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
29
+ # steps to be white instead of green. Examples:
30
+ #
31
+ # export GHERKIN_COLORS="passed=white"
32
+ # export GHERKIN_COLORS="passed=white,bold:passed_param=white,bold,underline"
33
+ #
34
+ # (If you're on Windows, use SET instead of export).
35
+ # To see what colours and effects are available, just run this in your shell:
36
+ #
37
+ # ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Term::ANSIColor.attributes"
38
+ #
39
+ # Although not listed, you can also use <tt>grey</tt>
40
+ module Colors
41
+ include Term::ANSIColor
42
+
43
+ ALIASES = Hash.new do |h,k|
44
+ if k.to_s =~ /(.*)_param/
45
+ h[$1] + ',bold'
46
+ end
47
+ end.merge({
48
+ 'undefined' => 'yellow',
49
+ 'pending' => 'yellow',
50
+ 'failed' => 'red',
51
+ 'passed' => 'green',
52
+ 'outline' => 'cyan',
53
+ 'skipped' => 'cyan',
54
+ 'comments' => 'grey',
55
+ 'tag' => 'cyan'
56
+ })
57
+
58
+ if ENV['GHERKIN_COLORS'] # Example: export GHERKIN_COLORS="passed=red:failed=yellow"
59
+ ENV['GHERKIN_COLORS'].split(':').each do |pair|
60
+ a = pair.split('=')
61
+ ALIASES[a[0]] = a[1]
62
+ end
63
+ end
64
+
65
+ ALIASES.each do |method, color|
66
+ unless method =~ /.*_param/
67
+ code = <<-EOF
68
+ def #{method}(string=nil, monochrome=false, &proc)
69
+ return string if monochrome
70
+ #{ALIASES[method].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method].split(",").length}
71
+ end
72
+ # This resets the colour to the non-param colour
73
+ def #{method}_param(string=nil, monochrome=false, &proc)
74
+ return string if monochrome
75
+ #{ALIASES[method+'_param'].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method+'_param'].split(",").length} + #{ALIASES[method].split(",").join(' + ')}
76
+ end
77
+ EOF
78
+ eval(code)
79
+ end
80
+ end
81
+
82
+ def self.define_grey #:nodoc:
83
+ begin
84
+ gem 'genki-ruby-terminfo'
85
+ require 'terminfo'
86
+ case TermInfo.default_object.tigetnum("colors")
87
+ when 0
88
+ raise "Your terminal doesn't support colours"
89
+ when 1
90
+ ::Term::ANSIColor.coloring = false
91
+ alias grey white
92
+ when 2..8
93
+ alias grey white
94
+ else
95
+ define_real_grey
96
+ end
97
+ rescue Exception => e
98
+ if e.class.name == 'TermInfo::TermInfoError'
99
+ STDERR.puts "*** WARNING ***"
100
+ STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
101
+ STDERR.puts "Try setting it to TERM=xterm-256color to get grey colour in output"
102
+ STDERR.puts "\n"
103
+ alias grey white
104
+ else
105
+ define_real_grey
106
+ end
107
+ end
108
+ end
109
+
110
+ def self.define_real_grey #:nodoc:
111
+ def grey(m) #:nodoc:
112
+ "\e[90m#{m}\e[0m"
113
+ end
114
+ end
115
+
116
+ define_grey
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,15 @@
1
+ module Gherkin
2
+ module Formatter
3
+ module Escaping
4
+ # Escapes a pipes and backslashes:
5
+ #
6
+ # * | becomes \|
7
+ # * \ becomes \\
8
+ #
9
+ # This is used in the pretty formatter.
10
+ def escape_cell(s)
11
+ s.gsub(/\|/, "\\|").gsub(/\\(?!\|)/, "\\\\\\\\")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class MonochromeFormat
4
+ def format_argument(arg)
5
+ arg
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,168 @@
1
+ # encoding: utf-8
2
+ require 'gherkin/formatter/colors'
3
+ require 'gherkin/formatter/monochrome_format'
4
+ require 'gherkin/formatter/argument'
5
+ require 'gherkin/formatter/escaping'
6
+ require 'gherkin/native'
7
+
8
+ module Gherkin
9
+ module Formatter
10
+ class PrettyFormatter
11
+ native_impl('gherkin')
12
+
13
+ include Colors
14
+ include Escaping
15
+
16
+ def initialize(io, monochrome=false)
17
+ @io = io
18
+ @monochrome = monochrome
19
+ @format = MonochromeFormat.new #@monochrome ? MonochromeFormat.new : AnsiColorFormat.new
20
+ @tags = nil
21
+ @comments = nil
22
+ end
23
+
24
+ def tag(name, line)
25
+ @tags ||= []
26
+ @tags << name
27
+ end
28
+
29
+ def comment(content, line)
30
+ @comments ||= []
31
+ @comments << content
32
+ end
33
+
34
+ def feature(keyword, name, line)
35
+ @io.puts "#{grab_comments!('')}#{grab_tags!('')}#{keyword}: #{indent(name, ' ')}"
36
+ end
37
+
38
+ def background(keyword, name, line)
39
+ @io.puts "\n#{grab_comments!(' ')} #{keyword}: #{indent(name, ' ')}"
40
+ end
41
+
42
+ def scenario(keyword, name, line, location=nil)
43
+ flush_table
44
+ @io.puts "\n#{grab_comments!(' ')}#{grab_tags!(' ')} #{keyword}: #{indent(name, ' ')}#{indented_scenario_location!(keyword, name, location)}"
45
+ end
46
+
47
+ def scenario_outline(keyword, name, line)
48
+ flush_table
49
+ @io.puts "\n#{grab_comments!(' ')}#{grab_tags!(' ')} #{keyword}: #{indent(name, ' ')}"
50
+ end
51
+
52
+ def examples(keyword, name, line)
53
+ flush_table
54
+ @io.puts "\n#{grab_comments!(' ')}#{grab_tags!(' ')} #{keyword}: #{indent(name, ' ')}"
55
+ end
56
+
57
+ def step(keyword, name, line, status=nil, exception=nil, arguments=nil, location=nil)
58
+ flush_table
59
+ status_param = "#{status}_param" if status
60
+ name = Gherkin::Formatter::Argument.format(name, @format, (arguments || []))
61
+ #{|arg| status_param ? self.__send__(status_param, arg, @monochrome) : arg} if arguments
62
+
63
+ step = "#{keyword}#{indent(name, ' ')}"
64
+ step = self.__send__(status, step, @monochrome) if status
65
+
66
+ @io.puts("#{grab_comments!(' ')} #{step}#{indented_step_location!(location)}")
67
+ end
68
+
69
+ def row(row, line)
70
+ @rows ||= []
71
+ @rows << row.map{|cell| escape_cell(cell)}
72
+ end
73
+
74
+ def py_string(string, line)
75
+ @io.puts " \"\"\"\n" + string.gsub(START, ' ').gsub(/"""/,'\"\"\"') + "\n \"\"\""
76
+ end
77
+
78
+ def syntax_error(state, event, legal_events, line)
79
+ raise "SYNTAX ERROR"
80
+ end
81
+
82
+ def eof
83
+ flush_table
84
+ end
85
+
86
+ # This method can be invoked before a #scenario, to ensure location arguments are aligned
87
+ def steps(steps)
88
+ @step_lengths = steps.map {|keyword, name| (keyword+name).unpack("U*").length}
89
+ @max_step_length = @step_lengths.max
90
+ @step_index = -1
91
+ end
92
+
93
+ def exception(exception)
94
+ exception_text = "#{exception.message} (#{exception.class})\n#{(exception.backtrace || []).join("\n")}".gsub(/^/, ' ')
95
+ @io.puts(failed(exception_text, @monochrome))
96
+ end
97
+
98
+ def flush_table(exception=nil, statuses=nil)
99
+ return if @rows.nil?
100
+ cell_lengths = @rows.map { |col| col.map { |cell| cell.unpack("U*").length }}
101
+ max_lengths = cell_lengths.transpose.map { |col_lengths| col_lengths.max }.flatten
102
+
103
+ @rows.each_with_index do |row, i|
104
+ j = -1
105
+ @io.puts ' | ' + row.zip(max_lengths).map { |cell, max_length|
106
+ j += 1
107
+ color(cell, statuses, j) + ' ' * (max_length - cell_lengths[i][j])
108
+ }.join(' | ') + ' |'
109
+ exception(exception) if exception
110
+ end
111
+ @rows = nil
112
+ end
113
+
114
+ private
115
+
116
+ def color(cell, statuses, col)
117
+ if statuses
118
+ self.__send__(statuses[col], cell, @monochrome) + (@monochrome ? '' : reset)
119
+ else
120
+ cell
121
+ end
122
+ end
123
+
124
+ if(RUBY_VERSION =~ /^1\.9/)
125
+ START = /#{"^".encode('UTF-8')}/
126
+ NL = Regexp.new("\n".encode('UTF-8'))
127
+ else
128
+ START = /^/
129
+ NL = /\n/n
130
+ end
131
+
132
+ def indent(string, indentation)
133
+ indent = ""
134
+ string.split(NL).map do |l|
135
+ s = "#{indent}#{l}"
136
+ indent = indentation
137
+ s
138
+ end.join("\n")
139
+ end
140
+
141
+ def grab_tags!(indent)
142
+ tags = @tags ? indent + @tags.join(' ') + "\n" : ''
143
+ @tags = nil
144
+ tags
145
+ end
146
+
147
+ def grab_comments!(indent)
148
+ comments = @comments ? indent + @comments.join("\n#{indent}") + "\n" : ''
149
+ @comments = nil
150
+ comments
151
+ end
152
+
153
+ def indented_scenario_location!(keyword, name, location)
154
+ return "" if location.nil?
155
+ l = (keyword+name).unpack("U*").length
156
+ @max_step_length = [@max_step_length, l].max
157
+ indent = @max_step_length - l
158
+ ' ' * indent + ' ' + comments("# #{location}", @monochrome)
159
+ end
160
+
161
+ def indented_step_location!(location)
162
+ return "" if location.nil?
163
+ indent = @max_step_length - @step_lengths[@step_index+=1]
164
+ ' ' * indent + ' ' + comments("# #{location}", @monochrome)
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,176 @@
1
+ require 'yaml'
2
+ require 'gherkin/rubify'
3
+ require 'gherkin/native'
4
+
5
+ module Gherkin
6
+ class I18n
7
+ native_impl('gherkin') unless defined?(BYPASS_NATIVE_IMPL)
8
+
9
+ FEATURE_ELEMENT_KEYS = %w{feature background scenario scenario_outline examples}
10
+ STEP_KEYWORD_KEYS = %w{given when then and but}
11
+ KEYWORD_KEYS = FEATURE_ELEMENT_KEYS + STEP_KEYWORD_KEYS
12
+ LANGUAGES = YAML.load_file(File.dirname(__FILE__) + '/i18n.yml')
13
+
14
+ class << self
15
+ include Rubify
16
+
17
+ # Used by code generators for other lexer tools like pygments lexer and textmate bundle
18
+ def all
19
+ LANGUAGES.keys.sort.map{|iso_code| get(iso_code)}
20
+ end
21
+
22
+ def get(iso_code)
23
+ languages[iso_code] ||= new(iso_code)
24
+ end
25
+
26
+ # Returns all keyword translations and aliases of +keywords+, escaped and joined with <tt>|</tt>.
27
+ # This method is convenient for editor support and syntax highlighting engines for Gherkin, where
28
+ # there is typically a code generation tool to generate regular expressions for recognising the
29
+ # various I18n translations of Gherkin's keywords.
30
+ #
31
+ # The +keywords+ arguments can be one of <tt>:feature</tt>, <tt>:background</tt>, <tt>:scenario</tt>,
32
+ # <tt>:scenario_outline</tt>, <tt>:examples</tt>, <tt>:step</tt>.
33
+ def keyword_regexp(*keywords)
34
+ unique_keywords = all.map do |i18n|
35
+ keywords.map do |keyword|
36
+ if keyword.to_s == 'step'
37
+ i18n.step_keywords
38
+ else
39
+ i18n.keywords(keyword)
40
+ end
41
+ end
42
+ end
43
+
44
+ unique_keywords.flatten.compact.sort.reverse.uniq.join('|').gsub(/\*/, '\*')
45
+ end
46
+
47
+ def code_keywords
48
+ rubify(all.map{|i18n| i18n.code_keywords}).flatten.uniq.sort
49
+ end
50
+
51
+ def code_keyword_for(gherkin_keyword)
52
+ gherkin_keyword.gsub(/[\s',]/, '').strip
53
+ end
54
+
55
+ def language_table
56
+ require 'stringio'
57
+ require 'gherkin/formatter/pretty_formatter'
58
+ io = defined?(JRUBY_VERSION) ? Java.java.io.StringWriter.new : StringIO.new
59
+ pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
60
+ all.each{|i18n| pf.row([i18n.iso_code, i18n.keywords('name')[0], i18n.keywords('native')[0]], 0)}
61
+ pf.flush_table
62
+ if defined?(JRUBY_VERSION)
63
+ io.getBuffer.toString
64
+ else
65
+ io.rewind
66
+ io.read
67
+ end
68
+ end
69
+
70
+ def unicode_escape(word, prefix="\\u")
71
+ word = word.unpack("U*").map do |c|
72
+ if c > 127 || c == 32
73
+ "#{prefix}%04x" % c
74
+ else
75
+ c.chr
76
+ end
77
+ end.join
78
+ end
79
+
80
+ private
81
+
82
+ def languages
83
+ @languages ||= {}
84
+ end
85
+ end
86
+
87
+ attr_reader :iso_code
88
+
89
+ def initialize(iso_code)
90
+ @iso_code = iso_code
91
+ @keywords = LANGUAGES[iso_code]
92
+ raise "Language not supported: #{iso_code.inspect}" if @iso_code.nil?
93
+ @keywords['grammar_name'] = @keywords['name'].gsub(/\s/, '')
94
+ end
95
+
96
+ def lexer(listener, force_ruby=false)
97
+ begin
98
+ if force_ruby
99
+ rb(listener)
100
+ else
101
+ begin
102
+ c(listener)
103
+ rescue NameError, LoadError => e
104
+ warn("WARNING: #{e.message}. Reverting to Ruby lexer.")
105
+ rb(listener)
106
+ end
107
+ end
108
+ rescue LoadError => e
109
+ raise I18nLexerNotFound, "No lexer was found for #{i18n_language_name} (#{e.message}). Supported languages are listed in gherkin/i18n.yml."
110
+ end
111
+ end
112
+
113
+ def c(listener)
114
+ require 'gherkin/c_lexer'
115
+ CLexer[underscored_iso_code].new(listener)
116
+ end
117
+
118
+ def rb(listener)
119
+ require 'gherkin/rb_lexer'
120
+ RbLexer[underscored_iso_code].new(listener)
121
+ end
122
+
123
+ def underscored_iso_code
124
+ @iso_code.gsub(/[\s-]/, '_').downcase
125
+ end
126
+
127
+ # Keywords that can be used in Gherkin source
128
+ def step_keywords
129
+ STEP_KEYWORD_KEYS.map{|iso_code| keywords(iso_code)}.flatten.uniq
130
+ end
131
+
132
+ # Keywords that can be used in code
133
+ def code_keywords
134
+ result = step_keywords.map{|keyword| self.class.code_keyword_for(keyword)}
135
+ result.delete('*')
136
+ result
137
+ end
138
+
139
+ def keywords(iso_code)
140
+ iso_code = iso_code.to_s
141
+ raise "No #{iso_code.inspect} in #{@keywords.inspect}" if @keywords[iso_code].nil?
142
+ @keywords[iso_code].split('|').map{|keyword| real_keyword(iso_code, keyword)}
143
+ end
144
+
145
+ def keyword_table
146
+ require 'stringio'
147
+ require 'gherkin/formatter/pretty_formatter'
148
+ io = StringIO.new
149
+ pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
150
+
151
+ KEYWORD_KEYS.each do |key|
152
+ pf.row([key, keywords(key).map{|keyword| %{"#{keyword}"}}.join(', ')], 0)
153
+ end
154
+ STEP_KEYWORD_KEYS.each do |key|
155
+ code_keywords = keywords(key).reject{|keyword| keyword == '* '}.map do |keyword|
156
+ %{"#{self.class.code_keyword_for(keyword)}"}
157
+ end.join(', ')
158
+ pf.row(["#{key} (code)", code_keywords], 0)
159
+ end
160
+
161
+ pf.flush_table
162
+ io.rewind
163
+ io.read
164
+ end
165
+
166
+ private
167
+
168
+ def real_keyword(iso_code, keyword)
169
+ if(STEP_KEYWORD_KEYS.index(iso_code))
170
+ (keyword + ' ').sub(/< $/, '')
171
+ else
172
+ keyword
173
+ end
174
+ end
175
+ end
176
+ end