gherkin 0.0.3-universal-java-1.5 → 0.0.4-universal-java-1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,7 +7,7 @@ import gherkin.Lexer;
7
7
  import gherkin.Listener;
8
8
  import gherkin.LexingError;
9
9
 
10
- public class <%= i18n_lexer_class_name %> implements Lexer {
10
+ public class <%= @i18n.capitalize %> implements Lexer {
11
11
  %%{
12
12
  machine lexer;
13
13
  alphtype byte;
@@ -72,10 +72,12 @@ public class <%= i18n_lexer_class_name %> implements Lexer {
72
72
 
73
73
  action store_comment_content {
74
74
  listener.comment(substring(data, contentStart, p).trim(), lineNumber);
75
+ keywordStart = -1;
75
76
  }
76
77
 
77
78
  action store_tag_content {
78
79
  listener.tag(substring(data, contentStart, p).trim(), currentLine);
80
+ keywordStart = -1;
79
81
  }
80
82
 
81
83
  action inc_line_number {
@@ -134,12 +136,12 @@ public class <%= i18n_lexer_class_name %> implements Lexer {
134
136
  }
135
137
  }
136
138
 
137
- include lexer_common "lexer_common.<%= i18n_language %>.rl";
139
+ include lexer_common "lexer_common.<%= @i18n %>.rl";
138
140
  }%%
139
141
 
140
142
  private final Listener listener;
141
143
 
142
- public <%= i18n_lexer_class_name %>(Listener listener) {
144
+ public <%= @i18n.capitalize %>(Listener listener) {
143
145
  this.listener = listener;
144
146
  }
145
147
 
@@ -1,12 +1,9 @@
1
+ require 'gherkin/core_ext/array'
2
+
1
3
  module Gherkin
2
4
  module RbLexer
3
- class <%= i18n_lexer_class_name %> #:nodoc:
5
+ class <%= @i18n.capitalize %> #:nodoc:
4
6
  %%{
5
- # patterns:
6
- # * data[start...end].pack("c*").strip_of_some_sort
7
- # * changing the end point of the range according to next_keyword_start
8
- # * methods taking the machine state because Ragel doesn't seem to know about ivars
9
-
10
7
  machine lexer;
11
8
 
12
9
  action begin_content {
@@ -24,7 +21,7 @@ module Gherkin
24
21
  }
25
22
 
26
23
  action store_pystring_content {
27
- con = unindent(@start_col, data[@content_start...@next_keyword_start-1].pack("c*").sub(/(\r?\n)?( )*\Z/, ''))
24
+ con = unindent(@start_col, data[@content_start...@next_keyword_start-1].utf8_pack("c*").sub(/(\r?\n)?( )*\Z/, ''))
28
25
  @listener.py_string(con, @current_line)
29
26
  }
30
27
 
@@ -59,18 +56,20 @@ module Gherkin
59
56
  }
60
57
 
61
58
  action store_step_content {
62
- con = data[@content_start...p].pack("c*").strip
59
+ con = data[@content_start...p].utf8_pack("c*").strip
63
60
  @listener.step(@keyword, con, @current_line)
64
61
  }
65
62
 
66
63
  action store_comment_content {
67
- con = data[@content_start...p].pack("c*").strip
64
+ con = data[@content_start...p].utf8_pack("c*").strip
68
65
  @listener.comment(con, @line_number)
66
+ @keyword_start = nil
69
67
  }
70
68
 
71
69
  action store_tag_content {
72
- con = data[@content_start...p].pack("c*").strip
70
+ con = data[@content_start...p].utf8_pack("c*").strip
73
71
  @listener.tag(con, @current_line)
72
+ @keyword_start = nil
74
73
  }
75
74
 
76
75
  action inc_line_number {
@@ -86,7 +85,7 @@ module Gherkin
86
85
  }
87
86
 
88
87
  action end_keyword {
89
- @keyword = data[@keyword_start...p].pack("c*").sub(/:$/,'').strip
88
+ @keyword = data[@keyword_start...p].utf8_pack("c*").sub(/:$/,'').strip
90
89
  @keyword_start = nil
91
90
  }
92
91
 
@@ -109,7 +108,7 @@ module Gherkin
109
108
  }
110
109
 
111
110
  action store_cell_content {
112
- con = data[@content_start...p].pack("c*").strip
111
+ con = data[@content_start...p].utf8_pack("c*").strip
113
112
  current_row << con
114
113
  }
115
114
 
@@ -130,7 +129,7 @@ module Gherkin
130
129
  end
131
130
  }
132
131
 
133
- include lexer_common "lexer_common.<%= i18n_language %>.rl";
132
+ include lexer_common "lexer_common.<%= @i18n %>.rl";
134
133
  }%%
135
134
 
136
135
  def initialize(listener)
@@ -159,13 +158,13 @@ module Gherkin
159
158
 
160
159
  def store_keyword_content(event, data, p, eof)
161
160
  end_point = (!@next_keyword_start or (p == eof)) ? p : @next_keyword_start
162
- con = yield data[@content_start...end_point].pack("c*")
161
+ con = yield data[@content_start...end_point].utf8_pack("c*")
163
162
  @listener.send(event, @keyword, con, @current_line)
164
163
  end
165
164
 
166
165
  def current_line_content(data, p)
167
166
  rest = data[@last_newline..-1]
168
- rest[0..rest.index(10)||-1].pack("c*").strip
167
+ rest[0..rest.index(10)||-1].utf8_pack("c*").strip
169
168
  end
170
169
  end
171
170
  end
@@ -2,12 +2,12 @@
2
2
  machine lexer_common;
3
3
 
4
4
  # Language specific
5
- I18N_Feature = <%= i18n['feature'] %> >start_keyword %end_keyword;
6
- I18N_Background = <%= i18n['background'] %> >start_keyword %end_keyword;
7
- I18N_ScenarioOutline = <%= i18n['scenario_outline'] %> >start_keyword %end_keyword;
8
- I18N_Scenario = <%= i18n['scenario'] %> >start_keyword %end_keyword;
9
- I18N_Step = (<%= i18n['given'] %> | <%= i18n['when'] %> | <%= i18n['and'] %> | <%= i18n['then'] %> | <%= i18n['but'] %>) >start_keyword %end_keyword;
10
- I18N_Examples = <%= i18n['examples'] %> >start_keyword %end_keyword;
5
+ I18N_Feature = <%= keywords['feature'] %> >start_keyword %end_keyword;
6
+ I18N_Background = <%= keywords['background'] %> >start_keyword %end_keyword;
7
+ I18N_ScenarioOutline = <%= keywords['scenario_outline'] %> >start_keyword %end_keyword;
8
+ I18N_Scenario = <%= keywords['scenario'] %> >start_keyword %end_keyword;
9
+ I18N_Step = (<%= keywords['given'] %> | <%= keywords['when'] %> | <%= keywords['and'] %> | <%= keywords['then'] %> | <%= keywords['but'] %>) >start_keyword %end_keyword;
10
+ I18N_Examples = <%= keywords['examples'] %> >start_keyword %end_keyword;
11
11
 
12
12
  EOF = '%_FEATURE_END_%'; # Explicit EOF added before scanning begins
13
13
  EOL = ('\r'? '\n') @inc_line_number @last_newline;
@@ -0,0 +1,8 @@
1
+ Feature: Logging in
2
+ So that I can be myself
3
+ # Comment
4
+ Scenario: Anonymous user can get a login form.
5
+ Scenery here
6
+
7
+ @tag
8
+ Scenario: Another one
@@ -1,6 +1,6 @@
1
1
  #Comment on line 1
2
+ #Comment on line 2
2
3
  @tag1 @tag2
3
- #Comment on line 3
4
4
  Feature: Feature Text
5
5
  In order to test multiline forms
6
6
  As a ragel writer
@@ -40,4 +40,4 @@ Feature: Feature Text
40
40
  """
41
41
  Makes Homer something something
42
42
  """
43
- Then crazy
43
+ Then crazy
@@ -362,15 +362,28 @@ Given I am a step
362
362
  ]
