Skip to content

Commit 6d735cf

Browse files
authored
Merge pull request #29 from gi/v0.3.4
V0.3.4
2 parents 04eaa96 + 05d442d commit 6d735cf

9 files changed

Lines changed: 84 additions & 18 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,15 @@ jobs:
6060
strategy:
6161
matrix:
6262
os:
63+
- macos-14
6364
- macos-latest
65+
- ubuntu-22.04
6466
- ubuntu-latest
6567
ruby:
66-
- ruby-2.6
67-
- ruby-2.7
68-
- ruby-3.0
6968
- ruby-3.1
69+
- ruby-3.2
70+
- ruby-3.3
71+
- ruby-3.4
7072
# - jruby
7173
# - truffleruby
7274
runs-on: ${{ matrix.os }}

.rubocop.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
require:
1+
plugins:
22
- rubocop-performance
33
- rubocop-rake
44
- rubocop-rspec
55

66
AllCops:
7-
TargetRubyVersion: 2.6
7+
TargetRubyVersion: 3.0
88
Exclude:
99
- bin/**/*
1010
- vendor/**/*
@@ -148,6 +148,9 @@ RSpec/ExampleLength:
148148
- hash
149149
- heredoc
150150

151+
RSpec/IncludeExamples:
152+
Enabled: false
153+
151154
RSpec/MultipleMemoizedHelpers:
152155
Max: 20
153156

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.3.4] - 2025-08-12
11+
12+
### Changed
13+
- `engine`: fixed issue with serialization of functions ([#26](https://github.com/gi/handlebars-ruby/pull/26))
14+
- `engine`: include optional logging ([#24](https://github.com/gi/handlebars-ruby/pull/24))
15+
- `ci`: test against macOS 14, Ubuntu 22.04, and ruby 3.1-3.4 ([#27](https://github.com/gi/handlebars-ruby/pull/27))
16+
1017
## [0.3.3] - 2022-02-17
1118

1219
### Changed

handlebars-engine.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
2323

2424
spec.homepage = "https://github.com/gi/handlebars-ruby"
2525
spec.license = "MIT"
26-
spec.required_ruby_version = ">= 2.6.0"
26+
spec.required_ruby_version = ">= 3.0"
2727

2828
spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
2929
spec.metadata["github_repo"] = spec.homepage

lib/handlebars/engine.rb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ class Engine
2121
# environment.
2222
# @param path [String, nil] the path to the version of Handlebars to load.
2323
# If `nil`, the contents of `Handlebars::Source.bundled_path` is loaded.
24-
def initialize(lazy: false, path: nil)
24+
def initialize(lazy: false, logger: nil, path: nil)
25+
@logger = logger
2526
@path = path
2627
init! unless lazy
2728
end
@@ -84,9 +85,9 @@ def register_helper(name = nil, function = nil, **helpers, &block)
8485
case f
8586
when Proc
8687
attach(n, &f)
87-
evaluate("registerHelper('#{n}', #{n})")
88+
evaluate("registerRbHelper('#{n}', #{n})")
8889
when String, Symbol
89-
evaluate("Handlebars.registerHelper('#{n}', #{f})")
90+
evaluate("registerJsHelper('#{n}', #{f})")
9091
end
9192
end
9293
end
@@ -175,13 +176,16 @@ def version
175176

176177
def attach(name, &block)
177178
init!
179+
@logger&.debug { "[handlebars] attaching #{name}" }
178180
@context.attach(name.to_s, block)
179181
end
180182

181183
def call(name, args, assign: false, eval: false)
182184
init!
183185
name = name.to_s
184186

187+
@logger&.debug { "[handlebars] calling #{name} with args #{args}" }
188+
185189
if assign || eval
186190
call_via_eval(name, args, assign: assign)
187191
else
@@ -207,6 +211,7 @@ def call_via_eval(name, args, assign: false)
207211
end
208212

209213
def evaluate(code)
214+
@logger&.debug { "[handlebars] evaluating #{code}" }
210215
@context.eval(code)
211216
end
212217

@@ -222,10 +227,18 @@ def helper_missing_name(type)
222227
def init!
223228
return if @init
224229

230+
@logger&.debug { "[handlebars] initializing" }
231+
225232
@context = MiniRacer::Context.new
233+
@context.attach(
234+
"console.log",
235+
->(*args) { @logger&.debug { "[handlebars] #{args.join(" ")}" } },
236+
)
226237
@context.load(@path || ::Handlebars::Source.bundled_path)
227238
@context.load(File.absolute_path("engine/init.js", __dir__))
228239

240+
@logger&.debug { "[handlebars] initialized" }
241+
229242
@init = true
230243
end
231244

lib/handlebars/engine/function.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ module Handlebars
44
class Engine
55
# A proxy for a JavaScript function defined in the context.
66
class Function
7-
def initialize(context, name)
7+
def initialize(context, name, logger: nil)
88
@context = context
9+
@logger = logger
910
@name = name
1011
end
1112

1213
def call(*args)
14+
@logger&.debug { "[handlebars] calling #{@name} with args #{args}" }
1315
@context.call(@name, *args)
1416
end
1517
end

lib/handlebars/engine/init.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,23 @@ var template = (spec) => {
1616
var registerPartial = Handlebars.registerPartial.bind(Handlebars);
1717
var unregisterPartial = Handlebars.unregisterPartial.bind(Handlebars);
1818

19-
var registerHelper = (...args) => {
20-
const fn = args[args.length - 1];
19+
var registerJsHelper = Handlebars.registerHelper.bind(Handlebars);
20+
21+
var registerRbHelper = (name, fn) => {
2122
function wrapper(...args) {
23+
// Ruby cannot access the `this` context, so pass it as the first argument.
2224
args.unshift(this);
25+
const { ...options } = args[args.length-1];
26+
Object.entries(options).forEach(([key, value]) => {
27+
if (typeof value === "function") {
28+
// functions are cannot be passed back to Ruby
29+
options[key] = "function";
30+
}
31+
});
32+
args[args.length-1] = options
2333
return fn(...args);
2434
}
25-
args[args.length - 1] = wrapper;
26-
return Handlebars.registerHelper(...args);
35+
return registerJsHelper(name, wrapper);
2736
};
2837

2938
var unregisterHelper = Handlebars.unregisterHelper.bind(Handlebars);

lib/handlebars/engine/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module Handlebars
44
class Engine
5-
VERSION = "0.3.3"
5+
VERSION = "0.3.4"
66
end
77
end

spec/handlebars/engine_spec.rb

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
# frozen_string_literal: true
22

3+
require "logger"
34
require "tempfile"
45

56
RSpec.describe Handlebars::Engine do
67
let(:engine) { described_class.new(**engine_options) }
78
let(:engine_context) { engine.instance_variable_get(:@context) }
89
let(:engine_options) { {} }
10+
let(:log) { Tempfile.new }
11+
let(:logger) { Logger.new(log, level: Logger::FATAL) }
912
let(:render) { renderer.call(render_context, render_options) }
1013
let(:render_context) { { name: "Zach", age: 30 } }
1114
let(:render_options) { {} }
@@ -40,7 +43,26 @@
4043
end
4144

4245
it "does not create the context" do
43-
expect(engine_context).to be nil
46+
expect(engine_context).to be_nil
47+
end
48+
end
49+
50+
context "when `logger` is defined" do
51+
before do
52+
engine_options[:logger] = logger
53+
logger.debug!
54+
end
55+
56+
it "logs initialization" do
57+
engine
58+
log.rewind
59+
expect(log.read).to include("[handlebars] initializing")
60+
end
61+
62+
it "logs javascript" do
63+
engine.send(:evaluate, "console.log('js', 'log')")
64+
log.rewind
65+
expect(log.read).to include("[handlebars] js log")
4466
end
4567
end
4668

@@ -255,7 +277,7 @@
255277
describe "the options" do
256278
it "includes the main block function" do
257279
opts = include(
258-
"fn" => kind_of(MiniRacer::JavaScriptFunction),
280+
"fn" => "function", # kind_of(MiniRacer::JavaScriptFunction),
259281
)
260282
args = [anything, any_args, opts]
261283
render
@@ -264,7 +286,7 @@
264286

265287
it "includes the else block function" do
266288
opts = include(
267-
"inverse" => kind_of(MiniRacer::JavaScriptFunction),
289+
"inverse" => "function", # kind_of(MiniRacer::JavaScriptFunction),
268290
)
269291
args = [anything, any_args, opts]
270292
render
@@ -279,6 +301,14 @@
279301
<<~JS
280302
function (...args) {
281303
args.unshift(this);
304+
const { ...options } = args[args.length-1];
305+
Object.entries(options).forEach(([key, value]) => {
306+
if (typeof value === "function") {
307+
// functions are cannot be passed back to Ruby
308+
options[key] = "function";
309+
}
310+
});
311+
args[args.length-1] = options
282312
return tester(...args);
283313
}
284314
JS

0 commit comments

Comments
 (0)