babl-json 0.1.1
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 +7 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +228 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +5 -0
- data/LICENSE +7 -0
- data/README.md +87 -0
- data/babl.gemspec +23 -0
- data/lib/babl.rb +41 -0
- data/lib/babl/builder/chain_builder.rb +85 -0
- data/lib/babl/builder/template_base.rb +37 -0
- data/lib/babl/operators/array.rb +42 -0
- data/lib/babl/operators/call.rb +25 -0
- data/lib/babl/operators/dep.rb +48 -0
- data/lib/babl/operators/each.rb +45 -0
- data/lib/babl/operators/enter.rb +22 -0
- data/lib/babl/operators/merge.rb +49 -0
- data/lib/babl/operators/nav.rb +55 -0
- data/lib/babl/operators/nullable.rb +16 -0
- data/lib/babl/operators/object.rb +55 -0
- data/lib/babl/operators/parent.rb +90 -0
- data/lib/babl/operators/partial.rb +46 -0
- data/lib/babl/operators/pin.rb +78 -0
- data/lib/babl/operators/source.rb +12 -0
- data/lib/babl/operators/static.rb +40 -0
- data/lib/babl/operators/switch.rb +71 -0
- data/lib/babl/operators/with.rb +51 -0
- data/lib/babl/railtie.rb +29 -0
- data/lib/babl/rendering/compiled_template.rb +28 -0
- data/lib/babl/rendering/context.rb +60 -0
- data/lib/babl/rendering/internal_value_node.rb +30 -0
- data/lib/babl/rendering/noop_preloader.rb +10 -0
- data/lib/babl/rendering/terminal_value_node.rb +54 -0
- data/lib/babl/template.rb +48 -0
- data/lib/babl/utils/hash.rb +11 -0
- data/lib/babl/version.rb +3 -0
- data/spec/construction_spec.rb +246 -0
- data/spec/navigation_spec.rb +133 -0
- data/spec/partial_spec.rb +53 -0
- data/spec/pinning_spec.rb +137 -0
- metadata +145 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Babl
|
4
|
+
module Rendering
|
5
|
+
# A TerminalValueNode node is always implicitely added to the end of the
|
6
|
+
# chain during compilation. It basically ensures that the output contains only
|
7
|
+
# primitives, arrays and hashes.
|
8
|
+
class TerminalValueNode
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def documentation
|
12
|
+
:__value__
|
13
|
+
end
|
14
|
+
|
15
|
+
def dependencies
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
|
19
|
+
def pinned_dependencies
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
|
23
|
+
def render(ctx)
|
24
|
+
render_object(ctx.object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_object(obj)
|
28
|
+
case obj
|
29
|
+
when String, Numeric, NilClass, TrueClass, FalseClass then obj
|
30
|
+
when Hash then render_hash(obj)
|
31
|
+
when Array then render_array(obj)
|
32
|
+
else raise Babl::RenderingError, "Only primitives can be serialized: #{obj}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def render_array(array)
|
39
|
+
array.map { |obj| render_object(obj) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_hash(hash)
|
43
|
+
hash.map { |k, v| [render_key(k), render_object(v)] }.to_h
|
44
|
+
end
|
45
|
+
|
46
|
+
def render_key(key)
|
47
|
+
case key
|
48
|
+
when Symbol, String, Numeric, NilClass, TrueClass, FalseClass then :"#{key}"
|
49
|
+
else raise Babl::RenderingError, "Invalid key for JSON object: #{obj}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'babl/utils/hash'
|
2
|
+
|
3
|
+
require 'babl/operators/array'
|
4
|
+
require 'babl/operators/call'
|
5
|
+
require 'babl/operators/dep'
|
6
|
+
require 'babl/operators/each'
|
7
|
+
require 'babl/operators/enter'
|
8
|
+
require 'babl/operators/merge'
|
9
|
+
require 'babl/operators/nav'
|
10
|
+
require 'babl/operators/nullable'
|
11
|
+
require 'babl/operators/object'
|
12
|
+
require 'babl/operators/parent'
|
13
|
+
require 'babl/operators/partial'
|
14
|
+
require 'babl/operators/pin'
|
15
|
+
require 'babl/operators/source'
|
16
|
+
require 'babl/operators/static'
|
17
|
+
require 'babl/operators/switch'
|
18
|
+
require 'babl/operators/with'
|
19
|
+
|
20
|
+
require 'babl/builder/template_base'
|
21
|
+
require 'babl/builder/chain_builder'
|
22
|
+
|
23
|
+
require 'babl/rendering/compiled_template'
|
24
|
+
require 'babl/rendering/context'
|
25
|
+
require 'babl/rendering/internal_value_node'
|
26
|
+
require 'babl/rendering/terminal_value_node'
|
27
|
+
require 'babl/rendering/noop_preloader'
|
28
|
+
|
29
|
+
module Babl
|
30
|
+
class Template < Babl::Builder::TemplateBase
|
31
|
+
include Operators::Array::DSL
|
32
|
+
include Operators::Call::DSL
|
33
|
+
include Operators::Dep::DSL
|
34
|
+
include Operators::Each::DSL
|
35
|
+
include Operators::Enter::DSL
|
36
|
+
include Operators::Merge::DSL
|
37
|
+
include Operators::Nav::DSL
|
38
|
+
include Operators::Nullable::DSL
|
39
|
+
include Operators::Object::DSL
|
40
|
+
include Operators::Parent::DSL
|
41
|
+
include Operators::Partial::DSL
|
42
|
+
include Operators::Pin::DSL
|
43
|
+
include Operators::Source::DSL
|
44
|
+
include Operators::Static::DSL
|
45
|
+
include Operators::Switch::DSL
|
46
|
+
include Operators::With::DSL
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Babl
|
2
|
+
module Utils
|
3
|
+
class Hash
|
4
|
+
# Source: http://stackoverflow.com/a/9381776/1434017 (Jon M)
|
5
|
+
def self.deep_merge(first, second)
|
6
|
+
merger = proc { |_key, v1, v2| ::Hash === v1 && ::Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
7
|
+
first.merge(second, &merger)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/babl/version.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'babl'
|
2
|
+
|
3
|
+
describe ::Babl::Template do
|
4
|
+
let(:dsl) { ::Babl::Template.new }
|
5
|
+
let(:compiled) { template.compile }
|
6
|
+
let(:json) { Oj.load(compiled.json(object)) }
|
7
|
+
let(:dependencies) { compiled.dependencies }
|
8
|
+
let(:documentation) { compiled.documentation }
|
9
|
+
|
10
|
+
describe '#object' do
|
11
|
+
let(:template) { dsl.source { object(:a, :b, c: _, d: nav(:d)) } }
|
12
|
+
let(:object) { { a: 1, b: 2, c: 3, d: 4 } }
|
13
|
+
|
14
|
+
it { expect(json).to eq('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4) }
|
15
|
+
it { expect(documentation).to eq(a: :__value__, b: :__value__, c: :__value__, d: :__value__) }
|
16
|
+
it { expect(dependencies).to eq(a: {}, b: {}, c: {}, d: {}) }
|
17
|
+
|
18
|
+
context 'misused (chaining after object)' do
|
19
|
+
let(:template) { dsl.source { object(:a).object(:b) } }
|
20
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#each' do
|
25
|
+
context 'when everything is fine' do
|
26
|
+
let(:template) { dsl.source { each.nav(:a) } }
|
27
|
+
let(:object) { [{ a: 3 }, { a: 2 }, { a: 1 }] }
|
28
|
+
|
29
|
+
it { expect(json).to eq [3, 2, 1] }
|
30
|
+
it { expect(dependencies).to eq(__each__: { a: {} }) }
|
31
|
+
it { expect(documentation).to eq [:__value__] }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'error while navigating' do
|
35
|
+
let(:object) { { box: [{ trololol: 2 }, 42] } }
|
36
|
+
let(:template) { dsl.source { nav(:box).each.nav(:trololol) } }
|
37
|
+
|
38
|
+
it { expect { json }.to raise_error(/\__root__\.box\.1\.trololol/) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#static' do
|
43
|
+
let(:template) { dsl.source { static('1': 'cava') } }
|
44
|
+
let(:object) { nil }
|
45
|
+
|
46
|
+
it { expect(json).to eq('1' => 'cava') }
|
47
|
+
it { expect(dependencies).to eq({}) }
|
48
|
+
it { expect(documentation).to eq('1': 'cava') }
|
49
|
+
|
50
|
+
context 'invalid' do
|
51
|
+
let(:template) { dsl.source { static(test: Object.new) } }
|
52
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#array' do
|
57
|
+
let(:template) { dsl.source { array('coucou', 45, a: 1, b: [_]) } }
|
58
|
+
let(:object) { { b: 12 } }
|
59
|
+
it { expect(json).to eq ['coucou', 45, { 'a' => 1, 'b' => [12] }] }
|
60
|
+
it { expect(dependencies).to eq(b: {}) }
|
61
|
+
it { expect(documentation).to eq ['coucou', 45, a: 1, b: [:__value__]] }
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#call' do
|
65
|
+
let(:object) { nil }
|
66
|
+
|
67
|
+
context 'false' do
|
68
|
+
let(:template) { dsl.call(false) }
|
69
|
+
|
70
|
+
it { expect(json).to eq false }
|
71
|
+
it { expect(dependencies).to eq({}) }
|
72
|
+
it { expect(documentation).to eq false }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'block' do
|
76
|
+
let(:object) { 2 }
|
77
|
+
let(:template) { dsl.call { self * 2 } }
|
78
|
+
|
79
|
+
it { expect(json).to eq 4 }
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'hash' do
|
83
|
+
let(:object) { nil }
|
84
|
+
let(:template) { dsl.call('a' => 1, b: 2) }
|
85
|
+
|
86
|
+
it { expect(json).to eq('a' => 1, 'b' => 2) }
|
87
|
+
it { expect(dependencies).to eq({}) }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'array' do
|
91
|
+
let(:object) { { b: 42 } }
|
92
|
+
let(:template) { dsl.call(['a', 2, :b]) }
|
93
|
+
|
94
|
+
it { expect(json).to eq(['a', 2, 42]) }
|
95
|
+
it { expect(dependencies).to eq(b: {}) }
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'block' do
|
99
|
+
let(:object) { OpenStruct.new(lol: 'tam') }
|
100
|
+
let(:template) { dsl.call(:lol) }
|
101
|
+
|
102
|
+
it { expect(json).to eq 'tam' }
|
103
|
+
it { expect(dependencies).to eq(lol: {}) }
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'template' do
|
107
|
+
let(:object) { OpenStruct.new(a: OpenStruct.new(b: 1)) }
|
108
|
+
let(:template) { dsl.source { object(coucou: nav(:a).call(nav(:b))) } }
|
109
|
+
|
110
|
+
it { expect(dependencies).to eq(a: { b: {} }) }
|
111
|
+
it { expect(json).to eq('coucou' => 1) }
|
112
|
+
it { expect(documentation).to eq(coucou: :__value__) }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#switch' do
|
117
|
+
context do
|
118
|
+
let(:template) {
|
119
|
+
dsl.source {
|
120
|
+
even = nullable.nav(:even?)
|
121
|
+
odd = nullable.nav(:odd?)
|
122
|
+
|
123
|
+
each.switch(
|
124
|
+
even => nav { |x| "#{x} is even" },
|
125
|
+
odd => nav { |x| "#{x} is odd" },
|
126
|
+
default => continue
|
127
|
+
).static('WTF')
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
let(:object) { [1, 2, nil, 5] }
|
132
|
+
|
133
|
+
it { expect(json).to eq ['1 is odd', '2 is even', 'WTF', '5 is odd'] }
|
134
|
+
it { expect(dependencies).to eq(__each__: { even?: {}, odd?: {} }) }
|
135
|
+
it {
|
136
|
+
expect(documentation).to eq [
|
137
|
+
'Case 1': :__value__,
|
138
|
+
'Case 2': :__value__,
|
139
|
+
'Case 3': 'WTF'
|
140
|
+
]
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'static condition' do
|
145
|
+
let(:template) { dsl.source { switch(true => 42) } }
|
146
|
+
let(:object) { {} }
|
147
|
+
it { expect(json).to eq 42 }
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'navigation before continue' do
|
151
|
+
let(:template) { dsl.source { nav(:abc).switch(false => 1, default => nav(:lol).continue).object(val: nav(:ok)) } }
|
152
|
+
|
153
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'continue in sub-object' do
|
157
|
+
let(:template) { dsl.source { object(a: switch(default => object(x: continue))) } }
|
158
|
+
|
159
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'unhandled default' do
|
163
|
+
let(:object) { { abc: { lol: { ok: 42 } } } }
|
164
|
+
let(:template) { dsl.source { switch(false => 1) } }
|
165
|
+
|
166
|
+
it { expect(dependencies).to eq({}) }
|
167
|
+
it { expect { json }.to raise_error Babl::RenderingError }
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'continue without switch' do
|
171
|
+
let(:template) { dsl.source { continue } }
|
172
|
+
|
173
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'non serializable objects are allowed internally' do
|
177
|
+
let(:template) { dsl.source { switch(test: 42) } }
|
178
|
+
let(:object) { { test: Object.new } }
|
179
|
+
|
180
|
+
it { expect(json).to eq 42 }
|
181
|
+
end
|
182
|
+
|
183
|
+
context do
|
184
|
+
let(:template) {
|
185
|
+
dsl.source {
|
186
|
+
nav(:test).switch(nav(:keke) => parent.nav(:lol))
|
187
|
+
}
|
188
|
+
}
|
189
|
+
it { expect(dependencies).to eq(test: { keke: {} }, lol: {}) }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#with' do
|
194
|
+
context 'everything is fine' do
|
195
|
+
let(:template) {
|
196
|
+
dsl.source {
|
197
|
+
object(
|
198
|
+
result: with(
|
199
|
+
unscoped,
|
200
|
+
:msg,
|
201
|
+
_.parent.nav(:msg).dep(:lol)
|
202
|
+
) { |obj, a, b| "#{a} #{b} #{obj[:msg]}" }
|
203
|
+
)
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
let(:object) { { result: 42, msg: 'Hello C' } }
|
208
|
+
|
209
|
+
it { expect(json).to eq('result' => 'Hello C Hello C Hello C') }
|
210
|
+
it { expect(dependencies).to eq(result: {}, msg: { lol: {} }) }
|
211
|
+
it { expect(documentation).to eq(result: :__value__) }
|
212
|
+
end
|
213
|
+
|
214
|
+
context 'when the block raise an exception' do
|
215
|
+
let(:object) { nil }
|
216
|
+
let(:template) { dsl.source { with { raise 'lol' } } }
|
217
|
+
it { expect { json }.to raise_error(/\__root__\.__block__/) }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#merge' do
|
222
|
+
context do
|
223
|
+
let(:template) {
|
224
|
+
dsl.source {
|
225
|
+
merge(
|
226
|
+
object(a: static('A')),
|
227
|
+
b: _
|
228
|
+
)
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
let(:object) { { b: 42 } }
|
233
|
+
|
234
|
+
it { expect(json).to eq('a' => 'A', 'b' => 42) }
|
235
|
+
it { expect(dependencies).to eq(b: {}) }
|
236
|
+
it { expect(documentation).to eq('Merge 1': { a: 'A' }, 'Merge 2': { b: :__value__ }) }
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'merge inside object' do
|
240
|
+
let(:template) { dsl.source { object(toto: merge(_, lol: 42)) } }
|
241
|
+
let(:object) { { toto: { cool: 'ouai' } } }
|
242
|
+
|
243
|
+
it { expect(json).to eq('toto' => { 'lol' => 42, 'cool' => 'ouai' }) }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'babl'
|
2
|
+
|
3
|
+
describe ::Babl::Template do
|
4
|
+
let(:dsl) { ::Babl::Template.new }
|
5
|
+
let(:compiled) { template.compile }
|
6
|
+
let(:json) { Oj.load(compiled.json(object)) }
|
7
|
+
let(:dependencies) { compiled.dependencies }
|
8
|
+
let(:documentation) { compiled.documentation }
|
9
|
+
|
10
|
+
describe '#parent' do
|
11
|
+
context 'valid usage' do
|
12
|
+
let(:template) {
|
13
|
+
dsl.source {
|
14
|
+
nav(:box).dep(:box_dep).parent.dep(:root_dep)
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:object) { { box: 42 } }
|
19
|
+
|
20
|
+
it { expect(documentation).to eq :__value__ }
|
21
|
+
it { expect(dependencies).to eq(box: { box_dep: {} }, root_dep: {}) }
|
22
|
+
it { expect(json).to eq('box' => 42) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'error while navigating' do
|
26
|
+
let(:object) { { a: { b: { c: 56 } } } }
|
27
|
+
let(:template) { dsl.source { nav(:a).parent.nav(:a).nav(:b, :x) } }
|
28
|
+
|
29
|
+
it { expect { json }.to raise_error(/\__root__\.a\.b\.x/) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'invalid usage' do
|
33
|
+
let(:template) { dsl.source { parent } }
|
34
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'deeply nested parent chain' do
|
38
|
+
let(:template) {
|
39
|
+
dsl.source {
|
40
|
+
nav(:a, :b, :c, :d, :e).parent.parent.parent.nav(:f, :g, :h).parent.parent.parent.parent.nav(:i)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
it { expect(dependencies).to eq(a: { b: { f: { g: { h: {} } }, c: { d: { e: {} } } }, i: {} }) }
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'same-level key + nested parent chain' do
|
47
|
+
let(:template) {
|
48
|
+
dsl.source {
|
49
|
+
object(
|
50
|
+
a: _.nav(:b, :c).parent.parent.nav(:h),
|
51
|
+
b: _.nav(:a).parent.nav(:a)
|
52
|
+
)
|
53
|
+
}
|
54
|
+
}
|
55
|
+
it { expect(dependencies).to eq(a: { b: { c: {} }, h: {} }, b: { a: {} }) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#dep' do
|
60
|
+
let(:template) {
|
61
|
+
dsl.source {
|
62
|
+
dep(a: [:b, :c]).nav(:b).dep(x: :y).nav(:z)
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
let(:object) { { b: { z: 42 } } }
|
67
|
+
|
68
|
+
it { expect(documentation).to eq :__value__ }
|
69
|
+
it { expect(dependencies).to eq(a: { b: {}, c: {} }, b: { x: { y: {} }, z: {} }) }
|
70
|
+
it { expect(json).to eq(42) }
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#enter' do
|
74
|
+
context 'invalid usage' do
|
75
|
+
let(:template) { dsl.source { enter } }
|
76
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'valid usage' do
|
80
|
+
let(:template) { dsl.source { object(a: enter) } }
|
81
|
+
let(:object) { { a: 42 } }
|
82
|
+
|
83
|
+
it { expect(documentation).to eq(a: :__value__) }
|
84
|
+
it { expect(dependencies).to eq(a: {}) }
|
85
|
+
it { expect(json).to eq('a' => 42) }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#nav' do
|
90
|
+
let(:template) { dsl.source { nav(:a) } }
|
91
|
+
|
92
|
+
context 'hash navigation' do
|
93
|
+
let(:object) { { a: 42 } }
|
94
|
+
it { expect(json).to eq(42) }
|
95
|
+
it { expect(dependencies).to eq(a: {}) }
|
96
|
+
|
97
|
+
context 'block navigation propagate dependency chain' do
|
98
|
+
let(:template) { dsl.source { nav(:a).nav(:to_i) } }
|
99
|
+
it { expect(dependencies).to eq(a: { to_i: {} }) }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'navigate to non serializable' do
|
104
|
+
let(:template) { dsl.source { nav(:a) } }
|
105
|
+
let(:object) { { a: :test } }
|
106
|
+
it { expect { json }.to raise_error Babl::RenderingError }
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'object navigation' do
|
110
|
+
let(:object) { Struct.new(:a).new(42) }
|
111
|
+
it { expect(json).to eq(42) }
|
112
|
+
it { expect(dependencies).to eq(a: {}) }
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'block navigation' do
|
116
|
+
let(:object) { 42 }
|
117
|
+
let(:template) { dsl.source { nav { |x| x * 2 } } }
|
118
|
+
|
119
|
+
it { expect(json).to eq(84) }
|
120
|
+
it { expect(dependencies).to eq({}) }
|
121
|
+
|
122
|
+
context 'block navigation breaks dependency chain' do
|
123
|
+
let(:template) { dsl.source { nav { |x| x * 2 }.nav(:to_i) } }
|
124
|
+
it { expect(dependencies).to eq({}) }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context '#nav should stop key propagation for #enter' do
|
129
|
+
let(:template) { dsl.source { object(a: nav._) } }
|
130
|
+
it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|