Skip to content

Commit 3acc531

Browse files
Merge branch 'evaluate-with-fresh-context-object' of https://github.com/mvz/ruby-handlebars into mvz-evaluate-with-fresh-context-object
2 parents e8fcfd3 + 97fd6c3 commit 3acc531

10 files changed

Lines changed: 103 additions & 79 deletions

File tree

lib/ruby-handlebars.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
module Handlebars
99
class Handlebars
10-
include Context
1110
attr_reader :escaper
1211

1312
def initialize()
@@ -46,10 +45,6 @@ def get_partial(name)
4645
@partials[name.to_s]
4746
end
4847

49-
def set_context(ctx)
50-
@data = ctx
51-
end
52-
5348
def set_escaper(escaper = nil)
5449
@escaper = escaper || Escapers::HTMLEscaper
5550
end

lib/ruby-handlebars/context.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
module Handlebars
2-
module Context
2+
class Context
3+
def initialize(hbs, data)
4+
@hbs = hbs
5+
@data = data
6+
end
7+
38
def get(path)
49
items = path.split('.'.freeze)
510
if locals.key? items.first.to_sym
@@ -15,6 +20,22 @@ def get(path)
1520
current
1621
end
1722

23+
def escaper
24+
@hbs.escaper
25+
end
26+
27+
def get_helper(name)
28+
@hbs.get_helper(name)
29+
end
30+
31+
def get_as_helper(name)
32+
@hbs.get_as_helper(name)
33+
end
34+
35+
def get_partial(name)
36+
@hbs.get_partial(name)
37+
end
38+
1839
def add_item(key, value)
1940
locals[key.to_sym] = value
2041
end

lib/ruby-handlebars/template.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ def initialize(hbs, ast)
88
end
99

1010
def call(args = nil)
11-
if args
12-
@hbs.set_context(args)
13-
end
11+
ctx = Context.new(@hbs, args)
1412

15-
@ast.eval(@hbs)
13+
@ast.eval(ctx)
14+
end
15+
16+
def call_with_context(ctx)
17+
@ast.eval(ctx)
1618
end
1719
end
1820
end

lib/ruby-handlebars/tree.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def _eval(context)
7474

7575
class Partial < TreeItem.new(:partial_name)
7676
def _eval(context)
77-
context.get_partial(partial_name.to_s).call
77+
context.get_partial(partial_name.to_s).call_with_context(context)
7878
end
7979
end
8080

@@ -83,7 +83,7 @@ def _eval(context)
8383
[arguments].flatten.map(&:values).map do |vals|
8484
context.add_item vals.first.to_s, vals.last._eval(context)
8585
end
86-
context.get_partial(partial_name.to_s).call
86+
context.get_partial(partial_name.to_s).call_with_context(context)
8787
end
8888
end
8989

spec/ruby-handlebars/context_spec.rb

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,142 +2,144 @@
22
require_relative '../../lib/ruby-handlebars/context'
33

44
describe Handlebars::Context do
5-
include Handlebars::Context
5+
let(:ctx) { described_class.new(nil, data) }
66

77
context 'get' do
8-
before do
9-
@data = {
10-
key_data: 'Some value'
11-
}
8+
let(:data) { {
9+
key_data: 'Some value'
10+
} }
1211

13-
@locals = {
14-
key_locals: 'Some other value',
15-
a_list: ['a', 'b', 'c'],
16-
a_hash: {key: 'A third value'}
17-
}
12+
before do
13+
ctx.add_item(:key_locals, 'Some other value')
14+
ctx.add_item(:a_list, ['a', 'b', 'c'])
15+
ctx.add_item(:a_hash, {key: 'A third value'})
1816
end
1917

2018
it 'fetches data stored in the context' do
21-
expect(get('key_data')).to eq('Some value')
22-
expect(get('key_locals')).to eq('Some other value')
19+
expect(ctx.get('key_data')).to eq('Some value')
20+
expect(ctx.get('key_locals')).to eq('Some other value')
2321
end
2422

2523
it 'uses data from @locals before @data' do
26-
@locals[:key_data] = 'Now stored in @locals'
24+
ctx.add_item(:key_data, 'Now stored in @locals')
2725

28-
expect(get('key_data')).to eq('Now stored in @locals')
26+
expect(ctx.get('key_data')).to eq('Now stored in @locals')
2927
end
3028

3129
context 'when digging inside data' do
3230
it 'uses keys separated by dots' do
33-
expect(get('a_hash.key')).to eq('A third value')
31+
expect(ctx.get('a_hash.key')).to eq('A third value')
3432
end
3533

3634
it 'can also use methods' do
37-
expect(get('a_list.first')).to eq('a')
38-
expect(get('a_list.last')).to eq('c')
35+
expect(ctx.get('a_list.first')).to eq('a')
36+
expect(ctx.get('a_list.last')).to eq('c')
3937
end
4038
end
4139
end
4240

