breezy_template 0.10.1 → 0.11.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 196103d517bfc16643b1bc270edf634b9ec60d72
4
- data.tar.gz: 7af3f57a2e858036f9b9a45051e2816539b45a52
3
+ metadata.gz: fd735e59d268c9b87e7bc62528a0a5fb848a23c0
4
+ data.tar.gz: 4064dde7ecda53a3c53564e04001d59389f5e6d5
5
5
  SHA512:
6
- metadata.gz: 0227c106472a3e605ebfbe4cafd22392ad93d70ffbf79a0fadfe12814e3741c6ce01256486620a36fb06361ae01e13066399fce8242b485a1b981ea95db366e8
7
- data.tar.gz: f9e1d92f429733c66db0d76307111ee388af65c697a3484a76e6a6a9886c174373f80c585aaba48c99e115eda9d0f3c721906716a1c2e3627c2f0ab731d98857
6
+ metadata.gz: a538e32972a47d82750036f7163c447dd68a964878c591a52f9a16f6ab3cd9693638cd23af36496e61b951bd7e848f9ed9881a274cda3557da9d55813a54b9e0
7
+ data.tar.gz: 334ff1aa1d34964f882e2ad8b10e91a534edcd934e7ec63c8b7229ce7844bf4429a8675a5f16c7e7473f7db757f8955ca7a22f1c2e960c996c4dea55828e540f
@@ -81,7 +81,7 @@ class BreezyTemplate
81
81
  end
82
82
 
83
83
  def _cache_options(options)
84
- return nil if !options
84
+ return nil if !options || options.blank?
85
85
  options = [*options[:cache]]
86
86
  key, options = options
87
87
 
@@ -18,7 +18,7 @@ class BreezyTemplate
18
18
 
19
19
  def _breezy_visit_current(path)
20
20
  uri = ::URI.parse(@request_path)
21
- qry = ::URI.decode_www_form(uri.query || '') << ["_bz", path.join('.')]
21
+ qry = ::URI.decode_www_form(uri.query || '') << ["bzq", path.join('.')]
22
22
  uri.query = ::URI.encode_www_form(qry)
23
23
  "defers.push({url:'#{uri}'});"
24
24
  end
@@ -28,4 +28,11 @@ class BreezyTemplate
28
28
  new(message)
29
29
  end
30
30
  end
31
+
32
+ class LeafTraversalError < ::StandardError
33
+ def self.build(key, value, options, search_path)
34
+ message = "Attempted to traverse into node named #{key} but got a value. This may happen if you forgot to use nil as a first value if you're using a partial, e.g, json.foo nil, partial: 'footer'. Key: #{key} Value: #{value} Options: #{options} Remaining search path: #{search_path}."
35
+ new(message)
36
+ end
37
+ end
31
38
  end
@@ -17,7 +17,7 @@ class BreezyTemplate
17
17
  options = _normalize_options_for_partial(options)
18
18
 
19
19
  if attributes.one? && _partial_options?(options)
20
- _render_partial_with_options(collection, options)
20
+ _render_partial_with_collection(collection, options)
21
21
  else
22
22
  super
23
23
  end
@@ -47,7 +47,7 @@ class BreezyTemplate
47
47
 
48
48
  def _partial_digest(partial)
49
49
  lookup_context = @context.lookup_context
50
- name = lookup_context.find(partial, lookup_context.prefixes, true).virtual_path
50
+ name = lookup_context.find(partial, [], true).virtual_path
51
51
  _partial_digestor({name: name, finder: lookup_context})
52
52
  end
53
53
 
@@ -64,12 +64,10 @@ class BreezyTemplate
64
64
  locals.merge!(partial_opts[:locals]) if partial_opts.key? :locals
65
65
  partial_opts.merge!(locals: locals)
66
66
 
67
- _scope{ _render_partial(options) }
67
+ _result(BLANK, options){ _render_partial(options) }
68
68
  end
69
69
 
70
- options = options.dup
71
- options.delete(:partial)
72
- set! name, value, options
70
+ set! name, value
73
71
  end
