gherkin 1.0.30-i386-mswin32 → 2.0.0-i386-mswin32
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/.rspec +1 -0
- data/History.txt +19 -0
- data/Rakefile +4 -4
- data/VERSION.yml +2 -2
- data/features/feature_parser.feature +11 -0
- data/features/json_formatter.feature +238 -0
- data/features/pretty_formatter.feature +9 -0
- data/features/step_definitions/gherkin_steps.rb +1 -1
- data/features/step_definitions/json_formatter_steps.rb +32 -0
- data/features/step_definitions/pretty_formatter_steps.rb +24 -23
- data/features/support/env.rb +3 -3
- data/lib/gherkin/formatter/json_formatter.rb +82 -0
- data/lib/gherkin/formatter/pretty_formatter.rb +73 -78
- data/lib/gherkin/i18n.rb +22 -18
- data/lib/gherkin/i18n.yml +9 -9
- data/lib/gherkin/i18n_lexer.rb +2 -2
- data/lib/gherkin/parser/event.rb +6 -6
- data/lib/gherkin/parser/filter_listener.rb +5 -1
- data/lib/gherkin/parser/formatter_listener.rb +113 -0
- data/lib/gherkin/parser/json_parser.rb +102 -0
- data/lib/gherkin/parser/parser.rb +10 -2
- data/lib/gherkin/parser/row.rb +15 -0
- data/lib/gherkin/rubify.rb +2 -0
- data/lib/gherkin/tools/files.rb +1 -1
- data/lib/gherkin/tools/reformat.rb +1 -2
- data/lib/gherkin/tools/stats.rb +1 -1
- data/lib/gherkin/tools/stats_listener.rb +5 -5
- data/ragel/lexer.c.rl.erb +41 -12
- data/ragel/lexer.java.rl.erb +26 -17
- data/ragel/lexer.rb.rl.erb +10 -5
- data/ragel/lexer_common.rl.erb +6 -6
- data/spec/gherkin/c_lexer_spec.rb +2 -2
- data/spec/gherkin/fixtures/complex.js +105 -0
- data/spec/gherkin/formatter/argument_spec.rb +3 -3
- data/spec/gherkin/formatter/colors_spec.rb +3 -4
- data/spec/gherkin/formatter/pretty_formatter_spec.rb +21 -50
- data/spec/gherkin/i18n_lexer_spec.rb +6 -6
- data/spec/gherkin/i18n_spec.rb +16 -9
- data/spec/gherkin/java_lexer_spec.rb +1 -2
- data/spec/gherkin/output_stream_string_io.rb +24 -0
- data/spec/gherkin/parser/filter_listener_spec.rb +16 -9
- data/spec/gherkin/parser/formatter_listener_spec.rb +134 -0
- data/spec/gherkin/parser/json_parser_spec.rb +129 -0
- data/spec/gherkin/parser/parser_spec.rb +9 -9
- data/spec/gherkin/parser/tag_expression_spec.rb +8 -8
- data/spec/gherkin/rb_lexer_spec.rb +1 -1
- data/spec/gherkin/sexp_recorder.rb +21 -1
- data/spec/gherkin/shared/{lexer_spec.rb → lexer_group.rb} +172 -102
- data/spec/gherkin/shared/{py_string_spec.rb → py_string_group.rb} +21 -17
- data/spec/gherkin/shared/{row_spec.rb → row_group.rb} +36 -19
- data/spec/gherkin/shared/{tags_spec.rb → tags_group.rb} +13 -9
- data/spec/spec_helper.rb +18 -38
- data/tasks/bench.rake +3 -3
- data/tasks/compile.rake +13 -14
- data/tasks/rspec.rake +6 -11
- metadata +42 -28
- data/features/pretty_printer.feature +0 -14
- data/spec/gherkin/csharp_lexer_spec.rb +0 -20
data/lib/gherkin/parser/event.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
module Gherkin
|
2
2
|
module Parser
|
3
3
|
class Event < Array
|
4
|
-
def initialize(*args)
|
5
|
-
super
|
6
|
-
self[1] = self[1].to_a if event == :row # Special JRuby handling
|
7
|
-
end
|
8
|
-
|
9
4
|
def event
|
10
5
|
self[0]
|
11
6
|
end
|
@@ -24,7 +19,12 @@ module Gherkin
|
|
24
19
|
end
|
25
20
|
|
26
21
|
def replay(listener)
|
27
|
-
|
22
|
+
begin
|
23
|
+
listener.__send__(event, *args)
|
24
|
+
rescue ArgumentError => e
|
25
|
+
e.message << "\nListener: #{listener.class}, args: #{args.inspect}"
|
26
|
+
raise e
|
27
|
+
end
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'gherkin/native'
|
2
|
+
require 'gherkin/parser/row'
|
3
|
+
|
4
|
+
module Gherkin
|
5
|
+
module Parser
|
6
|
+
# Adapter from the "raw" Gherkin <tt>Listener</tt> API
|
7
|
+
# to the slightly more high-level <tt>Formatter</tt> API,
|
8
|
+
# which is easier to implement (less state to keep track of).
|
9
|
+
class FormatterListener
|
10
|
+
native_impl('gherkin')
|
11
|
+
|
12
|
+
def initialize(formatter)
|
13
|
+
@formatter = formatter
|
14
|
+
@comments = []
|
15
|
+
@tags = []
|
16
|
+
@table = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def location(uri, offset)
|
20
|
+
@uri = uri
|
21
|
+
@offset = offset
|
22
|
+
end
|
23
|
+
|
24
|
+
def comment(content, line)
|
25
|
+
@comments << content
|
26
|
+
end
|
27
|
+
|
28
|
+
def tag(name, line)
|
29
|
+
@tags << name
|
30
|
+
end
|
31
|
+
|
32
|
+
def feature(keyword, name, description, line)
|
33
|
+
@formatter.feature(grab_comments!, grab_tags!, keyword, name, description, @uri)
|
34
|
+
end
|
35
|
+
|
36
|
+
def background(keyword, name, description, line)
|
37
|
+
@formatter.background(grab_comments!, keyword, name, description, line)
|
38
|
+
end
|
39
|
+
|
40
|
+
def scenario(keyword, name, description, line)
|
41
|
+
replay_step_or_examples
|
42
|
+
@formatter.scenario(grab_comments!, grab_tags!, keyword, name, description, line)
|
43
|
+
end
|
44
|
+
|
45
|
+
def scenario_outline(keyword, name, description, line)
|
46
|
+
replay_step_or_examples
|
47
|
+
@formatter.scenario_outline(grab_comments!, grab_tags!, keyword, name, description, line)
|
48
|
+
end
|
49
|
+
|
50
|
+
def examples(keyword, name, description, line)
|
51
|
+
replay_step_or_examples
|
52
|
+
@examples = [grab_comments!, grab_tags!, keyword, name, description, line]
|
53
|
+
end
|
54
|
+
|
55
|
+
def step(keyword, name, line)
|
56
|
+
replay_step_or_examples
|
57
|
+
@step = [grab_comments!, keyword, name, line]
|
58
|
+
end
|
59
|
+
|
60
|
+
def row(cells, line)
|
61
|
+
@table ||= []
|
62
|
+
@table << Row.new(cells, grab_comments!, line)
|
63
|
+
end
|
64
|
+
|
65
|
+
def py_string(py_string, line)
|
66
|
+
@py_string = py_string
|
67
|
+
end
|
68
|
+
|
69
|
+
def eof
|
70
|
+
replay_step_or_examples
|
71
|
+
@formatter.eof
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def grab_comments!
|
77
|
+
comments = @comments
|
78
|
+
@comments = []
|
79
|
+
comments
|
80
|
+
end
|
81
|
+
|
82
|
+
def grab_tags!
|
83
|
+
tags = @tags
|
84
|
+
@tags = []
|
85
|
+
tags
|
86
|
+
end
|
87
|
+
|
88
|
+
def grab_table!
|
89
|
+
table = @table
|
90
|
+
@table = nil
|
91
|
+
table
|
92
|
+
end
|
93
|
+
|
94
|
+
def grab_py_string!
|
95
|
+
py_string = @py_string
|
96
|
+
@py_string = nil
|
97
|
+
py_string
|
98
|
+
end
|
99
|
+
|
100
|
+
def replay_step_or_examples
|
101
|
+
if(@step)
|
102
|
+
multiline_arg = grab_py_string! || grab_table!
|
103
|
+
@formatter.step(*(@step + [multiline_arg, nil, nil, nil, nil]))
|
104
|
+
@step = nil
|
105
|
+
end
|
106
|
+
if(@examples)
|
107
|
+
@formatter.examples(*(@examples + [grab_table!]))
|
108
|
+
@examples = nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'gherkin/i18n'
|
3
|
+
|
4
|
+
module Gherkin
|
5
|
+
module Parser
|
6
|
+
class JSONParser
|
7
|
+
attr_reader :i18n_language
|
8
|
+
|
9
|
+
def initialize(listener)
|
10
|
+
@listener = listener
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(src)
|
14
|
+
feature = JSON.parse(src)
|
15
|
+
|
16
|
+
@i18n_language = Gherkin::I18n.get(feature["language"] || "en" )
|
17
|
+
|
18
|
+
tags_for(feature)
|
19
|
+
@listener.feature(keyword_for("feature", feature), feature["name"], line_for(feature)) if feature["name"]
|
20
|
+
|
21
|
+
if feature["background"]
|
22
|
+
@listener.background(keyword_for("background", feature["background"]), feature["background"]["name"], line_for(feature["background"]))
|
23
|
+
steps_for(feature["background"])
|
24
|
+
end
|
25
|
+
|
26
|
+
feature["elements"].each do |feature_element|
|
27
|
+
parse_element(feature_element)
|
28
|
+
end if feature["elements"]
|
29
|
+
|
30
|
+
@listener.eof
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_element(feature_element)
|
36
|
+
case feature_element["type"]
|
37
|
+
when "Scenario" then parse_scenario(feature_element)
|
38
|
+
when "Scenario Outline" then parse_outline(feature_element)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_outline(scenario_outline)
|
43
|
+
tags_for(scenario_outline)
|
44
|
+
@listener.scenario_outline(keyword_for("scenario_outline", scenario_outline), scenario_outline["name"], line_for(scenario_outline) )
|
45
|
+
steps_for(scenario_outline)
|
46
|
+
scenario_outline["examples"].each do |examples|
|
47
|
+
tags_for(examples)
|
48
|
+
@listener.examples(keyword_for("examples", examples), examples["name"], line_for(examples))
|
49
|
+
rows_for(examples)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_scenario(scenario)
|
54
|
+
tags_for(scenario)
|
55
|
+
@listener.scenario(keyword_for("scenario", scenario), scenario["name"], line_for(scenario))
|
56
|
+
steps_for(scenario)
|
57
|
+
end
|
58
|
+
|
59
|
+
def tags_for(element)
|
60
|
+
element["tags"].each do |tag|
|
61
|
+
@listener.tag(tag, 0)
|
62
|
+
end if element["tags"]
|
63
|
+
end
|
64
|
+
|
65
|
+
def steps_for(element)
|
66
|
+
element["steps"].each do |step|
|
67
|
+
@listener.step(keyword_for("given",step), step["name"], line_for(step))
|
68
|
+
py_string_for(step)
|
69
|
+
rows_for(step)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def py_string_for(element)
|
74
|
+
@listener.py_string(element["py_string"], 0) if element["py_string"]
|
75
|
+
end
|
76
|
+
|
77
|
+
def rows_for(element)
|
78
|
+
element["table"].each do |row|
|
79
|
+
@listener.row(cells_for(row), 0)
|
80
|
+
end if element["table"]
|
81
|
+
end
|
82
|
+
|
83
|
+
def cells_for(row)
|
84
|
+
row["cells"].inject([]) { |col, ele| col << ele["text"] }
|
85
|
+
end
|
86
|
+
|
87
|
+
def line_for(element)
|
88
|
+
if element["line"]
|
89
|
+
element["line"]
|
90
|
+
elsif element["file_colon_line"]
|
91
|
+
element["file_colon_line"].split(':')[1].to_i
|
92
|
+
else
|
93
|
+
0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def keyword_for(gherkin_keyword, element)
|
98
|
+
element["keyword"] || i18n_language.keywords(gherkin_keyword).reject { |kw| kw == "* " }.first
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -20,11 +20,15 @@ module Gherkin
|
|
20
20
|
push_machine(@machine_name)
|
21
21
|
end
|
22
22
|
|
23
|
+
def location(uri, offset)
|
24
|
+
@listener.location(uri, offset)
|
25
|
+
end
|
26
|
+
|
23
27
|
# Doesn't yet fall back to super
|
24
28
|
def method_missing(method, *args)
|
25
29
|
# TODO: Catch exception and call super
|
26
30
|
if(event(method.to_s, args[-1]))
|
27
|
-
@listener.
|
31
|
+
@listener.__send__(method, *args)
|
28
32
|
end
|
29
33
|
if method == :eof
|
30
34
|
pop_machine
|
@@ -117,7 +121,8 @@ module Gherkin
|
|
117
121
|
def transition_table(name)
|
118
122
|
state_machine_reader = StateMachineReader.new
|
119
123
|
lexer = Gherkin::I18n.new('en').lexer(state_machine_reader)
|
120
|
-
|
124
|
+
machine = File.dirname(__FILE__) + "/#{name}.txt"
|
125
|
+
lexer.scan(File.read(machine), machine, 0)
|
121
126
|
state_machine_reader.rows
|
122
127
|
end
|
123
128
|
|
@@ -128,6 +133,9 @@ module Gherkin
|
|
128
133
|
@rows = []
|
129
134
|
end
|
130
135
|
|
136
|
+
def location(uri, offset)
|
137
|
+
end
|
138
|
+
|
131
139
|
def row(row, line_number)
|
132
140
|
@rows << row
|
133
141
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gherkin/native'
|
2
|
+
|
3
|
+
module Gherkin
|
4
|
+
module Parser
|
5
|
+
class Row
|
6
|
+
native_impl('gherkin')
|
7
|
+
|
8
|
+
attr_reader :cells, :comments, :line
|
9
|
+
|
10
|
+
def initialize(cells, comments, line)
|
11
|
+
@cells, @comments, @line = cells, comments, line
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/gherkin/rubify.rb
CHANGED
@@ -2,6 +2,8 @@ module Gherkin
|
|
2
2
|
module Rubify
|
3
3
|
if defined?(JRUBY_VERSION)
|
4
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.
|
5
7
|
def rubify(o)
|
6
8
|
if Java.java.util.Collection === o || Array === o
|
7
9
|
o.map{|e| rubify(e)}
|
data/lib/gherkin/tools/files.rb
CHANGED
data/lib/gherkin/tools/stats.rb
CHANGED
@@ -10,7 +10,7 @@ module Gherkin
|
|
10
10
|
each do |f|
|
11
11
|
parser = Gherkin::Parser::Parser.new(listener, true)
|
12
12
|
lexer = Gherkin::I18nLexer.new(parser)
|
13
|
-
lexer.scan(IO.read(f))
|
13
|
+
lexer.scan(IO.read(f), f, 0)
|
14
14
|
end
|
15
15
|
puts "Features: #{listener.features}"
|
16
16
|
puts "Scenarios: #{listener.scenarios}"
|
@@ -20,21 +20,21 @@ module Gherkin
|
|
20
20
|
def comment(content, line)
|
21
21
|
end
|
22
22
|
|
23
|
-
def feature(keyword, name, line)
|
23
|
+
def feature(keyword, name, description, line)
|
24
24
|
@features += 1
|
25
25
|
end
|
26
26
|
|
27
|
-
def background(keyword, name, line)
|
27
|
+
def background(keyword, name, description, line)
|
28
28
|
end
|
29
29
|
|
30
|
-
def scenario(keyword, name, line)
|
30
|
+
def scenario(keyword, name, description, line)
|
31
31
|
@scenarios += 1
|
32
32
|
end
|
33
33
|
|
34
|
-
def scenario_outline(keyword, name, line)
|
34
|
+
def scenario_outline(keyword, name, description, line)
|
35
35
|
end
|
36
36
|
|
37
|
-
def examples(keyword, name, line)
|
37
|
+
def examples(keyword, name, description, line)
|
38
38
|
end
|
39
39
|
|
40
40
|
def step(keyword, name, line)
|
data/ragel/lexer.c.rl.erb
CHANGED
@@ -66,7 +66,7 @@ static VALUE rb_eGherkinLexingError;
|
|
66
66
|
#define PTR_TO(P) (data + lexer->P)
|
67
67
|
|
68
68
|
#define STORE_KW_END_CON(EVENT) \
|
69
|
-
|
69
|
+
store_multiline_kw_con(listener, # EVENT, \
|
70
70
|
PTR_TO(keyword_start), LEN(keyword_start, PTR_TO(keyword_end - 1)), \
|
71
71
|
PTR_TO(content_start), LEN(content_start, PTR_TO(content_end)), \
|
72
72
|
lexer->current_line, lexer->eol); \
|
@@ -129,7 +129,7 @@ static VALUE rb_eGherkinLexingError;
|
|
129
129
|
store_kw_con(listener, "step",
|
130
130
|
PTR_TO(keyword_start), LEN(keyword_start, PTR_TO(keyword_end)),
|
131
131
|
PTR_TO(content_start), LEN(content_start, p),
|
132
|
-
lexer->current_line
|
132
|
+
lexer->current_line);
|
133
133
|
}
|
134
134
|
|
135
135
|
action store_comment_content {
|
@@ -251,31 +251,59 @@ strip_i(VALUE str, VALUE ary)
|
|
251
251
|
}
|
252
252
|
|
253
253
|
static VALUE
|
254
|
-
multiline_strip(VALUE text
|
254
|
+
multiline_strip(VALUE text)
|
255
255
|
{
|
256
256
|
VALUE map = rb_ary_new();
|
257
257
|
VALUE split = rb_str_split(text, "\n");
|
258
258
|
|
259
259
|
rb_iterate(rb_each, split, strip_i, map);
|
260
260
|
|
261
|
-
return
|
262
|
-
eol == CRLF_FLAG ? CRLF : LF ));
|
261
|
+
return split;
|
263
262
|
}
|
264
263
|
|
265
264
|
static void
|
266
265
|
store_kw_con(VALUE listener, const char * event_name,
|
267
266
|
const char * keyword_at, size_t keyword_length,
|
268
267
|
const char * at, size_t length,
|
269
|
-
int current_line
|
268
|
+
int current_line)
|
270
269
|
{
|
271
270
|
VALUE con = Qnil, kw = Qnil;
|
272
271
|
kw = ENCODED_STR_NEW(keyword_at, keyword_length);
|
273
272
|
con = ENCODED_STR_NEW(at, length);
|
274
|
-
con = multiline_strip(con, eol);
|
275
273
|
rb_funcall(con, rb_intern("strip!"), 0);
|
276
274
|
rb_funcall(listener, rb_intern(event_name), 3, kw, con, INT2FIX(current_line));
|
277
275
|
}
|
278
276
|
|
277
|
+
static void
|
278
|
+
store_multiline_kw_con(VALUE listener, const char * event_name,
|
279
|
+
const char * keyword_at, size_t keyword_length,
|
280
|
+
const char * at, size_t length,
|
281
|
+
int current_line, int eol)
|
282
|
+
{
|
283
|
+
VALUE con = Qnil, kw = Qnil, name = Qnil, desc = Qnil;
|
284
|
+
|
285
|
+
kw = ENCODED_STR_NEW(keyword_at, keyword_length);
|
286
|
+
con = ENCODED_STR_NEW(at, length);
|
287
|
+
|
288
|
+
VALUE split = multiline_strip(con);
|
289
|
+
|
290
|
+
name = rb_funcall(split, rb_intern("shift"), 0);
|
291
|
+
desc = rb_ary_join(split, rb_str_new2( \
|
292
|
+
eol == CRLF_FLAG ? CRLF : LF ));
|
293
|
+
|
294
|
+
if( name == Qnil )
|
295
|
+
{
|
296
|
+
name = rb_str_new2("");
|
297
|
+
}
|
298
|
+
if( rb_funcall(desc, rb_intern("size"), 0) == 0)
|
299
|
+
{
|
300
|
+
desc = rb_str_new2("");
|
301
|
+
}
|
302
|
+
rb_funcall(name, rb_intern("strip!"), 0);
|
303
|
+
rb_funcall(desc, rb_intern("strip!"), 0);
|
304
|
+
rb_funcall(listener, rb_intern(event_name), 4, kw, name, desc, INT2FIX(current_line));
|
305
|
+
}
|
306
|
+
|
279
307
|
static void
|
280
308
|
store_attr(VALUE listener, const char * attr_type,
|
281
309
|
const char * at, size_t length,
|
@@ -307,7 +335,7 @@ store_pystring_content(VALUE listener,
|
|
307
335
|
static void
|
308
336
|
raise_lexer_error(const char * at, int line)
|
309
337
|
{
|
310
|
-
rb_raise(rb_eGherkinLexingError, "Lexing error on line %d: '%s'.", line, at);
|
338
|
+
rb_raise(rb_eGherkinLexingError, "Lexing error on line %d: '%s'. See http://wiki.github.com/aslakhellesoy/gherkin/lexingerror for more information.", line, at);
|
311
339
|
}
|
312
340
|
|
313
341
|
static int
|
@@ -361,12 +389,14 @@ static VALUE CLexer_init(VALUE self, VALUE listener)
|
|
361
389
|
return self;
|
362
390
|
}
|
363
391
|
|
364
|
-
static VALUE CLexer_scan(VALUE self, VALUE input)
|
392
|
+
static VALUE CLexer_scan(VALUE self, VALUE input, VALUE uri, VALUE offset)
|
365
393
|
{
|
394
|
+
VALUE listener = rb_iv_get(self, "@listener");
|
395
|
+
rb_funcall(listener, rb_intern("location"), 2, uri, offset);
|
396
|
+
|
366
397
|
lexer_state *lexer = NULL;
|
367
398
|
DATA_GET(self, lexer_state, lexer);
|
368
399
|
|
369
|
-
|
370
400
|
VALUE input_copy = rb_str_dup(input);
|
371
401
|
|
372
402
|
rb_str_append(input_copy, rb_str_new2("\n%_FEATURE_END_%"));
|
@@ -384,7 +414,6 @@ static VALUE CLexer_scan(VALUE self, VALUE input)
|
|
384
414
|
const char *p, *pe, *eof;
|
385
415
|
int cs = 0;
|
386
416
|
|
387
|
-
VALUE listener = rb_iv_get(self, "@listener");
|
388
417
|
VALUE current_row = Qnil;
|
389
418
|
|
390
419
|
p = data;
|
@@ -420,6 +449,6 @@ void Init_gherkin_lexer_<%= @i18n.underscored_iso_code %>()
|
|
420
449
|
cI18nLexer = rb_define_class_under(mCLexer, "<%= @i18n.underscored_iso_code.capitalize %>", rb_cObject);
|
421
450
|
rb_define_alloc_func(cI18nLexer, CLexer_alloc);
|
422
451
|
rb_define_method(cI18nLexer, "initialize", CLexer_init, 1);
|
423
|
-
rb_define_method(cI18nLexer, "scan", CLexer_scan,
|
452
|
+
rb_define_method(cI18nLexer, "scan", CLexer_scan, 3);
|
424
453
|
}
|
425
454
|
|