4341
context 'add_item' do
42+
let(:data) { {} }
43+
4444
it 'adds a new key to the stored data' do
45-
expect(get('my_key')).to be nil
46-
add_item('my_key', 'With some value')
47-
expect(get('my_key')).to eq('With some value')
45+
expect(ctx.get('my_key')).to be nil
46+
ctx.add_item('my_key', 'With some value')
47+
expect(ctx.get('my_key')).to eq('With some value')
4848
end
4949

5050
it 'overrides existing values' do
51-
add_item('a', 12)
52-
add_item('a', 25)
51+
ctx.add_item('a', 12)
52+
ctx.add_item('a', 25)
5353

54-
expect(get('a')).to eq(25)
54+
expect(ctx.get('a')).to eq(25)
5555
end
5656

5757
it 'does not make differences between string and sym keys' do
58-
add_item('a', 12)
59-
add_item(:a, 25)
58+
ctx.add_item('a', 12)
59+
ctx.add_item(:a, 25)
6060

61-
expect(get('a')).to eq(25)
61+
expect(ctx.get('a')).to eq(25)
6262
end
6363
end
6464

6565
context 'add_items' do
66+
let(:data) { {} }
67+
6668
it 'is basically a wrapper around add_item to add multiple items' do
67-
allow(self).to receive(:add_item)
69+
allow(ctx).to receive(:add_item)
6870

69-
add_items(a: 'One key', b: 'A second key', c: 'A third key')
70-
expect(self).to have_received(:add_item).at_most(3).times
71-
expect(self).to have_received(:add_item).once.with(:a, 'One key')
72-
expect(self).to have_received(:add_item).once.with(:b, 'A second key')
73-
expect(self).to have_received(:add_item).once.with(:c, 'A third key')
71+
ctx.add_items(a: 'One key', b: 'A second key', c: 'A third key')
72+
expect(ctx).to have_received(:add_item).at_most(3).times
73+
expect(ctx).to have_received(:add_item).once.with(:a, 'One key')
74+
expect(ctx).to have_received(:add_item).once.with(:b, 'A second key')
75+
expect(ctx).to have_received(:add_item).once.with(:c, 'A third key')
7476
end
7577
end
7678