74
72
 
75
73
  def _render_partial(options)
@@ -86,7 +84,7 @@ class BreezyTemplate
86
84
  @context.render options.merge(partial: partial)
87
85
  end
88
86
 
89
- def _render_partial_with_options(collection, options)
87
+ def _render_partial_with_collection(collection, options)
90
88
  options = _normalize_options_for_partial(options)
91
89
  partial, partial_opts = options[:partial]
92
90
  array_opts = options.dup
@@ -70,10 +70,12 @@ class BreezyTemplate
70
70
  if ::Kernel.block_given?
71
71
  yield self
72
72
  elsif _partial_options?(options)
73
- without_track = args.dup
74
- super(key, value, *without_track)
73
+ without = options.dup
74
+ without.delete(:cache)
75
+
76
+ super(key, value, without)
75
77
  else
76
- ::Kernel.raise 'This should not happen'
78
+ ::Kernel.raise LeafTraversalError.build(key, value, options, @search_path)
77
79
  end
78
80
  end
79
81
 
@@ -0,0 +1,334 @@
1
+ require "test_helper"
2
+
3
+
4
+ class CacheExtensionTest < BreezyTemplateTestCase
5
+ test "caching a value at a node" do
6
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
7
+
8
+ result = jbuild(<<-JBUILDER)
9
+ opts = {
10
+ cache: [['b', 'c']]
11
+ }
12
+ json.hello 32, opts
13
+ JBUILDER
14
+
15
+ expected = strip_format(<<-JS)
16
+ (function(){
17
+ var fragments={};
18
+ var lastFragmentName;
19
+ var lastFragmentPath;
20
+ var cache={};
21
+ var defers=[];
22
+ cache["#{cache_keys[0]}"]=32;
23
+ return ({"data":{"hello":cache["#{cache_keys[0]}"]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
24
+ })()
25
+ JS
26
+
27
+ assert_equal expected, result
28
+ end
29
+
30
+ test "caching elements in a list" do
31
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
32
+
33
+ result = jbuild(<<-JBUILDER)
34
+ json.hello do
35
+ opts = {
36
+ cache: ->(i){ ['a', i] }
37
+ }
38
+ json.array! [4,5], opts do |x|
39
+ json.top "hello" + x.to_s
40
+ end
41
+ end
42
+ JBUILDER
43
+
44
+ expected = strip_format(<<-JS)
45
+ (function(){
46
+ var fragments={};
47
+ var lastFragmentName;
48
+ var lastFragmentPath;
49
+ var cache={};
50
+ var defers=[];
51
+ cache["#{cache_keys[0]}"]={"top":"hello4"};
52
+ cache["#{cache_keys[1]}"]={"top":"hello5"};
53
+ return ({"data":{"hello":[cache["#{cache_keys[0]}"],cache["#{cache_keys[1]}"]]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
54
+ })()
55
+ JS
56
+
57
+ assert_equal expected, result
58
+ end
59
+
60
+ test "nested caching generates a depth-first list of cache nodes" do
61
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
62
+
63
+ result = jbuild(<<-JBUILDER)
64
+ json.hello cache: [['a', 'b']] do
65
+ json.content cache: [['d', 'z']] do
66
+ json.subcontent 'inner'
67
+ end
68
+ json.other cache: [['e', 'z']] do
69
+ json.subcontent 'other'
70
+ end
71
+ end
72
+ JBUILDER
73
+
74
+ expected = strip_format(<<-JS)
75
+ (function(){
76
+ var fragments={};
77
+ var lastFragmentName;
78
+ var lastFragmentPath;
79
+ var cache={};
80
+ var defers=[];
81
+ cache["#{cache_keys[0]}"]={"subcontent":"inner"};
82
+ cache["#{cache_keys[1]}"]={"subcontent":"other"};
83
+ cache["#{cache_keys[2]}"]={"content":cache["#{cache_keys[0]}"],"other":cache["#{cache_keys[1]}"]};
84
+ return ({"data":{"hello":cache["#{cache_keys[2]}"]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
85
+ })()
86
+ JS
87
+
88
+ assert_equal expected, result
89
+ end
90
+
91
+ test "caching an empty block generates no cache and no errors" do
92
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
93
+
94
+ result = nil
95
+
96
+ assert_nothing_raised do
97
+ result = jbuild(<<-JBUILDER)
98
+ json.hello do
99
+ json.array! [4,5], cache: ->(i){['a', i]} do |x|
100
+ end
101
+ end
102
+ JBUILDER
103
+ end
104
+
105
+ expected = strip_format(<<-JS)
106
+ (function(){
107
+ var fragments={};
108
+ var lastFragmentName;
109
+ var lastFragmentPath;
110
+ var cache={};
111
+ var defers=[];
112
+ return ({\"data\":{\"hello\":[]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
113
+ })()
114
+ JS
115
+
116
+ assert_equal expected, result
117
+ end
118
+
119
+ test "fragment caching" do
120
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
121
+
122
+ jbuild(<<-JBUILDER)
123
+ opts = {cache: ['cachekey']}
124
+ json.post opts do
125
+ json.name "Cache"
126
+ end
127
+ JBUILDER
128
+
129
+ result = jbuild(<<-JBUILDER)
130
+ opts = {cache: ['cachekey']}
131
+ json.post opts do
132
+ json.name "Miss"
133
+ end
134
+ JBUILDER
135
+
136
+ expected = strip_format(<<-JS)
137
+ (function(){
138
+ var fragments={};
139
+ var lastFragmentName;
140
+ var lastFragmentPath;
141
+ var cache={};
142
+ var defers=[];
143
+ cache["#{cache_keys[0]}"]={"name":"Cache"};
144
+ return ({"data":{"post":cache["#{cache_keys[0]}"]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
145
+ })()
146
+ JS
147
+
148
+ assert_equal expected, result
149
+ end
150
+
151
+ test "fragment caching deserializes an array" do
152
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
153
+
154
+ result = jbuild <<-JBUILDER
155
+ json.content cache: "cachekey" do
156
+ json.array! %w[a b c]
157
+ end
158
+ JBUILDER
159
+
160
+ expected = strip_format(<<-JS)
161
+ (function(){
162
+ var fragments={};
163
+ var lastFragmentName;
164
+ var lastFragmentPath;
165
+ var cache={};
166
+ var defers=[];
167
+ cache["#{cache_keys[0]}"]=["a","b","c"];
168
+ return ({"data":{"content":cache["#{cache_keys[0]}"]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
169
+ })()
170
+ JS
171
+
172
+ assert_equal expected, result
173
+ end
174
+
175
+ test "fragment caching works with previous version of cache digests" do
176
+ undef_context_methods :cache_fragment_name
177
+
178
+ if !@context.class.method_defined? :fragment_name_with_digest
179
+ @context.class_eval do
180
+ def fragment_name_with_digest
181
+ end
182
+ end
183
+ end
184
+
185
+ @context.expects :fragment_name_with_digest
186
+
187
+ jbuild <<-JBUILDER
188
+ json.content cache: 'cachekey' do
189
+ json.name "Cache"
190
+ end
191
+ JBUILDER
192
+ end
193
+
194
+ test "fragment caching works with current cache digests" do
195
+ undef_context_methods :fragment_name_with_digest
196
+
197
+ @context.expects :cache_fragment_name
198
+ ActiveSupport::Cache.expects :expand_cache_key
199
+
200
+ jbuild <<-JBUILDER
201
+ json.content cache: 'cachekey' do
202
+ json.name "Cache"
203
+ end
204
+ JBUILDER
205
+ end
206
+
207
+ test "does not perform caching when controller.perform_caching is false" do
208
+ controller.perform_caching = false
209
+
210
+ result = jbuild <<-JBUILDER
211
+ json.content cache: 'cachekey' do
212
+ json.name "Cache"
213
+ end
214
+ JBUILDER
215
+
216
+ expected = strip_format(<<-JS)
217
+ (function(){
218
+ var fragments={};
219
+ var lastFragmentName;
220
+ var lastFragmentPath;
221
+ var cache={};
222
+ var defers=[];
223
+ return ({"data":{"content":{"name":"Cache"}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
224
+ })()
225
+ JS
226
+
227
+ assert_equal expected, result
228
+ end
229
+
230
+ test "caches and runs a partial exactly once" do
231
+ jbuild(<<-JBUILDER)
232
+ json.hit nil, partial: ["raise_if_used", locals: {used: false}], cache: 'once'
233
+ json.miss nil, partial: ["raise_if_used", locals: {used: true}], cache: 'once'
234
+ JBUILDER
235
+ end
236
+
237
+ test "invokes templates via params via set! and caches" do
238
+ @post = BLOG_POST_COLLECTION.first
239
+
240
+ result = jbuild(<<-JBUILDER)
241
+ json.post @post, partial: ["blog_post", as: :blog_post], cache: [['a', 'b']]
242
+ JBUILDER
243
+
244
+ expected = strip_format(<<-JS)
245
+ (function(){
246
+ var fragments={};
247
+ var lastFragmentName;
248
+ var lastFragmentPath;
249
+ var cache={};
250
+ var defers=[];
251
+ cache["#{cache_keys[0]}"]={"id":1,"body":"post body 1","author":{"firstName":"David","lastName":"Heinemeier Hansson"}};
252
+ return ({"data":{"post":cache["#{cache_keys[0]}"]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
253
+ })()
254
+ JS
255
+
256
+ assert_equal expected, result
257
+ end
258
+
259
+ test "shares partial caches (via the partial's digest) across multiple templates" do
260
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
261
+
262
+ @hit = BlogPost.new(1, "hit", "John Smith")
263
+ @miss = BlogPost.new(2, "miss", "John Smith")
264
+
265
+ cat = jbuild(<<-JBUILDER)
266
+ opts = {
267
+ cache: [['a', 'b']],
268
+ partial: ["blog_post", as: :blog_post]
269
+ }
270
+
271
+ json.post @hit, opts
272
+ JBUILDER
273
+
274
+ result = jbuild(<<-JBUILDER)
275
+ opts = {
276
+ cache: [['a', 'b']],
277
+ partial: ["blog_post", as: :blog_post]
278
+ }
279
+
280
+ json.post @miss, opts
281
+ JBUILDER
282
+
283
+ expected = strip_format(<<-JS)
284
+ (function(){
285
+ var fragments={};
286
+ var lastFragmentName;
287
+ var lastFragmentPath;
288
+ var cache={};
289
+ var defers=[];
290
+ cache["#{cache_keys[0]}"]={"id":1,"body":"hit","author":{"firstName":"John","lastName":"Smith"}};
291
+ return ({"data":{"post":cache["#{cache_keys[0]}"]},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
292
+ })()
293
+ JS
294
+
295
+ assert_equal expected, result
296
+ end
297
+
298
+
299
+ test "render array of partials and caches" do
300
+ result = jbuild(<<-JBUILDER)
301
+ opts = {
302
+ cache: (->(d){ ['a', d.id] }),
303
+ partial: ["blog_post", as: :blog_post]
304
+ }
305
+ json.array! BLOG_POST_COLLECTION, opts
306
+ JBUILDER
307
+ Rails.cache.clear
308
+
309
+ expected = strip_format(<<-JS)
310
+ (function(){
311
+ var fragments={};
312
+ var lastFragmentName;
313
+ var lastFragmentPath;
314
+ var cache={};
315
+ var defers=[];
316
+ cache["#{cache_keys[0]}"]={"id":1,"body":"post body 1","author":{"firstName":"David","lastName":"Heinemeier Hansson"}};
317
+ cache["#{cache_keys[1]}"]={"id":2,"body":"post body 2","author":{"firstName":"Pavel","lastName":"Pravosud"}};
318
+ cache["#{cache_keys[2]}"]={"id":3,"body":"post body 3","author":{"firstName":"David","lastName":"Heinemeier Hansson"}};
319
+ cache["#{cache_keys[3]}"]={"id":4,"body":"post body 4","author":{"firstName":"Pavel","lastName":"Pravosud"}};
320
+ cache["#{cache_keys[4]}"]={"id":5,"body":"post body 5","author":{"firstName":"David","lastName":"Heinemeier Hansson"}};
321
+ cache["#{cache_keys[5]}"]={"id":6,"body":"post body 6","author":{"firstName":"Pavel","lastName":"Pravosud"}};
322
+ cache["#{cache_keys[6]}"]={"id":7,"body":"post body 7","author":{"firstName":"David","lastName":"Heinemeier Hansson"}};
323
+ cache["#{cache_keys[7]}"]={"id":8,"body":"post body 8","author":{"firstName":"Pavel","lastName":"Pravosud"}};
324
+ cache["#{cache_keys[8]}"]={"id":9,"body":"post body 9","author":{"firstName":"David","lastName":"Heinemeier Hansson"}};
325
+ cache["#{cache_keys[9]}"]={"id":10,"body":"post body 10","author":{"firstName":"Pavel","lastName":"Pravosud"}};
326
+ return ({"data":[cache["#{cache_keys[0]}"],cache["#{cache_keys[1]}"],cache["#{cache_keys[2]}"],cache["#{cache_keys[3]}"],cache["#{cache_keys[4]}"],cache["#{cache_keys[5]}"],cache["#{cache_keys[6]}"],cache["#{cache_keys[7]}"],cache["#{cache_keys[8]}"],cache["#{cache_keys[9]}"]],"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
327
+ })()
328
+ JS
329
+ assert_equal expected, result
330
+ end
331
+ end
332
+
333
+
334
+
@@ -0,0 +1,322 @@
1
+ require "test_helper"
2
+
3
+ class DefermentExtensionTest < BreezyTemplateTestCase
4
+ test "rendering with node deferement" do
5
+ req = action_controller_test_request
6
+ req.path = '/some_url'
7
+
8
+ result = jbuild(<<-JBUILDER, request: req)
9
+ json.hit do
10
+ json.hit2(defer: :auto)do
11
+ json.hit3 do
12
+ json.greeting 'hello world'
13
+ end
14
+ end
15
+ end
16
+ JBUILDER
17
+ Rails.cache.clear
18
+
19
+ expected = strip_format(<<-JS)
20
+ (function(){
21
+ var fragments={};
22
+ var lastFragmentName;
23
+ var lastFragmentPath;
24
+ var cache={};
25
+ var defers=[];
26
+ defers.push({url:'/some_url?bzq=hit.hit2'});
27
+ return (
28
+ {"data":{"hit":{"hit2":undefined}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
29
+ );
30
+ })()
31
+ JS
32
+
33
+ assert_equal expected, result
34
+ end
35
+
36
+ test "rendering with manual node deferement" do
37
+ req = action_controller_test_request
38
+ req.path = '/some_url'
39
+
40
+ result = jbuild(<<-JBUILDER, request: req)
41
+ json.hit do
42
+ json.hit2 defer: :manual do
43
+ json.hit3 do
44
+ json.greeting 'hello world'
45
+ end
46
+ end
47
+ end
48
+ JBUILDER
49
+ Rails.cache.clear
50
+
51
+ expected = strip_format(<<-JS)
52
+ (function(){
53
+ var fragments={};
54
+ var lastFragmentName;
55
+ var lastFragmentPath;
56
+ var cache={};
57
+ var defers=[];
58
+ return (
59
+ {"data":{"hit":{"hit2":undefined}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
60
+ );
61
+ })()
62
+ JS
63
+
64
+ assert_equal expected, result
65
+ end
66
+
67
+ test "rendering with selective array node deferment" do
68
+ req = action_controller_test_request
69
+ req.path = '/some_url'
70
+
71
+ result = jbuild(<<-JBUILDER, request: req)
72
+ keep_first = lambda do |item|
73
+ if item[:id] == 1
74
+ false
75
+ else
76
+ :auto
77
+ end
78
+ end
79
+
80
+ json.hit do
81
+ json.hit2 do
82
+ data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
83
+ json.array! data, key: :id, defer: keep_first do |item|
84
+ json.name item[:name]
85
+ end
86
+ end
87
+ end
88
+ JBUILDER
89
+ Rails.cache.clear
90
+
91
+ expected = strip_format(<<-JS)
92
+ (function(){
93
+ var fragments={};
94
+ var lastFragmentName;
95
+ var lastFragmentPath;
96
+ var cache={};
97
+ var defers=[];
98
+ defers.push({url:'/some_url?bzq=hit.hit2.id%3D2'});
99
+ return (
100
+ {"data":{"hit":{"hit2":[{"name":"foo"},{"id":2}]}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
101
+ );
102
+ })()
103
+ JS
104
+
105
+ assert_equal expected, result
106
+ end
107
+
108
+ test "rendering with node array partial deferment" do
109
+ req = action_controller_test_request
110
+ req.path = '/some_url'
111
+
112
+ result = jbuild(<<-JBUILDER, request: req)
113
+ keep_first = lambda do |item|
114
+ if item[:id] == 1
115
+ false
116
+ else
117
+ :auto
118
+ end
119
+ end
120
+
121
+ json.hit do
122
+ json.hit2 do
123
+ data = [{id: 1, email: 'foo'}, {id: 2, email: 'bar'}]
124
+ json.array! data, key: :id, defer: keep_first, partial: ['record', as: :record]
125
+ end
126
+ end
127
+ JBUILDER
128
+ Rails.cache.clear
129
+
130
+ expected = strip_format(<<-JS)
131
+ (function(){
132
+ var fragments={};
133
+ var lastFragmentName;
134
+ var lastFragmentPath;
135
+ var cache={};
136
+ var defers=[];
137
+ defers.push({url:'/some_url?bzq=hit.hit2.id%3D2'});
138
+ return (
139
+ {"data":{"hit":{"hit2":[{"email":"foo"},{"id":2}]}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
140
+ );
141
+ })()
142
+ JS
143
+
144
+ assert_equal expected, result
145
+ end
146
+
147
+ test "rendering with node array deferment" do
148
+ req = action_controller_test_request
149
+ req.path = '/some_url'
150
+
151
+ result = jbuild(<<-JBUILDER, request: req)
152
+ json.hit do
153
+ json.hit2 do
154
+ data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
155
+ json.array! data, key: :id, defer: :auto do |item|
156
+ json.name item[:name]
157
+ end
158
+ end
159
+ end
160
+ JBUILDER
161
+ Rails.cache.clear
162
+
163
+ expected = strip_format(<<-JS)
164
+ (function(){
165
+ var fragments={};
166
+ var lastFragmentName;
167
+ var lastFragmentPath;
168
+ var cache={};
169
+ var defers=[];
170
+ defers.push({url:'/some_url?bzq=hit.hit2.id%3D1'});
171
+ defers.push({url:'/some_url?bzq=hit.hit2.id%3D2'});
172
+ return (
173
+ {"data":{"hit":{"hit2":[{"id":1},{"id":2}]}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
174
+ );
175
+ })()
176
+ JS
177
+
178
+ assert_equal expected, result
179
+ end
180
+
181
+ test "rendering with node array deferment using index" do
182
+ req = action_controller_test_request
183
+ req.path = '/some_url'
184
+
185
+ result = jbuild(<<-JBUILDER, request: req)
186
+ json.hit do
187
+ json.hit2 do
188
+ data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
189
+ json.array! data, defer: :auto do |item|
190
+ json.name item[:name]
191
+ end
192
+ end
193
+ end
194
+ JBUILDER
195
+ Rails.cache.clear
196
+
197
+ expected = strip_format(<<-JS)
198
+ (function(){
199
+ var fragments={};
200
+ var lastFragmentName;
201
+ var lastFragmentPath;
202
+ var cache={};
203
+ var defers=[];
204
+ defers.push({url:'/some_url?bzq=hit.hit2.0'});
205
+ defers.push({url:'/some_url?bzq=hit.hit2.1'});
206
+ return (
207
+ {"data":{"hit":{"hit2":[undefined,undefined]}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
208
+ );
209
+ })()
210
+ JS
211
+
212
+ assert_equal expected, result
213
+ end
214
+
215
+ test "rendering with node array deferment on nested node" do
216
+ req = action_controller_test_request
217
+ req.path = '/some_url'
218
+
219
+ result = jbuild(<<-JBUILDER, request: req)
220
+ json.hit do
221
+ json.hit2 do
222
+ data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
223
+ json.array! data, key: :id do
224
+ json.greeting defer: :auto do
225
+ json.gree 'hi'
226
+ end
227
+ end
228
+ end
229
+ end
230
+ JBUILDER
231
+ Rails.cache.clear
232
+
233
+ expected = strip_format(<<-JS)
234
+ (function(){
235
+ var fragments={};
236
+ var lastFragmentName;
237
+ var lastFragmentPath;
238
+ var cache={};
239
+ var defers=[];
240
+ defers.push({url:'/some_url?bzq=hit.hit2.id%3D1.greeting'});
241
+ defers.push({url:'/some_url?bzq=hit.hit2.id%3D2.greeting'});
242
+ return (
243
+ {"data":{"hit":{"hit2":[{"greeting":undefined},{"greeting":undefined}]}},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}}
244
+ );
245
+ })()
246
+ JS
247
+
248
+ assert_equal expected, result
249
+ end
250
+
251
+ test 'deferment does not work on values' do
252
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
253
+
254
+ result = jbuild(<<-JBUILDER)
255
+ json.hello(32, defer: :auto)
256
+ JBUILDER
257
+
258
+ expected = strip_format(<<-JS)
259
+ (function(){
260
+ var fragments={};
261
+ var lastFragmentName;
262
+ var lastFragmentPath;
263
+ var cache={};
264
+ var defers=[];
265
+ return ({"data":{"hello":32},"screen":"test","fragments":fragments,"privateOpts":{"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
266
+ })()
267
+ JS
268
+
269
+ assert_equal expected, result
270
+ end
271
+
272
+ test 'deferment is disabled when filtering by keypath' do
273
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
274
+ result = jbuild(<<-JBUILDER, breezy_filter: 'hello.world')
275
+ json.hello defer: :auto do
276
+ json.world 32
277
+ end
278
+ JBUILDER
279
+
280
+ expected = strip_format(<<-JS)
281
+ (function(){
282
+ var fragments={};
283
+ var lastFragmentName;
284
+ var lastFragmentPath;
285
+ var cache={};
286
+ var defers=[];
287
+ return ({"data":32,"screen":"test","fragments":fragments,"privateOpts":{"action":"graft","path":"hello.world","lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
288
+ })()
289
+ JS
290
+
291
+ assert_equal expected, result
292
+
293
+ end
294
+
295
+ test 'deferment is enabled at the end of a keypath when filtering' do
296
+ undef_context_methods :fragment_name_with_digest, :cache_fragment_name
297
+ result = jbuild(<<-JBUILDER, breezy_filter: 'hello')
298
+ json.hello do
299
+ json.content defer: :auto do
300
+ json.world 32
301
+ end
302
+ end
303
+ JBUILDER
304
+
305
+ expected = strip_format(<<-JS)
306
+ (function(){
307
+ var fragments={};
308
+ var lastFragmentName;
309
+ var lastFragmentPath;
310
+ var cache={};
311
+ var defers=[];
312
+ defers.push({url:'?bzq=hello.content'});
313
+ return ({"data":{"content":undefined},"screen":"test","fragments":fragments,"privateOpts":{"action":"graft","path":"hello","lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});
314
+ })()
315
+ JS
316
+
317
+ assert_equal expected, result
318
+ end
319
+ end
320
+
321
+
322
+