props_template 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad98bb076e592658c137fd423771b211760ba047a1f6f394efa7a531a25eedc5
|
4
|
+
data.tar.gz: f5495c4eca8b7015ac5d18714a10a16735769128fac62b5693824b1ef0c6e505
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 629b8dc24b25dc596ee6f2bb9d03abce69e5af292121d118a83e3d53b83f38ef7ccc155e4cc79d4469a6e588c2efa3231ac02b05447ed11aa6c4642fca833d6f
|
7
|
+
data.tar.gz: 83d0aed77e8cba7cf1730307f15a6fed2b972a181a1722c0dbba85a03489c12ca8b47f89b515e48f8a776564f3c35b58c6118be9396e0eb270c48cfbe21794c9
|
data/README.md
ADDED
@@ -0,0 +1,517 @@
|
|
1
|
+
# PropsTemplate
|
2
|
+
|
3
|
+
PropsTemplate is a queryable JSON templating library inspired by JBuilder. It has support for layouts, partials, russian-doll caching, multi-fetch and can selectively render nodes in your tree without executing others.
|
4
|
+
|
5
|
+
Example:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
json.flash flash.to_h
|
9
|
+
|
10
|
+
json.menu do
|
11
|
+
# all keys will be formatted as camelCase
|
12
|
+
|
13
|
+
json.current_user do
|
14
|
+
json.email current_user.email
|
15
|
+
json.avatar current_user.avatar
|
16
|
+
json.inbox current_user.messages.count
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
json.dashboard(defer: :auto) do
|
21
|
+
sleep 5
|
22
|
+
json.complex_post_metric 500
|
23
|
+
end
|
24
|
+
|
25
|
+
json.posts do
|
26
|
+
page_num = params[:page_num]
|
27
|
+
paged_posts = @posts.page(page_num).per(20)
|
28
|
+
|
29
|
+
json.list do
|
30
|
+
json.array! paged_posts, key: :id do |post|
|
31
|
+
json.id post.id
|
32
|
+
json.description post.description
|
33
|
+
json.comments_count post.comments.count
|
34
|
+
json.edit_path edit_post_path(post)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
json.pagination_path posts_path
|
39
|
+
json.current paged_posts.current_page
|
40
|
+
json.total @posts.count
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
json.footer partial: 'shared/footer' do
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
## API
|
49
|
+
|
50
|
+
### json.set! or json.<your key here>
|
51
|
+
Defines the attribute or stucture. All keys are automatically camelized.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
json.set! :author_details, {..options...} do
|
55
|
+
json.set! :first_name, 'David'
|
56
|
+
end
|
57
|
+
|
58
|
+
or
|
59
|
+
|
60
|
+
json.author_details, {..options...} do
|
61
|
+
json.first_name, 'David'
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# => {"authorDetails": { "firstName": "David" }}
|
66
|
+
```
|
67
|
+
|
68
|
+
The inline form defines key and value
|
69
|
+
|
70
|
+
| Parameter | Notes |
|
71
|
+
| :--- | :--- |
|
72
|
+
| key | A json object key|
|
73
|
+
| value | A value |
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
json.set! :first_name, 'David'
|
77
|
+
|
78
|
+
or
|
79
|
+
|
80
|
+
json.first_name 'David'
|
81
|
+
|
82
|
+
# => { "firstName": "David" }
|
83
|
+
```
|
84
|
+
|
85
|
+
The block form defines key and structure
|
86
|
+
|
87
|
+
| Parameter | Notes |
|
88
|
+
| :--- | :--- |
|
89
|
+
| key | A json object key|
|
90
|
+
| options | Additional [options](#options)|
|
91
|
+
| block | Additional `json.set!`s or `json.array!`s|
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
json.set! :details do
|
95
|
+
...
|
96
|
+
end
|
97
|
+
|
98
|
+
or
|
99
|
+
|
100
|
+
json.details do
|
101
|
+
...
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
The difference between the block form and inline form is
|
106
|
+
1. The block form is an internal node. Partials, Deferement and other [options](#options) are only available on the block form.
|
107
|
+
2. The inline form is considered a leaf node, and you can only [search](#traversing) for internal nodes.
|
108
|
+
|
109
|
+
### json.array!
|
110
|
+
Generates an array of json objects.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
collection = [
|
114
|
+
{name: 'john'},
|
115
|
+
{name: 'jim'}
|
116
|
+
]
|
117
|
+
|
118
|
+
json.details do
|
119
|
+
json.array! collection, {....options...} do |person|
|
120
|
+
json.first_name person[:name]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# => {"details": [
|
125
|
+
{"firstName": 'john'},
|
126
|
+
{"firstName": 'jim'}
|
127
|
+
]}
|
128
|
+
```
|
129
|
+
|
130
|
+
| Parameter | Notes |
|
131
|
+
| :--- | :--- |
|
132
|
+
| collection | A collection that responds to `member_at` and `member_by` |
|
133
|
+
| options | Additional [options](#options)|
|
134
|
+
|
135
|
+
To support [traversing nodes](react-redux.md#traversing-nodes), any list passed to `array!` MUST implement `member_at(index)` and `member_by(attr, value)`.
|
136
|
+
|
137
|
+
For example, if you were using a delegate:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
class ObjectCollection < SimpleDelegator
|
141
|
+
def member_at(index)
|
142
|
+
at(index)
|
143
|
+
end
|
144
|
+
|
145
|
+
def member_by(attr, val)
|
146
|
+
find do |ele|
|
147
|
+
ele[attr] == val
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
Then in your template:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
data = ObjectCollection.new([{id: 1, name: 'foo'}, {id: 2, name: 'bar'}])
|
157
|
+
|
158
|
+
json.array! data do
|
159
|
+
...
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
Similarly for ActiveRecord:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
class ApplicationRecord < ActiveRecord::Base
|
167
|
+
def self.member_at(index)
|
168
|
+
offset(index).limit(1).first
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.member_by(attr, value)
|
172
|
+
find_by(Hash[attr, val])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
```
|
176
|
+
|
177
|
+
Then in your template:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
json.array! Post.all do
|
181
|
+
...
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
#### **Array core extension**
|
186
|
+
|
187
|
+
For convenience, PropsTemplate includes a core\_ext that adds these methods to `Array`. For example:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
require 'props_template/core_ext'
|
191
|
+
data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
|
192
|
+
|
193
|
+
json.posts
|
194
|
+
json.array! data do
|
195
|
+
...
|
196
|
+
end
|
197
|
+
end
|
198
|
+
```
|
199
|
+
|
200
|
+
PropsTemplate does not know what the elements are in your collection. The example above will be fine for [traversing](props-template.md#traversing_nodes) by index `\posts?bzq=posts.0`, but will raise a `NotImplementedError` if you traverse by attribute `/posts?bzq=posts.id=1`. You may still need a delegate that implements `member_by`.
|
201
|
+
|
202
|
+
### json.deferred!
|
203
|
+
Returns all deferred nodes used by the [#deferment](#deferment) option.
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
json.deferred json.deferred!
|
207
|
+
```
|
208
|
+
|
209
|
+
This method is normally used in `application.json.props` when first generated by `rails breezy:install:web`
|
210
|
+
|
211
|
+
### json.fragments!
|
212
|
+
Returns all fragment nodes used by the [partial fragments](#partial-fragments) option.
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
json.fragments json.fragments!
|
216
|
+
```
|
217
|
+
|
218
|
+
This method is normally used in `application.json.props` when first generated by `rails breezy:install:web`
|
219
|
+
|
220
|
+
### json.fragment_digest!
|
221
|
+
|
222
|
+
Returns the digest of the current partial name and the locals passed. Useful for [optimistic updates](#optimistic-updates).
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
# _some_partial.json.props
|
226
|
+
|
227
|
+
json.digest json.fragment_digest!
|
228
|
+
```
|
229
|
+
|
230
|
+
## Options
|
231
|
+
Functionality such as Partials, Deferements, and Caching can only be set on a block. It is normal to see empty blocks.
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
json.post(partial: 'blog_post') do
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
### Partials
|
239
|
+
|
240
|
+
Partials are supported. The following will render the file `views/posts/_blog_posts.json.props`, and set a local variable `foo` assigned with @post, which you can use inside the partial.
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
json.one_post partial: ["posts/blog_post", locals: {post: @post}] do
|
244
|
+
end
|
245
|
+
```
|
246
|
+
|
247
|
+
Usage with arrays:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
# as an option on an array. The `as:` option is supported when using `array!`
|
251
|
+
json.posts do
|
252
|
+
json.array! @posts, partial: ["posts/blog_post", locals: {foo: 'bar'}, as: 'post'] do
|
253
|
+
end
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
### Partial Fragments
|
258
|
+
|
259
|
+
A fragment uses a digest to identify a rendered partial across your page state in Redux. When BreezyJS recieves a payload with a fragment, it will update every fragment with the same digest in your Redux store.
|
260
|
+
|
261
|
+
You would need use partials and add the option `fragment: true`.
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
# index.json.props
|
265
|
+
json.header partial: ["profile", fragment: true] do
|
266
|
+
end
|
267
|
+
|
268
|
+
# _profile.json.props
|
269
|
+
json.profile do
|
270
|
+
json.address do
|
271
|
+
json.state "New York City"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
When using fragments with Arrays, the argument **MUST** be a lamda:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
require 'props_template/core_ext' #See (lists)[#Lists]
|
280
|
+
|
281
|
+
json.array! ['foo', 'bar'], partial: ["footer", fragment: ->(x){ x == 'foo'}]
|
282
|
+
```
|
283
|
+
|
284
|
+
PropsTemplate creates a name for the partial using a digest of your locals, partial name, and globalId (to_json as fallback if there is no globalId) on objects that you pass. You may override this behavior and use a custom identifier:
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
# index.js.breezy
|
288
|
+
json.header partial: ["profile", fragment: 'me_header'] do
|
289
|
+
end
|
290
|
+
```
|
291
|
+
|
292
|
+
#### Optimisitc Updates
|
293
|
+
Breezy uses the digest generated by `fragment: true` to uniquely identify a partial across the redux state. If you need to optimistically update a fragment, use `json.fragment_digest!` to obtain the identifier in your partial, and `updateFragments` from BreezyJS.
|
294
|
+
|
295
|
+
For example:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
# _header.js.props
|
299
|
+
json.fragment_digest json.fragment_digest!
|
300
|
+
```
|
301
|
+
|
302
|
+
And in your reducer
|
303
|
+
|
304
|
+
```javacript
|
305
|
+
import {updateFragments} from 'jho406/Breezy';
|
306
|
+
|
307
|
+
switch(action.type) {
|
308
|
+
case SOME_ACTION: {
|
309
|
+
const {
|
310
|
+
fragmentDigest,
|
311
|
+
prevNode // <- the content of the _header.js.props
|
312
|
+
} = action.payload
|
313
|
+
|
314
|
+
const nextNode = {
|
315
|
+
...prevNode,
|
316
|
+
foo: 'bar'
|
317
|
+
}
|
318
|
+
|
319
|
+
return updateFragments(state, {
|
320
|
+
[fragmentDigest]: nextNode
|
321
|
+
})
|
322
|
+
}
|
323
|
+
default:
|
324
|
+
return state
|
325
|
+
}
|
326
|
+
```
|
327
|
+
|
328
|
+
### Caching
|
329
|
+
Caching is supported on any node.
|
330
|
+
|
331
|
+
Usage:
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
json.author(cache: "some_cache_key") do
|
335
|
+
json.first_name "tommy"
|
336
|
+
end
|
337
|
+
|
338
|
+
#or
|
339
|
+
|
340
|
+
json.profile(cache: "cachekey", partial: ["profile", locals: {foo: 1}]) do
|
341
|
+
end
|
342
|
+
|
343
|
+
#or nest it
|
344
|
+
|
345
|
+
json.author(cache: "some_cache_key") do
|
346
|
+
json.address(cache: "some_other_cache_key") do
|
347
|
+
json.zip 11214
|
348
|
+
end
|
349
|
+
end
|
350
|
+
```
|
351
|
+
|
352
|
+
When used with arrays, PropsTemplate will use `Rails.cache.read_multi`.
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
require 'props_template/core_ext' #See (lists)[#Lists]
|
356
|
+
|
357
|
+
opts = {
|
358
|
+
cache: ->(i){ ['a', i] }
|
359
|
+
}
|
360
|
+
json.array! [4,5], opts do |x|
|
361
|
+
json.top "hello" + x.to_s
|
362
|
+
end
|
363
|
+
|
364
|
+
#or on arrays with partials
|
365
|
+
|
366
|
+
opts = {
|
367
|
+
cache: (->(d){ ['a', d.id] }),
|
368
|
+
partial: ["blog_post", as: :blog_post]
|
369
|
+
}
|
370
|
+
json.array! @options, opts
|
371
|
+
```
|
372
|
+
|
373
|
+
### Deferment
|
374
|
+
|
375
|
+
You can defer rendering of expensive nodes in your content tree using the `defer: :auto` option. Behind the scenes PropsTemplates will no-op the block entirely, replace the value with `{}` as a placeholder.
|
376
|
+
When the client recieves the payload, BreezyJS will use the meta data to issue a `remote` dispatch to fetch the missing node and immutibly graft it at the appropriate keypath in your Redux store.
|
377
|
+
|
378
|
+
You can access what was deferred with `json.deferred!`. If you use the generators, this will be set up in `application.json.props`.
|
379
|
+
|
380
|
+
Usage:
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
json.dashboard(defer: :auto) do
|
384
|
+
sleep 10
|
385
|
+
json.some_fancy_metric 42
|
386
|
+
end
|
387
|
+
```
|
388
|
+
|
389
|
+
A manual option is also available:
|
390
|
+
|
391
|
+
```ruby
|
392
|
+
json.dashboard(defer: :manual) do
|
393
|
+
sleep 10
|
394
|
+
json.some_fancy_metric 42
|
395
|
+
end
|
396
|
+
```
|
397
|
+
|
398
|
+
Finally in your `application.json.props`:
|
399
|
+
|
400
|
+
```ruby
|
401
|
+
json.defers json.deferred!
|
402
|
+
```
|
403
|
+
|
404
|
+
|
405
|
+
If `:manual` is used, PropsTemplate will no-op the block and will not populate `json.deferred!`. Its up to you to [traverse](props-template.md#traversing_nodes) to fetch the node seperately. A common usecase would be tab content that does not load until you click the tab.
|
406
|
+
|
407
|
+
#### Working with arrays
|
408
|
+
The default behavior for deferements is to use the index of the collection to identify an element. PropsTemplate will generate `?_bzq=a.b.c.0.title` in its metadata.
|
409
|
+
|
410
|
+
If you wish to use an attribute to identify the element. You must:
|
411
|
+
1. Implement `:key` to specify which attribute you want to use to uniquely identify the element in the collection. PropsTemplate will generate `?_bzq=a.b.c.some_id=some_value.title`
|
412
|
+
2. Implement `member_at`, and `member_key` on the collection to allow for BreezyJS to traverse the tree based on key value attributes.
|
413
|
+
|
414
|
+
For example:
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
require 'props_template/core_ext' #See (lists)[#Lists]
|
418
|
+
|
419
|
+
data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
|
420
|
+
|
421
|
+
json.posts
|
422
|
+
json.array! data, key: :some_id do |item|
|
423
|
+
json.contact(defer: :auto) do
|
424
|
+
json.address '123 example drive'
|
425
|
+
end
|
426
|
+
|
427
|
+
# json.some_id item.some_id will be appended automatically to the end of the block
|
428
|
+
end
|
429
|
+
end
|
430
|
+
```
|
431
|
+
|
432
|
+
When BreezyJS receives the response, it will automatically kick off `remote(?bzq=posts.some_id=1.contact)` and `remote(?bzq=posts.some_id=2.contact)`.
|
433
|
+
|
434
|
+
# Traversing
|
435
|
+
|
436
|
+
PropsTemplate has the ability to walk the tree you build, skipping execution of untargeted nodes. This feature is useful for partial updating your frontend state. See [traversing nodes](react-redux.md#traversing-nodes)
|
437
|
+
|
438
|
+
```ruby
|
439
|
+
traversal_path = ['data', 'details', 'personal']
|
440
|
+
|
441
|
+
json.data(search: traversal_path) do
|
442
|
+
json.details do
|
443
|
+
json.employment do
|
444
|
+
...more stuff...
|
445
|
+
end
|
446
|
+
|
447
|
+
json.personal do
|
448
|
+
json.name 'james'
|
449
|
+
json.zip_code 91210
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
json.footer do
|
455
|
+
...
|
456
|
+
end
|
457
|
+
```
|
458
|
+
|
459
|
+
PropsTemplate will will walk breath first, finds the matching key, executes the associated block, then repeats until it the node is found. The above will output the below:
|
460
|
+
|
461
|
+
```json
|
462
|
+
{
|
463
|
+
data: {
|
464
|
+
name: 'james',
|
465
|
+
zipCode: 91210
|
466
|
+
},
|
467
|
+
footer: {
|
468
|
+
....
|
469
|
+
}
|
470
|
+
}
|
471
|
+
```
|
472
|
+
|
473
|
+
Breezy's searching only works with blocks, and will NOT work with Scalars ("leaf" values). For example:
|
474
|
+
|
475
|
+
```ruby
|
476
|
+
traversal_path = ['data', 'details', 'personal', 'name'] <- not found
|
477
|
+
|
478
|
+
json.data(search: traversal_path) do
|
479
|
+
json.details do
|
480
|
+
json.personal do
|
481
|
+
json.name 'james'
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
```
|
487
|
+
|
488
|
+
## Nodes that do not exist
|
489
|
+
|
490
|
+
Nodes that are not found will not define the key where search was enabled on.
|
491
|
+
|
492
|
+
```ruby
|
493
|
+
traversal_path = ['data', 'details', 'does_not_exist']
|
494
|
+
|
495
|
+
json.data(search: traversal_path) do
|
496
|
+
json.details do
|
497
|
+
json.personal do
|
498
|
+
json.name 'james'
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
json.footer do
|
504
|
+
...
|
505
|
+
end
|
506
|
+
|
507
|
+
```
|
508
|
+
|
509
|
+
The above will render:
|
510
|
+
|
511
|
+
```
|
512
|
+
{
|
513
|
+
footer: {
|
514
|
+
...
|
515
|
+
}
|
516
|
+
}
|
517
|
+
```
|
@@ -78,23 +78,15 @@ module Props
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def handle_collection_item(collection, item, index, options)
|
81
|
-
if
|
82
|
-
member_key = collection.member_key
|
83
|
-
end
|
84
|
-
|
85
|
-
if !member_key
|
81
|
+
if !options[:key]
|
86
82
|
@traveled_path.push(index)
|
87
83
|
else
|
88
|
-
id =
|
89
|
-
item.send(member_key)
|
90
|
-
elsif item.is_a? Hash
|
91
|
-
item[member_key] || item[member_key.to_sym]
|
92
|
-
end
|
84
|
+
id, val = options[:key]
|
93
85
|
|
94
86
|
if id.nil?
|
95
87
|
@traveled_path.push(index)
|
96
88
|
else
|
97
|
-
@traveled_path.push("#{
|
89
|
+
@traveled_path.push("#{id.to_s}=#{val}")
|
98
90
|
end
|
99
91
|
end
|
100
92
|
|
@@ -110,6 +102,16 @@ module Props
|
|
110
102
|
|
111
103
|
|
112
104
|
def refine_item_options(item, options)
|
105
|
+
if key = options[:key]
|
106
|
+
val = if item.respond_to? key
|
107
|
+
item.send(key)
|
108
|
+
elsif item.is_a? Hash
|
109
|
+
item[key] || item[key.to_sym]
|
110
|
+
end
|
111
|
+
|
112
|
+
options[:key] = [options[:key], val]
|
113
|
+
end
|
114
|
+
|
113
115
|
@em.refine_options(options, item)
|
114
116
|
end
|
115
117
|
end
|
@@ -43,7 +43,7 @@ module Props
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def has_extensions(options)
|
46
|
-
options[:defer] || options[:cache] || options[:partial]
|
46
|
+
options[:defer] || options[:cache] || options[:partial] || options[:key]
|
47
47
|
end
|
48
48
|
|
49
49
|
def handle(commands, options)
|
@@ -64,6 +64,11 @@ module Props
|
|
64
64
|
else
|
65
65
|
yield
|
66
66
|
end
|
67
|
+
|
68
|
+
if options[:key]
|
69
|
+
id, val = options[:key]
|
70
|
+
base.set!(id, val)
|
71
|
+
end
|
67
72
|
end
|
68
73
|
end
|
69
74
|
end
|
@@ -35,6 +35,12 @@ module Props
|
|
35
35
|
type, rest = options[:defer]
|
36
36
|
placeholder = rest[:placeholder]
|
37
37
|
|
38
|
+
if type.to_sym == :auto && options[:key]
|
39
|
+
key, val = options[:key]
|
40
|
+
placeholder = {}
|
41
|
+
placeholder[key] = val
|
42
|
+
end
|
43
|
+
|
38
44
|
request_path = @base.context.controller.request.fullpath
|
39
45
|
path = @base.traveled_path.join('.')
|
40
46
|
uri = ::URI.parse(request_path)
|
@@ -18,9 +18,9 @@ module Props
|
|
18
18
|
def render_props_template(view, template, path, locals)
|
19
19
|
layout_locals = locals.dup
|
20
20
|
layout_locals.delete(:json)
|
21
|
+
layout_locals[:virtual_path_of_template] = template.virtual_path
|
21
22
|
|
22
|
-
layout = resolve_props_layout(path, layout_locals, [formats.first])
|
23
|
-
|
23
|
+
layout = resolve_props_layout(path, layout_locals.keys, [formats.first])
|
24
24
|
body = layout.render(view, layout_locals) do |json|
|
25
25
|
locals[:json] = json
|
26
26
|
template.render(view, locals)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: props_template
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -72,6 +72,7 @@ executables: []
|
|
72
72
|
extensions: []
|
73
73
|
extra_rdoc_files: []
|
74
74
|
files:
|
75
|
+
- README.md
|
75
76
|
- lib/props_template.rb
|
76
77
|
- lib/props_template/base.rb
|
77
78
|
- lib/props_template/base_with_extensions.rb
|