handlebars-engine 0.1.0 → 0.3.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/README.md +176 -3
- data/lib/handlebars/engine/function.rb +27 -0
- data/lib/handlebars/engine/init.js +43 -0
- data/lib/handlebars/engine/version.rb +2 -2
- data/lib/handlebars/engine.rb +228 -1
- data/lib/handlebars-engine.rb +3 -0
- metadata +51 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93107a1a86ac4a02cadbbfd8221cba9515ff839e948e39dc37c61a3de1d15400
|
4
|
+
data.tar.gz: '0091362554954a3f86ab24b7c0bc701595818b9b72af4b8780bccd3d6e4193ec'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cd86ebb6fbeb64acd29dc3c4cb0f6853a7193983c53e05d32e42490a38b70f37c8d99ae7b214e3f76923c7931b46c1d3dcda1326339dfcdfa00ec29be745ae9
|
7
|
+
data.tar.gz: 6f5fd77a08e73e9f2b9f40c1c769f2eca5a0359a35e9aa02ca9fd7d430e83e8f61d6c26541f0b2bbaf5caf3ff990663962cdedfc5dd61e8892c842a8b6404fec
|
data/CHANGELOG.md
CHANGED
@@ -6,3 +6,51 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
|
+
|
10
|
+
## [0.3.2] - 2022-02-17
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
- `engine`: fixed issue with memory leak ([#15](https://github.com/gi/handlebars-ruby/pull/15))
|
14
|
+
|
15
|
+
## [0.3.1] - 2022-02-04
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- `engine`: added `Error` class
|
19
|
+
- `specs`: added tests for (pre)compiling with options
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
- `gem`/`readme`: updated description
|
23
|
+
|
24
|
+
## [0.3.0] - 2022-01-31
|
25
|
+
|
26
|
+
### Added
|
27
|
+
- `initialize`: add path parameter ([#5](https://github.com/gi/handlebars-ruby/pull/5))
|
28
|
+
- `register_helper`: accept multiple helpers as keyword parameters ([#6](https://github.com/gi/handlebars-ruby/pull/6))
|
29
|
+
- `register_helper`: accept javascript function as string ([#7](https://github.com/gi/handlebars-ruby/pull/7))
|
30
|
+
- `ci`: verify gem builds ([#8](https://github.com/gi/handlebars-ruby/pull/8))
|
31
|
+
- `require`: allow loading from `handlebars-engine` and `handlebars/engine` ([#8](https://github.com/gi/handlebars-ruby/pull/8))
|
32
|
+
|
33
|
+
## [0.2.0] - 2022-01-27
|
34
|
+
|
35
|
+
This is the initial implementation, wrapping the JavaScript Handlebars.
|
36
|
+
|
37
|
+
### Added
|
38
|
+
- `Handlebars::Engine#compile`
|
39
|
+
- `Handlebars::Engine#precompile`
|
40
|
+
- `Handlebars::Engine#template`
|
41
|
+
- `Handlebars::Engine#register_helper`
|
42
|
+
- `Handlebars::Engine#unregister_helper`
|
43
|
+
- `Handlebars::Engine#register_partial`
|
44
|
+
- `Handlebars::Engine#unregister_partial`
|
45
|
+
- `Handlebars::Engine#register_helper_missing`
|
46
|
+
- `Handlebars::Engine#unregister_helper_missing`
|
47
|
+
- `Handlebars::Engine#register_partial_missing`
|
48
|
+
- `Handlebars::Engine#unregister_partial_missing`
|
49
|
+
- `Handlebars::Engine#version`
|
50
|
+
|
51
|
+
## [0.1.0] - 2022-01-13
|
52
|
+
|
53
|
+
This is the initial package.
|
54
|
+
|
55
|
+
### Added
|
56
|
+
- gem init
|
data/README.md
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
# Handlebars::Engine
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/handlebars-engine)
|
4
|
-
[](https://github.com/gi/handlebars-ruby/actions/workflows/ci.yml)
|
5
5
|
[](https://codeclimate.com/github/gi/handlebars-ruby/test_coverage)
|
6
6
|
[](https://codeclimate.com/github/gi/handlebars-ruby/maintainability)
|
7
7
|
[](LICENSE.txt)
|
8
8
|
|
9
|
-
A
|
9
|
+
A complete interface to [Handlebars.js](https://handlebarsjs.com) for Ruby.
|
10
|
+
|
11
|
+
`Handlebars::Engine` provides a complete Ruby API for the official JavaScript
|
12
|
+
version of Handlebars, including the abilities to register Ruby blocks/procs as
|
13
|
+
Handlebars helper functions and to dynamically register partials.
|
14
|
+
|
15
|
+
It uses [MiniRacer](https://github.com/rubyjs/mini_racer) for the bridge between
|
16
|
+
Ruby and the V8 JavaScript engine.
|
17
|
+
|
18
|
+
`Handlebars::Engine` was created as a replacement for
|
19
|
+
[handlebars.rb](https://github.com/cowboyd/handlebars.rb).
|
10
20
|
|
11
21
|
## Installation
|
12
22
|
|
@@ -26,7 +36,170 @@ Or install it yourself as:
|
|
26
36
|
|
27
37
|
## Usage
|
28
38
|
|
29
|
-
|
39
|
+
### Quick Start
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
handlebars = Handlebars::Engine.new
|
43
|
+
template = handlebars.compile("{{firstname}} {{lastname}}")
|
44
|
+
template.call({ firstname: "Yehuda", lastname: "Katz" })
|
45
|
+
# => "Yehuda Katz"
|
46
|
+
```
|
47
|
+
|
48
|
+
### Custom Helpers
|
49
|
+
|
50
|
+
Handlebars helpers can be accessed from any context in a template. You can
|
51
|
+
register a helper with the `register_helper` method:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
handlebars = Handlebars::Engine.new
|
55
|
+
handlebars.register_helper(:loud) do |ctx, arg, opts|
|
56
|
+
arg.upcase
|
57
|
+
end
|
58
|
+
template = handlebars.compile("{{firstname}} {{loud lastname}}")
|
59
|
+
template.call({ firstname: "Yehuda", lastname: "Katz" })
|
60
|
+
# => "Yehuda KATZ"
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Helper Arguments
|
64
|
+
|
65
|
+
Helpers receive the current context as the first argument of the block.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
handlebars = Handlebars::Engine.new
|
69
|
+
handlebars.register_helper(:full_name) do |ctx, opts|
|
70
|
+
"#{ctx["firstname"]} #{ctx["lastname"]}"
|
71
|
+
end
|
72
|
+
template = handlebars.compile("{{full_name}}")
|
73
|
+
template.call({ firstname: "Yehuda", lastname: "Katz" })
|
74
|
+
# => "Yehuda Katz"
|
75
|
+
```
|
76
|
+
|
77
|
+
Any arguments to the helper are included as individual positional arguments.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
handlebars = Handlebars::Engine.new
|
81
|
+
handlebars.register_helper(:join) do |ctx, *args, opts|
|
82
|
+
args.join(" ")
|
83
|
+
end
|
84
|
+
template = handlebars.compile("{{join firstname lastname}}")
|
85
|
+
template.call({ firstname: "Yehuda", lastname: "Katz" })
|
86
|
+
# => "Yehuda Katz"
|
87
|
+
```
|
88
|
+
|
89
|
+
The last argument is a hash of options.
|
90
|
+
|
91
|
+
See https://handlebarsjs.com/guide/#custom-helpers.
|
92
|
+
|
93
|
+
### Block Helpers
|
94
|
+
|
95
|
+
Block helpers make it possible to define custom iterators and other
|
96
|
+
functionality that can invoke the passed block with a new context.
|
97
|
+
|
98
|
+
Currently, there is a limitation with the underlying JavaScript engine: it does
|
99
|
+
not allow for reentrant calls from within attached Ruby functions: see
|
100
|
+
[MiniRacer#225](https://github.com/rubyjs/mini_racer/issues/225). Thus, the
|
101
|
+
block function returned to the helper (in `options.fn`) cannot be invoked.
|
102
|
+
|
103
|
+
Thus, for block helpers, a string of JavaScript must define the helper function:
|
104
|
+
```ruby
|
105
|
+
handlebars = Handlebars::Engine.new
|
106
|
+
handlebars.register_helper(map: <<~JS)
|
107
|
+
function(...args) {
|
108
|
+
const ctx = this;
|
109
|
+
const opts = args.pop();
|
110
|
+
const items = args[0];
|
111
|
+
const separator = args[1];
|
112
|
+
const mapped = items.map((item) => opts.fn(item));
|
113
|
+
return mapped.join(separator);
|
114
|
+
}
|
115
|
+
JS
|
116
|
+
template = handlebars.compile("{{#map items '|'}}'{{this}}'{{/map}}")
|
117
|
+
template.call({ items: [1, 2, 3] })
|
118
|
+
# => "'1'|2'|'3'"
|
119
|
+
```
|
120
|
+
|
121
|
+
See https://handlebarsjs.com/guide/#block-helpers.
|
122
|
+
|
123
|
+
### Partials
|
124
|
+
|
125
|
+
Handlebars partials allow for code reuse by creating shared templates.
|
126
|
+
|
127
|
+
You can register a partial using the `register_partial` method:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
handlebars = Handlebars::Engine.new
|
131
|
+
handlebars.register_partial(:person, "{{person.name}} is {{person.age}}.")
|
132
|
+
template = handlebars.compile("{{> person person=.}}")
|
133
|
+
template.call({ name: "Yehuda Katz", age: 20 })
|
134
|
+
# => "Yehuda Katz is 20."
|
135
|
+
```
|
136
|
+
|
137
|
+
See https://handlebarsjs.com/guide/#partials.
|
138
|
+
See https://handlebarsjs.com/guide/partials.html.
|
139
|
+
|
140
|
+
### Hooks
|
141
|
+
|
142
|
+
#### Helper Missing
|
143
|
+
|
144
|
+
This hook is called for a mustache or a block-statement when
|
145
|
+
* a simple mustache-expression is not a registered helper, *and*
|
146
|
+
* it is not a property of the current evaluation context.
|
147
|
+
|
148
|
+
You can add custom handling for those situations by registering a helper with
|
149
|
+
the `register_helper_missing` method:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
handlebars = Handlebars::Engine.new
|
153
|
+
handlebars.register_helper_missing do |ctx, *args, opts|
|
154
|
+
"Missing: #{opts["name"]}(#{args.join(", ")})"
|
155
|
+
end
|
156
|
+
|
157
|
+
template = handlebars.compile("{{foo 2 true}}")
|
158
|
+
template.call
|
159
|
+
# => "Missing: foo(2, true)"
|
160
|
+
|
161
|
+
template = handlebars.compile("{{#foo true}}{{/foo}}")
|
162
|
+
template.call
|
163
|
+
# => "Missing: foo(true)"
|
164
|
+
```
|
165
|
+
|
166
|
+
See https://handlebarsjs.com/guide/hooks.html#helpermissing.
|
167
|
+
|
168
|
+
##### Blocks
|
169
|
+
|
170
|
+
This hook is called for a block-statement when
|
171
|
+
* a block-expression calls a helper that is not registered, *and*
|
172
|
+
* the name is a property of the current evaluation context.
|
173
|
+
|
174
|
+
You can add custom handling for those situations by registering a helper with
|
175
|
+
the `register_helper_missing` method (with a `:block` argument):
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
handlebars = Handlebars::Engine.new
|
179
|
+
handlebars.register_helper_missing(:block) do |ctx, *args, opts|
|
180
|
+
"Missing: #{opts["name"]}(#{args.join(", ")})"
|
181
|
+
end
|
182
|
+
|
183
|
+
template = handlebars.compile("{{#person}}{{name}}{{/person}}")
|
184
|
+
template.call({ person: { name: "Yehuda Katz" } })
|
185
|
+
# => "Missing: person"
|
186
|
+
```
|
187
|
+
|
188
|
+
See https://handlebarsjs.com/guide/hooks.html#blockhelpermissing.
|
189
|
+
|
190
|
+
#### Partial Missing
|
191
|
+
|
192
|
+
This hook is called for a partial that is not registered.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
handlebars = Handlebars::Engine.new
|
196
|
+
handlebars.register_partial_missing do |name|
|
197
|
+
"partial: #{name}"
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
Note: This is not a part of the offical Handlebars API. It is provided for
|
202
|
+
convenience.
|
30
203
|
|
31
204
|
## Changelog
|
32
205
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Handlebars
|
4
|
+
class Engine
|
5
|
+
# A proxy for a JavaScript function defined in the context.
|
6
|
+
class Function
|
7
|
+
def initialize(context, name)
|
8
|
+
@context = context
|
9
|
+
@name = name
|
10
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(context, name))
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(*args)
|
14
|
+
@context.call(@name, *args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.finalizer(context, name)
|
18
|
+
proc {
|
19
|
+
begin
|
20
|
+
context.eval("delete #{name}")
|
21
|
+
rescue ThreadError # rubocop:disable Lint/SuppressedException
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
var {
|
2
|
+
compile,
|
3
|
+
precompile,
|
4
|
+
registerPartial,
|
5
|
+
unregisterPartial,
|
6
|
+
registerHelper,
|
7
|
+
unregisterHelper,
|
8
|
+
VERSION,
|
9
|
+
} = Handlebars;
|
10
|
+
|
11
|
+
var template = (spec) => {
|
12
|
+
eval(`spec = ${spec}`);
|
13
|
+
return Handlebars.template(spec);
|
14
|
+
};
|
15
|
+
|
16
|
+
var registerPartial = Handlebars.registerPartial.bind(Handlebars);
|
17
|
+
var unregisterPartial = Handlebars.unregisterPartial.bind(Handlebars);
|
18
|
+
|
19
|
+
var registerHelper = (...args) => {
|
20
|
+
const fn = args[args.length - 1];
|
21
|
+
function wrapper(...args) {
|
22
|
+
args.unshift(this);
|
23
|
+
return fn(...args);
|
24
|
+
}
|
25
|
+
args[args.length - 1] = wrapper;
|
26
|
+
return Handlebars.registerHelper(...args);
|
27
|
+
};
|
28
|
+
|
29
|
+
var unregisterHelper = Handlebars.unregisterHelper.bind(Handlebars);
|
30
|
+
|
31
|
+
var partialMissing;
|
32
|
+
|
33
|
+
const partialsHandler = {
|
34
|
+
get(partials, name) {
|
35
|
+
const partial = partials[name] ?? partialMissing?.(name);
|
36
|
+
if (partial) {
|
37
|
+
partials[name] = partial;
|
38
|
+
}
|
39
|
+
return partial;
|
40
|
+
},
|
41
|
+
};
|
42
|
+
|
43
|
+
Handlebars.partials = new Proxy(Handlebars.partials, partialsHandler);
|
data/lib/handlebars/engine.rb
CHANGED
@@ -1,9 +1,236 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "handlebars/source"
|
4
|
+
require "json"
|
5
|
+
require "mini_racer"
|
6
|
+
require "securerandom"
|
7
|
+
require_relative "engine/function"
|
3
8
|
require_relative "engine/version"
|
4
9
|
|
5
10
|
module Handlebars
|
6
11
|
# The Handlebars engine.
|
7
|
-
|
12
|
+
#
|
13
|
+
# This API follows the JavaScript API as closely as possible:
|
14
|
+
# https://handlebarsjs.com/api-reference/.
|
15
|
+
class Engine
|
16
|
+
Error = MiniRacer::RuntimeError
|
17
|
+
|
18
|
+
# Creates a new instance.
|
19
|
+
#
|
20
|
+
# @param lazy [true, false] immediately loads and initializes the JavaScript
|
21
|
+
# environment.
|
22
|
+
# @param path [String, nil] the path to the version of Handlebars to load.
|
23
|
+
# If `nil`, the contents of `Handlebars::Source.bundled_path` is loaded.
|
24
|
+
def initialize(lazy: false, path: nil)
|
25
|
+
@path = path
|
26
|
+
init! unless lazy
|
27
|
+
end
|
28
|
+
|
29
|
+
###################################
|
30
|
+
# Compilation
|
31
|
+
###################################
|
32
|
+
|
33
|
+
# Compiles a template so it can be executed immediately.
|
34
|
+
#
|
35
|
+
# @param template [String] the template string to compile
|
36
|
+
# @param options [Hash] the options
|
37
|
+
# @return [Proc] the template function to call
|
38
|
+
# @see https://handlebarsjs.com/api-reference/compilation.html#handlebars-compile-template-options
|
39
|
+
def compile(*args)
|
40
|
+
call(__method__, args, assign: true)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Precompiles a given template so it can be executed without compilation.
|
44
|
+
#
|
45
|
+
# @param template [String] the template string to precompiled
|
46
|
+
# @param options [Hash] the options
|
47
|
+
# @return [String] the precompiled template spec
|
48
|
+
# @see https://handlebarsjs.com/api-reference/compilation.html#handlebars-precompile-template-options
|
49
|
+
def precompile(*args)
|
50
|
+
call(__method__, args)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets up a template that was precompiled with `precompile`.
|
54
|
+
#
|
55
|
+
# @param spec [String] the precompiled template spec
|
56
|
+
# @return [Proc] the template function to call
|
57
|
+
# @see #precompile
|
58
|
+
# @see https://handlebarsjs.com/api-reference/compilation.html#handlebars-template-templatespec
|
59
|
+
def template(*args)
|
60
|
+
call(__method__, args, assign: true)
|
61
|
+
end
|
62
|
+
|
63
|
+
###################################
|
64
|
+
# Runtime
|
65
|
+
###################################
|
66
|
+
|
67
|
+
# Registers helpers accessible by any template in the environment.
|
68
|
+
#
|
69
|
+
# The function can be either a proc or a string:
|
70
|
+
# * When the function is a proc, it can be either passed in as a normal
|
71
|
+
# parameter or as a block.
|
72
|
+
# * When the function is a string, it is interpreted as a JavaScript
|
73
|
+
# function.
|
74
|
+
#
|
75
|
+
# @param name [String, Symbol] the name of the helper
|
76
|
+
# @param function [Proc, String] the helper function
|
77
|
+
# @yieldparam context [Hash] the current context
|
78
|
+
# @yieldparam arguments [Object] the arguments (optional)
|
79
|
+
# @yieldparam options [Hash] the options hash (optional)
|
80
|
+
# @see https://handlebarsjs.com/api-reference/runtime.html#handlebars-registerhelper-name-helper
|
81
|
+
def register_helper(name = nil, function = nil, **helpers, &block)
|
82
|
+
helpers[name] = block || function if name
|
83
|
+
helpers.each do |n, f|
|
84
|
+
case f
|
85
|
+
when Proc
|
86
|
+
attach(n, &f)
|
87
|
+
evaluate("registerHelper('#{n}', #{n})")
|
88
|
+
when String, Symbol
|
89
|
+
evaluate("Handlebars.registerHelper('#{n}', #{f})")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Unregisters a previously registered helper.
|
95
|
+
#
|
96
|
+
# @param name [String, Symbol] the name of the helper
|
97
|
+
# @see https://handlebarsjs.com/api-reference/runtime.html#handlebars-unregisterhelper-name
|
98
|
+
def unregister_helper(name)
|
99
|
+
call(:unregisterHelper, [name])
|
100
|
+
end
|
101
|
+
|
102
|
+
# Registers partials accessible by any template in the environment.
|
103
|
+
#
|
104
|
+
# @param name [String, Symbol] the name of the partial
|
105
|
+
# @param partial [String] the partial template
|
106
|
+
# @see https://handlebarsjs.com/api-reference/runtime.html#handlebars-registerpartial-name-partial
|
107
|
+
def register_partial(name = nil, partial = nil, **partials)
|
108
|
+
partials[name] = partial if name
|
109
|
+
call(:registerPartial, [partials])
|
110
|
+
end
|
111
|
+
|
112
|
+
# Unregisters a previously registered partial.
|
113
|
+
#
|
114
|
+
# @param name [String, Symbol] the name of the partial
|
115
|
+
# @see https://handlebarsjs.com/api-reference/runtime.html#handlebars-unregisterpartial-name
|
116
|
+
def unregister_partial(name)
|
117
|
+
call(:unregisterPartial, [name])
|
118
|
+
end
|
119
|
+
|
120
|
+
###################################
|
121
|
+
# Hooks
|
122
|
+
###################################
|
123
|
+
|
124
|
+
# Registers the hook called when a mustache or a block-statement is missing.
|
125
|
+
#
|
126
|
+
# @param type [Symbol] the type of hook to register (`:basic` or `:block`)
|
127
|
+
# @yieldparam arguments [Object] the arguments (optional)
|
128
|
+
# @yieldparam options [Hash] the options hash (optional)
|
129
|
+
# @see https://handlebarsjs.com/guide/hooks.html#helpermissing
|
130
|
+
def register_helper_missing(type = :basic, &block)
|
131
|
+
name = helper_missing_name(type)
|
132
|
+
register_helper(name, &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Unregisters the previously registered hook.
|
136
|
+
#
|
137
|
+
# @param type [Symbol] the type of hook to register (`:basic` or `:block`)
|
138
|
+
# @see https://handlebarsjs.com/guide/hooks.html#helpermissing
|
139
|
+
def unregister_helper_missing(type = :basic)
|
140
|
+
name = helper_missing_name(type)
|
141
|
+
unregister_helper(name)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Registers the hook called when a partial is missing.
|
145
|
+
#
|
146
|
+
# Note: This is not a part of the offical Handlebars API. It is provided for
|
147
|
+
# convenience.
|
148
|
+
#
|
149
|
+
# @yieldparam name [String] the name of the undefined partial
|
150
|
+
def register_partial_missing(&block)
|
151
|
+
attach(:partialMissing, &block)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Unregisters the previously registered hook.
|
155
|
+
def unregister_partial_missing
|
156
|
+
evaluate("delete partialMissing")
|
157
|
+
end
|
158
|
+
|
159
|
+
###################################
|
160
|
+
# Miscellaneous
|
161
|
+
###################################
|
162
|
+
|
163
|
+
# Returns the version of Handlebars.
|
164
|
+
#
|
165
|
+
# @return [String] the Handlebars version.
|
166
|
+
def version
|
167
|
+
evaluate("VERSION")
|
168
|
+
end
|
169
|
+
|
170
|
+
###################################
|
171
|
+
# Private
|
172
|
+
###################################
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def attach(name, &block)
|
177
|
+
init!
|
178
|
+
@context.attach(name.to_s, block)
|
179
|
+
end
|
180
|
+
|
181
|
+
def call(name, args, assign: false, eval: false)
|
182
|
+
init!
|
183
|
+
name = name.to_s
|
184
|
+
|
185
|
+
if assign || eval
|
186
|
+
call_via_eval(name, args, assign: assign)
|
187
|
+
else
|
188
|
+
@context.call(name, *args)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def call_via_eval(name, args, assign: false)
|
193
|
+
args = js_args(args)
|
194
|
+
|
195
|
+
var = assign ? "v#{SecureRandom.alphanumeric}" : nil
|
196
|
+
|
197
|
+
code = "#{name}(#{args.join(", ")})"
|
198
|
+
code = "#{var} = #{code}" if var
|
199
|
+
|
200
|
+
result = evaluate(code)
|
201
|
+
|
202
|
+
if var && result.is_a?(MiniRacer::JavaScriptFunction)
|
203
|
+
result = Function.new(@context, var)
|
204
|
+
end
|
205
|
+
|
206
|
+
result
|
207
|
+
end
|
208
|
+
|
209
|
+
def evaluate(code)
|
210
|
+
@context.eval(code)
|
211
|
+
end
|
212
|
+
|
213
|
+
def helper_missing_name(type)
|
214
|
+
case type
|
215
|
+
when :basic
|
216
|
+
:helperMissing
|
217
|
+
when :block
|
218
|
+
:blockHelperMissing
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def init!
|
223
|
+
return if @init
|
224
|
+
|
225
|
+
@context = MiniRacer::Context.new
|
226
|
+
@context.load(@path || ::Handlebars::Source.bundled_path)
|
227
|
+
@context.load(File.absolute_path("engine/init.js", __dir__))
|
228
|
+
|
229
|
+
@init = true
|
230
|
+
end
|
231
|
+
|
232
|
+
def js_args(args)
|
233
|
+
args.map { |arg| JSON.generate(arg) }
|
234
|
+
end
|
8
235
|
end
|
9
236
|
end
|
metadata
CHANGED
@@ -1,18 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: handlebars-engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Gianos
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2022-02-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: handlebars-source
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mini_racer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: |2
|
42
|
+
A complete interface to Handlebars.js for Ruby.
|
43
|
+
|
44
|
+
Handlebars::Engine provides a complete Ruby API for the official JavaScript
|
45
|
+
version of Handlebars, including the abilities to register Ruby blocks/procs
|
46
|
+
as Handlebars helper functions and to dynamically register partials.
|
47
|
+
|
48
|
+
It uses MiniRacer for the bridge between Ruby and the V8 JavaScript engine.
|
49
|
+
|
50
|
+
Handlebars::Engine was created as a replacement for handlebars.rb.
|
14
51
|
email:
|
15
|
-
- zach.gianos@gmail.com
|
52
|
+
- zach.gianos+git@gmail.com
|
16
53
|
executables:
|
17
54
|
- handlebars
|
18
55
|
extensions: []
|
@@ -22,17 +59,20 @@ files:
|
|
22
59
|
- LICENSE
|
23
60
|
- README.md
|
24
61
|
- exe/handlebars
|
62
|
+
- lib/handlebars-engine.rb
|
25
63
|
- lib/handlebars/engine.rb
|
64
|
+
- lib/handlebars/engine/function.rb
|
65
|
+
- lib/handlebars/engine/init.js
|
26
66
|
- lib/handlebars/engine/version.rb
|
27
67
|
homepage: https://github.com/gi/handlebars-ruby
|
28
68
|
licenses:
|
29
69
|
- MIT
|
30
70
|
metadata:
|
31
71
|
changelog_uri: https://github.com/gi/handlebars-ruby/CHANGELOG.md
|
72
|
+
github_repo: https://github.com/gi/handlebars-ruby
|
32
73
|
homepage_uri: https://github.com/gi/handlebars-ruby
|
33
|
-
rubygems_mfa_required: 'true'
|
34
74
|
source_code_uri: https://github.com/gi/handlebars-ruby
|
35
|
-
post_install_message:
|
75
|
+
post_install_message:
|
36
76
|
rdoc_options: []
|
37
77
|
require_paths:
|
38
78
|
- lib
|
@@ -47,8 +87,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
87
|
- !ruby/object:Gem::Version
|
48
88
|
version: '0'
|
49
89
|
requirements: []
|
50
|
-
rubygems_version: 3.
|
51
|
-
signing_key:
|
90
|
+
rubygems_version: 3.3.3
|
91
|
+
signing_key:
|
52
92
|
specification_version: 4
|
53
|
-
summary: A
|
93
|
+
summary: A complete interface to Handlebars.js for Ruby.
|
54
94
|
test_files: []
|