Erbal is a lightweight ERB parser that uses the Ragel State Machine Compiler (www.complang.org/ragel/). It’s written in C, it’s very fast. Erbal also produces faster Ruby code than Ruby’s ERB implementation to give you a evaluation-time performance benefit.
>> require 'erbal' >> src = Erbal.new("<% a=1 -%>a is: <%= a -%>").parse => "@output_buffer = ''; a=1 ;\n@output_buffer.concat(%Q`a is: \#{ a }`);@output_buffer" >> eval(src) => "a is: 1"
Erbal.new takes an optional 2nd argument which is a hash of options, available options are:
-
:buffer - The name of the output buffer. Default is ‘@output_buffer’.
-
:buffer_initial_value - The initial value of the output buffer. Default is a blank string.
-
:unsafe_concat_method - 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’.
-
:safe_concat_method - The method to call on the buffer when concatenating a string which doesn’t need escaping, i.e text outside of ERB tags (your raw HTML) uses the safe concatenation method. Default is ‘concat’.
-
:safe_concat_keyword - By default the ‘<%=’ tag uses the unsafe_concat_method, with this option you can specify a keyword to signify that the 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. Be mindful that even thought the ‘raw’ keyword looks like a method call, it isn’t. Erbal expects that the key is followed by one or more spaces, so a tag like ‘<%= raw(some_method) %>’ will not be recognised by Erbal. Whitespace before the keyword is optional, so ‘<%=raw’ is valid. The keyword can either be one or more a-z characters, or a single of the following: ! @ $ * = ^ & +. For example, given :safe_concat_keyword => ‘!’ then the following is valid: ‘<%=! some_method %>’. Default is blank, i.e no keyword is specified.
NOTE: Erbal itself does NOT perform escaping, it is the responsibility of your unsafe_concat_method to escape the string passed to it.
Create the file ‘config/initializers/erbal.rb’ containing:
require 'erbal/rails'
Rails 2.3 + rails_xss (github.com/rails/rails_xss)¶ ↑
If you’re using the rails_xss plugin, use this in your initialiser instead:
require 'erbal' class ErbalTemplateHandler < ActionView::TemplateHandler include ActionView::TemplateHandlers::Compilable def compile(template) ::Erbal.new("<% __in_erb_template=true %>#{template.source}", {:buffer => '@output_buffer', :buffer_initial_value => 'ActiveSupport::SafeBuffer.new', :safe_concat_method => 'safe_concat', :unsafe_concat_method => 'concat', :safe_concat_keyword => 'raw'} ).parse end end ActionView::Template.register_template_handler :erb, ErbalTemplateHandler
I’ve not looked into yet.. patches are welcome! ;)
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.
Ruby: 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.0], MBARI 0x6770, Ruby Enterprise Edition 2010.02
Erubis: 2.6.6
Erbal: 1.2
Parsing Benchmark
=> Erb 0.850 0.852 0.864 0.860 0.846 0.845 => Average: 0.853 => Erubis (using FastEruby engine) 0.438 0.442 0.475 0.444 0.442 0.442 => Average: 0.447 => Erubis (using default Eruby engine) 0.446 0.422 0.443 0.443 0.422 0.443 => Average: 0.437 => Erbal 0.042 0.068 0.067 0.040 0.068 0.041 => Average: 0.054
eval() Benchmark
=> Erb 0.207 0.179 0.179 0.191 0.179 0.179 => Average: 0.186 => Erubis (using FastEruby engine) 0.125 0.127 0.128 0.127 0.127 0.141 => Average: 0.129 => Erubis (using default Eruby engine) 0.165 0.176 0.176 0.176 0.165 0.176 => Average: 0.172 => Erbal 0.128 0.117 0.129 0.116 0.129 0.129 => Average: 0.124
-
Fork the project.
-
Make your feature addition or bug fix.
-
Add tests for it, specs live in the specs/ directory.
-
Commit and send me a pull request.
Many thanks to Adrian Thurston for writing the Ragel State Machine Compiler (www.complang.org/ragel/)!
Copyright © 2010-2011 Envato & Ian Leitch. See LICENSE for details.