ileitch-erbal 0.0.2
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/CHANGELOG +0 -0
- data/COPYING +18 -0
- data/README.rdoc +73 -0
- data/Rakefile +12 -0
- data/benchmark/bench.rb +57 -0
- data/benchmark/sample.erb +24 -0
- data/ext/erbal/erbal.c +41 -0
- data/ext/erbal/extconf.rb +2 -0
- data/ext/erbal/parser.c +232 -0
- data/ext/erbal/parser.h +19 -0
- data/ext/erbal/parser.rl +103 -0
- data/lib/erbal/rails.rb +8 -0
- data/tasks/ext.rake +42 -0
- data/tasks/gem.rake +54 -0
- data/tasks/spec.rake +0 -0
- metadata +70 -0
data/CHANGELOG
ADDED
File without changes
|
data/COPYING
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2009 Ian Leitch
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
= Erbal: Very small, very fast Ragel/C based ERB parser
|
2
|
+
|
3
|
+
== Intro
|
4
|
+
|
5
|
+
Erbal is a lightweight ERB parser based on the Ragel State Machine Compiler (http://www.complang.org/ragel/) and written in C. It's very fast.
|
6
|
+
|
7
|
+
Please note that Erbal isn't intended as a full replacement for the ERB implementation that ships with Ruby. Erbal only implements parsing of the following tags:
|
8
|
+
|
9
|
+
<%, <%=, <%#, -%>, %>
|
10
|
+
|
11
|
+
This is to keep Erbal very simple and very fast. If there's a good case for implementing more features from ERB and it doesn't impact performance or add much complexity then I'll consider it. Personally I've never needed anything more.
|
12
|
+
|
13
|
+
== Using Erbal
|
14
|
+
|
15
|
+
require 'erbal'
|
16
|
+
e = Erbal.new("<% a=1 -%> a is: <%= a -%>", "@output_buffer")
|
17
|
+
src = e.parse
|
18
|
+
eval(src)
|
19
|
+
|
20
|
+
== Rails
|
21
|
+
|
22
|
+
In your after_initialize block in config/environment.rb add:
|
23
|
+
|
24
|
+
require 'erbal/rails'
|
25
|
+
ActionView::Template.register_template_handler :erb, ErbalTemplateHandler
|
26
|
+
|
27
|
+
== Benchmarks
|
28
|
+
|
29
|
+
This benchmark was performed on a MacBook Pro with a 2.4Ghz Intel Core 2 Duo and 4GB 667Mhz DDR2 SDRAM. Running Mac OS X 10.6 (Snow Leopard). The code to run it is located in benchmark/bench.rb
|
30
|
+
|
31
|
+
Summary:
|
32
|
+
|
33
|
+
Erbal is 14.6x faster than Ruby's ERB and 7.5x faster than Erubis.
|
34
|
+
|
35
|
+
Details:
|
36
|
+
|
37
|
+
Ruby: 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin10]
|
38
|
+
Erubis: 2.6.5 using Erubis::FastEruby.
|
39
|
+
Erbal: 0.0.2
|
40
|
+
|
41
|
+
=> Warming up.... done
|
42
|
+
=> 10000 runs repeated 6 times
|
43
|
+
|
44
|
+
=> Erb:
|
45
|
+
1) 13.01
|
46
|
+
2) 13.00
|
47
|
+
3) 13.01
|
48
|
+
4) 13.04
|
49
|
+
5) 13.13
|
50
|
+
6) 13.23
|
51
|
+
=> Average: 13.07
|
52
|
+
|
53
|
+
=> Erbal:
|
54
|
+
1) 0.90
|
55
|
+
2) 0.89
|
56
|
+
3) 0.89
|
57
|
+
4) 0.90
|
58
|
+
5) 0.89
|
59
|
+
6) 0.89
|
60
|
+
=> Average: 0.89
|
61
|
+
|
62
|
+
=> Erubis:
|
63
|
+
1) 6.63
|
64
|
+
2) 6.67
|
65
|
+
3) 6.69
|
66
|
+
4) 6.71
|
67
|
+
5) 6.72
|
68
|
+
6) 6.75
|
69
|
+
=> Average: 6.70
|
70
|
+
|
71
|
+
== Credits
|
72
|
+
|
73
|
+
Many thanks to Adrian Thurston for writing the Ragel State Machine Compiler (http://www.complang.org/ragel/)!
|
data/Rakefile
ADDED
data/benchmark/bench.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'erubis'
|
4
|
+
require File.expand_path(File.dirname(__FILE__)) + '/../lib/erbal'
|
5
|
+
|
6
|
+
RUNS = 10000
|
7
|
+
REPEAT = 6
|
8
|
+
SRC = File.read('sample.erb')
|
9
|
+
|
10
|
+
class Benchmark
|
11
|
+
def self.run(runs, repeat, warmup=false)
|
12
|
+
puts "\n=> #{self.name.split('Benchmark').first}:" unless warmup
|
13
|
+
times = []
|
14
|
+
repeat.times do |i|
|
15
|
+
total = 0
|
16
|
+
runs.times do
|
17
|
+
start = Time.now
|
18
|
+
parse
|
19
|
+
total += Time.now-start
|
20
|
+
end
|
21
|
+
times << total
|
22
|
+
puts " #{i+1}) #{sprintf("%.2f", total)}" unless warmup
|
23
|
+
end
|
24
|
+
unless warmup
|
25
|
+
puts "=> Average: #{sprintf("%.2f", times.inject(0){|c, n| c += n} / times.size)}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class ErbalBenchmark < Benchmark
|
31
|
+
def self.parse
|
32
|
+
Erbal.new(SRC, "@output").parse
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ErbBenchmark < Benchmark
|
37
|
+
def self.parse
|
38
|
+
::ERB.new(SRC, nil, '-', '@output')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class ErubisBenchmark < Benchmark
|
43
|
+
def self.parse
|
44
|
+
Erubis::FastEruby.new.convert(SRC)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
parsers = [ErbBenchmark, ErbalBenchmark, ErubisBenchmark]
|
49
|
+
|
50
|
+
$stdout.write("=> Warming up.... ")
|
51
|
+
$stdout.flush
|
52
|
+
parsers.each do |b|
|
53
|
+
b.run(RUNS, 1, true)
|
54
|
+
end
|
55
|
+
puts "done"
|
56
|
+
puts "=> #{RUNS} runs repeated #{REPEAT} times"
|
57
|
+
parsers.map {|b| b.run(RUNS, REPEAT)}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, <% consectetur adipisicing elit -%>, sed do eiusmod tempor incididunt ut labore et dolore magna <%= aliqua -%>.
|
2
|
+
<%= Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
|
3
|
+
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. %>
|
4
|
+
<% Excepteur sint occaecat -%> cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est <%= laborum -%>.
|
5
|
+
|
6
|
+
<% Lorem %> ipsum dolor sit amet, <% consectetur %> adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
7
|
+
Ut enim ad minim veniam, <%# quis nostrud exercitation ullamco laboris nisi ut aliquip ex -%> ea commodo consequat. Duis aute irure dolor in
|
8
|
+
<%= reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur -%>.
|
9
|
+
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim <%= id est laborum -%>.
|
10
|
+
|
11
|
+
<%= Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. -%>
|
12
|
+
<% Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. %>
|
13
|
+
<%= Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. %>
|
14
|
+
<%#= Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -%>
|
15
|
+
|
16
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, <% sed do eiusmod tempor incididunt ut -%> labore et dolore magna aliqua.
|
17
|
+
Ut enim ad minim veniam, quis nostrud <%=%> exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
18
|
+
Duis aute irure dolor in reprehenderit in -%> <% voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
19
|
+
Excepteur sint occaecat cupidatat non proident, sunt -%> in culpa qui officia deserunt mollit <%= anim id est laborum -%>.
|
20
|
+
|
21
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
22
|
+
Ut enim ad minim veniam, <% quis -%> nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
23
|
+
Duis aute irure dolor in reprehenderit in <%= voluptate velit -%> esse cillum dolore eu fugiat nulla pariatur.
|
24
|
+
Excepteur sint occaecat cupidatat non proident, sunt in culpa <%= qui -%> <%= officia -%> <%= deserunt -%> <%= mollit -%> <%= anim -%> <%= id est laborum. -%>
|
data/ext/erbal/erbal.c
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "parser.h"
|
3
|
+
|
4
|
+
static VALUE cErbal;
|
5
|
+
|
6
|
+
void rb_erbal_free(void *data) {
|
7
|
+
if(data) {
|
8
|
+
free(data);
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
VALUE rb_erbal_alloc(VALUE klass) {
|
13
|
+
erbal_parser *parser = ALLOC_N(erbal_parser, 1);
|
14
|
+
VALUE obj = Data_Wrap_Struct(klass, NULL, rb_erbal_free, parser);
|
15
|
+
return obj;
|
16
|
+
}
|
17
|
+
|
18
|
+
VALUE rb_erbal_initialize(VALUE self, VALUE str, VALUE buffer) {
|
19
|
+
Check_Type(str, T_STRING);
|
20
|
+
Check_Type(buffer, T_STRING);
|
21
|
+
erbal_parser *parser = NULL;
|
22
|
+
Data_Get_Struct(self, erbal_parser, parser);
|
23
|
+
parser->buffer = buffer;
|
24
|
+
parser->str = str;
|
25
|
+
return self;
|
26
|
+
}
|
27
|
+
|
28
|
+
VALUE rb_erbal_parse(VALUE self) {
|
29
|
+
erbal_parser *parser = NULL;
|
30
|
+
Data_Get_Struct(self, erbal_parser, parser);
|
31
|
+
erbal_parser_init(parser);
|
32
|
+
erbal_parser_exec(parser);
|
33
|
+
return parser->src;
|
34
|
+
}
|
35
|
+
|
36
|
+
void Init_erbal() {
|
37
|
+
cErbal = rb_define_class("Erbal", rb_cObject);
|
38
|
+
rb_define_alloc_func(cErbal, rb_erbal_alloc);
|
39
|
+
rb_define_method(cErbal, "initialize", rb_erbal_initialize, 2);
|
40
|
+
rb_define_method(cErbal, "parse", rb_erbal_parse, 0);
|
41
|
+
}
|
data/ext/erbal/parser.c
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
|
2
|
+
#line 1 "parser.rl"
|
3
|
+
#include <stdio.h>
|
4
|
+
#include "parser.h"
|
5
|
+
|
6
|
+
|
7
|
+
#line 15 "parser.rl"
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
#line 12 "parser.c"
|
12
|
+
static const int erbal_parser_start = 1;
|
13
|
+
static const int erbal_parser_first_final = 1;
|
14
|
+
static const int erbal_parser_error = -1;
|
15
|
+
|
16
|
+
static const int erbal_parser_en_main = 1;
|
17
|
+
|
18
|
+
|
19
|
+
#line 18 "parser.rl"
|
20
|
+
|
21
|
+
static char *ts, *te, *p, *pe, *eof;
|
22
|
+
static int act, cs;
|
23
|
+
|
24
|
+
inline void erbal_parser_tag_open(erbal_parser *parser) {
|
25
|
+
parser->open = 1;
|
26
|
+
if (parser->mark) {
|
27
|
+
parser->mark = 0;
|
28
|
+
rb_str_buf_cat(parser->src, "\");", 3);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
inline void erbal_parser_tag_open_with_output(erbal_parser *parser) {
|
33
|
+
erbal_parser_tag_open(parser);
|
34
|
+
parser->output = 1;
|
35
|
+
rb_str_concat(parser->src, parser->buffer);
|
36
|
+
rb_str_buf_cat(parser->src, ".concat((", 9);
|
37
|
+
}
|
38
|
+
|
39
|
+
inline void erbal_parser_tag_open_with_comment(erbal_parser *parser) {
|
40
|
+
erbal_parser_tag_open(parser);
|
41
|
+
parser->comment = 1;
|
42
|
+
}
|
43
|
+
|
44
|
+
inline void erbal_parser_any(erbal_parser *parser) {
|
45
|
+
if (parser->comment) {
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
|
49
|
+
if (parser->open) {
|
50
|
+
rb_str_buf_cat(parser->src, p, 1);
|
51
|
+
} else {
|
52
|
+
if (!parser->mark) {
|
53
|
+
parser->mark = 1;
|
54
|
+
rb_str_concat(parser->src, parser->buffer);
|
55
|
+
rb_str_buf_cat(parser->src, ".concat(\"", 9);
|
56
|
+
}
|
57
|
+
if (p[0] == '"') {
|
58
|
+
rb_str_buf_cat(parser->src, "\\\"", 2);
|
59
|
+
} else {
|
60
|
+
rb_str_buf_cat(parser->src, p, 1);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
66
|
+
erbal_parser_tag_close(parser);
|
67
|
+
if (p[1] == '\n') {
|
68
|
+
p++;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
inline void erbal_parser_tag_close(erbal_parser *parser) {
|
73
|
+
parser->open = 0;
|
74
|
+
if (parser->output) {
|
75
|
+
parser->output = 0;
|
76
|
+
rb_str_buf_cat(parser->src, ").to_s);", 8);
|
77
|
+
} else if (!parser->comment) {
|
78
|
+
rb_str_buf_cat(parser->src, ";", 1);
|
79
|
+
}
|
80
|
+
parser->comment = 0;
|
81
|
+
}
|
82
|
+
|
83
|
+
inline void erbal_parser_finish(erbal_parser *parser) {
|
84
|
+
if (parser->mark) {
|
85
|
+
rb_str_buf_cat(parser->src, "\");", 3);
|
86
|
+
}
|
87
|
+
rb_str_concat(parser->src, parser->buffer);
|
88
|
+
}
|
89
|
+
|
90
|
+
void erbal_parser_init(erbal_parser *parser) {
|
91
|
+
parser->mark = 0;
|
92
|
+
parser->open = 0;
|
93
|
+
parser->output = 0;
|
94
|
+
parser->comment = 0;
|
95
|
+
parser->src = rb_str_dup(parser->buffer);
|
96
|
+
rb_str_buf_cat(parser->src, "=\"\";", 4);
|
97
|
+
|
98
|
+
#line 99 "parser.c"
|
99
|
+
{
|
100
|
+
cs = erbal_parser_start;
|
101
|
+
ts = 0;
|
102
|
+
te = 0;
|
103
|
+
act = 0;
|
104
|
+
}
|
105
|
+
|
106
|
+
#line 96 "parser.rl"
|
107
|
+
}
|
108
|
+
|
109
|
+
void erbal_parser_exec(erbal_parser *parser) {
|
110
|
+
p = RSTRING(parser->str)->ptr;
|
111
|
+
pe = p + strlen(p);
|
112
|
+
|
113
|
+
#line 114 "parser.c"
|
114
|
+
{
|
115
|
+
if ( p == pe )
|
116
|
+
goto _test_eof;
|
117
|
+
switch ( cs )
|
118
|
+
{
|
119
|
+
tr0:
|
120
|
+
#line 11 "parser.rl"
|
121
|
+
{{p = ((te))-1;}{ erbal_parser_any(parser); }}
|
122
|
+
goto st1;
|
123
|
+
tr1:
|
124
|
+
#line 12 "parser.rl"
|
125
|
+
{te = p+1;{ erbal_parser_tag_close_with_trim(parser); }}
|
126
|
+
goto st1;
|
127
|
+
tr2:
|
128
|
+
#line 11 "parser.rl"
|
129
|
+
{te = p+1;{ erbal_parser_any(parser); }}
|
130
|
+
goto st1;
|
131
|
+
tr6:
|
132
|
+
#line 11 "parser.rl"
|
133
|
+
{te = p;p--;{ erbal_parser_any(parser); }}
|
134
|
+
goto st1;
|
135
|
+
tr7:
|
136
|
+
#line 13 "parser.rl"
|
137
|
+
{te = p+1;{ erbal_parser_tag_close(parser); }}
|
138
|
+
goto st1;
|
139
|
+
tr10:
|
140
|
+
#line 8 "parser.rl"
|
141
|
+
{te = p;p--;{ erbal_parser_tag_open(parser); }}
|
142
|
+
goto st1;
|
143
|
+
tr11:
|
144
|
+
#line 9 "parser.rl"
|
145
|
+
{te = p+1;{ erbal_parser_tag_open_with_comment(parser); }}
|
146
|
+
goto st1;
|
147
|
+
tr12:
|
148
|
+
#line 10 "parser.rl"
|
149
|
+
{te = p+1;{ erbal_parser_tag_open_with_output(parser); }}
|
150
|
+
goto st1;
|
151
|
+
st1:
|
152
|
+
#line 1 "parser.rl"
|
153
|
+
{ts = 0;}
|
154
|
+
if ( ++p == pe )
|
155
|
+
goto _test_eof1;
|
156
|
+
case 1:
|
157
|
+
#line 1 "parser.rl"
|
158
|
+
{ts = p;}
|
159
|
+
#line 160 "parser.c"
|
160
|
+
switch( (*p) ) {
|
161
|
+
case 37: goto st2;
|
162
|
+
case 45: goto tr4;
|
163
|
+
case 60: goto st4;
|
164
|
+
}
|
165
|
+
goto tr2;
|
166
|
+
st2:
|
167
|
+
if ( ++p == pe )
|
168
|
+
goto _test_eof2;
|
169
|
+
case 2:
|
170
|
+
if ( (*p) == 62 )
|
171
|
+
goto tr7;
|
172
|
+
goto tr6;
|
173
|
+
tr4:
|
174
|
+
#line 1 "parser.rl"
|
175
|
+
{te = p+1;}
|
176
|
+
goto st3;
|
177
|
+
st3:
|
178
|
+
if ( ++p == pe )
|
179
|
+
goto _test_eof3;
|
180
|
+
case 3:
|
181
|
+
#line 182 "parser.c"
|
182
|
+
if ( (*p) == 37 )
|
183
|
+
goto st0;
|
184
|
+
goto tr6;
|
185
|
+
st0:
|
186
|
+
if ( ++p == pe )
|
187
|
+
goto _test_eof0;
|
188
|
+
case 0:
|
189
|
+
if ( (*p) == 62 )
|
190
|
+
goto tr1;
|
191
|
+
goto tr0;
|
192
|
+
st4:
|
193
|
+
if ( ++p == pe )
|
194
|
+
goto _test_eof4;
|
195
|
+
case 4:
|
196
|
+
if ( (*p) == 37 )
|
197
|
+
goto st5;
|
198
|
+
goto tr6;
|
199
|
+
st5:
|
200
|
+
if ( ++p == pe )
|
201
|
+
goto _test_eof5;
|
202
|
+
case 5:
|
203
|
+
switch( (*p) ) {
|
204
|
+
case 35: goto tr11;
|
205
|
+
case 61: goto tr12;
|
206
|
+
}
|
207
|
+
goto tr10;
|
208
|
+
}
|
209
|
+
_test_eof1: cs = 1; goto _test_eof;
|
210
|
+
_test_eof2: cs = 2; goto _test_eof;
|
211
|
+
_test_eof3: cs = 3; goto _test_eof;
|
212
|
+
_test_eof0: cs = 0; goto _test_eof;
|
213
|
+
_test_eof4: cs = 4; goto _test_eof;
|
214
|
+
_test_eof5: cs = 5; goto _test_eof;
|
215
|
+
|
216
|
+
_test_eof: {}
|
217
|
+
if ( p == eof )
|
218
|
+
{
|
219
|
+
switch ( cs ) {
|
220
|
+
case 2: goto tr6;
|
221
|
+
case 3: goto tr6;
|
222
|
+
case 0: goto tr0;
|
223
|
+
case 4: goto tr6;
|
224
|
+
case 5: goto tr10;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
}
|
229
|
+
|
230
|
+
#line 102 "parser.rl"
|
231
|
+
erbal_parser_finish(parser);
|
232
|
+
}
|
data/ext/erbal/parser.h
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#ifndef erbal_parser_h
|
2
|
+
#define erbal_parser_h
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
typedef struct erbal_parser {
|
7
|
+
int output, open, mark, comment;
|
8
|
+
VALUE str, src, buffer;
|
9
|
+
} erbal_parser;
|
10
|
+
|
11
|
+
inline void erbal_parser_tag_open(erbal_parser*);
|
12
|
+
inline void erbal_parser_tag_open_with_comment(erbal_parser*);
|
13
|
+
inline void erbal_parser_tag_open_with_output(erbal_parser*);
|
14
|
+
inline void erbal_parser_any(erbal_parser*);
|
15
|
+
inline void erbal_parser_tag_close(erbal_parser*);
|
16
|
+
inline void erbal_parser_tag_close_with_trim(erbal_parser*);
|
17
|
+
inline void erbal_parser_finish(erbal_parser*);
|
18
|
+
|
19
|
+
#endif
|
data/ext/erbal/parser.rl
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include "parser.h"
|
3
|
+
|
4
|
+
%%{
|
5
|
+
machine erbal_parser;
|
6
|
+
|
7
|
+
main := |*
|
8
|
+
'<%' => { erbal_parser_tag_open(parser); };
|
9
|
+
'<%#' => { erbal_parser_tag_open_with_comment(parser); };
|
10
|
+
'<%=' => { erbal_parser_tag_open_with_output(parser); };
|
11
|
+
any => { erbal_parser_any(parser); };
|
12
|
+
'-%>' => { erbal_parser_tag_close_with_trim(parser); };
|
13
|
+
'%>' => { erbal_parser_tag_close(parser); };
|
14
|
+
*|;
|
15
|
+
}%%
|
16
|
+
|
17
|
+
%% write data;
|
18
|
+
|
19
|
+
static char *ts, *te, *p, *pe, *eof;
|
20
|
+
static int act, cs;
|
21
|
+
|
22
|
+
inline void erbal_parser_tag_open(erbal_parser *parser) {
|
23
|
+
parser->open = 1;
|
24
|
+
if (parser->mark) {
|
25
|
+
parser->mark = 0;
|
26
|
+
rb_str_buf_cat(parser->src, "\");", 3);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
inline void erbal_parser_tag_open_with_output(erbal_parser *parser) {
|
31
|
+
erbal_parser_tag_open(parser);
|
32
|
+
parser->output = 1;
|
33
|
+
rb_str_concat(parser->src, parser->buffer);
|
34
|
+
rb_str_buf_cat(parser->src, ".concat((", 9);
|
35
|
+
}
|
36
|
+
|
37
|
+
inline void erbal_parser_tag_open_with_comment(erbal_parser *parser) {
|
38
|
+
erbal_parser_tag_open(parser);
|
39
|
+
parser->comment = 1;
|
40
|
+
}
|
41
|
+
|
42
|
+
inline void erbal_parser_any(erbal_parser *parser) {
|
43
|
+
if (parser->comment) {
|
44
|
+
return;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (parser->open) {
|
48
|
+
rb_str_buf_cat(parser->src, p, 1);
|
49
|
+
} else {
|
50
|
+
if (!parser->mark) {
|
51
|
+
parser->mark = 1;
|
52
|
+
rb_str_concat(parser->src, parser->buffer);
|
53
|
+
rb_str_buf_cat(parser->src, ".concat(\"", 9);
|
54
|
+
}
|
55
|
+
if (p[0] == '"') {
|
56
|
+
rb_str_buf_cat(parser->src, "\\\"", 2);
|
57
|
+
} else {
|
58
|
+
rb_str_buf_cat(parser->src, p, 1);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
64
|
+
erbal_parser_tag_close(parser);
|
65
|
+
if (p[1] == '\n') {
|
66
|
+
p++;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
inline void erbal_parser_tag_close(erbal_parser *parser) {
|
71
|
+
parser->open = 0;
|
72
|
+
if (parser->output) {
|
73
|
+
parser->output = 0;
|
74
|
+
rb_str_buf_cat(parser->src, ").to_s);", 8);
|
75
|
+
} else if (!parser->comment) {
|
76
|
+
rb_str_buf_cat(parser->src, ";", 1);
|
77
|
+
}
|
78
|
+
parser->comment = 0;
|
79
|
+
}
|
80
|
+
|
81
|
+
inline void erbal_parser_finish(erbal_parser *parser) {
|
82
|
+
if (parser->mark) {
|
83
|
+
rb_str_buf_cat(parser->src, "\");", 3);
|
84
|
+
}
|
85
|
+
rb_str_concat(parser->src, parser->buffer);
|
86
|
+
}
|
87
|
+
|
88
|
+
void erbal_parser_init(erbal_parser *parser) {
|
89
|
+
parser->mark = 0;
|
90
|
+
parser->open = 0;
|
91
|
+
parser->output = 0;
|
92
|
+
parser->comment = 0;
|
93
|
+
parser->src = rb_str_dup(parser->buffer);
|
94
|
+
rb_str_buf_cat(parser->src, "=\"\";", 4);
|
95
|
+
%% write init;
|
96
|
+
}
|
97
|
+
|
98
|
+
void erbal_parser_exec(erbal_parser *parser) {
|
99
|
+
p = RSTRING(parser->str)->ptr;
|
100
|
+
pe = p + strlen(p);
|
101
|
+
%% write exec;
|
102
|
+
erbal_parser_finish(parser);
|
103
|
+
}
|
data/lib/erbal/rails.rb
ADDED
data/tasks/ext.rake
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
CLEAN.include %w(**/*.{o,bundle,jar,so,obj,pdb,lib,def,exp,log} ext/*/Makefile ext/*/conftest.dSYM)
|
2
|
+
|
3
|
+
def ext_task(name)
|
4
|
+
ext_dir = "ext/#{name}"
|
5
|
+
ext_bundle = "#{ext_dir}/#{name}.#{Config::CONFIG['DLEXT']}"
|
6
|
+
ext_files = FileList[
|
7
|
+
"#{ext_dir}/*.c",
|
8
|
+
"#{ext_dir}/*.h",
|
9
|
+
"#{ext_dir}/*.rl",
|
10
|
+
"#{ext_dir}/extconf.rb",
|
11
|
+
"#{ext_dir}/Makefile",
|
12
|
+
"lib"
|
13
|
+
]
|
14
|
+
|
15
|
+
task "compile:#{name}" => ["#{ext_dir}/Makefile", ext_bundle]
|
16
|
+
task :compile => "compile:#{name}"
|
17
|
+
|
18
|
+
file "#{ext_dir}/Makefile" => ["#{ext_dir}/extconf.rb"] do
|
19
|
+
cd(ext_dir) { ruby "extconf.rb" }
|
20
|
+
end
|
21
|
+
|
22
|
+
file ext_bundle => ext_files do
|
23
|
+
cd ext_dir do
|
24
|
+
sh(WIN ? 'nmake' : 'make')
|
25
|
+
end
|
26
|
+
cp ext_bundle, 'lib/'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Compile the Ragel state machines"
|
31
|
+
task :ragel do
|
32
|
+
Dir.chdir 'ext/erbal' do
|
33
|
+
target = "parser.c"
|
34
|
+
File.unlink target if File.exist? target
|
35
|
+
sh "ragel -G2 -o parser.c parser.rl"
|
36
|
+
raise "Failed to compile Ragel state machine" unless File.exist? target
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Compile the extensions"
|
41
|
+
task :compile => :ragel
|
42
|
+
task :package => :compile
|
data/tasks/gem.rake
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
WIN_SUFFIX = ENV['WIN_SUFFIX'] || 'i386-mswin32'
|
5
|
+
ERBAL_VERSION = '0.0.2'
|
6
|
+
|
7
|
+
task :clean => :clobber_package
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'erbal'
|
11
|
+
s.version = ERBAL_VERSION
|
12
|
+
s.platform = WIN ? Gem::Platform::CURRENT : Gem::Platform::RUBY
|
13
|
+
s.summary =
|
14
|
+
s.description = "Very small, very fast Ragel/C based ERB parser"
|
15
|
+
s.author = "Ian Leitch"
|
16
|
+
s.email = 'ian.leitch@systino.net'
|
17
|
+
s.homepage = 'http://github.com/ileitch/erbal'
|
18
|
+
s.has_rdoc = false
|
19
|
+
|
20
|
+
s.files = %w(COPYING CHANGELOG README.rdoc Rakefile) +
|
21
|
+
Dir.glob("{lib,spec,tasks,benchmark}/**/*") +
|
22
|
+
Dir.glob("ext/**/*.{h,c,rb,rl}")
|
23
|
+
|
24
|
+
if WIN
|
25
|
+
s.files += ["lib/erbal.#{Config::CONFIG['DLEXT']}"]
|
26
|
+
else
|
27
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
28
|
+
end
|
29
|
+
|
30
|
+
s.require_path = "lib"
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::GemPackageTask.new(spec) do |p|
|
34
|
+
p.gem_spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
namespace :gem do
|
38
|
+
desc "Update the gemspec for GitHub's gem server"
|
39
|
+
task :github do
|
40
|
+
File.open("erbal.gemspec", 'w') { |f| f << YAML.dump(spec) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
task :install => [:clean, :clobber, :ragel, :compile, :package] do
|
45
|
+
sh "#{SUDO} #{gem} install pkg/#{spec.full_name}.gem"
|
46
|
+
end
|
47
|
+
|
48
|
+
task :uninstall => :clean do
|
49
|
+
sh "#{SUDO} #{gem} uninstall -v #{ERBAL_VERSION} -x erbal"
|
50
|
+
end
|
51
|
+
|
52
|
+
def gem
|
53
|
+
RUBY_1_9 ? 'gem19' : 'gem'
|
54
|
+
end
|
data/tasks/spec.rake
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ileitch-erbal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian Leitch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-01 21:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Very small, very fast Ragel/C based ERB parser
|
17
|
+
email: ian.leitch@systino.net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- ext/erbal/extconf.rb
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- COPYING
|
26
|
+
- CHANGELOG
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- lib/erbal
|
30
|
+
- lib/erbal/rails.rb
|
31
|
+
- tasks/ext.rake
|
32
|
+
- tasks/gem.rake
|
33
|
+
- tasks/spec.rake
|
34
|
+
- benchmark/bench.rb
|
35
|
+
- benchmark/sample.erb
|
36
|
+
- ext/erbal/parser.h
|
37
|
+
- ext/erbal/erbal.c
|
38
|
+
- ext/erbal/parser.c
|
39
|
+
- ext/erbal/extconf.rb
|
40
|
+
- ext/erbal/parser.rl
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/ileitch/erbal
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Very small, very fast Ragel/C based ERB parser
|
69
|
+
test_files: []
|
70
|
+
|