Skip to content

Herb::Engine v0.7.0+ ​

Herb::Engine is a drop-in replacement for Erubi::Engine that compiles HTML+ERB templates into Ruby code. It extends Erubi's functionality with HTML-aware parsing, validation, and security checks.

Usage ​

Basic usage (same as Erubi::Engine):

ruby
engine = Herb::Engine.new(source)
puts engine.src

With options:

ruby
engine = Herb::Engine.new(source,
  filename: "app/views/users/show.html.erb",
  escape: true,
)

Erubi Compatibility ​

Herb::Engine accepts all the same options as Erubi::Engine:

  • bufvar / outvar — Buffer variable name
  • bufval — Initial buffer value
  • escape / escape_html — Whether <%= %> escapes by default
  • escapefunc — Escape function name
  • filename — Template filename
  • freeze — Add frozen string literal comment
  • freeze_template_literals — Freeze template string literals
  • preamble / postamble — Custom preamble/postamble
  • chain_appends — Chain << calls for performance
  • ensure — Wrap in begin/ensure block
  • src — Initial source string

Herb-Specific Options ​

In addition to Erubi options, Herb::Engine supports:

OptionDefaultDescription
validation_mode:raiseHow to handle validation errors: :raise, :overlay, or :none
validators{}Per-validator overrides (e.g., { security: false })
stricttrueWhether to use strict parsing mode
visitors[]AST visitors to run before compilation
project_pathDir.pwdProject root for relative path resolution
debugfalseEnable debug mode

Validators ​

The engine runs validators on parsed templates to catch errors before compilation. Each validator can be enabled or disabled via .herb.yml configuration or per-instance overrides.

ValidatorDescription
SecurityDetects ERB output in unsafe positions (attribute names, attribute positions)
NestingValidates HTML nesting rules (e.g., no <div> inside <p>)
AccessibilityValidates accessibility-related attributes

Disable security validator for this template:

ruby
Herb::Engine.new(source, validators: { security: false })

See Engine Configuration for .herb.yml configuration.

Validation Mode ​

Controls how the engine presents validation results:

  • :raise — Raises SecurityError or CompilationError (default, used in tests and CLI)
  • :overlay — Renders errors as in-browser overlay (used by ReActionView in development)
  • :none — Skips validation entirely

Transform Visitors ​

The visitors option accepts visitors that run over the AST before compilation. Transform visitors rewrite the AST, which changes what the compiler emits.

Herb ships the following transform visitors:

VisitorDescription
AutoCloseOmittedTagsVisitorReplaces omitted closing tags with explicit ones

Transform visitors are not loaded when you require "herb". Require the ones you want and pass them to the engine:

ruby
require "herb/engine/auto_close_omitted_tags_visitor"

Herb::Engine.new(source, visitors: [Herb::Engine::AutoCloseOmittedTagsVisitor.new])

Your own visitors are passed the same way. See Visitors for how to write one.

AutoCloseOmittedTagsVisitor ​

Makes sure the compiled output always contains a closing tag, even when the template omits it.

Given this template:

html
<ul>
  <li>List Item 1
Element `<li>` at (2:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</li>` closing tag at (3:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<li>List Item 2
Missing explicit closing tag for `<li>`. Use `</li>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<li>` at (3:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</li>` closing tag at (4:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
</ul>
Missing explicit closing tag for `<li>`. Use `</li>` instead of relying on implicit tag closing. (html-require-closing-tags)

The engine renders:

html
<ul>
  <li>List Item 1
  </li><li>List Item 2
</li></ul>

The closing tag is inserted where the parser determined the element ends, which keeps the surrounding whitespace (and therefore the rendering of inline-block elements) identical to the template without the visitor.

ReActionView Integration ​

ReActionView registers Herb::Engine as the template handler for .html.erb and .html.herb files in Rails. It uses validation_mode: :overlay so validation errors appear as in-browser overlays during development instead of raising exceptions.

Validator settings from .herb.yml are respected automatically — no ReActionView-specific configuration needed.

ReActionView also lets you run transform visitors on every template it compiles, through config.transform_visitors:

ruby
# config/initializers/reactionview.rb
require "herb/engine/auto_close_omitted_tags_visitor"

ReActionView.configure do |config|
  config.transform_visitors = [
    Herb::Engine::AutoCloseOmittedTagsVisitor.new
  ]
end

Released under the MIT License.