363
363
  end
364
364
  end
365
-
365
+
366
+ describe "Comment or tag between Feature elements where previous narrative starts with same letter as a keyword" do
367
+ it "should lex this feature properly" do
368
+ scan_file("1.feature")
369
+ @listener.to_sexp.should == [
370
+ [:feature, "Feature", "Logging in\nSo that I can be myself", 1],
371
+ [:comment, "# Comment", 3],
372
+ [:scenario, "Scenario", "Anonymous user can get a login form.\nScenery here", 4],
373
+ [:tag, "tag", 7],
374
+ [:scenario, "Scenario", "Another one", 8]
375
+ ]
376
+ end
377
+ end
378
+
366
379
  describe "A complex feature with tags, comments, multiple scenarios, and multiple steps and tables" do
367
380
  it "should find things in the right order" do
368
381
  scan_file("complex.feature")
369
382
  @listener.to_sexp.should == [
370
383
  [:comment, "#Comment on line 1", 1],
371
- [:tag, "tag1", 2],
372
- [:tag, "tag2", 2],
373
- [:comment, "#Comment on line 3", 3],
384
+ [:comment, "#Comment on line 2", 2],
385
+ [:tag, "tag1", 3],
386
+ [:tag, "tag2", 3],
374
387
  [:feature, "Feature", "Feature Text\nIn order to test multiline forms\nAs a ragel writer\nI need to check for complex combinations", 4],
375
388
  [:comment, "#Comment on line 9", 9],
376
389
  [:comment, "#Comment on line 11", 11],
@@ -107,6 +107,18 @@ EOS
107
107
  @listener.should_receive(:py_string).with(" Line one", 1)
108
108
  @lexer.scan(str)
109
109
  end
110
+
111
+ it "should preserve the last newline(s) at the end of a py_string" do
112
+ str = <<EOS
113
+ """
114
+ PyString text
115
+
116
+
117
+ """
118
+ EOS
119
+ @listener.should_receive(:py_string).with("PyString text\n\n",1)
120
+ @lexer.scan(str)
121
+ end
110
122
  end
111
123
  end
112
124
  end
@@ -74,6 +74,7 @@ class Benchmarker
74
74
  def report_all
75
75
  Benchmark.bmbm do |x|
76
76
  x.report("c_gherkin:") { run_c_gherkin }
77
+ x.report("c_gherkin_no_parser:") { run_c_gherkin_no_parser }
77
78
  x.report("rb_gherkin:") { run_rb_gherkin }
78
79
  x.report("cucumber:") { run_cucumber }
79
80
  x.report("tt:") { run_tt }
@@ -93,32 +94,42 @@ class Benchmarker
93
94
  def run_tt
94
95
  require 'cucumber'
95
96
  # Using Cucumber's Treetop lexer, but never calling #build to build the AST
96
- lexer = Cucumber::Parser::NaturalLanguage.new(nil, 'en').lexer
97
+ lexer = Cucumber::Parser::NaturalLanguage.new(nil, 'en').parser
97
98
  @features.each do |file|
98
99
  source = IO.read(file)
99
100
  parse_tree = lexer.parse(source)
100
101
  if parse_tree.nil?
101
- raise Cucumber::Lexer::SyntaxError.new(lexer, file, 0)
102
+ raise Cucumber::Parser::SyntaxError.new(lexer, file, 0)
102
103
  end
103
104
  end
104
105
  end
105
106
 
106
107
  def run_rb_gherkin
107
108
  require 'gherkin'
109
+ require 'gherkin/rb_lexer'
108
110
  require 'null_listener'
109
- listener = NullListener.new
110
111
  @features.each do |feature|
111
- lexer = Gherkin::Feature.new('en', listener)
112
+ parser = Gherkin::Parser.new(NullListener.new, true, "root")
113
+ lexer = Gherkin::RbLexer['en'].new(parser)
112
114
  lexer.scan(File.read(feature))
113
115
  end
114
116
  end
115
117
 
116
- def run_c_gherkin
118
+ def run_c_gherkin
117
119
  require 'gherkin'
118
120
  require 'null_listener'
119
- listener = NullListener.new
120
- @features.each_with_index do |feature, idx|
121
- lexer = Gherkin::Feature.new('Native', listener)
121
+ @features.each do |feature|
122
+ parser = Gherkin::Parser.new(NullListener.new, true, "root")
123
+ lexer = Gherkin::CLexer['en'].new(parser)
124
+ lexer.scan(File.read(feature))
125
+ end
126
+ end
127
+
128
+ def run_c_gherkin_no_parser
129
+ require 'gherkin'
130
+ require 'null_listener'
131
+ @features.each do |feature|
132
+ lexer = Gherkin::CLexer['en'].new(NullListener.new)
122
133
  lexer.scan(File.read(feature))
123
134
  end
124
135
  end
@@ -144,24 +155,30 @@ namespace :bench do
144
155
  benchmarker.report("cucumber")
145
156
  end
146
157
 
147
- desc "Benchmark the Treetop lexer with the features in tasks/bench/generated"
158
+ desc "Benchmark the Treetop parser with the features in tasks/bench/generated"
148
159
  task :tt do
149
160
  benchmarker = Benchmarker.new
150
161
  benchmarker.report("tt")
151
162
  end
152
163
 
153
- desc "Benchmark the Ruby Gherkin lexer with the features in tasks/bench/generated"
164
+ desc "Benchmark the Ruby Gherkin lexer+parser with the features in tasks/bench/generated"
154
165
  task :rb_gherkin do
155
166
  benchmarker = Benchmarker.new
156
167
  benchmarker.report("rb_gherkin")
157
168
  end
158
169
 
159
- desc "Benchmark the C Gherkin lexer with the features in tasks/bench/generated"
170
+ desc "Benchmark the C Gherkin lexer+parser with the features in tasks/bench/generated"
160
171
  task :c_gherkin do
161
172
  benchmarker = Benchmarker.new
162
173
  benchmarker.report("c_gherkin")
163
174
  end
164
175
 
176
+ desc "Benchmark the C Gherkin lexer (no parser) with the features in tasks/bench/generated"
177
+ task :c_gherkin_no_parser do
178
+ benchmarker = Benchmarker.new
179
+ benchmarker.report("c_gherkin_no_parser")
180
+ end
181
+
165
182
  desc "Show basic statistics about the features in tasks/bench/generated"
166
183
  task :stats do
167
184
  ["Feature", "Scenario", "Given"].each do |kw|
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/ragel_task'
2
+
3
+ CLEAN.include [
4
+ '**/*.{o,bundle,jar,so,obj,pdb,lib,def,exp,log}', 'ext',
5
+ 'java/target',
6
+ 'ragel/i18n/*.rl',
7
+ 'lib/gherkin/rb_lexer/*.rb',
8
+ 'ext/**/*.c',
9
+ 'java/src/gherkin/lexer/*.java'
10
+ ]
11
+
12
+ desc "Compile the Java extensions"
13
+ task :jar do
14
+ sh("ant -f java/build.xml")
15
+ end
16
+
17
+ YAML.load_file(File.dirname(__FILE__) + '/../lib/gherkin/i18n.yml').each do |i18n, keywords|
18
+ i18n = i18n.gsub(/[\s-]/, '')
19
+
20
+ java = RagelTask.new('java', i18n, keywords)
21
+ rb = RagelTask.new('rb', i18n, keywords)
22
+
23
+ task :jar => java.target
24
+ task :jar => rb.target
25
+
26
+ begin
27
+ require 'rake/extensiontask'
28
+ c = RagelTask.new('c', i18n, keywords)
29
+
30
+ extconf = "ext/gherkin_lexer_#{i18n}/extconf.rb"
31
+
32
+ file extconf do
33
+ FileUtils.mkdir(File.dirname(extconf)) unless File.directory?(File.dirname(extconf))
34
+ File.open(extconf, "w") do |io|
35
+ io.write(<<-EOF)
36
+ require 'mkmf'
37
+ dir_config("gherkin_lexer_#{i18n}")
38
+ have_library("c", "main")
39
+ create_makefile("gherkin_lexer_#{i18n}")
40
+ EOF
41
+ end
42
+ end
43
+
44
+ Rake::ExtensionTask.new("gherkin_lexer_#{i18n}") do |ext|
45
+ if ENV['RUBY_CC_VERSION']
46
+ ext.cross_compile = true
47
+ ext.cross_platform = 'i386-mingw32'
48
+ end
49
+ end
50
+
51
+ task :compile => c.target
52
+ task :compile => rb.target
53
+
54
+ # The way tasks are defined with compile:xxx (but without namespace) in rake-compiler forces us
55
+ # to use these hacks for setting up dependencies. Ugly!
56
+ Rake::Task["compile:gherkin_lexer_#{i18n}"].prerequisites.unshift(extconf)
57
+ Rake::Task["compile:gherkin_lexer_#{i18n}"].prerequisites.unshift(c.target)
58
+ Rake::Task["compile:gherkin_lexer_#{i18n}"].prerequisites.unshift(rb.target)
59
+
60
+ Rake::Task["compile"].prerequisites.unshift(extconf)
61
+ Rake::Task["compile"].prerequisites.unshift(c.target)
62
+ Rake::Task["compile"].prerequisites.unshift(rb.target)
63
+ rescue LoadError
64
+ unless defined?($c_warned)
65
+ warn "WARNING: Rake::ExtensionTask not installed. Skipping C compilation."
66
+ $c_warned = true
67
+ task :compile # no-op
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,83 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+
4
+ class RagelTask
5
+ RL_OUTPUT_DIR = File.dirname(__FILE__) + "/../ragel/i18n"
6
+
7
+ def initialize(lang, i18n, keywords)
8
+ @lang = lang
9
+ @i18n = i18n
10
+ @keywords = keywords
11
+ define_tasks
12
+ end
13
+
14
+ def define_tasks
15
+ file target => [lang_ragel, common_ragel] do
16
+ mkdir_p(File.dirname(target)) unless File.directory?(File.dirname(target))
17
+ sh "ragel #{flags} #{lang_ragel} -o #{target}"
18
+ end
19
+
20
+ file lang_ragel => lang_erb do
21
+ impl = ERB.new(IO.read(lang_erb)).result(binding)
22
+ write(impl, lang_ragel)
23
+ end
24
+
25
+ file common_ragel => common_erb do
26
+ keywords = prep_keywords
27
+ common = ERB.new(IO.read(common_erb)).result(binding)
28
+ write(common, common_ragel)
29
+ end
30
+ end
31
+
32
+ def target
33
+ {
34
+ 'c' => "ext/gherkin_lexer_#{@i18n}/gherkin_lexer_#{@i18n}.c",
35
+ 'java' => "java/src/gherkin/lexer/#{@i18n.capitalize}.java",
36
+ 'rb' => "lib/gherkin/rb_lexer/#{@i18n}.rb"
37
+ }[@lang]
38
+ end
39
+
40
+ def common_ragel
41
+ RL_OUTPUT_DIR + "/lexer_common.#{@i18n}.rl"
42
+ end
43
+
44
+ def common_erb
45
+ File.dirname(__FILE__) + '/../ragel/lexer_common.rl.erb'
46
+ end
47
+
48
+ def lang_ragel
49
+ RL_OUTPUT_DIR + "/#{@i18n}.#{@lang}.rl"
50
+ end
51
+
52
+ def lang_erb
53
+ File.dirname(__FILE__) + "/../ragel/lexer.#{@lang}.rl.erb"
54
+ end
55
+
56
+ def flags
57
+ {
58
+ 'c' => '-C',
59
+ 'java' => '-J',
60
+ 'rb' => '-R'
61
+ }[@lang]
62
+ end
63
+
64
+ def prep_keywords
65
+ keywords = @keywords.dup
66
+ delimited_keywords = %w{feature background scenario scenario_outline examples}
67
+ bare_keywords = %w{given when then and but}
68
+ all_keywords = delimited_keywords + bare_keywords
69
+
70
+ all_keywords.each { |k| keywords[k] = keywords[k].split("|") }
71
+ delimited_keywords.each { |k| keywords[k].map! { |v| v += ':'} }
72
+ bare_keywords.each { |k| keywords[k].map! { |v| (v + ' ').sub(/< $/, '')} }
73
+ all_keywords.each { |k| keywords[k] = '("' + keywords[k].join('" | "') + '")' }
74
+ keywords
75
+ end
76
+
77
+ def write(content, filename)
78
+ mkdir_p(File.dirname(filename)) unless File.directory?(File.dirname(filename))
79
+ File.open(filename, "wb") do |file|
80
+ file.write(content)
81
+ end
82
+ end
83
+ end