forked from rouge-ruby/rouge
-
Notifications
You must be signed in to change notification settings - Fork 1
/
gherkin.rb
140 lines (119 loc) · 3.32 KB
/
gherkin.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
class Gherkin < RegexLexer
tag 'gherkin'
aliases 'cucumber', 'behat'
title "Gherkin"
desc 'A business-readable spec DSL (github.com/cucumber/cucumber/wiki/Gherkin)'
filenames '*.feature'
mimetypes 'text/x-gherkin'
def self.detect?(text)
return true if text.shebang? 'cucumber'
end
# self-modifying method that loads the keywords file
def self.keywords
Kernel::load File.join(Lexers::BASE_DIR, 'gherkin/keywords.rb')
keywords
end
def self.step_regex
# in Gherkin's config, keywords that end in < don't
# need word boundaries at the ends - all others do.
@step_regex ||= Regexp.new(
keywords[:step].map do |w|
if w.end_with? '<'
Regexp.escape(w.chop)
elsif w.end_with?(' ')
Regexp.escape(w)
else
"#{Regexp.escape(w)}\\b"
end
end.join('|')
)
end
rest_of_line = /.*?(?=[#\n])/
state :basic do
rule %r(#.*$), Comment
rule %r/[ \r\t]+/, Text
end
state :root do
mixin :basic
rule %r(\n), Text
rule %r(""".*?""")m, Str
rule %r(@[^\s@]+), Name::Tag
mixin :has_table
mixin :has_examples
end
state :has_scenarios do
rule %r((.*?)(:)) do |m|
reset_stack
keyword = m[1]
keyword_tok = if self.class.keywords[:element].include? keyword
push :description; Keyword::Namespace
elsif self.class.keywords[:feature].include? keyword
push :feature_description; Keyword::Declaration
elsif self.class.keywords[:examples].include? keyword
push :example_description; Name::Namespace
else
Error
end
groups keyword_tok, Punctuation
end
end
state :has_examples do
mixin :has_scenarios
rule Gherkin.step_regex, Name::Function do
token Name::Function
reset_stack; push :step
end
end
state :has_table do
rule(/(?=[|])/) { push :table_header }
end
state :table_header do
rule %r/[^|\s]+/, Name::Variable
rule %r/\n/ do
token Text
goto :table
end
mixin :table
end
state :table do
mixin :basic
rule %r/\n/, Text, :table_bol
rule %r/[|]/, Punctuation
rule %r/[^|\s]+/, Name
end
state :table_bol do
rule(/(?=\s*[^\s|])/) { reset_stack }
rule(//) { pop! }
end
state :description do
mixin :basic
mixin :has_examples
rule %r/\n/, Text
rule rest_of_line, Text
end
state :feature_description do
mixin :basic
mixin :has_scenarios
rule %r/\n/, Text
rule rest_of_line, Text
end
state :example_description do
mixin :basic
mixin :has_table
rule %r/\n/, Text
rule rest_of_line, Text
end
state :step do
mixin :basic
rule %r/<.*?>/, Name::Variable
rule %r/".*?"/, Str
rule %r/\S[^\s<]*/, Text
rule rest_of_line, Text, :pop!
end
end
end
end