7779
context 'with_temporary_context' do
80+
let(:data) { {} }
81+
7882
before do
79-
add_items(
83+
ctx.add_items(
8084
key: 'some key',
8185
value: 'some value'
8286
)
8387
end
8488

8589
it 'allows creating temporary variables' do
86-
expect(get('unknown_key')).to be nil
90+
expect(ctx.get('unknown_key')).to be nil
8791

88-
with_temporary_context(unknown_key: 42) do
89-
expect(get('unknown_key')).to eq(42)
92+
ctx.with_temporary_context(unknown_key: 42) do
93+
expect(ctx.get('unknown_key')).to eq(42)
9094
end
9195
end
9296

9397
it 'can override an existing variable' do
94-
with_temporary_context(value: 'A completelly new value') do
95-
expect(get('value')).to eq('A completelly new value')
98+
ctx.with_temporary_context(value: 'A completelly new value') do
99+
expect(ctx.get('value')).to eq('A completelly new value')
96100
end
97101
end
98102

99103
it 'provides mutable variables (well, variables ...)' do
100-
with_temporary_context(unknown_key: 42) do
101-
expect(get('unknown_key')).to eq(42)
102-
add_item('unknown_key', 56)
103-
expect(get('unknown_key')).to eq(56)
104+
ctx.with_temporary_context(unknown_key: 42) do
105+
expect(ctx.get('unknown_key')).to eq(42)
106+
ctx.add_item('unknown_key', 56)
107+
expect(ctx.get('unknown_key')).to eq(56)
104108
end
105109
end
106110

107111
it 'after the block, existing variables are restored' do
108-
with_temporary_context(value: 'A completelly new value') do
109-
expect(get('value')).to eq('A completelly new value')
112+
ctx.with_temporary_context(value: 'A completelly new value') do
113+
expect(ctx.get('value')).to eq('A completelly new value')
110114
end
111115

112-
expect(get('value')).to eq('some value')
116+
expect(ctx.get('value')).to eq('some value')
113117
end
114118

115119
it 'after the block, the declared variables are not available anymore' do
116-
with_temporary_context(unknown_key: 42) do
117-
expect(get('unknown_key')).to eq(42)
120+
ctx.with_temporary_context(unknown_key: 42) do
121+
expect(ctx.get('unknown_key')).to eq(42)
118122
end
119123

120-
expect(get('unknown_key')).to be nil
124+
expect(ctx.get('unknown_key')).to be nil
121125
end
122126

123127
it 'returns the data executed by the block' do
124-
expect( with_temporary_context(value: 'A completelly new value') { 12 } ).to eq(12)
128+
expect( ctx.with_temporary_context(value: 'A completelly new value') { 12 } ).to eq(12)
125129
end
126130

127131
context 'when data are stored in @data' do
128-
before do
129-
@data = {my_key: "With some value"}
130-
end
132+
let(:data) { {my_key: "With some value"} }
131133

132134
it 'let them available after the block is executed' do
133-
expect(get('my_key')).to eq('With some value')
135+
expect(ctx.get('my_key')).to eq('With some value')
134136

135-
with_temporary_context(my_key: 12) do
136-
expect(get('my_key')).to eq(12)
137+
ctx.with_temporary_context(my_key: 12) do
138+
expect(ctx.get('my_key')).to eq(12)
137139
end
138140

139-
expect(get('my_key')).to eq('With some value')
141+
expect(ctx.get('my_key')).to eq('With some value')
140142
end
141143
end
142144
end
143-
end
145+
end

spec/ruby-handlebars/helpers/each_helper_spec.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
describe Handlebars::Helpers::EachHelper do
1010
let(:subject) { Handlebars::Helpers::EachHelper }
1111
let(:hbs) {Handlebars::Handlebars.new}
12+
let(:ctx) {Handlebars::Context.new(hbs, {})}
1213

1314
it_behaves_like "a registerable helper", "each"
1415

@@ -18,7 +19,7 @@
1819
let(:values) { [Handlebars::Tree::String.new('a'), Handlebars::Tree::String.new('b'), Handlebars::Tree::String.new('c') ]}
1920

2021
it 'applies the block on all values' do
21-
subject.apply(hbs, values, block, else_block)
22+
subject.apply(ctx, values, block, else_block)
2223

2324
expect(block).to have_received(:fn).exactly(3).times
2425
expect(else_block).not_to have_received(:fn)
@@ -28,29 +29,29 @@
2829
let(:values) { nil }
2930

3031
it 'uses the else_block if provided' do
31-
subject.apply(hbs, values, block, else_block)
32+
subject.apply(ctx, values, block, else_block)
3233

3334
expect(block).not_to have_received(:fn)
3435
expect(else_block).to have_received(:fn).once
3536
end
3637

3738
it 'returns nil if no else_block is provided' do
38-
expect(subject.apply(hbs, values, block, nil)).to be nil
39+
expect(subject.apply(ctx, values, block, nil)).to be nil
3940
end
4041
end
4142

4243
context 'when values is empty' do
4344
let(:values) { [] }
4445

4546
it 'uses the else_block if provided' do
46-
subject.apply(hbs, values, block, else_block)
47+
subject.apply(ctx, values, block, else_block)
4748

4849
expect(block).not_to have_received(:fn)
4950
expect(else_block).to have_received(:fn).once
5051
end
5152

5253
it 'returns nil if no else_block is provided' do
53-
expect(subject.apply(hbs, values, block, nil)).to be nil
54+
expect(subject.apply(ctx, values, block, nil)).to be nil
5455
end
5556
end
5657
end

spec/ruby-handlebars/helpers/helper_missing_helper_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
describe Handlebars::Helpers::HelperMissingHelper do
1010
let(:subject) { Handlebars::Helpers::HelperMissingHelper }
1111
let(:hbs) { Handlebars::Handlebars.new }
12+
let(:ctx) {Handlebars::Context.new(hbs, {})}
1213

1314
it_behaves_like "a registerable helper", "helperMissing"
1415

1516
context '.apply' do
1617
let(:name) { "missing_helper" }
1718

1819
it 'raises a Handlebars::UnknownHelper exception with the name given as a parameter' do
19-
expect { subject.apply(hbs, name, nil, nil) }.to raise_exception(Handlebars::UnknownHelper, "Helper \"#{name}\" does not exist")
20+
expect { subject.apply(ctx, name, nil, nil) }.to raise_exception(Handlebars::UnknownHelper, "Helper \"#{name}\" does not exist")
2021
end
2122
end
2223

spec/ruby-handlebars/helpers/if_helper_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
describe Handlebars::Helpers::IfHelper do
99
let(:subject) { Handlebars::Helpers::IfHelper }
1010
let(:hbs) {Handlebars::Handlebars.new}
11+
let(:ctx) {Handlebars::Context.new(hbs, {})}
1112

1213
it_behaves_like "a registerable helper", "if"
1314

@@ -28,7 +29,7 @@
2829
let(:else_block) { nil }
2930

3031
it 'returns an empty-string' do
31-
expect(subject.apply(hbs, params, block, else_block)).to eq("")
32+
expect(subject.apply(ctx, params, block, else_block)).to eq("")
3233

3334
expect(block).not_to have_received(:fn)
3435
expect(else_block).not_to have_received(:fn)

spec/ruby-handlebars/helpers/shared.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def evaluate(template, args = {})
3636
include_context "shared apply helper"
3737

3838
it "when condition is #{title}" do
39-
subject.apply(hbs, params, block, else_block)
39+
subject.apply(ctx, params, block, else_block)
4040

4141
expect(block).to have_received(:fn).once
4242
expect(else_block).not_to have_received(:fn)
@@ -47,7 +47,7 @@ def evaluate(template, args = {})
4747
include_context "shared apply helper"
4848

4949
it "when condition is #{title}" do
50-
subject.apply(hbs, params, block, else_block)
50+
subject.apply(ctx, params, block, else_block)
5151

5252
expect(block).not_to have_received(:fn)
5353
expect(else_block).to have_received(:fn).once

0 commit comments

Comments
 (0)