erbal 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,8 +14,8 @@ Erbal is a lightweight ERB parser that uses the Ragel State Machine Compiler (ht
14
14
 
15
15
  Erbal.new takes an optional 2nd argument which is a hash of options, available options are:
16
16
 
17
- * `:buffer` The name of the output buffer, default is '@output_buffer'
18
- * `:buffer_initial_value` The initial value of the output buffer, defaults to a blank string.
17
+ * :buffer The name of the output buffer, default is '@output_buffer'
18
+ * :buffer_initial_value The initial value of the output buffer, defaults to a blank string.
19
19
 
20
20
  == Rails 2.3
21
21
 
@@ -28,6 +28,50 @@ Create the file 'config/initializers/erbal.rb' containing:
28
28
 
29
29
  I've not looked into yet.. patches are welcome! ;)
30
30
 
31
+ == Benchmarks
32
+
33
+ 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
+
35
+ 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
+
49
+ => Erubis (using default Eruby engine)
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
66
+
67
+ => Erubis (using default Eruby engine)
68
+ 0.178 0.176 0.165 0.176 0.175 0.164
69
+ => Average: 0.172
70
+
71
+ => Erbal
72
+ 0.111 0.125 0.124 0.110 0.133 0.124
73
+ => Average: 0.121
74
+
31
75
  == Contributing
32
76
 
33
77
  * Fork the project.
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
1
3
  require 'erb'
2
4
  require 'rubygems'
3
5
  require 'erubis'
@@ -5,31 +7,46 @@ require File.expand_path(File.dirname(__FILE__)) + '/../lib/erbal'
5
7
 
6
8
  RUNS = 3000
7
9
  REPEAT = 6
8
- SRC = File.read('sample.erb')
10
+ SRC = File.read(File.expand_path(File.dirname(__FILE__)) + '/sample.erb')
9
11
 
10
12
  class Benchmark
11
- def self.run(runs, repeat, warmup=false)
12
- puts "\n=> #{self.name.split('Benchmark').first}:" unless warmup
13
+ def self.run(what, runs, repeat, warmup=false)
14
+ puts "\n=> #{canonical_name}" unless warmup
13
15
  times = []
14
16
  repeat.times do |i|
15
17
  total = 0
16
- runs.times do
18
+ runs.times do |n|
17
19
  start = Time.now
18
- parse
20
+ send(what)
19
21
  total += Time.now-start
20
22
  end
21
23
  times << total
22
- puts " #{i+1}) #{sprintf("%.3f", total)}" unless warmup
24
+ unless warmup
25
+ $stdout.write(sprintf("%.3f ", total))
26
+ $stdout.flush
27
+ end
23
28
  end
24
29
  unless warmup
25
- puts "=> Average: #{sprintf("%.3f", times.inject(0){|c, n| c += n} / times.size)}"
30
+ puts "\n=> Average: #{sprintf("%.3f", times.inject(0){|c, n| c += n} / times.size)}"
26
31
  end
27
32
  end
33
+
34
+ def self.prep_for_eval
35
+ @src = parse
36
+ end
37
+
38
+ def self.eval_src
39
+ eval(@src)
40
+ end
41
+
42
+ def self.canonical_name
43
+ name.split('Benchmark').first
44
+ end
28
45
  end
29
46
 
30
47
  class ErbalBenchmark < Benchmark
31
48
  def self.parse
32
- Erbal.new(SRC, "@output").parse
49
+ Erbal.new(SRC).parse
33
50
  end
34
51
  end
35
52
 
@@ -37,21 +54,45 @@ class ErbBenchmark < Benchmark
37
54
  def self.parse
38
55
  ::ERB.new(SRC, nil, '-', '@output')
39
56
  end
57
+
58
+ def self.prep_for_eval
59
+ @src = parse.src
60
+ end
40
61
  end
41
62
 
42
- class ErubisBenchmark < Benchmark
63
+ class ErubisFastBenchmark < Benchmark
43
64
  def self.parse
44
65
  Erubis::FastEruby.new.convert(SRC)
45
66
  end
67
+
68
+ def self.canonical_name
69
+ "Erubis (using FastEruby engine)"
70
+ end
71
+ end
72
+
73
+ class ErubisBenchmark < Benchmark
74
+ def self.parse
75
+ Erubis::Eruby.new.convert(SRC)
76
+ end
77
+
78
+ def self.canonical_name
79
+ "Erubis (using default Eruby engine)"
80
+ end
46
81
  end
47
82
 
48
- parsers = [ErbBenchmark, ErbalBenchmark, ErubisBenchmark]
83
+ parsers = [ErbBenchmark, ErubisFastBenchmark, ErubisBenchmark, ErbalBenchmark]
49
84
 
50
85
  $stdout.write("=> Warming up.... ")
51
86
  $stdout.flush
52
87
  parsers.each do |b|
53
- b.run(RUNS, 1, true)
88
+ b.run(:parse, 10, 2, true)
54
89
  end
55
90
  puts "done"
56
- puts "=> #{RUNS} runs repeated #{REPEAT} times"
57
- parsers.map {|b| b.run(RUNS, REPEAT)}
91
+ puts
92
+ puts "=> Parsing Benchmark"
93
+ parsers.map {|b| b.run(:parse, RUNS, REPEAT)}
94
+
95
+ puts
96
+ puts "=> eval() Benchmark"
97
+ parsers.map {|b| b.prep_for_eval}
98
+ parsers.map {|b| b.run(:eval_src, RUNS, REPEAT)}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/erbal'
4
+
5
+ SRC = File.read(File.expand_path(File.dirname(__FILE__)) + '/sample.erb')
6
+ GC.enable_stats
7
+
8
+ i = 0
9
+ while true do
10
+ i += 1
11
+ 5000.times do
12
+ e = Erbal.new(SRC)
13
+ e.parse
14
+ end
15
+ GC.start
16
+ rss = `ps -orss #{Process.pid}`.split("\n").last.strip
17
+ puts
18
+ puts "Run #{i}"
19
+ puts "RSS #{rss}"
20
+ puts "Live objects #{ObjectSpace.live_objects}"
21
+ GC.dump
22
+ end
@@ -1,24 +1,20 @@
1
- Lorem ipsum dolor sit amet, <% consectetur adipisicing elit -%>, sed do eiusmod tempor incididunt ut labore et dolore magna <%= aliqua -%>.
2
- <%= Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
3
- reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. %>
4
- <% Excepteur sint occaecat -%> cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est <%= laborum -%>.
5
-
6
- <% Lorem %> ipsum dolor sit amet, <% consectetur %> adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
7
- Ut enim ad minim veniam, <%# quis nostrud exercitation ullamco laboris nisi ut aliquip ex -%> ea commodo consequat. Duis aute irure dolor in
8
- <%= reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur -%>.
9
- Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim <%= id est laborum -%>.
10
-
11
- <%= Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. -%>
12
- <% Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. %>
13
- <%= Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. %>
14
- <%#= Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -%>
15
-
16
- Lorem ipsum dolor sit amet, consectetur adipisicing elit, <% sed do eiusmod tempor incididunt ut -%> labore et dolore magna aliqua.
17
- Ut enim ad minim veniam, quis nostrud <%=%> exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
18
- Duis aute irure dolor in reprehenderit in -%> <% voluptate velit esse cillum dolore eu fugiat nulla pariatur.
19
- Excepteur sint occaecat cupidatat non proident, sunt -%> in culpa qui officia deserunt mollit <%= anim id est laborum -%>.
20
-
21
- Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
22
- Ut enim ad minim veniam, <% quis -%> nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
23
- Duis aute irure dolor in reprehenderit in <%= voluptate velit -%> esse cillum dolore eu fugiat nulla pariatur.
24
- Excepteur sint occaecat cupidatat non proident, sunt in culpa <%= qui -%> <%= officia -%> <%= deserunt -%> <%= mollit -%> <%= anim -%> <%= id est laborum. -%>
1
+ Hello! I'm the sample Erbal template.
2
+
3
+ The time now is: <%= Time.now -%>
4
+
5
+ <% if true %>
6
+ Once upon a time there was a small pig called Pinki. He died.
7
+ <% end -%>
8
+
9
+ 1 + 1 is: <%= 1 + 1 %>
10
+ <%= "2 + 2 is :#{2 + 2}" %>
11
+
12
+ <%= %><%= %><%= "hi mom" %><%= %><%= -%><% true || false %>
13
+
14
+ #{exit 1}
15
+
16
+ `exit 1`
17
+
18
+ <%# almost the end %>
19
+
20
+ "The end."
@@ -3,15 +3,9 @@
3
3
 
4
4
  static VALUE cErbal;
5
5
 
6
- void rb_erbal_free(void *data) {
7
- if(data) {
8
- free(data);
9
- }
10
- }
11
-
12
6
  VALUE rb_erbal_alloc(VALUE klass) {
13
- erbal_parser *parser = ALLOC_N(erbal_parser, 1);
14
- VALUE obj = Data_Wrap_Struct(klass, NULL, rb_erbal_free, parser);
7
+ erbal_parser *parser = ALLOC(erbal_parser);
8
+ VALUE obj = Data_Wrap_Struct(klass, 0, free, parser);
15
9
  return obj;
16
10
  }
17
11
 
@@ -22,7 +16,7 @@ VALUE rb_erbal_initialize(int argc, VALUE *argv, VALUE self) {
22
16
 
23
17
  Check_Type(str, T_STRING);
24
18
 
25
- erbal_parser *parser = NULL;
19
+ erbal_parser *parser;
26
20
  Data_Get_Struct(self, erbal_parser, parser);
27
21
  parser->str = str;
28
22
 
@@ -33,13 +27,32 @@ VALUE rb_erbal_initialize(int argc, VALUE *argv, VALUE self) {
33
27
  parser->options = options;
34
28
  }
35
29
 
30
+ rb_iv_set(self, "@options", parser->options);
31
+
32
+ if (rb_hash_aref(parser->options, ID2SYM(rb_intern("debug"))) == Qtrue) {
33
+ parser->debug = 1;
34
+ } else {
35
+ parser->debug = 0;
36
+ }
37
+
38
+ VALUE buffer_name_val = rb_hash_aref(parser->options, ID2SYM(rb_intern("buffer")));
39
+
40
+ if (!NIL_P(buffer_name_val)) {
41
+ Check_Type(buffer_name_val, T_STRING);
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);
48
+
36
49
  return self;
37
50
  }
38
51
 
39
52
  VALUE rb_erbal_parse(VALUE self) {
40
- erbal_parser *parser = NULL;
53
+ erbal_parser *parser;
41
54
  Data_Get_Struct(self, erbal_parser, parser);
42
- erbal_parser_init(parser);
55
+ erbal_parser_init(self, parser);
43
56
  erbal_parser_exec(parser);
44
57
  return parser->src;
45
58
  }
@@ -164,28 +164,14 @@ inline void erbal_parser_finish(erbal_parser *parser) {
164
164
  }
165
165
  }
