Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MiniRacer remix #53

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: ci
on: push
# push:
# tags:
# - '*'
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: RSpec
run: bundle exec rspec spec/
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
dist/dev-unmanual-${{ github.ref }}.pdf%
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ pkg/*
.bundle
Gemfile.lock
.ruby-gemset
.ruby-version
vendor/
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.7.5
7 changes: 0 additions & 7 deletions .travis.yml

This file was deleted.

13 changes: 13 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
# 0.1.0

* Smolbars rename
* Replace therubyracer with mini_racer
* No more invoking Ruby from JS
* We build templates through string concatentation. Do not pass in untrusted handlebars templates.
* All data passed to JS environment is serialized with JSON
* Remove support for partial_missing, it's deprecated since handlebars 4.3.0
* Remove precompiling (doesn't seem useful in the ruby setting)
* Remove setting data from ruby (use eval and do it yourself)
* Remove support for SafeString (use eval and do it yourself)

# 0.8.0

* bumped handlebars-source version to 4.0.5

# 0.2.3
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
source "https://rubygems.org"
# Specify your gem's dependencies in handlebars.gemspec
# Specify your gem's dependencies in smolbars.gemspec
gemspec
144 changes: 54 additions & 90 deletions README.mdown
Original file line number Diff line number Diff line change
@@ -1,123 +1,87 @@
## Handlebars.rb
## Smolbars

[![Gem Version](https://badge.fury.io/rb/handlebars.png)](http://badge.fury.io/rb/handlebars)
[![Gem Version](https://badge.fury.io/rb/smolbars.png)](http://badge.fury.io/rb/handlebars)
[![Build Status](https://travis-ci.org/cowboyd/handlebars.rb.png?branch=master)](https://travis-ci.org/cowboyd/handlebars.rb)
[![Dependency Status](https://gemnasium.com/cowboyd/handlebars.rb.png)](https://gemnasium.com/cowboyd/handlebars.rb)


This uses [therubyracer][1] to bind to the _actual_ JavaScript implementation of
[Handlebars.js][2] so that you can use it from ruby.
This uses [mini_racer][1] to bind to the _actual_ JavaScript implementation of
[Handlebars.js][2] so that you can use it from ruby. This is a fork of [handlebars.rb][3] to
change out the deprecated [therubyracer][4] JS integration. 99% the same idea as the better-named
[minibars][5].

Please be mindful of how this library works: it brings in the full libv8 JS VM to your ruby environment. Each
`Context` is a full blown JS machine (memory management, JIT, etc). This fork does not support attaching ruby
functions to the JS VM.

Note on security: do not compile untrusted Handlebars templates. We compile Handlebars template by building ad-hoc
javascript statements, a bad actor could perform an SQL-injection like attack using the v8 environment for bad things.

## Usage

### Simple stuff

require 'handlebars'
handlebars = Handlebars::Context.new
template = handlebars.compile("{{say}} {{what}}")
require 'smolbars'
smolbars = Smolbars::Context.new
template = smolbars.compile("{{say}} {{what}}")
template.call(:say => "Hey", :what => "Yuh!") #=> "Hey Yuh!"

### functions as properties

template.call(:say => "Hey ", :what => lambda {|this| ("yo" * 2) + "!"}) #=> "Hey yoyo!"

### Block Helpers:

Just like JavaScript, you can write block helpers with an `{{else}}` section. To print
out a section twice if a condition is met:

# V8 maps the first argument sent to a block to "this". All subsequent arguments are as
# described in the Handlebars documentation.
handlebars.register_helper(:twice) do |context, condition, block|
if condition
"#{block.fn(context)}#{block.fn(context)}"
else
block.inverse(context)
end
end
template = handlebars.compile("{{#twice foo}}Hurray!{{else}}Boo!{{/twice}}")
template.call(foo: true) #=> Hurray!Hurray!
template.call(foo: false) #=> Boo!

### Private variables:

Just like JavaScript, block helpers can inject private variables into their child templates.
These can be accessed in a template using the `@` prefix:

handlebars.register_helper(:list) do |this, context, block|
"<ul>" + context.each_with_index.map do |x, i|
if block.keys.include? "data"
data = handlebars.create_frame(block.data)
data.index = i
end
"<li>" + block.fn(x, data: data) + "</li>"
end.join + "</ul>"
end
template = handlebars.compile("{{#list array}}{{@index}}. {{title}}{{/list}}")
template.call(array: [{title: "Memento"}, {title: "Inception"}])
#=> "<ul><li>0. Memento</li><li>1. Inception</li></ul>"
### Helpers

### Hash arguments:
You must write helpers with JavaScript. The JavaScript code should include calls to the Handlebars class registration
function.

When using hash arguments, beware of one gotcha - V8 defines the #hash method for every
object. Therefore, to access the hash object of the options argument Handlebars sends to your
block, you must use the `[]` method:
require 'smolbars'
helper = %Q{
Handlebars.registerHelper("nthTimes", function(n, options){
var buffer = "";

handlebars.register_helper :list do |this, context, options|
attrs = options[:hash].map{|k,v| "#{k}=\"#{v}\""}.join(' ')
"<ul #{attrs}>" + context.map{|item| "<li>" + options.fn(item) + "</li>"}.join + "</ul>"
end
template = handlebars.compile(%({{#list nav id="nav-bar" class="top"}}<a href="{{url}}">{{title}}</a>{{/list}}))
template.call({nav: [{url: 'www.google.com', title: 'Google'}]})
#=> <ul class="top" id="nav-bar"><li><a href="www.google.com">Google</a></li></ul>
for(var i = 0; i < n; i++) {
buffer += options.fn();
}

### Safe Strings

By default, handlebars will escape strings that are returned by your block helpers. To
mark a string as safe:

template = handlebars.compile("{{safe}}")
template.call(:safe => proc {Handlebars::SafeString.new("<pre>Totally Safe!<pre>")})
return buffer;
});
}
smolbars = Smolbars::Context.new
smolbars.eval(helper)
template = smolbars.compile('{{#nthTimes 2}}yep {{/nthTimes}}hurrah!')
template.call # 'yep yep hurrah!'

### Partials

You can directly register partials

handlebars.register_partial("whoami", "I am {{who}}")
handlebars.compile("{{>whoami}}").call(:who => 'Legend') #=> I am Legend

Partials can also be dynamically looked up by defining a partial_missing behavior:
You must write partials with JavaScript. The JavaScript code should include calls to the Handlebars class registration
function.

handlebars.partial_missing do |name|
"unable to find >#{name}"
end
handlebars.compile("{{>missing}}").call #=> unable to find >missing

Missing partials can also be returned as a function:

count = 0
handlebars.partial_missing do |name|
lambda do |this, context, options|
count += 1
"#{count} miss(es) when trying to look up a partial"
end
end
t = handlebars.compile("{{>missing}}")
t.call #=> 1 miss(es) when trying to look up a partial
t.call #=> 2 miss(es) when tyring to look up a partial
require 'smolbars'
partial = %Q{
Handlebars.registerPartial("legend", "I am {{ who }}");
}
smolbars = Smolbars::Context.new
smolbars.eval(partial)
template = smolbars.compile('{{> legend}}')
template.call # 'I am Legend!'

### Security

In general, you should not trust user-provided templates: a template can call any method
(with no arguments) or access any property on any object in the `Handlebars::Context`.
(with no arguments) or access any property on any object in the `Smolbars::Context`.

If you'd like to render user-provided templates, you'd want to make sure you do so in a
sanitized Context, e.g. no filesystem access, read-only or no database access, etc.

You can try setting the timeout on a Smolbars::Context through kwargs that are passed to the
underlying JS instance

Smolbars::Context.new(timeout: 500)

## Test

rspec spec/


[1]: http://github.com/cowboyd/therubyracer "The Ruby Racer"
[2]: http://github.com/wycats/handlebars.js "Handlebars JavaScript templating library"
[1]: https://github.com/rubyjs/mini_racer "mini_racer"
[2]: https://github.com/wycats/handlebars.js "Handlebars JavaScript templating library"
[3]: https://github.com/cowboyd/handlebars.rb "Handlebars Ruby library"
[4]: https://github.com/cowboyd/therubyracer "The Ruby Racer"
[5]: https://github.com/combinaut/minibars "Minibars"
18 changes: 9 additions & 9 deletions handlebars.gemspec
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
require "./lib/handlebars/version"
require "./lib/smolbars/version"

Gem::Specification.new do |s|
s.name = "handlebars"
s.version = Handlebars::VERSION
s.authors = ["Charles Lowell"]
s.name = "smolbars"
s.version = Smolbars::VERSION
s.authors = ["Charles Lowell", "Xavier Lange"]
s.email = ["[email protected]"]
s.homepage = "https://github.com/cowboyd/handlebars.rb"
s.summary = "Ruby bindings for the handlebars.js templating library"
s.description = "Uses the actual JavaScript implementation of Handlebars, but supports using Ruby objects as template contexts and Ruby procs as view functions and named helpers"
s.homepage = "https://github.com/cowboyd/smolbars.rb"
s.summary = "Ruby bindings for the smolbars.js templating library"
s.description = "Uses the actual JavaScript implementation of Handlebars"
s.license = "MIT"

s.files = `git ls-files lib README.mdown`.split("\n")

s.add_dependency "therubyracer", "~> 0.12.1"
s.add_dependency "handlebars-source", "~> 4.0.5"
s.add_dependency "mini_racer"
s.add_dependency "handlebars-source"
s.add_development_dependency "rake"
s.add_development_dependency "rspec", "~> 2.0"
end
7 changes: 0 additions & 7 deletions lib/handlebars.rb

This file was deleted.

68 changes: 0 additions & 68 deletions lib/handlebars/context.rb

This file was deleted.

23 changes: 0 additions & 23 deletions lib/handlebars/partials.rb

This file was deleted.

11 changes: 0 additions & 11 deletions lib/handlebars/safe_string.rb

This file was deleted.

Loading