erbal 1.1 → 1.2.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +46 -40
- data/ext/erbal/erbal.c +26 -11
- data/ext/erbal/extconf.rb +1 -1
- data/ext/erbal/parser.c +222 -111
- data/ext/erbal/parser.h +24 -13
- data/ext/erbal/parser.rl +84 -39
- data/lib/erbal/rails.rb +42 -0
- data/spec/erbal_spec.rb +74 -30
- data/tasks/gem.rake +1 -1
- metadata +13 -10
- data/lib/erbal/rails23.rb +0 -21
data/README.rdoc
CHANGED
@@ -8,21 +8,25 @@ Erbal is a lightweight ERB parser that uses the Ragel State Machine Compiler (ht
|
|
8
8
|
|
9
9
|
>> require 'erbal'
|
10
10
|
>> src = Erbal.new("<% a=1 -%>a is: <%= a -%>").parse
|
11
|
-
=> "@output_buffer = ''; a=1 ;\n@output_buffer
|
11
|
+
=> "@output_buffer = ''; a=1 ;\n@output_buffer.concat(%Q`a is: \#{ a }`);@output_buffer"
|
12
12
|
>> eval(src)
|
13
13
|
=> "a is: 1"
|
14
14
|
|
15
15
|
Erbal.new takes an optional 2nd argument which is a hash of options, available options are:
|
16
16
|
|
17
|
-
*
|
18
|
-
*
|
17
|
+
* <b>:buffer</b> - The name of the output buffer. Default is '@output_buffer'.
|
18
|
+
* <b>:buffer_initial_value</b> - The initial value of the output buffer. Default is a blank string.
|
19
|
+
* <b>:safe_concat_method</b> - The method to call on the buffer when concatenating a string which doesn't need escaping, i.e text outside of ERB tags uses the safe concatenation method. Default is 'concat'.
|
20
|
+
* <b>:unsafe_concat_method</b> - The method to call on the buffer when concatenating a string which DOES need escaping, i.e <%= some_method %> will result in the use of unsafe_concat_method. Default is 'concat'.
|
21
|
+
* <b>:safe_concat_method</b> - Normally the '<%=' tag uses the unsafe_concat_method, with this option you can specify a keyword to signify that safe_concat_method should be used instead. For example if safe_concat_method is set to 'raw' then <%= raw some_method %> will result in a concatenation using the safe_concat_method. Default is blank, i.e no keyword is specified.
|
22
|
+
|
23
|
+
<b>NOTE: Erbal itself does NOT perform escaping, it is the responsibility of your unsafe_concat_method to escape the string passed to it.</b>
|
19
24
|
|
20
25
|
== Rails 2.3
|
21
26
|
|
22
27
|
Create the file 'config/initializers/erbal.rb' containing:
|
23
28
|
|
24
|
-
require 'erbal/
|
25
|
-
ActionView::Template.register_template_handler :erb, ErbalTemplateHandler
|
29
|
+
require 'erbal/rails'
|
26
30
|
|
27
31
|
== Rails 3
|
28
32
|
|
@@ -33,44 +37,46 @@ I've not looked into yet.. patches are welcome! ;)
|
|
33
37
|
These benchmarks were run on a Mac OS X 10.6.4, 2.66 Ghx Intel Core i5 with 8 GB of 1067 MHz DDR3 RAM.
|
34
38
|
|
35
39
|
Ruby: 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.0], MBARI 0x6770, Ruby Enterprise Edition 2010.02
|
36
|
-
Erubis: 2.6.6
|
37
|
-
Erbal: 1.1
|
38
|
-
|
39
|
-
=> Parsing Benchmark
|
40
|
-
|
41
|
-
=> Erb
|
42
|
-
0.851 0.853 0.848 0.847 0.849 0.847
|
43
|
-
=> Average: 0.849
|
44
|
-
|
45
|
-
=> Erubis (using FastEruby engine)
|
46
|
-
0.442 0.442 0.444 0.442 0.441 0.442
|
47
|
-
=> Average: 0.442
|
48
40
|
|
49
|
-
|
50
|
-
0.451 0.424 0.446 0.425 0.445 0.446
|
51
|
-
=> Average: 0.439
|
52
|
-
|
53
|
-
=> Erbal
|
54
|
-
0.036 0.039 0.066 0.038 0.067 0.039
|
55
|
-
=> Average: 0.047
|
56
|
-
|
57
|
-
=> eval() Benchmark
|
58
|
-
|
59
|
-
=> Erb
|
60
|
-
0.203 0.192 0.180 0.180 0.179 0.191
|
61
|
-
=> Average: 0.187
|
62
|
-
|
63
|
-
=> Erubis (using FastEruby engine)
|
64
|
-
0.129 0.127 0.128 0.128 0.114 0.128
|
65
|
-
=> Average: 0.125
|
41
|
+
Erubis: 2.6.6
|
66
42
|
|
67
|
-
|
68
|
-
0.178 0.176 0.165 0.176 0.175 0.164
|
69
|
-
=> Average: 0.172
|
43
|
+
Erbal: 1.1
|
70
44
|
|
71
|
-
|
72
|
-
|
73
|
-
|
45
|
+
=> Parsing Benchmark
|
46
|
+
|
47
|
+
=> Erb
|
48
|
+
0.851 0.853 0.848 0.847 0.849 0.847
|
49
|
+
=> Average: 0.849
|
50
|
+
|
51
|
+
=> Erubis (using FastEruby engine)
|
52
|
+
0.442 0.442 0.444 0.442 0.441 0.442
|
53
|
+
=> Average: 0.442
|
54
|
+
|
55
|
+
=> Erubis (using default Eruby engine)
|
56
|
+
0.451 0.424 0.446 0.425 0.445 0.446
|
57
|
+
=> Average: 0.439
|
58
|
+
|
59
|
+
=> Erbal
|
60
|
+
0.036 0.039 0.066 0.038 0.067 0.039
|
61
|
+
=> Average: 0.047
|
62
|
+
|
63
|
+
=> eval() Benchmark
|
64
|
+
|
65
|
+
=> Erb
|
66
|
+
0.203 0.192 0.180 0.180 0.179 0.191
|
67
|
+
=> Average: 0.187
|
68
|
+
|
69
|
+
=> Erubis (using FastEruby engine)
|
70
|
+
0.129 0.127 0.128 0.128 0.114 0.128
|
71
|
+
=> Average: 0.125
|
72
|
+
|
73
|
+
=> Erubis (using default Eruby engine)
|
74
|
+
0.178 0.176 0.165 0.176 0.175 0.164
|
75
|
+
=> Average: 0.172
|
76
|
+
|
77
|
+
=> Erbal
|
78
|
+
0.111 0.125 0.124 0.110 0.133 0.124
|
79
|
+
=> Average: 0.121
|
74
80
|
|
75
81
|
== Contributing
|
76
82
|
|
data/ext/erbal/erbal.c
CHANGED
@@ -3,12 +3,33 @@
|
|
3
3
|
|
4
4
|
static VALUE cErbal;
|
5
5
|
|
6
|
+
void rb_erbal_free(erbal_parser *parser) {
|
7
|
+
free(parser->state);
|
8
|
+
free(parser);
|
9
|
+
}
|
10
|
+
|
6
11
|
VALUE rb_erbal_alloc(VALUE klass) {
|
7
12
|
erbal_parser *parser = ALLOC(erbal_parser);
|
8
|
-
|
13
|
+
parser->state = ALLOC(parser_state);
|
14
|
+
VALUE obj = Data_Wrap_Struct(klass, 0, rb_erbal_free, parser);
|
9
15
|
return obj;
|
10
16
|
}
|
11
17
|
|
18
|
+
void rb_erbal_setup_option(VALUE self, erbal_parser* parser, VALUE* parser_option, const char* key, const char* default_value) {
|
19
|
+
VALUE value = rb_hash_aref(parser->options, ID2SYM(rb_intern(key)));
|
20
|
+
|
21
|
+
if (!NIL_P(value)) {
|
22
|
+
Check_Type(value, T_STRING);
|
23
|
+
*(parser_option) = value;
|
24
|
+
} else {
|
25
|
+
*(parser_option) = rb_str_new2(default_value);
|
26
|
+
}
|
27
|
+
|
28
|
+
VALUE ivar = rb_str_new2("@");
|
29
|
+
ivar = rb_str_cat2(ivar, key);
|
30
|
+
rb_iv_set(self, RSTRING(ivar)->ptr, *(parser_option));
|
31
|
+
}
|
32
|
+
|
12
33
|
VALUE rb_erbal_initialize(int argc, VALUE *argv, VALUE self) {
|
13
34
|
VALUE str, options;
|
14
35
|
|
@@ -35,16 +56,10 @@ VALUE rb_erbal_initialize(int argc, VALUE *argv, VALUE self) {
|
|
35
56
|
parser->debug = 0;
|
36
57
|
}
|
37
58
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
parser->buffer_name = buffer_name_val;
|
43
|
-
} else {
|
44
|
-
parser->buffer_name = rb_str_new2("@output_buffer");
|
45
|
-
}
|
46
|
-
|
47
|
-
rb_iv_set(self, "@buffer_name", parser->buffer_name);
|
59
|
+
rb_erbal_setup_option(self, parser, &parser->buffer_name, "buffer", "@output_buffer");
|
60
|
+
rb_erbal_setup_option(self, parser, &parser->safe_concat_method, "safe_concat_method", "concat");
|
61
|
+
rb_erbal_setup_option(self, parser, &parser->unsafe_concat_method, "unsafe_concat_method", "concat");
|
62
|
+
rb_erbal_setup_option(self, parser, &parser->safe_concat_keyword, "safe_concat_keyword", "");
|
48
63
|
|
49
64
|
return self;
|
50
65
|
}
|
data/ext/erbal/extconf.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
create_makefile("erbal")
|
2
|
+
create_makefile("erbal")
|
data/ext/erbal/parser.c
CHANGED
@@ -4,78 +4,99 @@
|
|
4
4
|
#include "parser.h"
|
5
5
|
|
6
6
|
|
7
|
-
#line
|
7
|
+
#line 31 "parser.rl"
|
8
8
|
|
9
9
|
|
10
10
|
|
11
11
|
#line 12 "parser.c"
|
12
|
-
static const int erbal_parser_start =
|
13
|
-
static const int erbal_parser_first_final =
|
12
|
+
static const int erbal_parser_start = 3;
|
13
|
+
static const int erbal_parser_first_final = 3;
|
14
14
|
static const int erbal_parser_error = -1;
|
15
15
|
|
16
|
-
static const int erbal_parser_en_main =
|
16
|
+
static const int erbal_parser_en_main = 3;
|
17
17
|
|
18
18
|
|
19
|
-
#line
|
19
|
+
#line 34 "parser.rl"
|
20
20
|
|
21
21
|
static char *ts, *te, *p, *pe, *eof;
|
22
22
|
static int act, cs;
|
23
23
|
|
24
24
|
inline void erbal_parser_tag_open_common(erbal_parser *parser, int shift) {
|
25
|
-
if (parser->chars_seen != 0) {
|
26
|
-
if (!parser->
|
27
|
-
|
25
|
+
if (parser->state->chars_seen != 0) {
|
26
|
+
if (!parser->state->in_concat) {
|
27
|
+
erbal_open_buffer_concat(parser, 1);
|
28
28
|
}
|
29
29
|
|
30
30
|
erbal_concat_chars_seen(parser, shift);
|
31
|
-
parser->chars_seen = 0;
|
31
|
+
parser->state->chars_seen = 0;
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
35
35
|
inline void erbal_parser_tag_open(erbal_parser *parser) {
|
36
36
|
erbal_parser_tag_open_common(parser, -1);
|
37
|
-
parser->state = TAG_OPEN;
|
37
|
+
parser->state->tag = TAG_OPEN;
|
38
38
|
}
|
39
39
|
|
40
40
|
inline void erbal_parser_tag_open_with_dash(erbal_parser *parser) {
|
41
41
|
erbal_parser_tag_open_common(parser, -2);
|
42
|
-
parser->state = TAG_OPEN;
|
42
|
+
parser->state->tag = TAG_OPEN;
|
43
43
|
}
|
44
44
|
|
45
|
-
inline void
|
45
|
+
inline void erbal_parser_tag_open_choose_concat(erbal_parser *parser) {
|
46
|
+
if (strcmp(RSTRING(parser->keyword)->ptr, RSTRING(parser->safe_concat_keyword)->ptr) != 0) {
|
47
|
+
/* Keyword doesn't match, reset the buffer to the start of the expression match and act as if a keyword wasn't seen. */
|
48
|
+
p = parser->keyword_preceding_whitespace - 1;
|
49
|
+
erbal_parser_tag_open_for_unsafe_concat(parser);
|
50
|
+
} else {
|
51
|
+
/* Rewind the buffer to preserve whitespace following the keyword. */
|
52
|
+
p = p - (parser->keyword_trailing_whitespace - parser->keyword_end);
|
53
|
+
erbal_parser_tag_open_for_safe_concat(parser);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
inline void erbal_parser_tag_open_for_unsafe_concat(erbal_parser *parser) {
|
46
58
|
erbal_parser_tag_open_common(parser, -2);
|
47
|
-
parser->state =
|
59
|
+
parser->state->tag = TAG_OPEN_FOR_UNSAFE_CONCAT;
|
60
|
+
}
|
61
|
+
|
62
|
+
inline void erbal_parser_tag_open_for_safe_concat(erbal_parser *parser) {
|
63
|
+
erbal_parser_tag_open_common(parser, -2);
|
64
|
+
parser->state->tag = TAG_OPEN_FOR_SAFE_CONCAT;
|
48
65
|
}
|
49
66
|
|
50
67
|
inline void erbal_parser_tag_open_for_comment(erbal_parser *parser) {
|
51
68
|
erbal_parser_tag_open_common(parser, -2);
|
52
|
-
parser->state = TAG_OPEN_FOR_COMMENT;
|
69
|
+
parser->state->tag = TAG_OPEN_FOR_COMMENT;
|
53
70
|
}
|
54
71
|
|
55
72
|
inline void erbal_parser_non_tag(erbal_parser *parser) {
|
56
|
-
parser->chars_seen += 1;
|
73
|
+
parser->state->chars_seen += 1;
|
57
74
|
}
|
58
75
|
|
59
76
|
inline void erbal_parser_tag_close_common(erbal_parser *parser, int tag_size) {
|
60
|
-
if (parser->state ==
|
61
|
-
if (!parser->
|
62
|
-
|
77
|
+
if (parser->state->tag == TAG_OPEN_FOR_UNSAFE_CONCAT || parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
78
|
+
if (!parser->state->in_concat) {
|
79
|
+
if (parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
80
|
+
erbal_open_buffer_concat(parser, 1);
|
81
|
+
} else {
|
82
|
+
erbal_open_buffer_concat(parser, 0);
|
83
|
+
}
|
63
84
|
}
|
64
85
|
|
65
86
|
rb_str_buf_cat(parser->src, "#{", 2);
|
66
87
|
erbal_concat_chars_seen(parser, -tag_size);
|
67
88
|
rb_str_buf_cat(parser->src, "}", 1);
|
68
|
-
} else if (parser->state == TAG_OPEN) {
|
69
|
-
if (parser->
|
70
|
-
|
89
|
+
} else if (parser->state->tag == TAG_OPEN) {
|
90
|
+
if (parser->state->in_concat) {
|
91
|
+
erbal_close_buffer_concat(parser);
|
71
92
|
}
|
72
93
|
|
73
94
|
erbal_concat_chars_seen(parser, -tag_size);
|
74
95
|
rb_str_buf_cat(parser->src, ";\n", 2);
|
75
96
|
}
|
76
97
|
|
77
|
-
parser->state = OUTSIDE_TAG;
|
78
|
-
parser->chars_seen = 0;
|
98
|
+
parser->state->tag = OUTSIDE_TAG;
|
99
|
+
parser->state->chars_seen = 0;
|
79
100
|
}
|
80
101
|
|
81
102
|
inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
@@ -95,8 +116,8 @@ inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
|
|
95
116
|
int i, n, slashes_seen = 0;
|
96
117
|
char *current_char;
|
97
118
|
|
98
|
-
for (i = 0; i < parser->chars_seen; i++) {
|
99
|
-
current_char = (((p + shift) - parser->chars_seen) + i);
|
119
|
+
for (i = 0; i < parser->state->chars_seen; i++) {
|
120
|
+
current_char = (((p + shift) - parser->state->chars_seen) + i);
|
100
121
|
|
101
122
|
if (*current_char == '#' || *current_char == '`') {
|
102
123
|
if (slashes_seen == 0) {
|
@@ -122,39 +143,48 @@ inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
|
|
122
143
|
}
|
123
144
|
|
124
145
|
inline void erbal_concat_chars_seen(erbal_parser *parser, int shift) {
|
125
|
-
if (parser->chars_seen != 0) {
|
126
|
-
if (parser->
|
146
|
+
if (parser->state->chars_seen != 0) {
|
147
|
+
if (parser->state->in_concat && parser->state->tag == OUTSIDE_TAG) {
|
127
148
|
rb_str_concat(parser->src, erbal_escape_special_chars(parser, shift));
|
128
149
|
} else {
|
129
|
-
rb_str_buf_cat(parser->src, ((p + shift) - parser->chars_seen), parser->chars_seen);
|
150
|
+
rb_str_buf_cat(parser->src, ((p + shift) - parser->state->chars_seen), parser->state->chars_seen);
|
130
151
|
}
|
131
152
|
}
|
132
153
|
|
133
|
-
parser->chars_seen = 0;
|
154
|
+
parser->state->chars_seen = 0;
|
134
155
|
}
|
135
156
|
|
136
|
-
inline void
|
157
|
+
inline void erbal_open_buffer_concat(erbal_parser *parser, int safe_concat) {
|
137
158
|
rb_str_concat(parser->src, parser->buffer_name);
|
138
|
-
rb_str_buf_cat(parser->src, "
|
139
|
-
|
159
|
+
rb_str_buf_cat(parser->src, ".", 1);
|
160
|
+
|
161
|
+
if (safe_concat) {
|
162
|
+
rb_str_concat(parser->src, parser->safe_concat_method);
|
163
|
+
} else {
|
164
|
+
rb_str_concat(parser->src, parser->unsafe_concat_method);
|
165
|
+
}
|
166
|
+
|
167
|
+
rb_str_buf_cat(parser->src, "(", 1);
|
168
|
+
rb_str_buf_cat(parser->src, "%Q`", 3);
|
169
|
+
parser->state->in_concat = 1;
|
140
170
|
}
|
141
171
|
|
142
|
-
inline void
|
143
|
-
rb_str_buf_cat(parser->src, "
|
144
|
-
parser->
|
172
|
+
inline void erbal_close_buffer_concat(erbal_parser *parser) {
|
173
|
+
rb_str_buf_cat(parser->src, "`);", 3);
|
174
|
+
parser->state->in_concat = 0;
|
145
175
|
}
|
146
176
|
|
147
177
|
inline void erbal_parser_finish(erbal_parser *parser) {
|
148
|
-
if (parser->chars_seen != 0) {
|
149
|
-
if (!parser->
|
150
|
-
|
178
|
+
if (parser->state->chars_seen != 0) {
|
179
|
+
if (!parser->state->in_concat) {
|
180
|
+
erbal_open_buffer_concat(parser, 1);
|
151
181
|
}
|
152
182
|
|
153
183
|
erbal_concat_chars_seen(parser, 0);
|
154
184
|
}
|
155
185
|
|
156
|
-
if (parser->
|
157
|
-
|
186
|
+
if (parser->state->in_concat) {
|
187
|
+
erbal_close_buffer_concat(parser);
|
158
188
|
}
|
159
189
|
|
160
190
|
rb_str_concat(parser->src, parser->buffer_name);
|
@@ -165,9 +195,9 @@ inline void erbal_parser_finish(erbal_parser *parser) {
|
|
165
195
|
}
|
166
196
|
|
167
197
|
void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
168
|
-
parser->chars_seen = 0;
|
169
|
-
parser->
|
170
|
-
parser->state = OUTSIDE_TAG;
|
198
|
+
parser->state->chars_seen = 0;
|
199
|
+
parser->state->in_concat = 0;
|
200
|
+
parser->state->tag = OUTSIDE_TAG;
|
171
201
|
parser->src = rb_str_dup(parser->buffer_name);
|
172
202
|
|
173
203
|
rb_iv_set(self, "@src", parser->src);
|
@@ -184,7 +214,7 @@ void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
|
184
214
|
}
|
185
215
|
|
186
216
|
|
187
|
-
#line
|
217
|
+
#line 218 "parser.c"
|
188
218
|
{
|
189
219
|
cs = erbal_parser_start;
|
190
220
|
ts = 0;
|
@@ -192,89 +222,99 @@ void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
|
192
222
|
act = 0;
|
193
223
|
}
|
194
224
|
|
195
|
-
#line
|
225
|
+
#line 231 "parser.rl"
|
196
226
|
}
|
197
227
|
|
198
228
|
void erbal_parser_exec(erbal_parser *parser) {
|
199
229
|
p = RSTRING(parser->str)->ptr;
|
200
230
|
pe = p + strlen(p);
|
201
231
|
|
202
|
-
#line
|
232
|
+
#line 233 "parser.c"
|
203
233
|
{
|
204
234
|
if ( p == pe )
|
205
235
|
goto _test_eof;
|
206
236
|
switch ( cs )
|
207
237
|
{
|
208
238
|
tr0:
|
209
|
-
#line
|
239
|
+
#line 23 "parser.rl"
|
210
240
|
{{p = ((te))-1;}{ erbal_parser_non_tag(parser); }}
|
211
|
-
goto
|
241
|
+
goto st3;
|
212
242
|
tr1:
|
213
|
-
#line
|
243
|
+
#line 21 "parser.rl"
|
214
244
|
{te = p+1;{ erbal_parser_tag_close_with_trim(parser); }}
|
215
|
-
goto
|
245
|
+
goto st3;
|
216
246
|
tr2:
|
217
|
-
#line
|
247
|
+
#line 20 "parser.rl"
|
248
|
+
{{p = ((te))-1;}{ erbal_parser_tag_open_for_unsafe_concat(parser); }}
|
249
|
+
goto st3;
|
250
|
+
tr7:
|
251
|
+
#line 23 "parser.rl"
|
218
252
|
{te = p+1;{ erbal_parser_non_tag(parser); }}
|
219
|
-
goto
|
220
|
-
|
221
|
-
#line
|
253
|
+
goto st3;
|
254
|
+
tr11:
|
255
|
+
#line 23 "parser.rl"
|
222
256
|
{te = p;p--;{ erbal_parser_non_tag(parser); }}
|
223
|
-
goto
|
224
|
-
|
225
|
-
#line
|
257
|
+
goto st3;
|
258
|
+
tr12:
|
259
|
+
#line 22 "parser.rl"
|
226
260
|
{te = p+1;{ erbal_parser_tag_close(parser); }}
|
227
|
-
goto
|
228
|
-
|
229
|
-
#line
|
261
|
+
goto st3;
|
262
|
+
tr15:
|
263
|
+
#line 17 "parser.rl"
|
230
264
|
{te = p;p--;{ erbal_parser_tag_open(parser); }}
|
231
|
-
goto
|
232
|
-
|
233
|
-
#line
|
265
|
+
goto st3;
|
266
|
+
tr16:
|
267
|
+
#line 19 "parser.rl"
|
234
268
|
{te = p+1;{ erbal_parser_tag_open_for_comment(parser); }}
|
235
|
-
goto
|
236
|
-
|
237
|
-
#line
|
269
|
+
goto st3;
|
270
|
+
tr17:
|
271
|
+
#line 18 "parser.rl"
|
238
272
|
{te = p+1;{ erbal_parser_tag_open_with_dash(parser); }}
|
239
|
-
goto
|
240
|
-
|
241
|
-
#line
|
242
|
-
{te = p
|
243
|
-
goto
|
244
|
-
|
273
|
+
goto st3;
|
274
|
+
tr19:
|
275
|
+
#line 20 "parser.rl"
|
276
|
+
{te = p;p--;{ erbal_parser_tag_open_for_unsafe_concat(parser); }}
|
277
|
+
goto st3;
|
278
|
+
tr22:
|
279
|
+
#line 9 "parser.rl"
|
280
|
+
{ parser->keyword_trailing_whitespace = p; }
|
281
|
+
#line 29 "parser.rl"
|
282
|
+
{te = p;p--;{ erbal_parser_tag_open_choose_concat(parser); }}
|
283
|
+
goto st3;
|
284
|
+
st3:
|
245
285
|
#line 1 "NONE"
|
246
286
|
{ts = 0;}
|
247
287
|
if ( ++p == pe )
|
248
|
-
goto
|
249
|
-
case
|
288
|
+
goto _test_eof3;
|
289
|
+
case 3:
|
250
290
|
#line 1 "NONE"
|
251
291
|
{ts = p;}
|
252
|
-
#line
|
292
|
+
#line 293 "parser.c"
|
253
293
|
switch( (*p) ) {
|
254
|
-
case 37: goto
|
255
|
-
case 45: goto
|
256
|
-
case 60: goto
|
294
|
+
case 37: goto st4;
|
295
|
+
case 45: goto tr9;
|
296
|
+
case 60: goto st6;
|
257
297
|
}
|
258
|
-
goto
|
259
|
-
|
298
|
+
goto tr7;
|
299
|
+
st4:
|
260
300
|
if ( ++p == pe )
|
261
|
-
goto
|
262
|
-
case
|
301
|
+
goto _test_eof4;
|
302
|
+
case 4:
|
263
303
|
if ( (*p) == 62 )
|
264
|
-
goto
|
265
|
-
goto
|
266
|
-
|
304
|
+
goto tr12;
|
305
|
+
goto tr11;
|
306
|
+
tr9:
|
267
307
|
#line 1 "NONE"
|
268
308
|
{te = p+1;}
|
269
|
-
goto
|
270
|
-
|
309
|
+
goto st5;
|
310
|
+
st5:
|
271
311
|
if ( ++p == pe )
|
272
|
-
goto
|
273
|
-
case
|
274
|
-
#line
|
312
|
+
goto _test_eof5;
|
313
|
+
case 5:
|
314
|
+
#line 315 "parser.c"
|
275
315
|
if ( (*p) == 37 )
|
276
316
|
goto st0;
|
277
|
-
goto
|
317
|
+
goto tr11;
|
278
318
|
st0:
|
279
319
|
if ( ++p == pe )
|
280
320
|
goto _test_eof0;
|
@@ -282,45 +322,116 @@ case 0:
|
|
282
322
|
if ( (*p) == 62 )
|
283
323
|
goto tr1;
|
284
324
|
goto tr0;
|
285
|
-
|
325
|
+
st6:
|
286
326
|
if ( ++p == pe )
|
287
|
-
goto
|
288
|
-
case
|
327
|
+
goto _test_eof6;
|
328
|
+
case 6:
|
289
329
|
if ( (*p) == 37 )
|
290
|
-
goto
|
291
|
-
goto
|
292
|
-
|
330
|
+
goto st7;
|
331
|
+
goto tr11;
|
332
|
+
st7:
|
293
333
|
if ( ++p == pe )
|
294
|
-
goto
|
295
|
-
case
|
334
|
+
goto _test_eof7;
|
335
|
+
case 7:
|
296
336
|
switch( (*p) ) {
|
297
|
-
case 35: goto
|
298
|
-
case 45: goto
|
299
|
-
case 61: goto
|
337
|
+
case 35: goto tr16;
|
338
|
+
case 45: goto tr17;
|
339
|
+
case 61: goto tr18;
|
300
340
|
}
|
301
|
-
goto
|
341
|
+
goto tr15;
|
342
|
+
tr18:
|
343
|
+
#line 1 "NONE"
|
344
|
+
{te = p+1;}
|
345
|
+
goto st8;
|
346
|
+
st8:
|
347
|
+
if ( ++p == pe )
|
348
|
+
goto _test_eof8;
|
349
|
+
case 8:
|
350
|
+
#line 351 "parser.c"
|
351
|
+
if ( (*p) == 32 )
|
352
|
+
goto tr20;
|
353
|
+
if ( 97 <= (*p) && (*p) <= 122 )
|
354
|
+
goto tr21;
|
355
|
+
goto tr19;
|
356
|
+
tr20:
|
357
|
+
#line 8 "parser.rl"
|
358
|
+
{ parser->keyword_preceding_whitespace = p; }
|
359
|
+
goto st1;
|
360
|
+
st1:
|
361
|
+
if ( ++p == pe )
|
362
|
+
goto _test_eof1;
|
363
|
+
case 1:
|
364
|
+
#line 365 "parser.c"
|
365
|
+
if ( (*p) == 32 )
|
366
|
+
goto st1;
|
367
|
+
if ( 97 <= (*p) && (*p) <= 122 )
|
368
|
+
goto tr4;
|
369
|
+
goto tr2;
|
370
|
+
tr4:
|
371
|
+
#line 7 "parser.rl"
|
372
|
+
{ parser->keyword_start = p; }
|
373
|
+
goto st2;
|
374
|
+
tr21:
|
375
|
+
#line 8 "parser.rl"
|
376
|
+
{ parser->keyword_preceding_whitespace = p; }
|
377
|
+
#line 7 "parser.rl"
|
378
|
+
{ parser->keyword_start = p; }
|
379
|
+
goto st2;
|
380
|
+
st2:
|
381
|
+
if ( ++p == pe )
|
382
|
+
goto _test_eof2;
|
383
|
+
case 2:
|
384
|
+
#line 385 "parser.c"
|
385
|
+
if ( (*p) == 32 )
|
386
|
+
goto tr5;
|
387
|
+
if ( 97 <= (*p) && (*p) <= 122 )
|
388
|
+
goto st2;
|
389
|
+
goto tr2;
|
390
|
+
tr5:
|
391
|
+
#line 11 "parser.rl"
|
392
|
+
{
|
393
|
+
parser->keyword_end = p;
|
394
|
+
parser->keyword = rb_str_new(parser->keyword_start, (p - parser->keyword_start));
|
395
|
+
}
|
396
|
+
goto st9;
|
397
|
+
st9:
|
398
|
+
if ( ++p == pe )
|
399
|
+
goto _test_eof9;
|
400
|
+
case 9:
|
401
|
+
#line 402 "parser.c"
|
402
|
+
if ( (*p) == 32 )
|
403
|
+
goto st9;
|
404
|
+
goto tr22;
|
302
405
|
}
|
303
|
-
_test_eof1: cs = 1; goto _test_eof;
|
304
|
-
_test_eof2: cs = 2; goto _test_eof;
|
305
406
|
_test_eof3: cs = 3; goto _test_eof;
|
306
|
-
_test_eof0: cs = 0; goto _test_eof;
|
307
407
|
_test_eof4: cs = 4; goto _test_eof;
|
308
408
|
_test_eof5: cs = 5; goto _test_eof;
|
409
|
+
_test_eof0: cs = 0; goto _test_eof;
|
410
|
+
_test_eof6: cs = 6; goto _test_eof;
|
411
|
+
_test_eof7: cs = 7; goto _test_eof;
|
412
|
+
_test_eof8: cs = 8; goto _test_eof;
|
413
|
+
_test_eof1: cs = 1; goto _test_eof;
|
414
|
+
_test_eof2: cs = 2; goto _test_eof;
|
415
|
+
_test_eof9: cs = 9; goto _test_eof;
|
309
416
|
|
310
417
|
_test_eof: {}
|
311
418
|
if ( p == eof )
|
312
419
|
{
|
313
420
|
switch ( cs ) {
|
314
|
-
case
|
315
|
-
case
|
421
|
+
case 4: goto tr11;
|
422
|
+
case 5: goto tr11;
|
316
423
|
case 0: goto tr0;
|
317
|
-
case
|
318
|
-
case
|
424
|
+
case 6: goto tr11;
|
425
|
+
case 7: goto tr15;
|
426
|
+
case 8: goto tr19;
|
427
|
+
case 1: goto tr2;
|
428
|
+
case 2: goto tr2;
|
429
|
+
case 9: goto tr22;
|
319
430
|
}
|
320
431
|
}
|
321
432
|
|
322
433
|
}
|
323
434
|
|
324
|
-
#line
|
435
|
+
#line 237 "parser.rl"
|
325
436
|
erbal_parser_finish(parser);
|
326
437
|
}
|
data/ext/erbal/parser.h
CHANGED
@@ -3,29 +3,40 @@
|
|
3
3
|
|
4
4
|
#include "ruby.h"
|
5
5
|
|
6
|
+
typedef struct parser_state {
|
7
|
+
unsigned int tag;
|
8
|
+
unsigned int chars_seen;
|
9
|
+
unsigned int in_concat;
|
10
|
+
} parser_state;
|
11
|
+
|
6
12
|
typedef struct erbal_parser {
|
7
|
-
|
8
|
-
|
13
|
+
parser_state *state;
|
14
|
+
unsigned int debug;
|
15
|
+
VALUE str, src, buffer_name, options, safe_concat_method, unsafe_concat_method, keyword, safe_concat_keyword;
|
16
|
+
char *keyword_start, *keyword_end, *keyword_trailing_whitespace, *keyword_preceding_whitespace;
|
9
17
|
} erbal_parser;
|
10
18
|
|
11
19
|
inline void erbal_parser_tag_open(erbal_parser*);
|
12
20
|
inline void erbal_parser_tag_open_with_dash(erbal_parser*);
|
13
21
|
inline void erbal_parser_tag_open_for_comment(erbal_parser*);
|
14
|
-
inline void
|
22
|
+
inline void erbal_parser_tag_open_choose_concat(erbal_parser*);
|
23
|
+
inline void erbal_parser_tag_open_for_unsafe_concat(erbal_parser*);
|
24
|
+
inline void erbal_parser_tag_open_for_safe_concat(erbal_parser*);
|
15
25
|
inline void erbal_parser_non_tag(erbal_parser*);
|
16
26
|
inline void erbal_parser_tag_close(erbal_parser*);
|
17
27
|
inline void erbal_parser_tag_close_with_trim(erbal_parser*);
|
18
|
-
inline void erbal_parser_tag_close_common(erbal_parser*, int
|
28
|
+
inline void erbal_parser_tag_close_common(erbal_parser*, int);
|
19
29
|
inline void erbal_parser_finish(erbal_parser*);
|
20
|
-
inline void erbal_concat_chars_seen(erbal_parser*, int
|
21
|
-
inline void erbal_parser_tag_open_common(erbal_parser*, int
|
22
|
-
inline void
|
23
|
-
inline void
|
24
|
-
inline VALUE erbal_escape_special_chars(erbal_parser*, int
|
30
|
+
inline void erbal_concat_chars_seen(erbal_parser*, int);
|
31
|
+
inline void erbal_parser_tag_open_common(erbal_parser*, int);
|
32
|
+
inline void erbal_open_buffer_concat(erbal_parser*, int);
|
33
|
+
inline void erbal_close_buffer_concat(erbal_parser*);
|
34
|
+
inline VALUE erbal_escape_special_chars(erbal_parser*, int);
|
25
35
|
|
26
|
-
#define TAG_OPEN
|
27
|
-
#define TAG_OPEN_FOR_COMMENT
|
28
|
-
#define
|
29
|
-
#define
|
36
|
+
#define TAG_OPEN 1
|
37
|
+
#define TAG_OPEN_FOR_COMMENT 2
|
38
|
+
#define TAG_OPEN_FOR_SAFE_CONCAT 3
|
39
|
+
#define TAG_OPEN_FOR_UNSAFE_CONCAT 4
|
40
|
+
#define OUTSIDE_TAG 5
|
30
41
|
|
31
42
|
#endif
|
data/ext/erbal/parser.rl
CHANGED
@@ -4,14 +4,29 @@
|
|
4
4
|
%%{
|
5
5
|
machine erbal_parser;
|
6
6
|
|
7
|
+
action keyword_start { parser->keyword_start = fpc; }
|
8
|
+
action keyword_preceding_whitespace { parser->keyword_preceding_whitespace = fpc; }
|
9
|
+
action keyword_trailing_whitespace { parser->keyword_trailing_whitespace = fpc; }
|
10
|
+
|
11
|
+
action keyword_end {
|
12
|
+
parser->keyword_end = fpc;
|
13
|
+
parser->keyword = rb_str_new(parser->keyword_start, (fpc - parser->keyword_start));
|
14
|
+
}
|
15
|
+
|
7
16
|
main := |*
|
8
17
|
'<%' => { erbal_parser_tag_open(parser); };
|
9
18
|
'<%-' => { erbal_parser_tag_open_with_dash(parser); };
|
10
19
|
'<%#' => { erbal_parser_tag_open_for_comment(parser); };
|
11
|
-
'<%=' => {
|
20
|
+
'<%=' => { erbal_parser_tag_open_for_unsafe_concat(parser); };
|
12
21
|
'-%>' => { erbal_parser_tag_close_with_trim(parser); };
|
13
22
|
'%>' => { erbal_parser_tag_close(parser); };
|
14
23
|
any => { erbal_parser_non_tag(parser); };
|
24
|
+
|
25
|
+
'<%=' (
|
26
|
+
[ ]* >keyword_preceding_whitespace
|
27
|
+
[a-z]+ >keyword_start %keyword_end
|
28
|
+
[ ]+ %keyword_trailing_whitespace
|
29
|
+
) => { erbal_parser_tag_open_choose_concat(parser); };
|
15
30
|
*|;
|
16
31
|
}%%
|
17
32
|
|
@@ -21,60 +36,81 @@ static char *ts, *te, *p, *pe, *eof;
|
|
21
36
|
static int act, cs;
|
22
37
|
|
23
38
|
inline void erbal_parser_tag_open_common(erbal_parser *parser, int shift) {
|
24
|
-
if (parser->chars_seen != 0) {
|
25
|
-
if (!parser->
|
26
|
-
|
39
|
+
if (parser->state->chars_seen != 0) {
|
40
|
+
if (!parser->state->in_concat) {
|
41
|
+
erbal_open_buffer_concat(parser, 1);
|
27
42
|
}
|
28
43
|
|
29
44
|
erbal_concat_chars_seen(parser, shift);
|
30
|
-
parser->chars_seen = 0;
|
45
|
+
parser->state->chars_seen = 0;
|
31
46
|
}
|
32
47
|
}
|
33
48
|
|
34
49
|
inline void erbal_parser_tag_open(erbal_parser *parser) {
|
35
50
|
erbal_parser_tag_open_common(parser, -1);
|
36
|
-
parser->state = TAG_OPEN;
|
51
|
+
parser->state->tag = TAG_OPEN;
|
37
52
|
}
|
38
53
|
|
39
54
|
inline void erbal_parser_tag_open_with_dash(erbal_parser *parser) {
|
40
55
|
erbal_parser_tag_open_common(parser, -2);
|
41
|
-
parser->state = TAG_OPEN;
|
56
|
+
parser->state->tag = TAG_OPEN;
|
42
57
|
}
|
43
58
|
|
44
|
-
inline void
|
59
|
+
inline void erbal_parser_tag_open_choose_concat(erbal_parser *parser) {
|
60
|
+
if (strcmp(RSTRING(parser->keyword)->ptr, RSTRING(parser->safe_concat_keyword)->ptr) != 0) {
|
61
|
+
/* Keyword doesn't match, reset the buffer to the start of the expression match and act as if a keyword wasn't seen. */
|
62
|
+
p = parser->keyword_preceding_whitespace - 1;
|
63
|
+
erbal_parser_tag_open_for_unsafe_concat(parser);
|
64
|
+
} else {
|
65
|
+
/* Rewind the buffer to preserve whitespace following the keyword. */
|
66
|
+
p = p - (parser->keyword_trailing_whitespace - parser->keyword_end);
|
67
|
+
erbal_parser_tag_open_for_safe_concat(parser);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
inline void erbal_parser_tag_open_for_unsafe_concat(erbal_parser *parser) {
|
45
72
|
erbal_parser_tag_open_common(parser, -2);
|
46
|
-
parser->state =
|
73
|
+
parser->state->tag = TAG_OPEN_FOR_UNSAFE_CONCAT;
|
74
|
+
}
|
75
|
+
|
76
|
+
inline void erbal_parser_tag_open_for_safe_concat(erbal_parser *parser) {
|
77
|
+
erbal_parser_tag_open_common(parser, -2);
|
78
|
+
parser->state->tag = TAG_OPEN_FOR_SAFE_CONCAT;
|
47
79
|
}
|
48
80
|
|
49
81
|
inline void erbal_parser_tag_open_for_comment(erbal_parser *parser) {
|
50
82
|
erbal_parser_tag_open_common(parser, -2);
|
51
|
-
parser->state = TAG_OPEN_FOR_COMMENT;
|
83
|
+
parser->state->tag = TAG_OPEN_FOR_COMMENT;
|
52
84
|
}
|
53
85
|
|
54
86
|
inline void erbal_parser_non_tag(erbal_parser *parser) {
|
55
|
-
parser->chars_seen += 1;
|
87
|
+
parser->state->chars_seen += 1;
|
56
88
|
}
|
57
89
|
|
58
90
|
inline void erbal_parser_tag_close_common(erbal_parser *parser, int tag_size) {
|
59
|
-
if (parser->state ==
|
60
|
-
if (!parser->
|
61
|
-
|
91
|
+
if (parser->state->tag == TAG_OPEN_FOR_UNSAFE_CONCAT || parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
92
|
+
if (!parser->state->in_concat) {
|
93
|
+
if (parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
94
|
+
erbal_open_buffer_concat(parser, 1);
|
95
|
+
} else {
|
96
|
+
erbal_open_buffer_concat(parser, 0);
|
97
|
+
}
|
62
98
|
}
|
63
99
|
|
64
100
|
rb_str_buf_cat(parser->src, "#{", 2);
|
65
101
|
erbal_concat_chars_seen(parser, -tag_size);
|
66
102
|
rb_str_buf_cat(parser->src, "}", 1);
|
67
|
-
} else if (parser->state == TAG_OPEN) {
|
68
|
-
if (parser->
|
69
|
-
|
103
|
+
} else if (parser->state->tag == TAG_OPEN) {
|
104
|
+
if (parser->state->in_concat) {
|
105
|
+
erbal_close_buffer_concat(parser);
|
70
106
|
}
|
71
107
|
|
72
108
|
erbal_concat_chars_seen(parser, -tag_size);
|
73
109
|
rb_str_buf_cat(parser->src, ";\n", 2);
|
74
110
|
}
|
75
111
|
|
76
|
-
parser->state = OUTSIDE_TAG;
|
77
|
-
parser->chars_seen = 0;
|
112
|
+
parser->state->tag = OUTSIDE_TAG;
|
113
|
+
parser->state->chars_seen = 0;
|
78
114
|
}
|
79
115
|
|
80
116
|
inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
@@ -94,8 +130,8 @@ inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
|
|
94
130
|
int i, n, slashes_seen = 0;
|
95
131
|
char *current_char;
|
96
132
|
|
97
|
-
for (i = 0; i < parser->chars_seen; i++) {
|
98
|
-
current_char = (((p + shift) - parser->chars_seen) + i);
|
133
|
+
for (i = 0; i < parser->state->chars_seen; i++) {
|
134
|
+
current_char = (((p + shift) - parser->state->chars_seen) + i);
|
99
135
|
|
100
136
|
if (*current_char == '#' || *current_char == '`') {
|
101
137
|
if (slashes_seen == 0) {
|
@@ -121,39 +157,48 @@ inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
|
|
121
157
|
}
|
122
158
|
|
123
159
|
inline void erbal_concat_chars_seen(erbal_parser *parser, int shift) {
|
124
|
-
if (parser->chars_seen != 0) {
|
125
|
-
if (parser->
|
160
|
+
if (parser->state->chars_seen != 0) {
|
161
|
+
if (parser->state->in_concat && parser->state->tag == OUTSIDE_TAG) {
|
126
162
|
rb_str_concat(parser->src, erbal_escape_special_chars(parser, shift));
|
127
163
|
} else {
|
128
|
-
rb_str_buf_cat(parser->src, ((p + shift) - parser->chars_seen), parser->chars_seen);
|
164
|
+
rb_str_buf_cat(parser->src, ((p + shift) - parser->state->chars_seen), parser->state->chars_seen);
|
129
165
|
}
|
130
166
|
}
|
131
167
|
|
132
|
-
parser->chars_seen = 0;
|
168
|
+
parser->state->chars_seen = 0;
|
133
169
|
}
|
134
170
|
|
135
|
-
inline void
|
171
|
+
inline void erbal_open_buffer_concat(erbal_parser *parser, int safe_concat) {
|
136
172
|
rb_str_concat(parser->src, parser->buffer_name);
|
137
|
-
rb_str_buf_cat(parser->src, "
|
138
|
-
|
173
|
+
rb_str_buf_cat(parser->src, ".", 1);
|
174
|
+
|
175
|
+
if (safe_concat) {
|
176
|
+
rb_str_concat(parser->src, parser->safe_concat_method);
|
177
|
+
} else {
|
178
|
+
rb_str_concat(parser->src, parser->unsafe_concat_method);
|
179
|
+
}
|
180
|
+
|
181
|
+
rb_str_buf_cat(parser->src, "(", 1);
|
182
|
+
rb_str_buf_cat(parser->src, "%Q`", 3);
|
183
|
+
parser->state->in_concat = 1;
|
139
184
|
}
|
140
185
|
|
141
|
-
inline void
|
142
|
-
rb_str_buf_cat(parser->src, "
|
143
|
-
parser->
|
186
|
+
inline void erbal_close_buffer_concat(erbal_parser *parser) {
|
187
|
+
rb_str_buf_cat(parser->src, "`);", 3);
|
188
|
+
parser->state->in_concat = 0;
|
144
189
|
}
|
145
190
|
|
146
191
|
inline void erbal_parser_finish(erbal_parser *parser) {
|
147
|
-
if (parser->chars_seen != 0) {
|
148
|
-
if (!parser->
|
149
|
-
|
192
|
+
if (parser->state->chars_seen != 0) {
|
193
|
+
if (!parser->state->in_concat) {
|
194
|
+
erbal_open_buffer_concat(parser, 1);
|
150
195
|
}
|
151
196
|
|
152
197
|
erbal_concat_chars_seen(parser, 0);
|
153
198
|
}
|
154
199
|
|
155
|
-
if (parser->
|
156
|
-
|
200
|
+
if (parser->state->in_concat) {
|
201
|
+
erbal_close_buffer_concat(parser);
|
157
202
|
}
|
158
203
|
|
159
204
|
rb_str_concat(parser->src, parser->buffer_name);
|
@@ -164,9 +209,9 @@ inline void erbal_parser_finish(erbal_parser *parser) {
|
|
164
209
|
}
|
165
210
|
|
166
211
|
void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
167
|
-
parser->chars_seen = 0;
|
168
|
-
parser->
|
169
|
-
parser->state = OUTSIDE_TAG;
|
212
|
+
parser->state->chars_seen = 0;
|
213
|
+
parser->state->in_concat = 0;
|
214
|
+
parser->state->tag = OUTSIDE_TAG;
|
170
215
|
parser->src = rb_str_dup(parser->buffer_name);
|
171
216
|
|
172
217
|
rb_iv_set(self, "@src", parser->src);
|
data/lib/erbal/rails.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'erbal'
|
2
|
+
|
3
|
+
class Erbal
|
4
|
+
module Rails
|
5
|
+
class Rails_2_3_10_TemplateHandler < ActionView::TemplateHandler
|
6
|
+
include ActionView::TemplateHandlers::Compilable
|
7
|
+
def compile(template)
|
8
|
+
::Erbal.new("<% __in_erb_template=true %>#{template.source}", {:buffer => '@output_buffer', :buffer_initial_value => 'ActiveSupport::SafeBuffer.new',
|
9
|
+
:safe_concat_method => 'safe_concat', :unsafe_concat_method => 'concat', :safe_concat_keyword => 'raw'}).parse
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.version_unsupported
|
14
|
+
raise "Sorry, this version of Erbal doesn't support Rails #{ActionPack::VERSION::MAJOR}.#{ActionPack::VERSION::MINOR}.#{ActionPack::VERSION::TINY}."
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.register_template_handler(handler_class)
|
18
|
+
ActionView::Template.register_template_handler :erb, handler_class
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.register_template_handler_for_2_3_10
|
22
|
+
register_template_handler(Rails_2_3_10_TemplateHandler)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
case ActionPack::VERSION::MAJOR
|
28
|
+
when 2
|
29
|
+
case ActionPack::VERSION::MINOR
|
30
|
+
when 3
|
31
|
+
case ActionPack::VERSION::TINY
|
32
|
+
when 10
|
33
|
+
Erbal::Rails.register_template_handler_for_2_3_10
|
34
|
+
else
|
35
|
+
Erbal::Rails.version_unsupported
|
36
|
+
end
|
37
|
+
else
|
38
|
+
Erbal::Rails.version_unsupported
|
39
|
+
end
|
40
|
+
else
|
41
|
+
Erbal::Rails.version_unsupported
|
42
|
+
end
|
data/spec/erbal_spec.rb
CHANGED
@@ -40,7 +40,7 @@ describe Erbal do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should parse content without any tags" do
|
43
|
-
erbal_parse("I love unicorns!").should == "@out = '';@out
|
43
|
+
erbal_parse("I love unicorns!").should == "@out = '';@out.concat(%Q`I love unicorns!`);@out"
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should parse the <% tag" do
|
@@ -48,68 +48,112 @@ describe Erbal do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should parse the <%- tag" do
|
51
|
-
erbal_parse("1 + 1 is <%- 1 + 1 %>").should == "@out = '';@out
|
51
|
+
erbal_parse("1 + 1 is <%- 1 + 1 %>").should == "@out = '';@out.concat(%Q`1 + 1 is `); 1 + 1 ;\n@out"
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should add a line break after <% %> tags incase the tags ended with a comment" do
|
55
|
-
erbal_parse("<% 1 + 1 # eeek comment! %> hi mom").should == "@out = ''; 1 + 1 # eeek comment! ;\n@out
|
55
|
+
erbal_parse("<% 1 + 1 # eeek comment! %> hi mom").should == "@out = ''; 1 + 1 # eeek comment! ;\n@out.concat(%Q` hi mom`);@out"
|
56
56
|
end
|
57
57
|
|
58
58
|
it "should parse the <%= tag" do
|
59
|
-
erbal_parse("<%= 1 + 1 %>").should == "@out = '';@out
|
59
|
+
erbal_parse("<%= 1 + 1 %>").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 }`);@out"
|
60
60
|
end
|
61
61
|
|
62
62
|
it "should parse the comment tag <%#" do
|
63
|
-
erbal_parse("Something:<br />\n<%# I'm a comment %>").should == "@out = '';@out
|
63
|
+
erbal_parse("Something:<br />\n<%# I'm a comment %>").should == "@out = '';@out.concat(%Q`Something:<br />\n`);@out"
|
64
64
|
end
|
65
65
|
|
66
66
|
it "should swallow the following newline if the -%> tag is used" do
|
67
|
-
erbal_parse("<%= 1 + 1 -%>\n\n").should == "@out = '';@out
|
67
|
+
erbal_parse("<%= 1 + 1 -%>\n\n").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 }\n`);@out"
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should not swallow the following character if the -%> tag is used and the following character is not a newline" do
|
71
|
-
erbal_parse("<%= 1 + 1 -%>Z").should == "@out = '';@out
|
71
|
+
erbal_parse("<%= 1 + 1 -%>Z").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 }Z`);@out"
|
72
72
|
end
|
73
73
|
|
74
74
|
it "should concat text surrounding the tags when the opening tag is <%" do
|
75
|
-
erbal_parse("1 + 1 is <% 1 + 1 %>. Easy!").should == "@out = '';@out
|
75
|
+
erbal_parse("1 + 1 is <% 1 + 1 %>. Easy!").should == "@out = '';@out.concat(%Q`1 + 1 is `); 1 + 1 ;\n@out.concat(%Q`. Easy!`);@out"
|
76
76
|
end
|
77
77
|
|
78
78
|
it "should concat text surrounding the tags when the opening tag is <%=" do
|
79
|
-
erbal_parse("1 + 1 is <%= 1 + 1 %>. Easy!").should == "@out = '';@out
|
79
|
+
erbal_parse("1 + 1 is <%= 1 + 1 %>. Easy!").should == "@out = '';@out.concat(%Q`1 + 1 is \#{ 1 + 1 }. Easy!`);@out"
|
80
80
|
end
|
81
81
|
|
82
82
|
it "should not open a new buffer shift when there is more than one consecutive <%= tag" do
|
83
|
-
erbal_parse("1 + 1 is <%= 1 + 1 %>, and 2 + 2 is <%= 2 + 2 %>. Easy!").should == "@out = '';@out
|
83
|
+
erbal_parse("1 + 1 is <%= 1 + 1 %>, and 2 + 2 is <%= 2 + 2 %>. Easy!").should == "@out = '';@out.concat(%Q`1 + 1 is \#{ 1 + 1 }, and 2 + 2 is \#{ 2 + 2 }. Easy!`);@out"
|
84
84
|
end
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
describe "when escaping special characters" do
|
87
|
+
it "should escape a hash character that signifies the start of a string interpolation when outside tags" do
|
88
|
+
erbal_parse("<%= 1 + 1 -%> wee \#{1 + 3}").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 } wee \\\#{1 + 3}`);@out"
|
89
|
+
eval(erbal_parse("<%= 1 + 1 -%> wee \#{1 + 3}")).should == eval(erubis_parse("<%= 1 + 1 -%> wee \#{1 + 3}"))
|
89
90
|
|
90
|
-
|
91
|
-
|
91
|
+
erbal_parse("<%= 1 + 1 -%> wee \\\#{1 + 3}").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 } wee \\\\\\\#{1 + 3}`);@out"
|
92
|
+
eval(erbal_parse("<%= 1 + 1 -%> wee \\\#{1 + 3}")).should == eval(erubis_parse("<%= 1 + 1 -%> wee \\\#{1 + 3}"))
|
92
93
|
|
93
|
-
|
94
|
-
|
94
|
+
erbal_parse("<%= 1 + 1 -%> wee \\\\\\\#{1 + 3}").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 } wee \\\\\\\\\\\\\\\#{1 + 3}`);@out"
|
95
|
+
eval(erbal_parse("<%= 1 + 1 -%> wee \\\\\\\#{1 + 3}")).should == eval(erubis_parse("<%= 1 + 1 -%> wee \\\\\\\#{1 + 3}"))
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
erbal_parse('<%= 1 + 1 -%> wee #{1 + 3}').should == "@out = '';@out.concat(%Q`\#{ 1 + 1 } wee \\\#{1 + 3}`);@out"
|
98
|
+
eval(erbal_parse('<%= 1 + 1 -%> wee #{1 + 3}')).should == eval(erubis_parse('<%= 1 + 1 -%> wee #{1 + 3}'))
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should not escape a hash character that signifies the start of a string interpolation when inside tags" do
|
102
|
+
erbal_parse('<%= "#{1 + 1}" -%>').should == "@out = '';@out.concat(%Q`\#{ \"\#{1 + 1}\" }`);@out"
|
103
|
+
eval(erbal_parse('<%= "#{1 + 1}" -%>')).should == eval(erubis_parse('<%= "#{1 + 1}" -%>'))
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should escape a backtick character that signifies the end off a buffer shift" do
|
107
|
+
erbal_parse("weeee `").should == "@out = '';@out.concat(%Q`weeee \\``);@out"
|
108
|
+
eval(erbal_parse("weeee `")).should == eval(erubis_parse("weeee `"));
|
99
109
|
|
100
|
-
|
101
|
-
|
102
|
-
|
110
|
+
erbal_parse("weeee \\`").should == "@out = '';@out.concat(%Q`weeee \\\\\\``);@out"
|
111
|
+
eval(erbal_parse("weeee \\`")).should == eval(erubis_parse("weeee \\`"))
|
112
|
+
|
113
|
+
erbal_parse("weeee \\\\\\\`").should == "@out = '';@out.concat(%Q`weeee \\\\\\\\\\\\\\``);@out"
|
114
|
+
eval(erbal_parse("weeee \\\\\\\`")).should == eval(erubis_parse("weeee \\\\\\\`"))
|
115
|
+
end
|
103
116
|
end
|
104
117
|
|
105
|
-
|
106
|
-
|
107
|
-
|
118
|
+
describe "when using the safe_concat_method, unsafe_concat_method and safe_concat_keyword options" do
|
119
|
+
it "should default to using 'concat' if the :safe_concat_method option is not specified" do
|
120
|
+
erbal_parse("hello").should == "@out = '';@out.concat(%Q`hello`);@out"
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should default to using 'concat' if the :unsafe_concat_method option is not specified" do
|
124
|
+
erbal_parse("<%= 1 + 1 %>").should == "@out = '';@out.concat(%Q`\#{ 1 + 1 }`);@out"
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should use the safe concat method for text outside of tags" do
|
128
|
+
erbal_parse("hello", :safe_concat_method => 'safe_concat').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`hello`);@output_buffer"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should use the unsafe concat method for the <%= tag" do
|
132
|
+
erbal_parse("<%= 1 + 1 %>", :unsafe_concat_method => 'unsafe_concat').should == "@output_buffer = '';@output_buffer.unsafe_concat(%Q`\#{ 1 + 1 }`);@output_buffer"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should use the safe concat method for the <%= tag if the safe_concat_keyword option is also used" do
|
136
|
+
erbal_parse("<%= raw 1 + 1 %>", :safe_concat_method => 'safe_concat', :safe_concat_keyword => 'raw').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`\#{ 1 + 1 }`);@output_buffer"
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not use the safe concat method for the <%= tag if the safe_concat_keyword option is also used but not applicable" do
|
140
|
+
erbal_parse("<%= blah 1 + 1 %>", :unsafe_concat_method => 'unsafe_concat').should == "@output_buffer = '';@output_buffer.unsafe_concat(%Q`\#{ blah 1 + 1 }`);@output_buffer"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should not set a default safe_concat_keyword option" do
|
144
|
+
erbal_parse("<%= raw 1 + 1 %>", :unsafe_concat_method => 'unsafe_concat', :safe_concat_keyword => nil).should == "@output_buffer = '';@output_buffer.unsafe_concat(%Q`\#{ raw 1 + 1 }`);@output_buffer"
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should preserve the whitespace following the safe_concat_keyword" do
|
148
|
+
erbal_parse("<%= raw 1 + 1 %>", :safe_concat_method => 'safe_concat', :safe_concat_keyword => 'raw').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`\#{ 1 + 1 }`);@output_buffer"
|
149
|
+
end
|
108
150
|
|
109
|
-
|
110
|
-
|
151
|
+
it "should use the safe concat method for the <%= tag if the safe_concat_keyword option is also used and the keyword has no preceding whitespace" do
|
152
|
+
erbal_parse("<%=raw 1 + 1 %>", :safe_concat_method => 'safe_concat', :safe_concat_keyword => 'raw').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`\#{ 1 + 1 }`);@output_buffer"
|
153
|
+
end
|
111
154
|
|
112
|
-
|
113
|
-
|
155
|
+
it "should not use the safe concat method for the <%= tag if the safe_concat_keyword option is also used but not applicable and the keyword has no preceding whitespace" do
|
156
|
+
erbal_parse("<%=blah 1 + 1 %>", :unsafe_concat_method => 'unsafe_concat').should == "@output_buffer = '';@output_buffer.unsafe_concat(%Q`\#{blah 1 + 1 }`);@output_buffer"
|
157
|
+
end
|
114
158
|
end
|
115
159
|
end
|
data/tasks/gem.rake
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erbal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 977940510
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
|
8
|
+
- 2
|
9
|
+
- rc1
|
10
|
+
version: 1.2.rc1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Ian Leitch
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
+
date: 2011-01-05 00:00:00 +11:00
|
18
19
|
default_executable:
|
19
20
|
dependencies: []
|
20
21
|
|
@@ -31,7 +32,7 @@ files:
|
|
31
32
|
- CHANGELOG
|
32
33
|
- README.rdoc
|
33
34
|
- Rakefile
|
34
|
-
- lib/erbal/
|
35
|
+
- lib/erbal/rails.rb
|
35
36
|
- spec/erbal_spec.rb
|
36
37
|
- spec/spec_helper.rb
|
37
38
|
- tasks/ext.rake
|
@@ -66,12 +67,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
67
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
68
|
none: false
|
68
69
|
requirements:
|
69
|
-
- - "
|
70
|
+
- - ">"
|
70
71
|
- !ruby/object:Gem::Version
|
71
|
-
hash:
|
72
|
+
hash: 25
|
72
73
|
segments:
|
73
|
-
-
|
74
|
-
|
74
|
+
- 1
|
75
|
+
- 3
|
76
|
+
- 1
|
77
|
+
version: 1.3.1
|
75
78
|
requirements: []
|
76
79
|
|
77
80
|
rubyforge_project:
|
data/lib/erbal/rails23.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'erbal'
|
2
|
-
|
3
|
-
if ActiveSupport.const_defined?('SafeBuffer')
|
4
|
-
|
5
|
-
class ErbalTemplateHandler < ActionView::TemplateHandler
|
6
|
-
include ActionView::TemplateHandlers::Compilable
|
7
|
-
def compile(template)
|
8
|
-
::Erbal.new("<% __in_erb_template=true %>#{template.source}", {:buffer => '@output_buffer', :buffer_initial_value => 'ActiveSupport::SafeBuffer.new'}).parse
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
else
|
13
|
-
|
14
|
-
class ErbalTemplateHandler < ActionView::TemplateHandler
|
15
|
-
include ActionView::TemplateHandlers::Compilable
|
16
|
-
def compile(template)
|
17
|
-
::Erbal.new("<% __in_erb_template=true %>#{template.source}", {:buffer => '@output_buffer'}).parse
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|