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 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, int shift) {
24
+ inline void erbal_parser_tag_open_common(erbal_parser *parser) {
25
25
  if (parser->state->chars_seen != 0) {
26
- if (!parser->state->in_concat) {
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, shift);
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, -1);
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, -2);
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, -2);
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, -2);
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, -2);
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, int tag_size) {
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 (!parser->state->in_concat) {
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, -tag_size);
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->in_concat) {
100
+ if (parser->state->concat != OUTSIDE_CONCAT) {
91
101
  erbal_close_buffer_concat(parser);
92
102
  }
93
103
 
94
- erbal_concat_chars_seen(parser, -tag_size);
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, 2);
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, 1);
121
+ erbal_parser_tag_close_common(parser);
112
122
  }
113
123
 
114
- inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
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 = (((p + shift) - parser->state->chars_seen) + i);
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, int shift) {
155
+ inline void erbal_concat_chars_seen(erbal_parser *parser) {
146
156
  if (parser->state->chars_seen != 0) {
147
- if (parser->state->in_concat && parser->state->tag == OUTSIDE_TAG) {
148
- rb_str_concat(parser->src, erbal_escape_special_chars(parser, shift));
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, ((p + shift) - parser->state->chars_seen), parser->state->chars_seen);
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->in_concat = 0;
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 (!parser->state->in_concat) {
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, 0);
203
+ erbal_concat_chars_seen(parser);
184
204
  }
185
205
 
186
- if (parser->state->in_concat) {
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->in_concat = 0;
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 218 "parser.c"
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 231 "parser.rl"
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 233 "parser.c"
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 293 "parser.c"
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 315 "parser.c"
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 351 "parser.c"
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 365 "parser.c"
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 385 "parser.c"
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 402 "parser.c"
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 237 "parser.rl"
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 in_concat;
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*, int);
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*, int);
31
- inline void erbal_parser_tag_open_common(erbal_parser*, int);
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 VALUE erbal_escape_special_chars(erbal_parser*, int);
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, int shift) {
38
+ inline void erbal_parser_tag_open_common(erbal_parser *parser) {
39
39
  if (parser->state->chars_seen != 0) {
40
- if (!parser->state->in_concat) {
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, shift);
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, -1);
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, -2);
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, -2);
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, -2);
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, -2);
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, int tag_size) {
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 (!parser->state->in_concat) {
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, -tag_size);
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->in_concat) {
114
+ if (parser->state->concat != OUTSIDE_CONCAT) {
105
115
  erbal_close_buffer_concat(parser);
106
116
  }
107
117
 
108
- erbal_concat_chars_seen(parser, -tag_size);
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, 2);
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, 1);
135
+ erbal_parser_tag_close_common(parser);
126
136
  }
127
137
 
128
- inline VALUE erbal_escape_special_chars(erbal_parser *parser, int shift) {
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 = (((p + shift) - parser->state->chars_seen) + i);
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, int shift) {
169
+ inline void erbal_concat_chars_seen(erbal_parser *parser) {
160
170
  if (parser->state->chars_seen != 0) {
161
- if (parser->state->in_concat && parser->state->tag == OUTSIDE_TAG) {
162
- rb_str_concat(parser->src, erbal_escape_special_chars(parser, shift));
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, ((p + shift) - parser->state->chars_seen), parser->state->chars_seen);
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->in_concat = 0;
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 (!parser->state->in_concat) {
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, 0);
217
+ erbal_concat_chars_seen(parser);
198
218
  }
199
219
 
200
- if (parser->state->in_concat) {
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->in_concat = 0;
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 1 + 1 %>", :safe_concat_method => 'safe_concat', :safe_concat_keyword => 'raw').should == "@output_buffer = '';@output_buffer.safe_concat(%Q`\#{ 1 + 1 }`);@output_buffer"
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
@@ -2,7 +2,7 @@ require 'rake/gempackagetask'
2
2
  require 'yaml'
3
3
 
4
4
  WIN_SUFFIX = ENV['WIN_SUFFIX'] || 'i386-mswin32'
5
- ERBAL_VERSION = '1.2.rc1'
5
+ ERBAL_VERSION = '1.2.rc2'
6
6
 
7
7
  task :clean => :clobber_package
8
8
 
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: 977940510
4
+ hash: 977940511
5
5
  prerelease: true
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - rc1
10
- version: 1.2.rc1
9
+ - rc2
10
+ version: 1.2.rc2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ian Leitch