A complete interface to Handlebars.js for Ruby.
Handlebars::Engine
provides a complete Ruby API for the official JavaScript
version of Handlebars, including the abilities to register Ruby blocks/procs as
Handlebars helper functions and to dynamically register partials.
It uses MiniRacer for the bridge between Ruby and the V8 JavaScript engine.
Handlebars::Engine
was created as a replacement for
handlebars.rb.
Add this line to your application's Gemfile:
gem 'handlebars-engine'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install handlebars-engine
handlebars = Handlebars::Engine.new
template = handlebars.compile("{{firstname}} {{lastname}}")
template.call({ firstname: "Yehuda", lastname: "Katz" })
# => "Yehuda Katz"
Handlebars helpers can be accessed from any context in a template. You can
register a helper with the register_helper
method:
handlebars = Handlebars::Engine.new
handlebars.register_helper(:loud) do |ctx, arg, opts|
arg.upcase
end
template = handlebars.compile("{{firstname}} {{loud lastname}}")
template.call({ firstname: "Yehuda", lastname: "Katz" })
# => "Yehuda KATZ"
Helpers receive the current context as the first argument of the block.
handlebars = Handlebars::Engine.new
handlebars.register_helper(:full_name) do |ctx, opts|
"#{ctx["firstname"]} #{ctx["lastname"]}"
end
template = handlebars.compile("{{full_name}}")
template.call({ firstname: "Yehuda", lastname: "Katz" })
# => "Yehuda Katz"
Any arguments to the helper are included as individual positional arguments.
handlebars = Handlebars::Engine.new
handlebars.register_helper(:join) do |ctx, *args, opts|
args.join(" ")
end
template = handlebars.compile("{{join firstname lastname}}")
template.call({ firstname: "Yehuda", lastname: "Katz" })
# => "Yehuda Katz"
The last argument is a hash of options.
See https://handlebarsjs.com/guide/#custom-helpers.
Block helpers make it possible to define custom iterators and other functionality that can invoke the passed block with a new context.
Currently, there is a limitation with the underlying JavaScript engine: it does
not allow for reentrant calls from within attached Ruby functions: see
MiniRacer#225. Thus, the
block function returned to the helper (in options.fn
) cannot be invoked.
Thus, for block helpers, a string of JavaScript must define the helper function:
handlebars = Handlebars::Engine.new
handlebars.register_helper(map: <<~JS)
function(...args) {
const ctx = this;
const opts = args.pop();
const items = args[0];
const separator = args[1];
const mapped = items.map((item) => opts.fn(item));
return mapped.join(separator);
}
JS
template = handlebars.compile("{{#map items '|'}}'{{this}}'{{/map}}")
template.call({ items: [1, 2, 3] })
# => "'1'|2'|'3'"
See https://handlebarsjs.com/guide/#block-helpers.
Handlebars partials allow for code reuse by creating shared templates.
You can register a partial using the register_partial
method:
handlebars = Handlebars::Engine.new
handlebars.register_partial(:person, "{{person.name}} is {{person.age}}.")
template = handlebars.compile("{{> person person=.}}")
template.call({ name: "Yehuda Katz", age: 20 })
# => "Yehuda Katz is 20."
See https://handlebarsjs.com/guide/#partials. See https://handlebarsjs.com/guide/partials.html.
This hook is called for a mustache or a block-statement when
- a simple mustache-expression is not a registered helper, and
- it is not a property of the current evaluation context.
You can add custom handling for those situations by registering a helper with
the register_helper_missing
method:
handlebars = Handlebars::Engine.new
handlebars.register_helper_missing do |ctx, *args, opts|
"Missing: #{opts["name"]}(#{args.join(", ")})"
end
template = handlebars.compile("{{foo 2 true}}")
template.call
# => "Missing: foo(2, true)"
template = handlebars.compile("{{#foo true}}{{/foo}}")
template.call
# => "Missing: foo(true)"
See https://handlebarsjs.com/guide/hooks.html#helpermissing.
This hook is called for a block-statement when
- a block-expression calls a helper that is not registered, and
- the name is a property of the current evaluation context.
You can add custom handling for those situations by registering a helper with
the register_helper_missing
method (with a :block
argument):
handlebars = Handlebars::Engine.new
handlebars.register_helper_missing(:block) do |ctx, *args, opts|
"Missing: #{opts["name"]}(#{args.join(", ")})"
end
template = handlebars.compile("{{#person}}{{name}}{{/person}}")
template.call({ person: { name: "Yehuda Katz" } })
# => "Missing: person"
See https://handlebarsjs.com/guide/hooks.html#blockhelpermissing.
This hook is called for a partial that is not registered.
handlebars = Handlebars::Engine.new
handlebars.register_partial_missing do |name|
"partial: #{name}"
end
Note: This is not a part of the offical Handlebars API. It is provided for convenience.
See CHANGELOG.md for more details.
Bug reports and pull requests are welcome on GitHub: https://github.com/gi/handlebars-ruby.
See CONTRIBUTING.md for more details.
The gem is available as open source under the terms of the MIT License.