erbal 1.2.rc1 → 1.2.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/erbal/parser.c +65 -38
- data/ext/erbal/parser.h +12 -6
- data/ext/erbal/parser.rl +55 -28
- data/spec/erbal_spec.rb +37 -3
- data/tasks/gem.rake +1 -1
- metadata +3 -3
data/ext/erbal/parser.c
CHANGED
@@ -21,29 +21,31 @@ static const int erbal_parser_en_main = 3;
|
|
21
21
|
static char *ts, *te, *p, *pe, *eof;
|
22
22
|
static int act, cs;
|
23
23
|
|
24
|
-
inline void erbal_parser_tag_open_common(erbal_parser *parser
|
24
|
+
inline void erbal_parser_tag_open_common(erbal_parser *parser) {
|
25
25
|
if (parser->state->chars_seen != 0) {
|
26
|
-
if (
|
26
|
+
if (parser->state->concat == OUTSIDE_CONCAT) {
|
27
27
|
erbal_open_buffer_concat(parser, 1);
|
28
|
+
} else if (parser->state->concat == UNSAFE_CONCAT) {
|
29
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 1);
|
28
30
|
}
|
29
31
|
|
30
|
-
erbal_concat_chars_seen(parser
|
32
|
+
erbal_concat_chars_seen(parser);
|
31
33
|
parser->state->chars_seen = 0;
|
32
34
|
}
|
33
35
|
}
|
34
36
|
|
35
37
|
inline void erbal_parser_tag_open(erbal_parser *parser) {
|
36
|
-
erbal_parser_tag_open_common(parser
|
38
|
+
erbal_parser_tag_open_common(parser);
|
37
39
|
parser->state->tag = TAG_OPEN;
|
38
40
|
}
|
39
41
|
|
40
42
|
inline void erbal_parser_tag_open_with_dash(erbal_parser *parser) {
|
41
|
-
erbal_parser_tag_open_common(parser
|
43
|
+
erbal_parser_tag_open_common(parser);
|
42
44
|
parser->state->tag = TAG_OPEN;
|
43
45
|
}
|
44
46
|
|
45
47
|
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) {
|
48
|
+
if (strcmp(RSTRING(parser->safe_concat_keyword)->ptr, "") == 0 || strcmp(RSTRING(parser->keyword)->ptr, RSTRING(parser->safe_concat_keyword)->ptr) != 0) {
|
47
49
|
/* Keyword doesn't match, reset the buffer to the start of the expression match and act as if a keyword wasn't seen. */
|
48
50
|
p = parser->keyword_preceding_whitespace - 1;
|
49
51
|
erbal_parser_tag_open_for_unsafe_concat(parser);
|
@@ -55,43 +57,51 @@ inline void erbal_parser_tag_open_choose_concat(erbal_parser *parser) {
|
|
55
57
|
}
|
56
58
|
|
57
59
|
inline void erbal_parser_tag_open_for_unsafe_concat(erbal_parser *parser) {
|
58
|
-
erbal_parser_tag_open_common(parser
|
60
|
+
erbal_parser_tag_open_common(parser);
|
59
61
|
parser->state->tag = TAG_OPEN_FOR_UNSAFE_CONCAT;
|
60
62
|
}
|
61
63
|
|
62
64
|
inline void erbal_parser_tag_open_for_safe_concat(erbal_parser *parser) {
|
63
|
-
erbal_parser_tag_open_common(parser
|
65
|
+
erbal_parser_tag_open_common(parser);
|
64
66
|
parser->state->tag = TAG_OPEN_FOR_SAFE_CONCAT;
|
65
67
|
}
|
66
68
|
|
67
69
|
inline void erbal_parser_tag_open_for_comment(erbal_parser *parser) {
|
68
|
-
erbal_parser_tag_open_common(parser
|
70
|
+
erbal_parser_tag_open_common(parser);
|
69
71
|
parser->state->tag = TAG_OPEN_FOR_COMMENT;
|
70
72
|
}
|
71
73
|
|
72
74
|
inline void erbal_parser_non_tag(erbal_parser *parser) {
|
75
|
+
if (parser->state->chars_seen == 0) {
|
76
|
+
parser->state->chars_seen_start = p;
|
77
|
+
}
|
78
|
+
|
73
79
|
parser->state->chars_seen += 1;
|
74
80
|
}
|
75
81
|
|
76
|
-
inline void erbal_parser_tag_close_common(erbal_parser *parser
|
82
|
+
inline void erbal_parser_tag_close_common(erbal_parser *parser) {
|
77
83
|
if (parser->state->tag == TAG_OPEN_FOR_UNSAFE_CONCAT || parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
78
|
-
if (
|
84
|
+
if (parser->state->concat == OUTSIDE_CONCAT) {
|
79
85
|
if (parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
80
86
|
erbal_open_buffer_concat(parser, 1);
|
81
87
|
} else {
|
82
88
|
erbal_open_buffer_concat(parser, 0);
|
83
89
|
}
|
90
|
+
} else if (parser->state->concat == SAFE_CONCAT && parser->state->tag == TAG_OPEN_FOR_UNSAFE_CONCAT) {
|
91
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 0);
|
92
|
+
} else if (parser->state->concat == UNSAFE_CONCAT && parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
93
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 1);
|
84
94
|
}
|
85
95
|
|
86
96
|
rb_str_buf_cat(parser->src, "#{", 2);
|
87
|
-
erbal_concat_chars_seen(parser
|
97
|
+
erbal_concat_chars_seen(parser);
|
88
98
|
rb_str_buf_cat(parser->src, "}", 1);
|
89
99
|
} else if (parser->state->tag == TAG_OPEN) {
|
90
|
-
if (parser->state->
|
100
|
+
if (parser->state->concat != OUTSIDE_CONCAT) {
|
91
101
|
erbal_close_buffer_concat(parser);
|
92
102
|
}
|
93
103
|
|
94
|
-
erbal_concat_chars_seen(parser
|
104
|
+
erbal_concat_chars_seen(parser);
|
95
105
|
rb_str_buf_cat(parser->src, ";\n", 2);
|
96
106
|
}
|
97
107
|
|
@@ -100,7 +110,7 @@ inline void erbal_parser_tag_close_common(erbal_parser *parser, int tag_size) {
|
|
100
110
|
}
|
101
111
|
|
102
112
|
inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
103
|
-
erbal_parser_tag_close_common(parser
|
113
|
+
erbal_parser_tag_close_common(parser);
|
104
114
|
|
105
115
|
if (*(p + 1) == '\n') {
|
106
116
|
p++;
|
@@ -108,16 +118,16 @@ inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
|
108
118
|
}
|
109
119
|
|
110
120
|
inline void erbal_parser_tag_close(erbal_parser *parser) {
|
111
|
-
erbal_parser_tag_close_common(parser
|
121
|
+
erbal_parser_tag_close_common(parser);
|
112
122
|
}
|
113
123
|
|
114
|
-
inline VALUE erbal_escape_special_chars(erbal_parser *parser
|
124
|
+
inline VALUE erbal_escape_special_chars(erbal_parser *parser) {
|
115
125
|
VALUE buf = rb_str_buf_new(0);
|
116
126
|
int i, n, slashes_seen = 0;
|
117
127
|
char *current_char;
|
118
128
|
|
119
129
|
for (i = 0; i < parser->state->chars_seen; i++) {
|
120
|
-
current_char = (
|
130
|
+
current_char = (parser->state->chars_seen_start + i);
|
121
131
|
|
122
132
|
if (*current_char == '#' || *current_char == '`') {
|
123
133
|
if (slashes_seen == 0) {
|
@@ -142,48 +152,58 @@ inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
|
|
142
152
|
return buf;
|
143
153
|
}
|
144
154
|
|
145
|
-
inline void erbal_concat_chars_seen(erbal_parser *parser
|
155
|
+
inline void erbal_concat_chars_seen(erbal_parser *parser) {
|
146
156
|
if (parser->state->chars_seen != 0) {
|
147
|
-
if (parser->state->
|
148
|
-
rb_str_concat(parser->src, erbal_escape_special_chars(parser
|
157
|
+
if (parser->state->concat != OUTSIDE_CONCAT && parser->state->tag == OUTSIDE_TAG) {
|
158
|
+
rb_str_concat(parser->src, erbal_escape_special_chars(parser));
|
149
159
|
} else {
|
150
|
-
rb_str_buf_cat(parser->src,
|
160
|
+
rb_str_buf_cat(parser->src, parser->state->chars_seen_start, parser->state->chars_seen);
|
151
161
|
}
|
152
162
|
}
|
153
163
|
|
154
164
|
parser->state->chars_seen = 0;
|
155
165
|
}
|
156
166
|
|
167
|
+
inline void erbal_close_and_open_buffer_concat_if_needed(erbal_parser *parser, int safe_concat) {
|
168
|
+
if (!parser->concat_methods_identical) {
|
169
|
+
erbal_close_buffer_concat(parser);
|
170
|
+
erbal_open_buffer_concat(parser, safe_concat);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
157
174
|
inline void erbal_open_buffer_concat(erbal_parser *parser, int safe_concat) {
|
158
175
|
rb_str_concat(parser->src, parser->buffer_name);
|
159
176
|
rb_str_buf_cat(parser->src, ".", 1);
|
160
177
|
|
161
178
|
if (safe_concat) {
|
162
179
|
rb_str_concat(parser->src, parser->safe_concat_method);
|
180
|
+
parser->state->concat = SAFE_CONCAT;
|
163
181
|
} else {
|
164
182
|
rb_str_concat(parser->src, parser->unsafe_concat_method);
|
183
|
+
parser->state->concat = UNSAFE_CONCAT;
|
165
184
|
}
|
166
185
|
|
167
186
|
rb_str_buf_cat(parser->src, "(", 1);
|
168
187
|
rb_str_buf_cat(parser->src, "%Q`", 3);
|
169
|
-
parser->state->in_concat = 1;
|
170
188
|
}
|
171
189
|
|
172
190
|
inline void erbal_close_buffer_concat(erbal_parser *parser) {
|
173
191
|
rb_str_buf_cat(parser->src, "`);", 3);
|
174
|
-
parser->state->
|
192
|
+
parser->state->concat = OUTSIDE_CONCAT;
|
175
193
|
}
|
176
194
|
|
177
195
|
inline void erbal_parser_finish(erbal_parser *parser) {
|
178
196
|
if (parser->state->chars_seen != 0) {
|
179
|
-
if (
|
197
|
+
if (parser->state->concat == OUTSIDE_CONCAT) {
|
180
198
|
erbal_open_buffer_concat(parser, 1);
|
199
|
+
} else if (parser->state->concat == UNSAFE_CONCAT) {
|
200
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 1);
|
181
201
|
}
|
182
202
|
|
183
|
-
erbal_concat_chars_seen(parser
|
203
|
+
erbal_concat_chars_seen(parser);
|
184
204
|
}
|
185
205
|
|
186
|
-
if (parser->state->
|
206
|
+
if (parser->state->concat != OUTSIDE_CONCAT) {
|
187
207
|
erbal_close_buffer_concat(parser);
|
188
208
|
}
|
189
209
|
|
@@ -196,8 +216,15 @@ inline void erbal_parser_finish(erbal_parser *parser) {
|
|
196
216
|
|
197
217
|
void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
198
218
|
parser->state->chars_seen = 0;
|
199
|
-
parser->state->
|
219
|
+
parser->state->concat = OUTSIDE_CONCAT;
|
200
220
|
parser->state->tag = OUTSIDE_TAG;
|
221
|
+
|
222
|
+
if (strcmp(RSTRING(parser->safe_concat_method)->ptr, RSTRING(parser->unsafe_concat_method)->ptr) == 0) {
|
223
|
+
parser->concat_methods_identical = 1;
|
224
|
+
} else {
|
225
|
+
parser->concat_methods_identical = 0;
|
226
|
+
}
|
227
|
+
|
201
228
|
parser->src = rb_str_dup(parser->buffer_name);
|
202
229
|
|
203
230
|
rb_iv_set(self, "@src", parser->src);
|
@@ -214,7 +241,7 @@ void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
|
214
241
|
}
|
215
242
|
|
216
243
|
|
217
|
-
#line
|
244
|
+
#line 245 "parser.c"
|
218
245
|
{
|
219
246
|
cs = erbal_parser_start;
|
220
247
|
ts = 0;
|
@@ -222,14 +249,14 @@ void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
|
222
249
|
act = 0;
|
223
250
|
}
|
224
251
|
|
225
|
-
#line
|
252
|
+
#line 258 "parser.rl"
|
226
253
|
}
|
227
254
|
|
228
255
|
void erbal_parser_exec(erbal_parser *parser) {
|
229
256
|
p = RSTRING(parser->str)->ptr;
|
230
257
|
pe = p + strlen(p);
|
231
258
|
|
232
|
-
#line
|
259
|
+
#line 260 "parser.c"
|
233
260
|
{
|
234
261
|
if ( p == pe )
|
235
262
|
goto _test_eof;
|
@@ -289,7 +316,7 @@ st3:
|
|
289
316
|
case 3:
|
290
317
|
#line 1 "NONE"
|
291
318
|
{ts = p;}
|
292
|
-
#line
|
319
|
+
#line 320 "parser.c"
|
293
320
|
switch( (*p) ) {
|
294
321
|
case 37: goto st4;
|
295
322
|
case 45: goto tr9;
|
@@ -311,7 +338,7 @@ st5:
|
|
311
338
|
if ( ++p == pe )
|
312
339
|
goto _test_eof5;
|
313
340
|
case 5:
|
314
|
-
#line
|
341
|
+
#line 342 "parser.c"
|
315
342
|
if ( (*p) == 37 )
|
316
343
|
goto st0;
|
317
344
|
goto tr11;
|
@@ -347,7 +374,7 @@ st8:
|
|
347
374
|
if ( ++p == pe )
|
348
375
|
goto _test_eof8;
|
349
376
|
case 8:
|
350
|
-
#line
|
377
|
+
#line 378 "parser.c"
|
351
378
|
if ( (*p) == 32 )
|
352
379
|
goto tr20;
|
353
380
|
if ( 97 <= (*p) && (*p) <= 122 )
|
@@ -361,7 +388,7 @@ st1:
|
|
361
388
|
if ( ++p == pe )
|
362
389
|
goto _test_eof1;
|
363
390
|
case 1:
|
364
|
-
#line
|
391
|
+
#line 392 "parser.c"
|
365
392
|
if ( (*p) == 32 )
|
366
393
|
goto st1;
|
367
394
|
if ( 97 <= (*p) && (*p) <= 122 )
|
@@ -381,7 +408,7 @@ st2:
|
|
381
408
|
if ( ++p == pe )
|
382
409
|
goto _test_eof2;
|
383
410
|
case 2:
|
384
|
-
#line
|
411
|
+
#line 412 "parser.c"
|
385
412
|
if ( (*p) == 32 )
|
386
413
|
goto tr5;
|
387
414
|
if ( 97 <= (*p) && (*p) <= 122 )
|
@@ -398,7 +425,7 @@ st9:
|
|
398
425
|
if ( ++p == pe )
|
399
426
|
goto _test_eof9;
|
400
427
|
case 9:
|
401
|
-
#line
|
428
|
+
#line 429 "parser.c"
|
402
429
|
if ( (*p) == 32 )
|
403
430
|
goto st9;
|
404
431
|
goto tr22;
|
@@ -432,6 +459,6 @@ case 9:
|
|
432
459
|
|
433
460
|
}
|
434
461
|
|
435
|
-
#line
|
462
|
+
#line 264 "parser.rl"
|
436
463
|
erbal_parser_finish(parser);
|
437
464
|
}
|
data/ext/erbal/parser.h
CHANGED
@@ -6,12 +6,13 @@
|
|
6
6
|
typedef struct parser_state {
|
7
7
|
unsigned int tag;
|
8
8
|
unsigned int chars_seen;
|
9
|
-
unsigned int
|
9
|
+
unsigned int concat;
|
10
|
+
char *chars_seen_start;
|
10
11
|
} parser_state;
|
11
12
|
|
12
13
|
typedef struct erbal_parser {
|
13
14
|
parser_state *state;
|
14
|
-
unsigned int debug;
|
15
|
+
unsigned int debug, concat_methods_identical;
|
15
16
|
VALUE str, src, buffer_name, options, safe_concat_method, unsafe_concat_method, keyword, safe_concat_keyword;
|
16
17
|
char *keyword_start, *keyword_end, *keyword_trailing_whitespace, *keyword_preceding_whitespace;
|
17
18
|
} erbal_parser;
|
@@ -25,13 +26,14 @@ inline void erbal_parser_tag_open_for_safe_concat(erbal_parser*);
|
|
25
26
|
inline void erbal_parser_non_tag(erbal_parser*);
|
26
27
|
inline void erbal_parser_tag_close(erbal_parser*);
|
27
28
|
inline void erbal_parser_tag_close_with_trim(erbal_parser*);
|
28
|
-
inline void erbal_parser_tag_close_common(erbal_parser
|
29
|
+
inline void erbal_parser_tag_close_common(erbal_parser*);
|
29
30
|
inline void erbal_parser_finish(erbal_parser*);
|
30
|
-
inline void erbal_concat_chars_seen(erbal_parser
|
31
|
-
inline void erbal_parser_tag_open_common(erbal_parser
|
31
|
+
inline void erbal_concat_chars_seen(erbal_parser*);
|
32
|
+
inline void erbal_parser_tag_open_common(erbal_parser*);
|
32
33
|
inline void erbal_open_buffer_concat(erbal_parser*, int);
|
33
34
|
inline void erbal_close_buffer_concat(erbal_parser*);
|
34
|
-
inline
|
35
|
+
inline void erbal_close_and_open_buffer_concat_if_needed(erbal_parser*, int);
|
36
|
+
inline VALUE erbal_escape_special_chars(erbal_parser*);
|
35
37
|
|
36
38
|
#define TAG_OPEN 1
|
37
39
|
#define TAG_OPEN_FOR_COMMENT 2
|
@@ -39,4 +41,8 @@ inline VALUE erbal_escape_special_chars(erbal_parser*, int);
|
|
39
41
|
#define TAG_OPEN_FOR_UNSAFE_CONCAT 4
|
40
42
|
#define OUTSIDE_TAG 5
|
41
43
|
|
44
|
+
#define SAFE_CONCAT 1
|
45
|
+
#define UNSAFE_CONCAT 2
|
46
|
+
#define OUTSIDE_CONCAT 3
|
47
|
+
|
42
48
|
#endif
|
data/ext/erbal/parser.rl
CHANGED
@@ -35,29 +35,31 @@
|
|
35
35
|
static char *ts, *te, *p, *pe, *eof;
|
36
36
|
static int act, cs;
|
37
37
|
|
38
|
-
inline void erbal_parser_tag_open_common(erbal_parser *parser
|
38
|
+
inline void erbal_parser_tag_open_common(erbal_parser *parser) {
|
39
39
|
if (parser->state->chars_seen != 0) {
|
40
|
-
if (
|
40
|
+
if (parser->state->concat == OUTSIDE_CONCAT) {
|
41
41
|
erbal_open_buffer_concat(parser, 1);
|
42
|
+
} else if (parser->state->concat == UNSAFE_CONCAT) {
|
43
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 1);
|
42
44
|
}
|
43
45
|
|
44
|
-
erbal_concat_chars_seen(parser
|
46
|
+
erbal_concat_chars_seen(parser);
|
45
47
|
parser->state->chars_seen = 0;
|
46
48
|
}
|
47
49
|
}
|
48
50
|
|
49
51
|
inline void erbal_parser_tag_open(erbal_parser *parser) {
|
50
|
-
erbal_parser_tag_open_common(parser
|
52
|
+
erbal_parser_tag_open_common(parser);
|
51
53
|
parser->state->tag = TAG_OPEN;
|
52
54
|
}
|
53
55
|
|
54
56
|
inline void erbal_parser_tag_open_with_dash(erbal_parser *parser) {
|
55
|
-
erbal_parser_tag_open_common(parser
|
57
|
+
erbal_parser_tag_open_common(parser);
|
56
58
|
parser->state->tag = TAG_OPEN;
|
57
59
|
}
|
58
60
|
|
59
61
|
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) {
|
62
|
+
if (strcmp(RSTRING(parser->safe_concat_keyword)->ptr, "") == 0 || strcmp(RSTRING(parser->keyword)->ptr, RSTRING(parser->safe_concat_keyword)->ptr) != 0) {
|
61
63
|
/* Keyword doesn't match, reset the buffer to the start of the expression match and act as if a keyword wasn't seen. */
|
62
64
|
p = parser->keyword_preceding_whitespace - 1;
|
63
65
|
erbal_parser_tag_open_for_unsafe_concat(parser);
|
@@ -69,43 +71,51 @@ inline void erbal_parser_tag_open_choose_concat(erbal_parser *parser) {
|
|
69
71
|
}
|
70
72
|
|
71
73
|
inline void erbal_parser_tag_open_for_unsafe_concat(erbal_parser *parser) {
|
72
|
-
erbal_parser_tag_open_common(parser
|
74
|
+
erbal_parser_tag_open_common(parser);
|
73
75
|
parser->state->tag = TAG_OPEN_FOR_UNSAFE_CONCAT;
|
74
76
|
}
|
75
77
|
|
76
78
|
inline void erbal_parser_tag_open_for_safe_concat(erbal_parser *parser) {
|
77
|
-
erbal_parser_tag_open_common(parser
|
79
|
+
erbal_parser_tag_open_common(parser);
|
78
80
|
parser->state->tag = TAG_OPEN_FOR_SAFE_CONCAT;
|
79
81
|
}
|
80
82
|
|
81
83
|
inline void erbal_parser_tag_open_for_comment(erbal_parser *parser) {
|
82
|
-
erbal_parser_tag_open_common(parser
|
84
|
+
erbal_parser_tag_open_common(parser);
|
83
85
|
parser->state->tag = TAG_OPEN_FOR_COMMENT;
|
84
86
|
}
|
85
87
|
|
86
88
|
inline void erbal_parser_non_tag(erbal_parser *parser) {
|
89
|
+
if (parser->state->chars_seen == 0) {
|
90
|
+
parser->state->chars_seen_start = p;
|
91
|
+
}
|
92
|
+
|
87
93
|
parser->state->chars_seen += 1;
|
88
94
|
}
|
89
95
|
|
90
|
-
inline void erbal_parser_tag_close_common(erbal_parser *parser
|
96
|
+
inline void erbal_parser_tag_close_common(erbal_parser *parser) {
|
91
97
|
if (parser->state->tag == TAG_OPEN_FOR_UNSAFE_CONCAT || parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
92
|
-
if (
|
98
|
+
if (parser->state->concat == OUTSIDE_CONCAT) {
|
93
99
|
if (parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
94
100
|
erbal_open_buffer_concat(parser, 1);
|
95
101
|
} else {
|
96
102
|
erbal_open_buffer_concat(parser, 0);
|
97
103
|
}
|
104
|
+
} else if (parser->state->concat == SAFE_CONCAT && parser->state->tag == TAG_OPEN_FOR_UNSAFE_CONCAT) {
|
105
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 0);
|
106
|
+
} else if (parser->state->concat == UNSAFE_CONCAT && parser->state->tag == TAG_OPEN_FOR_SAFE_CONCAT) {
|
107
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 1);
|
98
108
|
}
|
99
109
|
|
100
110
|
rb_str_buf_cat(parser->src, "#{", 2);
|
101
|
-
erbal_concat_chars_seen(parser
|
111
|
+
erbal_concat_chars_seen(parser);
|
102
112
|
rb_str_buf_cat(parser->src, "}", 1);
|
103
113
|
} else if (parser->state->tag == TAG_OPEN) {
|
104
|
-
if (parser->state->
|
114
|
+
if (parser->state->concat != OUTSIDE_CONCAT) {
|
105
115
|
erbal_close_buffer_concat(parser);
|
106
116
|
}
|
107
117
|
|
108
|
-
erbal_concat_chars_seen(parser
|
118
|
+
erbal_concat_chars_seen(parser);
|
109
119
|
rb_str_buf_cat(parser->src, ";\n", 2);
|
110
120
|
}
|
111
121
|
|
@@ -114,7 +124,7 @@ inline void erbal_parser_tag_close_common(erbal_parser *parser, int tag_size) {
|
|
114
124
|
}
|
115
125
|
|
116
126
|
inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
117
|
-
erbal_parser_tag_close_common(parser
|
127
|
+
erbal_parser_tag_close_common(parser);
|
118
128
|
|
119
129
|
if (*(p + 1) == '\n') {
|
120
130
|
p++;
|
@@ -122,16 +132,16 @@ inline void erbal_parser_tag_close_with_trim(erbal_parser *parser) {
|
|
122
132
|
}
|
123
133
|
|
124
134
|
inline void erbal_parser_tag_close(erbal_parser *parser) {
|
125
|
-
erbal_parser_tag_close_common(parser
|
135
|
+
erbal_parser_tag_close_common(parser);
|
126
136
|
}
|
127
137
|
|
128
|
-
inline VALUE erbal_escape_special_chars(erbal_parser *parser
|
138
|
+
inline VALUE erbal_escape_special_chars(erbal_parser *parser) {
|
129
139
|
VALUE buf = rb_str_buf_new(0);
|
130
140
|
int i, n, slashes_seen = 0;
|
131
141
|
char *current_char;
|
132
142
|
|
133
143
|
for (i = 0; i < parser->state->chars_seen; i++) {
|
134
|
-
current_char = (
|
144
|
+
current_char = (parser->state->chars_seen_start + i);
|
135
145
|
|
136
146
|
if (*current_char == '#' || *current_char == '`') {
|
137
147
|
if (slashes_seen == 0) {
|
@@ -156,48 +166,58 @@ inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
|
|
156
166
|
return buf;
|
157
167
|
}
|
158
168
|
|
159
|
-
inline void erbal_concat_chars_seen(erbal_parser *parser
|
169
|
+
inline void erbal_concat_chars_seen(erbal_parser *parser) {
|
160
170
|
if (parser->state->chars_seen != 0) {
|
161
|
-
if (parser->state->
|
162
|
-
rb_str_concat(parser->src, erbal_escape_special_chars(parser
|
171
|
+
if (parser->state->concat != OUTSIDE_CONCAT && parser->state->tag == OUTSIDE_TAG) {
|
172
|
+
rb_str_concat(parser->src, erbal_escape_special_chars(parser));
|
163
173
|
} else {
|
164
|
-
rb_str_buf_cat(parser->src,
|
174
|
+
rb_str_buf_cat(parser->src, parser->state->chars_seen_start, parser->state->chars_seen);
|
165
175
|
}
|
166
176
|
}
|
167
177
|
|
168
178
|
parser->state->chars_seen = 0;
|
169
179
|
}
|
170
180
|
|
181
|
+
inline void erbal_close_and_open_buffer_concat_if_needed(erbal_parser *parser, int safe_concat) {
|
182
|
+
if (!parser->concat_methods_identical) {
|
183
|
+
erbal_close_buffer_concat(parser);
|
184
|
+
erbal_open_buffer_concat(parser, safe_concat);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
171
188
|
inline void erbal_open_buffer_concat(erbal_parser *parser, int safe_concat) {
|
172
189
|
rb_str_concat(parser->src, parser->buffer_name);
|
173
190
|
rb_str_buf_cat(parser->src, ".", 1);
|
174
191
|
|
175
192
|
if (safe_concat) {
|
176
193
|
rb_str_concat(parser->src, parser->safe_concat_method);
|
194
|
+
parser->state->concat = SAFE_CONCAT;
|
177
195
|
} else {
|
178
196
|
rb_str_concat(parser->src, parser->unsafe_concat_method);
|
197
|
+
parser->state->concat = UNSAFE_CONCAT;
|
179
198
|
}
|
180
199
|
|
181
200
|
rb_str_buf_cat(parser->src, "(", 1);
|
182
201
|
rb_str_buf_cat(parser->src, "%Q`", 3);
|
183
|
-
parser->state->in_concat = 1;
|
184
202
|
}
|
185
203
|
|
186
204
|
inline void erbal_close_buffer_concat(erbal_parser *parser) {
|
187
205
|
rb_str_buf_cat(parser->src, "`);", 3);
|
188
|
-
parser->state->
|
206
|
+
parser->state->concat = OUTSIDE_CONCAT;
|
189
207
|
}
|
190
208
|
|
191
209
|
inline void erbal_parser_finish(erbal_parser *parser) {
|
192
210
|
if (parser->state->chars_seen != 0) {
|
193
|
-
if (
|
211
|
+
if (parser->state->concat == OUTSIDE_CONCAT) {
|
194
212
|
erbal_open_buffer_concat(parser, 1);
|
213
|
+
} else if (parser->state->concat == UNSAFE_CONCAT) {
|
214
|
+
erbal_close_and_open_buffer_concat_if_needed(parser, 1);
|
195
215
|
}
|
196
216
|
|
197
|
-
erbal_concat_chars_seen(parser
|
217
|
+
erbal_concat_chars_seen(parser);
|
198
218
|
}
|
199
219
|
|
200
|
-
if (parser->state->
|
220
|
+
if (parser->state->concat != OUTSIDE_CONCAT) {
|
201
221
|
erbal_close_buffer_concat(parser);
|
202
222
|
}
|
203
223
|
|
@@ -210,8 +230,15 @@ inline void erbal_parser_finish(erbal_parser *parser) {
|
|
210
230
|
|
211
231
|
void erbal_parser_init(VALUE self, erbal_parser *parser) {
|
212
232
|
parser->state->chars_seen = 0;
|
213
|
-
parser->state->
|
233
|
+
parser->state->concat = OUTSIDE_CONCAT;
|
214
234
|
parser->state->tag = OUTSIDE_TAG;
|
235
|
+
|
236
|
+
if (strcmp(RSTRING(parser->safe_concat_method)->ptr, RSTRING(parser->unsafe_concat_method)->ptr) == 0) {
|
237
|
+
parser->concat_methods_identical = 1;
|
238
|
+
} else {
|
239
|
+
parser->concat_methods_identical = 0;
|
240
|
+
}
|
241
|
+
|
215
242
|
parser->src = rb_str_dup(parser->buffer_name);
|
216
243
|
|
217
244
|
rb_iv_set(self, "@src", parser->src);
|
data/spec/erbal_spec.rb
CHANGED
@@ -141,11 +141,15 @@ describe Erbal do
|
|
141
141
|
end
|
142
142
|
|
143
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"
|
144
|
+
erbal_parse("1 + 1 is <%= raw 1 + 1 %>", :unsafe_concat_method => 'unsafe_concat', :safe_concat_keyword => nil).should == "@output_buffer = '';@output_buffer.concat(%Q`1 + 1 is `);@output_buffer.unsafe_concat(%Q`\#{ raw 1 + 1 }`);@output_buffer"
|
145
145
|
end
|
146
146
|
|
147
147
|
it "should preserve the whitespace following the safe_concat_keyword" do
|
148
|
-
erbal_parse("<%= raw
|
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
|
150
|
+
|
151
|
+
it "should not swallow the text preceding the safe concat" do
|
152
|
+
erbal_parse("omg don't eat me! <%= raw 1 + 1 %>", :safe_concat_method => 'safe_concat', :safe_concat_keyword => 'raw').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`omg don't eat me! \#{ 1 + 1 }`);@output_buffer"
|
149
153
|
end
|
150
154
|
|
151
155
|
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
|
@@ -153,7 +157,37 @@ describe Erbal do
|
|
153
157
|
end
|
154
158
|
|
155
159
|
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"
|
160
|
+
erbal_parse("omglololo <%=blah 1 + 1 %>", :unsafe_concat_method => 'unsafe_concat').should == "@output_buffer = '';@output_buffer.concat(%Q`omglololo `);@output_buffer.unsafe_concat(%Q`\#{blah 1 + 1 }`);@output_buffer"
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should end the current safe concat and begin a new unsafe concat" do
|
164
|
+
erbal_parse("hello <%= \"world\" %>", :unsafe_concat_method => 'unsafe_concat', :safe_concat_method => 'safe_concat').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`hello `);@output_buffer.unsafe_concat(%Q`\#{ \"world\" }`);@output_buffer"
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should end the current unsafe concat and begin a new safe concat when at the end of the source" do
|
168
|
+
erbal_parse("<%= \"hello\" %> world", :unsafe_concat_method => 'unsafe_concat', :safe_concat_method => 'safe_concat').should == "@output_buffer = '';@output_buffer.unsafe_concat(%Q`\#{ \"hello\" }`);@output_buffer.safe_concat(%Q` world`);@output_buffer"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should end the current unsafe concat and begin a new safe concat when inbetween two unsafe concats" do
|
172
|
+
erbal_parse("<%= \"hello\" %> world <%= \"woot\" %>", :unsafe_concat_method => 'unsafe_concat', :safe_concat_method => 'safe_concat').should == "@output_buffer = '';@output_buffer.unsafe_concat(%Q`\#{ \"hello\" }`);@output_buffer.safe_concat(%Q` world `);@output_buffer.unsafe_concat(%Q`\#{ \"woot\" }`);@output_buffer"
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "when preserving string interpolation optimizations if safe and unsafe concat methods are the same" do
|
176
|
+
it "should use interpolation if we switch from a safe concat to an unsafe concat" do
|
177
|
+
erbal_parse("hello <%= \"world\" %>", :unsafe_concat_method => 'concat', :safe_concat_method => 'concat').should == "@output_buffer = '';@output_buffer.concat(%Q`hello \#{ \"world\" }`);@output_buffer"
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should use interpolation if we switch from an unsafe concat to a safe concat" do
|
181
|
+
erbal_parse("<%= \"hello\" %> world", :unsafe_concat_method => 'concat', :safe_concat_method => 'concat').should == "@output_buffer = '';@output_buffer.concat(%Q`\#{ \"hello\" } world`);@output_buffer"
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should use interpolation if we switch from a safe concat to an unsafe concat and then back again" do
|
185
|
+
erbal_parse("hello <%= \"world\" %> woot", :unsafe_concat_method => 'concat', :safe_concat_method => 'concat').should == "@output_buffer = '';@output_buffer.concat(%Q`hello \#{ \"world\" } woot`);@output_buffer"
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should use interpolation if we switch from an unsafe concat to a safe concat and then back again" do
|
189
|
+
erbal_parse("omg <%= \"hello\" %> world", :unsafe_concat_method => 'concat', :safe_concat_method => 'concat').should == "@output_buffer = '';@output_buffer.concat(%Q`omg \#{ \"hello\" } world`);@output_buffer"
|
190
|
+
end
|
157
191
|
end
|
158
192
|
end
|
159
193
|
end
|
data/tasks/gem.rake
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erbal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 977940511
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 1.2.
|
9
|
+
- rc2
|
10
|
+
version: 1.2.rc2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ian Leitch
|