gherkin_jruby 0.3.1.pre.jruby

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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