166
166
 
167
- void erbal_parser_init(erbal_parser *parser) {
167
+ void erbal_parser_init(VALUE self, erbal_parser *parser) {
168
168
  parser->chars_seen = 0;
169
169
  parser->in_buffer_shift = 0;
170
170
  parser->state = OUTSIDE_TAG;
171
-
172
- if (rb_hash_aref(parser->options, ID2SYM(rb_intern("debug"))) == Qtrue) {
173
- parser->debug = 1;
174
- } else {
175
- parser->debug = 0;
176
- }
177
-
178
- VALUE buffer_name_val = rb_hash_aref(parser->options, ID2SYM(rb_intern("buffer")));
179
-
180
- if (!NIL_P(buffer_name_val)) {
181
- Check_Type(buffer_name_val, T_STRING);
182
- parser->buffer_name = buffer_name_val;
183
- } else {
184
- parser->buffer_name = rb_str_new2("@output_buffer");
185
- }
186
-
187
171
  parser->src = rb_str_dup(parser->buffer_name);
188
172
 
173
+ rb_iv_set(self, "@src", parser->src);
174
+
189
175
  VALUE buffer_init_val = rb_hash_aref(parser->options, ID2SYM(rb_intern("buffer_initial_value")));
190
176
 
191
177
  if (!NIL_P(buffer_init_val)) {
@@ -198,7 +184,7 @@ void erbal_parser_init(erbal_parser *parser) {
198
184
  }
199
185
 
200
186
 
201
- #line 202 "parser.c"
187
+ #line 188 "parser.c"
202
188
  {
203
189
  cs = erbal_parser_start;
204
190
  ts = 0;
@@ -206,14 +192,14 @@ void erbal_parser_init(erbal_parser *parser) {
206
192
  act = 0;
207
193
  }
208
194
 
209
- #line 200 "parser.rl"
195
+ #line 186 "parser.rl"
210
196
  }
211
197
 
212
198
  void erbal_parser_exec(erbal_parser *parser) {
213
199
  p = RSTRING(parser->str)->ptr;
214
200
  pe = p + strlen(p);
215
201
 
216
- #line 217 "parser.c"
202
+ #line 203 "parser.c"
217
203
  {
218
204
  if ( p == pe )
219
205
  goto _test_eof;
@@ -263,7 +249,7 @@ st1:
263
249
  case 1:
264
250
  #line 1 "NONE"
265
251
  {ts = p;}
266
- #line 267 "parser.c"
252
+ #line 253 "parser.c"
267
253
  switch( (*p) ) {
268
254
  case 37: goto st2;
269
255
  case 45: goto tr4;
@@ -285,7 +271,7 @@ st3:
285
271
  if ( ++p == pe )
286
272
  goto _test_eof3;
287
273
  case 3:
288
- #line 289 "parser.c"
274
+ #line 275 "parser.c"
289
275
  if ( (*p) == 37 )
290
276
  goto st0;
291
277
  goto tr6;
@@ -335,6 +321,6 @@ case 5:
335
321
 
336
322
  }
337
323
 
338
- #line 206 "parser.rl"
324
+ #line 192 "parser.rl"
339
325
  erbal_parser_finish(parser);
340
326
  }
@@ -163,28 +163,14 @@ inline void erbal_parser_finish(erbal_parser *parser) {
163
163
  }
164
164
  }
165
165
 
166
- void erbal_parser_init(erbal_parser *parser) {
166
+ void erbal_parser_init(VALUE self, erbal_parser *parser) {
167
167
  parser->chars_seen = 0;
168
168
  parser->in_buffer_shift = 0;
169
169
  parser->state = OUTSIDE_TAG;
170
-
171
- if (rb_hash_aref(parser->options, ID2SYM(rb_intern("debug"))) == Qtrue) {
172
- parser->debug = 1;
173
- } else {
174
- parser->debug = 0;
175
- }
176
-
177
- VALUE buffer_name_val = rb_hash_aref(parser->options, ID2SYM(rb_intern("buffer")));
178
-
179
- if (!NIL_P(buffer_name_val)) {
180
- Check_Type(buffer_name_val, T_STRING);
181
- parser->buffer_name = buffer_name_val;
182
- } else {
183
- parser->buffer_name = rb_str_new2("@output_buffer");
184
- }
185
-
186
170
  parser->src = rb_str_dup(parser->buffer_name);
187
171
 
172
+ rb_iv_set(self, "@src", parser->src);
173
+
188
174
  VALUE buffer_init_val = rb_hash_aref(parser->options, ID2SYM(rb_intern("buffer_initial_value")));
189
175
 
190
176
  if (!NIL_P(buffer_init_val)) {
@@ -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.0'
5
+ ERBAL_VERSION = '1.1'
6
6
 
7
7
  task :clean => :clobber_package
8
8
 
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erbal
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 0
9
- version: "1.0"
8
+ - 1
9
+ version: "1.1"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ian Leitch
@@ -38,6 +38,7 @@ files:
38
38
  - tasks/gem.rake
39
39
  - tasks/spec.rake
40
40
  - benchmark/bench.rb
41
+ - benchmark/mem_leak_detect.rb
41
42
  - benchmark/sample.erb
42
43
  - ext/erbal/parser.h
43
44
  - ext/erbal/erbal.c