bryanl-gherkin 2.11.1.1
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.
- data/.gitattributes +2 -0
- data/.mailmap +2 -0
- data/.rbenv-gemsets +1 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +16 -0
- data/.yardopts +5 -0
- data/Gemfile +5 -0
- data/History.md +788 -0
- data/LICENSE +20 -0
- data/README.md +272 -0
- data/Rakefile +26 -0
- data/build_native_gems.sh +7 -0
- data/cucumber.yml +4 -0
- data/examples/parse_and_output_json.rb +19 -0
- data/features/.cucumber/stepdefs.json +244 -0
- data/features/escaped_pipes.feature +8 -0
- data/features/feature_parser.feature +237 -0
- data/features/json_formatter.feature +498 -0
- data/features/json_parser.feature +331 -0
- data/features/native_lexer.feature +19 -0
- data/features/parser_with_native_lexer.feature +205 -0
- data/features/pretty_formatter.feature +16 -0
- data/features/step_definitions/eyeball_steps.rb +3 -0
- data/features/step_definitions/gherkin_steps.rb +29 -0
- data/features/step_definitions/json_formatter_steps.rb +30 -0
- data/features/step_definitions/json_parser_steps.rb +20 -0
- data/features/step_definitions/pretty_formatter_steps.rb +85 -0
- data/features/steps_parser.feature +46 -0
- data/features/support/env.rb +42 -0
- data/gherkin.gemspec +77 -0
- data/install_mingw_os_x.sh +7 -0
- data/js/.npmignore +1 -0
- data/js/lib/gherkin/lexer/.npmignore +0 -0
- data/lib/gherkin.rb +2 -0
- data/lib/gherkin/c_lexer.rb +17 -0
- data/lib/gherkin/formatter/ansi_escapes.rb +97 -0
- data/lib/gherkin/formatter/argument.rb +16 -0
- data/lib/gherkin/formatter/escaping.rb +15 -0
- data/lib/gherkin/formatter/filter_formatter.rb +146 -0
- data/lib/gherkin/formatter/hashable.rb +19 -0
- data/lib/gherkin/formatter/json_formatter.rb +122 -0
- data/lib/gherkin/formatter/line_filter.rb +26 -0
- data/lib/gherkin/formatter/model.rb +281 -0
- data/lib/gherkin/formatter/pretty_formatter.rb +244 -0
- data/lib/gherkin/formatter/regexp_filter.rb +21 -0
- data/lib/gherkin/formatter/step_printer.rb +21 -0
- data/lib/gherkin/formatter/tag_count_formatter.rb +47 -0
- data/lib/gherkin/formatter/tag_filter.rb +19 -0
- data/lib/gherkin/i18n.rb +180 -0
- data/lib/gherkin/i18n.yml +613 -0
- data/lib/gherkin/js_lexer.rb +20 -0
- data/lib/gherkin/json_parser.rb +177 -0
- data/lib/gherkin/lexer/i18n_lexer.rb +46 -0
- data/lib/gherkin/listener/event.rb +45 -0
- data/lib/gherkin/listener/formatter_listener.rb +143 -0
- data/lib/gherkin/native.rb +7 -0
- data/lib/gherkin/native/java.rb +72 -0
- data/lib/gherkin/native/null.rb +5 -0
- data/lib/gherkin/native/therubyracer.rb +39 -0
- data/lib/gherkin/parser/meta.txt +5 -0
- data/lib/gherkin/parser/parser.rb +164 -0
- data/lib/gherkin/parser/root.txt +11 -0
- data/lib/gherkin/parser/steps.txt +4 -0
- data/lib/gherkin/rb_lexer.rb +8 -0
- data/lib/gherkin/rb_lexer/README.rdoc +8 -0
- data/lib/gherkin/rb_lexer/ar.rb +1165 -0
- data/lib/gherkin/rb_lexer/bg.rb +1377 -0
- data/lib/gherkin/rb_lexer/bm.rb +1081 -0
- data/lib/gherkin/rb_lexer/ca.rb +1305 -0
- data/lib/gherkin/rb_lexer/cs.rb +1157 -0
- data/lib/gherkin/rb_lexer/cy_gb.rb +1027 -0
- data/lib/gherkin/rb_lexer/da.rb +1043 -0
- data/lib/gherkin/rb_lexer/de.rb +1151 -0
- data/lib/gherkin/rb_lexer/en.rb +1151 -0
- data/lib/gherkin/rb_lexer/en_au.rb +971 -0
- data/lib/gherkin/rb_lexer/en_lol.rb +929 -0
- data/lib/gherkin/rb_lexer/en_pirate.rb +1205 -0
- data/lib/gherkin/rb_lexer/en_scouse.rb +1357 -0
- data/lib/gherkin/rb_lexer/en_tx.rb +1011 -0
- data/lib/gherkin/rb_lexer/eo.rb +990 -0
- data/lib/gherkin/rb_lexer/es.rb +1135 -0
- data/lib/gherkin/rb_lexer/et.rb +985 -0
- data/lib/gherkin/rb_lexer/fi.rb +964 -0
- data/lib/gherkin/rb_lexer/fr.rb +1223 -0
- data/lib/gherkin/rb_lexer/he.rb +1113 -0
- data/lib/gherkin/rb_lexer/hr.rb +1061 -0
- data/lib/gherkin/rb_lexer/hu.rb +1113 -0
- data/lib/gherkin/rb_lexer/id.rb +958 -0
- data/lib/gherkin/rb_lexer/is.rb +1115 -0
- data/lib/gherkin/rb_lexer/it.rb +1081 -0
- data/lib/gherkin/rb_lexer/ja.rb +1413 -0
- data/lib/gherkin/rb_lexer/ko.rb +1097 -0
- data/lib/gherkin/rb_lexer/lt.rb +1040 -0
- data/lib/gherkin/rb_lexer/lu.rb +1127 -0
- data/lib/gherkin/rb_lexer/lv.rb +1161 -0
- data/lib/gherkin/rb_lexer/nl.rb +1110 -0
- data/lib/gherkin/rb_lexer/no.rb +1055 -0
- data/lib/gherkin/rb_lexer/pl.rb +1452 -0
- data/lib/gherkin/rb_lexer/pt.rb +1425 -0
- data/lib/gherkin/rb_lexer/ro.rb +1159 -0
- data/lib/gherkin/rb_lexer/ru.rb +1749 -0
- data/lib/gherkin/rb_lexer/sk.rb +1041 -0
- data/lib/gherkin/rb_lexer/sr_cyrl.rb +1798 -0
- data/lib/gherkin/rb_lexer/sr_latn.rb +1289 -0
- data/lib/gherkin/rb_lexer/sv.rb +1065 -0
- data/lib/gherkin/rb_lexer/tr.rb +1087 -0
- data/lib/gherkin/rb_lexer/uk.rb +1641 -0
- data/lib/gherkin/rb_lexer/uz.rb +1371 -0
- data/lib/gherkin/rb_lexer/vi.rb +1193 -0
- data/lib/gherkin/rb_lexer/zh_cn.rb +1053 -0
- data/lib/gherkin/rb_lexer/zh_tw.rb +1047 -0
- data/lib/gherkin/rubify.rb +24 -0
- data/lib/gherkin/tag_expression.rb +62 -0
- data/ragel/lexer.c.rl.erb +454 -0
- data/ragel/lexer.java.rl.erb +219 -0
- data/ragel/lexer.js.rl.erb +227 -0
- data/ragel/lexer.rb.rl.erb +174 -0
- data/ragel/lexer_common.rl.erb +50 -0
- data/spec/gherkin/c_lexer_spec.rb +22 -0
- data/spec/gherkin/fixtures/1.feature +8 -0
- data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
- data/spec/gherkin/fixtures/complex.feature +45 -0
- data/spec/gherkin/fixtures/complex.json +139 -0
- data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
- data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
- data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
- data/spec/gherkin/fixtures/examples_with_only_header.feature +14 -0
- data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
- data/spec/gherkin/fixtures/i18n_fr.feature +14 -0
- data/spec/gherkin/fixtures/i18n_fr2.feature +8 -0
- data/spec/gherkin/fixtures/i18n_no.feature +7 -0
- data/spec/gherkin/fixtures/i18n_pt1.feature +44 -0
- data/spec/gherkin/fixtures/i18n_pt2.feature +4 -0
- data/spec/gherkin/fixtures/i18n_pt3.feature +4 -0
- data/spec/gherkin/fixtures/i18n_pt4.feature +4 -0
- data/spec/gherkin/fixtures/i18n_zh-CN.feature +9 -0
- data/spec/gherkin/fixtures/issue_145.feature +22 -0
- data/spec/gherkin/fixtures/scenario_outline_with_tags.feature +13 -0
- data/spec/gherkin/fixtures/scenario_without_steps.feature +5 -0
- data/spec/gherkin/fixtures/simple_with_comments.feature +7 -0
- data/spec/gherkin/fixtures/simple_with_tags.feature +11 -0
- data/spec/gherkin/fixtures/with_bom.feature +3 -0
- data/spec/gherkin/formatter/ansi_escapes_spec.rb +32 -0
- data/spec/gherkin/formatter/filter_formatter_spec.rb +204 -0
- data/spec/gherkin/formatter/json_formatter_spec.rb +92 -0
- data/spec/gherkin/formatter/model_spec.rb +28 -0
- data/spec/gherkin/formatter/pretty_formatter_spec.rb +177 -0
- data/spec/gherkin/formatter/spaces.feature +9 -0
- data/spec/gherkin/formatter/step_printer_spec.rb +55 -0
- data/spec/gherkin/formatter/tabs.feature +9 -0
- data/spec/gherkin/formatter/tag_count_formatter_spec.rb +30 -0
- data/spec/gherkin/i18n_spec.rb +241 -0
- data/spec/gherkin/java_lexer_spec.rb +20 -0
- data/spec/gherkin/js_lexer_spec.rb +23 -0
- data/spec/gherkin/json_parser_spec.rb +176 -0
- data/spec/gherkin/lexer/i18n_lexer_spec.rb +43 -0
- data/spec/gherkin/output_stream_string_io.rb +20 -0
- data/spec/gherkin/parser/parser_spec.rb +16 -0
- data/spec/gherkin/rb_lexer_spec.rb +20 -0
- data/spec/gherkin/sexp_recorder.rb +59 -0
- data/spec/gherkin/shared/bom_group.rb +20 -0
- data/spec/gherkin/shared/doc_string_group.rb +163 -0
- data/spec/gherkin/shared/lexer_group.rb +591 -0
- data/spec/gherkin/shared/row_group.rb +125 -0
- data/spec/gherkin/shared/tags_group.rb +54 -0
- data/spec/gherkin/tag_expression_spec.rb +142 -0
- data/spec/spec_helper.rb +75 -0
- data/tasks/bench.rake +184 -0
- data/tasks/bench/feature_builder.rb +49 -0
- data/tasks/bench/null_listener.rb +4 -0
- data/tasks/compile.rake +120 -0
- data/tasks/cucumber.rake +22 -0
- data/tasks/gems.rake +31 -0
- data/tasks/ikvm.rake +124 -0
- data/tasks/ragel_task.rb +100 -0
- data/tasks/release.rake +49 -0
- data/tasks/rspec.rake +8 -0
- data/tasks/yard.rake +7 -0
- data/tasks/yard/default/layout/html/bubble_32x32.png +0 -0
- data/tasks/yard/default/layout/html/bubble_48x48.png +0 -0
- data/tasks/yard/default/layout/html/footer.erb +5 -0
- data/tasks/yard/default/layout/html/index.erb +1 -0
- data/tasks/yard/default/layout/html/layout.erb +25 -0
- data/tasks/yard/default/layout/html/logo.erb +1 -0
- data/tasks/yard/default/layout/html/setup.rb +4 -0
- metadata +473 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module Gherkin
|
2
|
+
module Rubify
|
3
|
+
if defined?(JRUBY_VERSION)
|
4
|
+
# Translate Java objects to Ruby.
|
5
|
+
# This is especially important to convert java.util.List coming
|
6
|
+
# from Java and back to a Ruby Array.
|
7
|
+
def rubify(o)
|
8
|
+
case(o)
|
9
|
+
when Java.java.util.Collection, Array
|
10
|
+
o.map{|e| rubify(e)}
|
11
|
+
when Java.gherkin.formatter.model.DocString
|
12
|
+
require 'gherkin/formatter/model'
|
13
|
+
Formatter::Model::DocString.new(o.content_type, o.value, o.line)
|
14
|
+
else
|
15
|
+
o
|
16
|
+
end
|
17
|
+
end
|
18
|
+
else
|
19
|
+
def rubify(o)
|
20
|
+
o
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'gherkin/native'
|
2
|
+
|
3
|
+
module Gherkin
|
4
|
+
class TagExpression
|
5
|
+
native_impl('gherkin')
|
6
|
+
|
7
|
+
attr_reader :limits
|
8
|
+
|
9
|
+
def initialize(tag_expressions)
|
10
|
+
@ands = []
|
11
|
+
@limits = {}
|
12
|
+
tag_expressions.each do |expr|
|
13
|
+
add(expr.strip.split(/\s*,\s*/))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
@ands.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def eval(tags)
|
22
|
+
return true if @ands.flatten.empty?
|
23
|
+
vars = Hash[*tags.map{|tag| [tag.name, true]}.flatten]
|
24
|
+
!!Kernel.eval(ruby_expression)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def add(tags_with_negation_and_limits)
|
30
|
+
negatives, positives = tags_with_negation_and_limits.partition{|tag| tag =~ /^~/}
|
31
|
+
@ands << (store_and_extract_limits(negatives, true) + store_and_extract_limits(positives, false))
|
32
|
+
end
|
33
|
+
|
34
|
+
def store_and_extract_limits(tags_with_negation_and_limits, negated)
|
35
|
+
tags_with_negation = []
|
36
|
+
tags_with_negation_and_limits.each do |tag_with_negation_and_limit|
|
37
|
+
tag_with_negation, limit = tag_with_negation_and_limit.split(':')
|
38
|
+
tags_with_negation << tag_with_negation
|
39
|
+
if limit
|
40
|
+
tag_without_negation = negated ? tag_with_negation[1..-1] : tag_with_negation
|
41
|
+
if @limits[tag_without_negation] && @limits[tag_without_negation] != limit.to_i
|
42
|
+
raise "Inconsistent tag limits for #{tag_without_negation}: #{@limits[tag_without_negation]} and #{limit.to_i}"
|
43
|
+
end
|
44
|
+
@limits[tag_without_negation] = limit.to_i
|
45
|
+
end
|
46
|
+
end
|
47
|
+
tags_with_negation
|
48
|
+
end
|
49
|
+
|
50
|
+
def ruby_expression
|
51
|
+
"(" + @ands.map do |ors|
|
52
|
+
ors.map do |tag|
|
53
|
+
if tag =~ /^~(.*)/
|
54
|
+
"!vars['#{$1}']"
|
55
|
+
else
|
56
|
+
"vars['#{tag}']"
|
57
|
+
end
|
58
|
+
end.join("||")
|
59
|
+
end.join(")&&(") + ")"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,454 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
#if defined(_WIN32)
|
5
|
+
#include <stddef.h>
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#ifdef HAVE_RUBY_RE_H
|
9
|
+
#include <ruby/re.h>
|
10
|
+
#else
|
11
|
+
#include <re.h>
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
15
|
+
#include <ruby/encoding.h>
|
16
|
+
#define ENCODED_STR_NEW(ptr, len) \
|
17
|
+
rb_enc_str_new(ptr, len, rb_utf8_encoding())
|
18
|
+
#else
|
19
|
+
#define ENCODED_STR_NEW(ptr, len) \
|
20
|
+
rb_str_new(ptr, len)
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#ifndef RSTRING_PTR
|
24
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
25
|
+
#endif
|
26
|
+
|
27
|
+
#ifndef RSTRING_LEN
|
28
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
29
|
+
#endif
|
30
|
+
|
31
|
+
#define DATA_GET(FROM, TYPE, NAME) \
|
32
|
+
Data_Get_Struct(FROM, TYPE, NAME); \
|
33
|
+
if (NAME == NULL) { \
|
34
|
+
rb_raise(rb_eArgError, "NULL found for " # NAME " when it shouldn't be."); \
|
35
|
+
}
|
36
|
+
|
37
|
+
typedef struct lexer_state {
|
38
|
+
int content_len;
|
39
|
+
int line_number;
|
40
|
+
int current_line;
|
41
|
+
int start_col;
|
42
|
+
size_t mark;
|
43
|
+
size_t keyword_start;
|
44
|
+
size_t keyword_end;
|
45
|
+
size_t next_keyword_start;
|
46
|
+
size_t content_start;
|
47
|
+
size_t content_end;
|
48
|
+
size_t docstring_content_type_start;
|
49
|
+
size_t docstring_content_type_end;
|
50
|
+
size_t query_start;
|
51
|
+
size_t last_newline;
|
52
|
+
size_t final_newline;
|
53
|
+
} lexer_state;
|
54
|
+
|
55
|
+
static VALUE mGherkin;
|
56
|
+
static VALUE mGherkinLexer;
|
57
|
+
static VALUE mCLexer;
|
58
|
+
static VALUE cI18nLexer;
|
59
|
+
static VALUE rb_eGherkinLexingError;
|
60
|
+
|
61
|
+
#define LEN(AT, P) (P - data - lexer->AT)
|
62
|
+
#define MARK(M, P) (lexer->M = (P) - data)
|
63
|
+
#define PTR_TO(P) (data + lexer->P)
|
64
|
+
|
65
|
+
#define STORE_KW_END_CON(EVENT) \
|
66
|
+
store_multiline_kw_con(listener, # EVENT, \
|
67
|
+
PTR_TO(keyword_start), LEN(keyword_start, PTR_TO(keyword_end - 1)), \
|
68
|
+
PTR_TO(content_start), LEN(content_start, PTR_TO(content_end)), \
|
69
|
+
lexer->current_line, lexer->start_col); \
|
70
|
+
if (lexer->content_end != 0) { \
|
71
|
+
p = PTR_TO(content_end - 1); \
|
72
|
+
} \
|
73
|
+
lexer->content_end = 0
|
74
|
+
|
75
|
+
#define STORE_ATTR(ATTR) \
|
76
|
+
store_attr(listener, # ATTR, \
|
77
|
+
PTR_TO(content_start), LEN(content_start, p), \
|
78
|
+
lexer->line_number)
|
79
|
+
|
80
|
+
%%{
|
81
|
+
machine lexer;
|
82
|
+
|
83
|
+
action begin_content {
|
84
|
+
MARK(content_start, p);
|
85
|
+
lexer->current_line = lexer->line_number;
|
86
|
+
lexer->start_col = lexer->content_start - lexer->last_newline - (lexer->keyword_end - lexer->keyword_start) + 2;
|
87
|
+
}
|
88
|
+
|
89
|
+
action begin_docstring_content {
|
90
|
+
MARK(content_start, p);
|
91
|
+
}
|
92
|
+
|
93
|
+
action start_docstring {
|
94
|
+
lexer->current_line = lexer->line_number;
|
95
|
+
lexer->start_col = p - data - lexer->last_newline;
|
96
|
+
}
|
97
|
+
|
98
|
+
action store_docstring_content {
|
99
|
+
int len = LEN(content_start, PTR_TO(final_newline));
|
100
|
+
int type_len = LEN(docstring_content_type_start, PTR_TO(docstring_content_type_end));
|
101
|
+
|
102
|
+
if (len < 0) len = 0;
|
103
|
+
if (type_len < 0) len = 0;
|
104
|
+
|
105
|
+
store_docstring_content(listener, lexer->start_col, PTR_TO(docstring_content_type_start), type_len, PTR_TO(content_start), len, lexer->current_line);
|
106
|
+
}
|
107
|
+
|
108
|
+
action start_docstring_content_type {
|
109
|
+
MARK(docstring_content_type_start, p);
|
110
|
+
}
|
111
|
+
|
112
|
+
action end_docstring_content_type {
|
113
|
+
MARK(docstring_content_type_end, p);
|
114
|
+
}
|
115
|
+
|
116
|
+
action store_feature_content {
|
117
|
+
STORE_KW_END_CON(feature);
|
118
|
+
}
|
119
|
+
|
120
|
+
action store_background_content {
|
121
|
+
STORE_KW_END_CON(background);
|
122
|
+
}
|
123
|
+
|
124
|
+
action store_scenario_content {
|
125
|
+
STORE_KW_END_CON(scenario);
|
126
|
+
}
|
127
|
+
|
128
|
+
action store_scenario_outline_content {
|
129
|
+
STORE_KW_END_CON(scenario_outline);
|
130
|
+
}
|
131
|
+
|
132
|
+
action store_examples_content {
|
133
|
+
STORE_KW_END_CON(examples);
|
134
|
+
}
|
135
|
+
|
136
|
+
action store_step_content {
|
137
|
+
store_kw_con(listener, "step",
|
138
|
+
PTR_TO(keyword_start), LEN(keyword_start, PTR_TO(keyword_end)),
|
139
|
+
PTR_TO(content_start), LEN(content_start, p),
|
140
|
+
lexer->current_line);
|
141
|
+
}
|
142
|
+
|
143
|
+
action store_comment_content {
|
144
|
+
STORE_ATTR(comment);
|
145
|
+
lexer->mark = 0;
|
146
|
+
}
|
147
|
+
|
148
|
+
action store_tag_content {
|
149
|
+
STORE_ATTR(tag);
|
150
|
+
lexer->mark = 0;
|
151
|
+
}
|
152
|
+
|
153
|
+
action inc_line_number {
|
154
|
+
lexer->line_number += 1;
|
155
|
+
MARK(final_newline, p);
|
156
|
+
}
|
157
|
+
|
158
|
+
action last_newline {
|
159
|
+
MARK(last_newline, p + 1);
|
160
|
+
}
|
161
|
+
|
162
|
+
action start_keyword {
|
163
|
+
if (lexer->mark == 0) {
|
164
|
+
MARK(mark, p);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
action end_keyword {
|
169
|
+
MARK(keyword_end, p);
|
170
|
+
MARK(keyword_start, PTR_TO(mark));
|
171
|
+
MARK(content_start, p + 1);
|
172
|
+
lexer->mark = 0;
|
173
|
+
}
|
174
|
+
|
175
|
+
action next_keyword_start {
|
176
|
+
MARK(content_end, p);
|
177
|
+
}
|
178
|
+
|
179
|
+
action start_row {
|
180
|
+
p = p - 1;
|
181
|
+
lexer->current_line = lexer->line_number;
|
182
|
+
current_row = rb_ary_new();
|
183
|
+
}
|
184
|
+
|
185
|
+
action begin_cell_content {
|
186
|
+
MARK(content_start, p);
|
187
|
+
}
|
188
|
+
|
189
|
+
action store_cell_content {
|
190
|
+
VALUE re_pipe, re_newline, re_backslash;
|
191
|
+
VALUE con = ENCODED_STR_NEW(PTR_TO(content_start), LEN(content_start, p));
|
192
|
+
rb_funcall(con, rb_intern("strip!"), 0);
|
193
|
+
re_pipe = rb_reg_regcomp(rb_str_new2("\\\\\\|"));
|
194
|
+
re_newline = rb_reg_regcomp(rb_str_new2("\\\\n"));
|
195
|
+
re_backslash = rb_reg_regcomp(rb_str_new2("\\\\\\\\"));
|
196
|
+
rb_funcall(con, rb_intern("gsub!"), 2, re_pipe, rb_str_new2("|"));
|
197
|
+
rb_funcall(con, rb_intern("gsub!"), 2, re_newline, rb_str_new2("\n"));
|
198
|
+
rb_funcall(con, rb_intern("gsub!"), 2, re_backslash, rb_str_new2("\\"));
|
199
|
+
|
200
|
+
rb_ary_push(current_row, con);
|
201
|
+
}
|
202
|
+
|
203
|
+
action store_row {
|
204
|
+
rb_funcall(listener, rb_intern("row"), 2, current_row, INT2FIX(lexer->current_line));
|
205
|
+
}
|
206
|
+
|
207
|
+
action end_feature {
|
208
|
+
int line;
|
209
|
+
if (cs < lexer_first_final) {
|
210
|
+
size_t count = 0;
|
211
|
+
VALUE newstr_val;
|
212
|
+
char *newstr;
|
213
|
+
int newstr_count = 0;
|
214
|
+
size_t len;
|
215
|
+
const char *buff;
|
216
|
+
if (lexer->last_newline != 0) {
|
217
|
+
len = LEN(last_newline, eof);
|
218
|
+
buff = PTR_TO(last_newline);
|
219
|
+
} else {
|
220
|
+
len = strlen(data);
|
221
|
+
buff = data;
|
222
|
+
}
|
223
|
+
|
224
|
+
// Allocate as a ruby string so that it gets cleaned up by GC
|
225
|
+
newstr_val = rb_str_new(buff, len);
|
226
|
+
newstr = RSTRING_PTR(newstr_val);
|
227
|
+
|
228
|
+
|
229
|
+
for (count = 0; count < len; count++) {
|
230
|
+
if(buff[count] == 10) {
|
231
|
+
newstr[newstr_count] = '\0'; // terminate new string at first newline found
|
232
|
+
break;
|
233
|
+
} else {
|
234
|
+
if (buff[count] == '%') {
|
235
|
+
newstr[newstr_count++] = buff[count];
|
236
|
+
newstr[newstr_count] = buff[count];
|
237
|
+
} else {
|
238
|
+
newstr[newstr_count] = buff[count];
|
239
|
+
}
|
240
|
+
}
|
241
|
+
newstr_count++;
|
242
|
+
}
|
243
|
+
|
244
|
+
line = lexer->line_number;
|
245
|
+
lexer_init(lexer); // Re-initialize so we can scan again with the same lexer
|
246
|
+
raise_lexer_error(newstr, line);
|
247
|
+
} else {
|
248
|
+
rb_funcall(listener, rb_intern("eof"), 0);
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
include lexer_common "lexer_common.<%= @i18n.underscored_iso_code %>.rl";
|
253
|
+
|
254
|
+
}%%
|
255
|
+
|
256
|
+
/** Data **/
|
257
|
+
%% write data;
|
258
|
+
|
259
|
+
static VALUE
|
260
|
+
unindent(VALUE con, int start_col)
|
261
|
+
{
|
262
|
+
VALUE re;
|
263
|
+
// Gherkin will crash gracefully if the string representation of start_col pushes the pattern past 32 characters
|
264
|
+
char pat[32];
|
265
|
+
snprintf(pat, 32, "^[\t ]{0,%d}", start_col);
|
266
|
+
re = rb_reg_regcomp(rb_str_new2(pat));
|
267
|
+
rb_funcall(con, rb_intern("gsub!"), 2, re, rb_str_new2(""));
|
268
|
+
|
269
|
+
return Qnil;
|
270
|
+
|
271
|
+
}
|
272
|
+
|
273
|
+
static void
|
274
|
+
store_kw_con(VALUE listener, const char * event_name,
|
275
|
+
const char * keyword_at, size_t keyword_length,
|
276
|
+
const char * at, size_t length,
|
277
|
+
int current_line)
|
278
|
+
{
|
279
|
+
VALUE con = Qnil, kw = Qnil;
|
280
|
+
kw = ENCODED_STR_NEW(keyword_at, keyword_length);
|
281
|
+
con = ENCODED_STR_NEW(at, length);
|
282
|
+
rb_funcall(con, rb_intern("strip!"), 0);
|
283
|
+
rb_funcall(listener, rb_intern(event_name), 3, kw, con, INT2FIX(current_line));
|
284
|
+
}
|
285
|
+
|
286
|
+
static void
|
287
|
+
store_multiline_kw_con(VALUE listener, const char * event_name,
|
288
|
+
const char * keyword_at, size_t keyword_length,
|
289
|
+
const char * at, size_t length,
|
290
|
+
int current_line, int start_col)
|
291
|
+
{
|
292
|
+
VALUE split;
|
293
|
+
VALUE con = Qnil, kw = Qnil, name = Qnil, desc = Qnil;
|
294
|
+
|
295
|
+
kw = ENCODED_STR_NEW(keyword_at, keyword_length);
|
296
|
+
con = ENCODED_STR_NEW(at, length);
|
297
|
+
|
298
|
+
unindent(con, start_col);
|
299
|
+
|
300
|
+
split = rb_str_split(con, "\n");
|
301
|
+
|
302
|
+
name = rb_funcall(split, rb_intern("shift"), 0);
|
303
|
+
desc = rb_ary_join(split, rb_str_new2( "\n" ));
|
304
|
+
|
305
|
+
if( name == Qnil )
|
306
|
+
{
|
307
|
+
name = rb_str_new2("");
|
308
|
+
}
|
309
|
+
if( rb_funcall(desc, rb_intern("size"), 0) == 0)
|
310
|
+
{
|
311
|
+
desc = rb_str_new2("");
|
312
|
+
}
|
313
|
+
rb_funcall(name, rb_intern("strip!"), 0);
|
314
|
+
rb_funcall(desc, rb_intern("rstrip!"), 0);
|
315
|
+
rb_funcall(listener, rb_intern(event_name), 4, kw, name, desc, INT2FIX(current_line));
|
316
|
+
}
|
317
|
+
|
318
|
+
static void
|
319
|
+
store_attr(VALUE listener, const char * attr_type,
|
320
|
+
const char * at, size_t length,
|
321
|
+
int line)
|
322
|
+
{
|
323
|
+
VALUE val = ENCODED_STR_NEW(at, length);
|
324
|
+
rb_funcall(listener, rb_intern(attr_type), 2, val, INT2FIX(line));
|
325
|
+
}
|
326
|
+
static void
|
327
|
+
store_docstring_content(VALUE listener,
|
328
|
+
int start_col,
|
329
|
+
const char *type_at, size_t type_length,
|
330
|
+
const char *at, size_t length,
|
331
|
+
int current_line)
|
332
|
+
{
|
333
|
+
VALUE re2;
|
334
|
+
VALUE unescape_escaped_quotes;
|
335
|
+
VALUE con = ENCODED_STR_NEW(at, length);
|
336
|
+
VALUE con_type = ENCODED_STR_NEW(type_at, type_length);
|
337
|
+
|
338
|
+
unindent(con, start_col);
|
339
|
+
|
340
|
+
re2 = rb_reg_regcomp(rb_str_new2("\r\\Z"));
|
341
|
+
unescape_escaped_quotes = rb_reg_regcomp(rb_str_new2("\\\\\"\\\\\"\\\\\""));
|
342
|
+
rb_funcall(con, rb_intern("sub!"), 2, re2, rb_str_new2(""));
|
343
|
+
rb_funcall(con_type, rb_intern("strip!"), 0);
|
344
|
+
rb_funcall(con, rb_intern("gsub!"), 2, unescape_escaped_quotes, rb_str_new2("\"\"\""));
|
345
|
+
rb_funcall(listener, rb_intern("doc_string"), 3, con_type, con, INT2FIX(current_line));
|
346
|
+
}
|
347
|
+
static void
|
348
|
+
raise_lexer_error(const char * at, int line)
|
349
|
+
{
|
350
|
+
rb_raise(rb_eGherkinLexingError, "Lexing error on line %d: '%s'. See http://wiki.github.com/cucumber/gherkin/lexingerror for more information.", line, at);
|
351
|
+
}
|
352
|
+
|
353
|
+
static void lexer_init(lexer_state *lexer) {
|
354
|
+
lexer->content_start = 0;
|
355
|
+
lexer->content_end = 0;
|
356
|
+
lexer->content_len = 0;
|
357
|
+
lexer->docstring_content_type_start = 0;
|
358
|
+
lexer->docstring_content_type_end = 0;
|
359
|
+
lexer->mark = 0;
|
360
|
+
lexer->keyword_start = 0;
|
361
|
+
lexer->keyword_end = 0;
|
362
|
+
lexer->next_keyword_start = 0;
|
363
|
+
lexer->line_number = 1;
|
364
|
+
lexer->last_newline = 0;
|
365
|
+
lexer->final_newline = 0;
|
366
|
+
lexer->start_col = 0;
|
367
|
+
}
|
368
|
+
|
369
|
+
static VALUE CLexer_alloc(VALUE klass)
|
370
|
+
{
|
371
|
+
VALUE obj;
|
372
|
+
lexer_state *lxr = ALLOC(lexer_state);
|
373
|
+
lexer_init(lxr);
|
374
|
+
|
375
|
+
obj = Data_Wrap_Struct(klass, NULL, -1, lxr);
|
376
|
+
|
377
|
+
return obj;
|
378
|
+
}
|
379
|
+
|
380
|
+
static VALUE CLexer_init(VALUE self, VALUE listener)
|
381
|
+
{
|
382
|
+
lexer_state *lxr;
|
383
|
+
rb_iv_set(self, "@listener", listener);
|
384
|
+
|
385
|
+
lxr = NULL;
|
386
|
+
DATA_GET(self, lexer_state, lxr);
|
387
|
+
lexer_init(lxr);
|
388
|
+
|
389
|
+
return self;
|
390
|
+
}
|
391
|
+
|
392
|
+
static VALUE CLexer_scan(VALUE self, VALUE input)
|
393
|
+
{
|
394
|
+
VALUE input_copy;
|
395
|
+
char *data;
|
396
|
+
size_t len;
|
397
|
+
VALUE listener = rb_iv_get(self, "@listener");
|
398
|
+
|
399
|
+
lexer_state *lexer;
|
400
|
+
lexer = NULL;
|
401
|
+
DATA_GET(self, lexer_state, lexer);
|
402
|
+
|
403
|
+
input_copy = rb_str_dup(input);
|
404
|
+
|
405
|
+
rb_str_append(input_copy, rb_str_new2("\n%_FEATURE_END_%"));
|
406
|
+
data = RSTRING_PTR(input_copy);
|
407
|
+
len = RSTRING_LEN(input_copy);
|
408
|
+
|
409
|
+
if (len == 0) {
|
410
|
+
rb_raise(rb_eGherkinLexingError, "No content to lex.");
|
411
|
+
} else {
|
412
|
+
|
413
|
+
const char *p, *pe, *eof;
|
414
|
+
int cs = 0;
|
415
|
+
|
416
|
+
VALUE current_row = Qnil;
|
417
|
+
|
418
|
+
p = data;
|
419
|
+
pe = data + len;
|
420
|
+
eof = pe;
|
421
|
+
|
422
|
+
assert(*pe == '\0' && "pointer does not end on NULL");
|
423
|
+
|
424
|
+
%% write init;
|
425
|
+
%% write exec;
|
426
|
+
|
427
|
+
assert(p <= pe && "data overflow after parsing execute");
|
428
|
+
assert(lexer->content_start <= len && "content starts after data end");
|
429
|
+
assert(lexer->mark < len && "mark is after data end");
|
430
|
+
|
431
|
+
// Reset lexer by re-initializing the whole thing
|
432
|
+
lexer_init(lexer);
|
433
|
+
|
434
|
+
if (cs == lexer_error) {
|
435
|
+
rb_raise(rb_eGherkinLexingError, "Invalid format, lexing fails.");
|
436
|
+
} else {
|
437
|
+
return Qtrue;
|
438
|
+
}
|
439
|
+
}
|
440
|
+
}
|
441
|
+
|
442
|
+
void Init_gherkin_lexer_<%= @i18n.underscored_iso_code %>()
|
443
|
+
{
|
444
|
+
mGherkin = rb_define_module("Gherkin");
|
445
|
+
mGherkinLexer = rb_define_module_under(mGherkin, "Lexer");
|
446
|
+
rb_eGherkinLexingError = rb_const_get(mGherkinLexer, rb_intern("LexingError"));
|
447
|
+
|
448
|
+
mCLexer = rb_define_module_under(mGherkin, "CLexer");
|
449
|
+
cI18nLexer = rb_define_class_under(mCLexer, "<%= @i18n.underscored_iso_code.capitalize %>", rb_cObject);
|
450
|
+
rb_define_alloc_func(cI18nLexer, CLexer_alloc);
|
451
|
+
rb_define_method(cI18nLexer, "initialize", CLexer_init, 1);
|
452
|
+
rb_define_method(cI18nLexer, "scan", CLexer_scan, 1);
|
453
|
+
}
|
454
|
+
|