gherkin_jruby 0.3.1.pre.jruby

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38b437fd9881eff6dfbe7bd8d3c3b7fae7635ab2
4
+ data.tar.gz: 6c7f61a399113bfeac0ae3115029a1974e8a9f90
5
+ SHA512:
6
+ metadata.gz: 068fb7ebc94d293c51a52734d13cfea9d14b66cd79ecf5b40064735511db9736471f7dbdedaa9317921bb96e53e9e15a06e7771f201c4a70bd0ea0e5333abd7c
7
+ data.tar.gz: 57137563b34f849e71ed29278983991488e2f87e7d7b78b28568a1028963c7c2572c90584c2f5d0dd4ec1025ea0db4a4d151cd05a464434b61f46af4d4a5d523
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rbx
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ env:
2
+ - RBXOPT=-X19
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - rbx-2.0.0
7
+ - ruby-head
8
+ - rbx-head
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gherkin.gemspec
4
+ gemspec
5
+ gem 'rake'
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ require 'bundler'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new do |t|
7
+ t.libs << "test"
8
+ t.test_files = FileList['./test/**/*_test.rb']
9
+ end
10
+
11
+ desc "Regenerate Gherkin-ruby lexer and parser."
12
+ task :regenerate do
13
+ has_rex = `which rex`
14
+ has_racc = `which racc`
15
+
16
+ if has_rex && has_racc
17
+ `rex lib/gherkin_ruby/parser/gherkin.rex -o lib/gherkin_ruby/parser/lexer.rb`
18
+ `racc #{'--debug' if ENV['DEBUG_RACC']} lib/gherkin_ruby/parser/gherkin.y -o lib/gherkin_ruby/parser/parser.rb`
19
+ else
20
+ puts "You need both Rexical and Racc to do that. Install them by doing:"
21
+ puts
22
+ puts "\t\tgem install rexical"
23
+ puts "\t\tgem install racc"
24
+ puts
25
+ puts "Or just type `bundle install`."
26
+ end
27
+ end
28
+
29
+ task :default => [:regenerate, :test]
data/Readme.md ADDED
@@ -0,0 +1,98 @@
1
+ # gherkin-ruby [![Build Status](https://secure.travis-ci.org/codegram/gherkin-ruby.png)](http://travis-ci.org/codegram/gherkin-ruby) [![Dependency Status](https://gemnasium.com/codegram/gherkin-ruby.png)](http://gemnasium.com/codegram/gherkin-ruby)
2
+ Gherkin-ruby is a pure Ruby implementation of a [Gherkin](http://github.com/cucumber/gherkin) parser.
3
+
4
+ Tested with MRI 1.9.3, 2.0.0, head, Rubinius 2.0.0-rc1 and Rubinius head.
5
+
6
+ ## WARNING: Will be deprecated after Gherkin 3.0
7
+
8
+ A new rewrite of the Gherkin parser used by Cucumber is planned (for version
9
+ 3.0) gherkin-ruby will not add any more features until then, and will
10
+ eventually be deprecated in favor of Gherkin 3.0.
11
+
12
+ ## FAQ
13
+
14
+ ### Why this one over the official, fast, Ragel-based Gherkin parser?
15
+
16
+ * Less than 200 LOC.
17
+ * No Java/.NET crap.
18
+ * Fast enough for our purposes (using it for the [Spinach](http://github.com/codegram/spinach) project)
19
+
20
+ ### Why don't you support tables?
21
+
22
+ * Because we believe it's a BDD anti-pattern. Tables show the need for more
23
+ unit tests.
24
+
25
+ ## Install
26
+
27
+ $ gem install gherkin-ruby
28
+
29
+ Or in your Gemfile:
30
+
31
+ ```ruby
32
+ # Gemfile
33
+
34
+ gem 'gherkin-ruby'
35
+ ```
36
+
37
+ ## Usage
38
+ You can easily implement your own visitors to traverse the Abstract Syntax Tree. The following example just prints the step names to standard output:
39
+
40
+ ```ruby
41
+ class MyVisitor
42
+ def visit(ast)
43
+ ast.accept(self)
44
+ end
45
+
46
+ def visit_Feature(feature)
47
+ # Do something nasty with the feature
48
+ # Set whatever state you want:
49
+ # @current_feature = feature
50
+ # etc etc
51
+ # And keep visiting its children:
52
+
53
+ feature.each { |scenario| scenario.accept(self) }
54
+ end
55
+
56
+ def visit_Scenario(scenario)
57
+ # Do something nasty with the scenario
58
+ # Set whatever state you want:
59
+ # @current_scenario = scenario
60
+ # etc etc
61
+ # And keep visiting its children:
62
+
63
+ scenario.each { |step| step.accept(self) }
64
+ end
65
+
66
+ def visit_Background(background)
67
+ # Do something nasty with the background
68
+ # And keep visiting its children:
69
+
70
+ background.each { |step| step.accept(self) }
71
+ end
72
+
73
+ def visit_Tag(tag)
74
+ # Do something nasty with the tag
75
+ end
76
+
77
+ def visit_Step(step)
78
+ # Finally, print the step name.
79
+ puts "STEP: #{step.name}"
80
+ end
81
+ end
82
+
83
+ ast = Gherkin.parse(File.read('some.feature'))
84
+ visitor = MyVisitor.new
85
+ visitor.visit(ast)
86
+ ```
87
+
88
+ ## Todo
89
+
90
+ * Some optimization
91
+
92
+ ## FAQ
93
+
94
+
95
+
96
+ ## License
97
+
98
+ MIT (Expat) License. Copyright 2011-2013 [Codegram Technologies](http://codegram.com)
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "gherkin_ruby/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gherkin_jruby"
7
+ s.version = GherkinRuby::VERSION
8
+ s.authors = ["Marc Divins", "Josep M. Bach", "Rodrigo Alvarez"]
9
+ s.email = ["marcdivc@gmail.com", "josep.m.bach@gmail.com", "papipo@gmail.com"]
10
+ s.homepage = "http://github.com/Papipo/gherkin-jruby"
11
+ s.summary = %q{Gherkin-ruby is a Gherkin parser in pure Ruby using Rexical and Racc that works on jruby}
12
+ s.description = %q{Gherkin-ruby is a Gherkin parser in pure Ruby using Rexical and Racc that works on jruby}
13
+
14
+ s.add_development_dependency 'minitest'
15
+ s.add_development_dependency 'rexical'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "gherkin_ruby/version"
2
+ require_relative 'gherkin_ruby/ast'
3
+ require_relative 'gherkin_ruby/parser'
4
+
5
+ module GherkinRuby
6
+ def self.parse(input)
7
+ parser = Parser.new
8
+ parser.parse(input)
9
+ end
10
+ end
@@ -0,0 +1,89 @@
1
+ module GherkinRuby
2
+ module AST
3
+ class Node
4
+ attr_reader :filename, :line
5
+
6
+ def accept(visitor)
7
+ name = self.class.name.split('::').last
8
+ visitor.send("visit_#{name}".to_sym, self)
9
+ end
10
+
11
+ def pos(filename, line=nil)
12
+ @filename, @line = filename, line
13
+ end
14
+ end
15
+
16
+ class Feature < Node
17
+ attr_reader :name, :background, :scenarios, :tags
18
+ attr_writer :background, :scenarios, :tags
19
+ attr_accessor :description
20
+
21
+ include Enumerable
22
+
23
+ def initialize(name, scenarios=[], tags=[], background=nil)
24
+ @name = name
25
+ @background = background
26
+ @tags = tags
27
+ @scenarios = scenarios
28
+ end
29
+
30
+ def each
31
+ @scenarios.each
32
+ end
33
+ end
34
+
35
+ class Background < Node
36
+ attr_reader :steps
37
+ attr_writer :steps
38
+
39
+ include Enumerable
40
+
41
+ def initialize(steps=[])
42
+ @steps = steps
43
+ end
44
+
45
+ def line
46
+ @steps.first.line - 1 if @steps.any?
47
+ end
48
+
49
+ def each
50
+ @steps.each
51
+ end
52
+ end
53
+
54
+ class Scenario < Node
55
+ attr_reader :name, :steps, :tags
56
+
57
+ include Enumerable
58
+
59
+ def initialize(name, steps=[], tags=[])
60
+ @name = name.to_s
61
+ @steps = steps
62
+ @tags = tags
63
+ end
64
+
65
+ def line
66
+ @steps.first.line - 1 if @steps.any?
67
+ end
68
+
69
+ def each
70
+ @steps.each
71
+ end
72
+ end
73
+
74
+ class Step < Node
75
+ attr_reader :name, :keyword
76
+ def initialize(name, keyword)
77
+ @name = name.to_s
78
+ @keyword = keyword.to_s
79
+ end
80
+ end
81
+
82
+ class Tag < Node
83
+ attr_reader :name
84
+ def initialize(name)
85
+ @name = name
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1 @@
1
+ require_relative 'parser/parser'
@@ -0,0 +1,44 @@
1
+ # Compile with: rex gherkin.rex -o lexer.rb
2
+
3
+ class GherkinRuby::Parser
4
+
5
+ macro
6
+ BLANK [\ \t]+
7
+
8
+ rule
9
+ # Whitespace
10
+ {BLANK} # no action
11
+ \#.*$
12
+
13
+ # Literals
14
+ \n { [:NEWLINE, text] }
15
+
16
+ # Keywords
17
+ Feature: { [:FEATURE, text[0..-2]] }
18
+ Background: { [:BACKGROUND, text[0..-2]] }
19
+ Scenario: { [:SCENARIO, text[0..-2]] }
20
+
21
+ # Tags
22
+ @(\w|-)+ { [:TAG, text[1..-1]] }
23
+
24
+ # Step keywords
25
+ Given { [:GIVEN, text] }
26
+ When { [:WHEN, text] }
27
+ Then { [:THEN, text] }
28
+ And { [:AND, text] }
29
+ But { [:BUT, text] }
30
+
31
+ # Text
32
+ [^#\n]* { [:TEXT, text.strip] }
33
+
34
+ inner
35
+ def tokenize(code)
36
+ scan_setup(code)
37
+ tokens = []
38
+ while token = next_token
39
+ tokens << token
40
+ end
41
+ tokens
42
+ end
43
+
44
+ end
@@ -0,0 +1,108 @@
1
+ # Compile with: racc gherkin.y -o parser.rb
2
+
3
+ class GherkinRuby::Parser
4
+
5
+ # Declare tokens produced by the lexer
6
+ token NEWLINE
7
+ token FEATURE BACKGROUND SCENARIO
8
+ token TAG
9
+ token GIVEN WHEN THEN AND BUT
10
+ token TEXT
11
+
12
+ rule
13
+
14
+ Root:
15
+ Feature { result = val[0]; }
16
+ |
17
+ Feature
18
+ Scenarios { result = val[0]; result.scenarios = val[1] }
19
+ | FeatureTags Feature { result = val[1]; result.tags = val[0] }
20
+ | FeatureTags Feature
21
+ Scenarios { result = val[1]; result.scenarios = val[2]; result.tags = val[0] }
22
+ ;
23
+
24
+ Newline:
25
+ NEWLINE
26
+ | Newline NEWLINE
27
+ ;
28
+
29
+ FeatureTags:
30
+ Tags { result = val[0] }
31
+ | Newline Tags { result = val[1] }
32
+
33
+ Feature:
34
+ FeatureHeader { result = val[0] }
35
+ | FeatureHeader
36
+ Background { result = val[0]; result.background = val[1] }
37
+ ;
38
+
39
+ FeatureHeader:
40
+ FeatureName { result = val[0] }
41
+ | FeatureName Newline { result = val[0] }
42
+ | FeatureName Newline
43
+ Description { result = val[0]; result.description = val[2] }
44
+ ;
45
+
46
+ FeatureName:
47
+ FEATURE TEXT { result = AST::Feature.new(val[1]); result.pos(filename, lineno) }
48
+ | Newline FEATURE TEXT { result = AST::Feature.new(val[2]); result.pos(filename, lineno) }
49
+ ;
50
+
51
+ Description:
52
+ TEXT Newline { result = val[0] }
53
+ | Description TEXT Newline { result = val[0...-1].flatten }
54
+ ;
55
+
56
+ Background:
57
+ BackgroundHeader
58
+ Steps { result = val[0]; result.steps = val[1] }
59
+ ;
60
+
61
+ BackgroundHeader:
62
+ BACKGROUND Newline { result = AST::Background.new; result.pos(filename, lineno) }
63
+ ;
64
+
65
+ Steps:
66
+ Step { result = [val[0]] }
67
+ | Step Newline { result = [val[0]] }
68
+ | Step Newline Steps { val[2].unshift(val[0]); result = val[2] }
69
+ ;
70
+
71
+ Step:
72
+ Keyword TEXT { result = AST::Step.new(val[1], val[0]); result.pos(filename, lineno) }
73
+ ;
74
+
75
+ Keyword:
76
+ GIVEN | WHEN | THEN | AND | BUT
77
+ ;
78
+
79
+ Scenarios:
80
+ Scenario { result = [val[0]] }
81
+ | Scenarios Scenario { result = val[0] << val[1] }
82
+ ;
83
+
84
+ Scenario:
85
+ SCENARIO TEXT Newline
86
+ Steps { result = AST::Scenario.new(val[1], val[3]); result.pos(filename, lineno - 1) }
87
+ | Tags Newline
88
+ SCENARIO TEXT Newline
89
+ Steps { result = AST::Scenario.new(val[3], val[5], val[0]); result.pos(filename, lineno - 2) }
90
+ ;
91
+
92
+ Tags:
93
+ TAG { result = [AST::Tag.new(val[0])] }
94
+ | Tags TAG { result = val[0] << AST::Tag.new(val[1]) }
95
+ ;
96
+
97
+ end
98
+
99
+ ---- header
100
+ require_relative "lexer"
101
+ require_relative "../ast"
102
+
103
+ ---- inner
104
+
105
+ def parse(input)
106
+ @yydebug = true if ENV['DEBUG_RACC']
107
+ scan_str(input)
108
+ end
@@ -0,0 +1,120 @@
1
+ #--
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.5
4
+ # from lexical definition file "lib/gherkin_ruby/parser/gherkin.rex".
5
+ #++
6
+
7
+ require 'racc/parser'
8
+ # Compile with: rex gherkin.rex -o lexer.rb
9
+
10
+ class GherkinRuby::Parser < Racc::Parser
11
+ require 'strscan'
12
+
13
+ class ScanError < StandardError ; end
14
+
15
+ attr_reader :lineno
16
+ attr_reader :filename
17
+ attr_accessor :state
18
+
19
+ def scan_setup(str)
20
+ @ss = StringScanner.new(str)
21
+ @lineno = 1
22
+ @state = nil
23
+ end
24
+
25
+ def action
26
+ yield
27
+ end
28
+
29
+ def scan_str(str)
30
+ scan_setup(str)
31
+ do_parse
32
+ end
33
+ alias :scan :scan_str
34
+
35
+ def load_file( filename )
36
+ @filename = filename
37
+ open(filename, "r") do |f|
38
+ scan_setup(f.read)
39
+ end
40
+ end
41
+
42
+ def scan_file( filename )
43
+ load_file(filename)
44
+ do_parse
45
+ end
46
+
47
+
48
+ def next_token
49
+ return if @ss.eos?
50
+
51
+ # skips empty actions
52
+ until token = _next_token or @ss.eos?; end
53
+ token
54
+ end
55
+
56
+ def _next_token
57
+ text = @ss.peek(1)
58
+ @lineno += 1 if text == "\n"
59
+ token = case @state
60
+ when nil
61
+ case
62
+ when (text = @ss.scan(/[ \t]+/))
63
+ ;
64
+
65
+ when (text = @ss.scan(/\#.*$/))
66
+ ;
67
+
68
+ when (text = @ss.scan(/\n/))
69
+ action { [:NEWLINE, text] }
70
+
71
+ when (text = @ss.scan(/Feature:/))
72
+ action { [:FEATURE, text[0..-2]] }
73
+
74
+ when (text = @ss.scan(/Background:/))
75
+ action { [:BACKGROUND, text[0..-2]] }
76
+
77
+ when (text = @ss.scan(/Scenario:/))
78
+ action { [:SCENARIO, text[0..-2]] }
79
+
80
+ when (text = @ss.scan(/@(\w|-)+/))
81
+ action { [:TAG, text[1..-1]] }
82
+
83
+ when (text = @ss.scan(/Given/))
84
+ action { [:GIVEN, text] }
85
+
86
+ when (text = @ss.scan(/When/))
87
+ action { [:WHEN, text] }
88
+
89
+ when (text = @ss.scan(/Then/))
90
+ action { [:THEN, text] }
91
+
92
+ when (text = @ss.scan(/And/))
93
+ action { [:AND, text] }
94
+
95
+ when (text = @ss.scan(/But/))
96
+ action { [:BUT, text] }
97
+
98
+ when (text = @ss.scan(/[^#\n]*/))
99
+ action { [:TEXT, text.strip] }
100
+
101
+ else
102
+ text = @ss.string[@ss.pos .. -1]
103
+ raise ScanError, "can not match: '" + text + "'"
104
+ end # if
105
+
106
+ else
107
+ raise ScanError, "undefined state: '" + state.to_s + "'"
108
+ end # case state
109
+ token
110
+ end # def _next_token
111
+
112
+ def tokenize(code)
113
+ scan_setup(code)
114
+ tokens = []
115
+ while token = next_token
116
+ tokens << token
117
+ end
118
+ tokens
119
+ end
120
+ end # class