erbal 1.1 → 1.2.rc1
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/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
|