erbal 1.0 → 1.1

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.
@@ -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