props_template 1.0.0.alpha.3 → 1.0.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 +4 -4
- data/README.md +111 -39
- data/lib/props_template/base.rb +24 -26
- data/lib/props_template/base_with_extensions.rb +31 -29
- data/lib/props_template/extension_manager.rb +29 -31
- data/lib/props_template/extensions/cache.rb +19 -36
- data/lib/props_template/extensions/deferment.rb +12 -22
- data/lib/props_template/extensions/fragment.rb +7 -3
- data/lib/props_template/extensions/partial_renderer.rb +16 -34
- data/lib/props_template/helper.rb +7 -0
- data/lib/props_template/options.rb +39 -0
- data/lib/props_template/railtie.rb +1 -0
- data/lib/props_template/searcher.rb +7 -16
- data/lib/props_template/test.md +28 -0
- data/lib/props_template/version.rb +1 -1
- data/lib/props_template.rb +5 -2
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e8ec3d3579ed65bb2a927d2bf7abb10c9e5f4ee4d5a5147da09e8efb1e6a030
|
|
4
|
+
data.tar.gz: f21d46d7b34d47ee191b0ddcfe68ceb506d15d316a4ad00e433ca3752d82045a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: db8bb1f529058a5dc7f2be56fe29720f638194e756a229da90deb85b3b885cd8de56dab5609219c73df23d1fe4de2cb80a2edc8803bce6a550ee8a4f16c36f70
|
|
7
|
+
data.tar.gz: dc997a26a9e941c8468e8b1cf755cb3c81e6b541ca7c56661f3ecaab8a701fed67712fd368e1cea50eb8b3dba76238ae169b3b8abb6e2e07485b5a8349ba5673
|
data/README.md
CHANGED
|
@@ -14,6 +14,49 @@ that other libraries perform by using Oj's `StringWriter` in `rails` mode.
|
|
|
14
14
|
|
|
15
15
|

|
|
16
16
|
|
|
17
|
+
It's really fast.
|
|
18
|
+
|
|
19
|
+
`props_template` is second only to `panko` while being feature packed. The
|
|
20
|
+
`Props::Base` [class](./lib/props_template/base.rb) that be used standalone
|
|
21
|
+
is the fastest among all JSON serializers. Results derived from [alba benchmarks](https://github.com/thoughtbot/alba/tree/main/benchmark).
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
props_base_class: 1439.9 i/s
|
|
25
|
+
panko: 1287.6 i/s - 1.12x slower
|
|
26
|
+
props_template: 998.8 i/s - 1.44x slower
|
|
27
|
+
turbostreamer: 912.9 i/s - 1.58x slower
|
|
28
|
+
alba: 871.0 i/s - 1.65x slower
|
|
29
|
+
jserializer: 668.7 i/s - 2.15x slower
|
|
30
|
+
alba_with_transformation: 604.2 i/s - 2.38x slower
|
|
31
|
+
barley: 452.2 i/s - 3.18x slower
|
|
32
|
+
barley_cache: 441.4 i/s - 3.26x slower
|
|
33
|
+
jbuilder: 432.6 i/s - 3.33x slower
|
|
34
|
+
fast_serializer: 390.1 i/s - 3.69x slower
|
|
35
|
+
rails: 374.1 i/s - 3.85x slower
|
|
36
|
+
rabl: 310.3 i/s - 4.64x slower
|
|
37
|
+
blueprinter: 268.4 i/s - 5.36x slower
|
|
38
|
+
representable: 187.2 i/s - 7.69x slower
|
|
39
|
+
simple_ams: 124.5 i/s - 11.57x slower
|
|
40
|
+
ams: 41.5 i/s - 34.67x slower
|
|
41
|
+
alba_inline: 10.9 i/s - 131.64x slower
|
|
42
|
+
|
|
43
|
+
Gem versions:
|
|
44
|
+
active_model_serializers: 0.10.16
|
|
45
|
+
alba: 3.10.0
|
|
46
|
+
barley: 0.9.0
|
|
47
|
+
blueprinter: 1.2.1
|
|
48
|
+
jbuilder: 2.14.1
|
|
49
|
+
jserializer: 0.2.1
|
|
50
|
+
panko_serializer: 0.8.4
|
|
51
|
+
rabl: 0.17.0
|
|
52
|
+
representable: 3.2.0
|
|
53
|
+
simple_ams: 0.2.6
|
|
54
|
+
turbostreamer: 1.11.0
|
|
55
|
+
|
|
56
|
+
Ruby version: 3.4.8
|
|
57
|
+
Apple M4 Pro
|
|
58
|
+
```
|
|
59
|
+
|
|
17
60
|
Caching is fast too.
|
|
18
61
|
|
|
19
62
|
While other libraries spend time unmarshaling,
|
|
@@ -36,7 +79,7 @@ json.menu do
|
|
|
36
79
|
end
|
|
37
80
|
end
|
|
38
81
|
|
|
39
|
-
json.dashboard(defer:
|
|
82
|
+
json.dashboard(with.defer(:auto)) do
|
|
40
83
|
sleep 5
|
|
41
84
|
json.complexPostMetric 500
|
|
42
85
|
end
|
|
@@ -46,7 +89,7 @@ json.posts do
|
|
|
46
89
|
paged_posts = @posts.page(page_num).per(20)
|
|
47
90
|
|
|
48
91
|
json.list do
|
|
49
|
-
json.array! paged_posts,
|
|
92
|
+
json.array! paged_posts, with.id_key(:id) do |post|
|
|
50
93
|
json.id post.id
|
|
51
94
|
json.description post.description
|
|
52
95
|
json.commentsCount post.comments.count
|
|
@@ -59,8 +102,7 @@ json.posts do
|
|
|
59
102
|
json.total @posts.count
|
|
60
103
|
end
|
|
61
104
|
|
|
62
|
-
json.footer partial
|
|
63
|
-
end
|
|
105
|
+
json.footer with.partial('shared/footer')
|
|
64
106
|
```
|
|
65
107
|
|
|
66
108
|
## Installation
|
|
@@ -96,12 +138,18 @@ You can also add a [layout](#layouts).
|
|
|
96
138
|
Defines the attribute or structure. All keys are not formatted by default. See [Change Key Format](#change-key-format) to change this behavior.
|
|
97
139
|
|
|
98
140
|
```ruby
|
|
99
|
-
json.set! :authorDetails,
|
|
141
|
+
json.set! :authorDetails, with.some_option do
|
|
100
142
|
json.set! :firstName, 'David'
|
|
101
143
|
end
|
|
102
144
|
|
|
103
145
|
# or
|
|
104
146
|
|
|
147
|
+
json.authorDetails, with.some_option do
|
|
148
|
+
json.firstName 'David'
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# or with hash options
|
|
152
|
+
|
|
105
153
|
json.authorDetails, {...options} do
|
|
106
154
|
json.firstName 'David'
|
|
107
155
|
end
|
|
@@ -115,7 +163,7 @@ The inline form defines key and value
|
|
|
115
163
|
| Parameter | Notes |
|
|
116
164
|
| :--- | :--- |
|
|
117
165
|
| key | A json object key|
|
|
118
|
-
| value | A value |
|
|
166
|
+
| value | A value or an [options][#options] object enabled with [partial](#partials)|
|
|
119
167
|
|
|
120
168
|
```ruby
|
|
121
169
|
|
|
@@ -126,6 +174,10 @@ json.set! :firstName, 'David'
|
|
|
126
174
|
json.firstName 'David'
|
|
127
175
|
|
|
128
176
|
# => { "firstName": "David" }
|
|
177
|
+
|
|
178
|
+
# or
|
|
179
|
+
|
|
180
|
+
json.postDetails with.partial("blog_post")
|
|
129
181
|
```
|
|
130
182
|
|
|
131
183
|
The block form defines key and structure
|
|
@@ -133,7 +185,7 @@ The block form defines key and structure
|
|
|
133
185
|
| Parameter | Notes |
|
|
134
186
|
| :--- | :--- |
|
|
135
187
|
| key | A json object key|
|
|
136
|
-
| options | Additional [options](#options)|
|
|
188
|
+
| options | Additional hash [options](#options) or a [options](#options) object|
|
|
137
189
|
| block | Additional `json.set!`s or `json.array!`s|
|
|
138
190
|
|
|
139
191
|
```ruby
|
|
@@ -149,11 +201,12 @@ end
|
|
|
149
201
|
```
|
|
150
202
|
|
|
151
203
|
The difference between the block form and inline form is
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
204
|
+
|
|
205
|
+
1. Passing options as a [hash](#hash-options) is only available for the
|
|
206
|
+
block form (also called an internal node)
|
|
207
|
+
2. The inline form is considered a leaf node, if you need features like
|
|
208
|
+
partials you may use [options](#options) objects only.
|
|
209
|
+
3. Only internal nodes may dug for [digging](#digging)
|
|
157
210
|
|
|
158
211
|
### json.extract!
|
|
159
212
|
Extracts attributes from object or hash in 1 line
|
|
@@ -189,7 +242,7 @@ Generates an array of json objects.
|
|
|
189
242
|
collection = [ {name: 'john'}, {name: 'jim'} ]
|
|
190
243
|
|
|
191
244
|
json.details do
|
|
192
|
-
json.array! collection,
|
|
245
|
+
json.array! collection, with.some_option do |person|
|
|
193
246
|
json.firstName person[:name]
|
|
194
247
|
end
|
|
195
248
|
end
|
|
@@ -306,11 +359,29 @@ option.
|
|
|
306
359
|
`application.json.props` when first running `rails superglue:install:web`
|
|
307
360
|
|
|
308
361
|
## Options
|
|
309
|
-
|
|
310
|
-
|
|
362
|
+
|
|
363
|
+
PropsTemplate provides a `with` helper to build a `Props::Option` object that enable
|
|
364
|
+
functionality such as Partials, Deferments, and Caching
|
|
365
|
+
|
|
366
|
+
The following are equivalent:
|
|
367
|
+
|
|
368
|
+
```ruby
|
|
369
|
+
json.post(with.partial('blog_post')
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
or
|
|
373
|
+
|
|
374
|
+
```ruby
|
|
375
|
+
json.post(Props::Options.new.partial('blog_post')
|
|
376
|
+
```
|
|
377
|
+
### Hash options
|
|
378
|
+
|
|
379
|
+
Previously, a normal hash was supported for internal nodes as long as an empty
|
|
380
|
+
block accompanied the option. This option is still supported, but its
|
|
381
|
+
recommended to use the `with` option builder.
|
|
311
382
|
|
|
312
383
|
```ruby
|
|
313
|
-
json.post(partial: 'blog_post') do
|
|
384
|
+
json.post(partial: 'blog_post', locals: {post: @post}) do
|
|
314
385
|
end
|
|
315
386
|
```
|
|
316
387
|
|
|
@@ -321,6 +392,10 @@ Partials are supported. The following will render the file
|
|
|
321
392
|
with @post, which you can use inside the partial.
|
|
322
393
|
|
|
323
394
|
```ruby
|
|
395
|
+
json.one_post(with.partial("posts/blog_post", locals: {post: @post}))
|
|
396
|
+
|
|
397
|
+
# or with hash options
|
|
398
|
+
|
|
324
399
|
json.one_post partial: ["posts/blog_post", locals: {post: @post}] do
|
|
325
400
|
end
|
|
326
401
|
```
|
|
@@ -332,8 +407,7 @@ Usage with arrays:
|
|
|
332
407
|
# Without `as:` option you can use blog_post variable (name is based on partial's name) inside partial
|
|
333
408
|
|
|
334
409
|
json.posts do
|
|
335
|
-
json.array! @posts, partial
|
|
336
|
-
end
|
|
410
|
+
json.array! @posts, with.partial("posts/blog_post", locals: {foo: 'bar'}, as: 'post')
|
|
337
411
|
end
|
|
338
412
|
```
|
|
339
413
|
|
|
@@ -344,16 +418,14 @@ cause performance problems. It's best used for things like a shared header or fo
|
|
|
344
418
|
Do:
|
|
345
419
|
|
|
346
420
|
```ruby
|
|
347
|
-
json.partial! partial
|
|
348
|
-
end
|
|
421
|
+
json.partial! with.partial("header", locals: {user: @user})
|
|
349
422
|
```
|
|
350
423
|
|
|
351
424
|
or
|
|
352
425
|
|
|
353
426
|
```ruby
|
|
354
427
|
json.posts do
|
|
355
|
-
json.array! @posts, partial
|
|
356
|
-
end
|
|
428
|
+
json.array! @posts, with.partial("posts/blog_post", locals: {post: @post})
|
|
357
429
|
end
|
|
358
430
|
```
|
|
359
431
|
|
|
@@ -374,8 +446,7 @@ update cross cutting concerns like a header bar.
|
|
|
374
446
|
|
|
375
447
|
```ruby
|
|
376
448
|
# index.json.props
|
|
377
|
-
json.header partial
|
|
378
|
-
end
|
|
449
|
+
json.header with.partial("profile").fragment("header")
|
|
379
450
|
|
|
380
451
|
# _profile.json.props
|
|
381
452
|
json.profile do
|
|
@@ -390,8 +461,7 @@ When using fragments with Arrays, the argument **MUST** be a lamda:
|
|
|
390
461
|
```ruby
|
|
391
462
|
require 'props_template/core_ext'
|
|
392
463
|
|
|
393
|
-
json.array! ['foo', 'bar'], partial
|
|
394
|
-
end
|
|
464
|
+
json.array! ['foo', 'bar'], with.partial("footer").fragment(->(x){ x == 'foo'})
|
|
395
465
|
```
|
|
396
466
|
|
|
397
467
|
### Caching
|
|
@@ -402,19 +472,18 @@ use [push_json](http://www.ohler.com/oj/doc/Oj/StringWriter.html#push_json-insta
|
|
|
402
472
|
Usage:
|
|
403
473
|
|
|
404
474
|
```ruby
|
|
405
|
-
json.author(cache
|
|
475
|
+
json.author(with.cache("some_cache_key")) do
|
|
406
476
|
json.firstName "tommy"
|
|
407
477
|
end
|
|
408
478
|
|
|
409
479
|
# or
|
|
410
480
|
|
|
411
|
-
json.profile(cache
|
|
412
|
-
end
|
|
481
|
+
json.profile(with.cache("cachekey").partial("profile", locals: {foo: 1}))
|
|
413
482
|
|
|
414
483
|
# or nest it
|
|
415
484
|
|
|
416
|
-
json.author(cache
|
|
417
|
-
json.address(cache
|
|
485
|
+
json.author(with.cache("some_cache_key")) do
|
|
486
|
+
json.address(with.cache("some_other_cache_key")) do
|
|
418
487
|
json.zip 11214
|
|
419
488
|
end
|
|
420
489
|
end
|
|
@@ -425,7 +494,7 @@ When used with arrays, PropsTemplate will use `Rails.cache.read_multi`.
|
|
|
425
494
|
```ruby
|
|
426
495
|
require 'props_template/core_ext'
|
|
427
496
|
|
|
428
|
-
opts =
|
|
497
|
+
opts = with.cache(->(i){ ['a', i] } )
|
|
429
498
|
|
|
430
499
|
json.array! [4,5], opts do |x|
|
|
431
500
|
json.top "hello" + x.to_s
|
|
@@ -433,7 +502,7 @@ end
|
|
|
433
502
|
|
|
434
503
|
# or on arrays with partials
|
|
435
504
|
|
|
436
|
-
opts =
|
|
505
|
+
opts = with.cache(->(d){ ['a', d.id] }).partial("blog_post", as: :blog_post)
|
|
437
506
|
|
|
438
507
|
json.array! @options, opts do
|
|
439
508
|
end
|
|
@@ -457,7 +526,7 @@ store.
|
|
|
457
526
|
Usage:
|
|
458
527
|
|
|
459
528
|
```ruby
|
|
460
|
-
json.dashboard(defer:
|
|
529
|
+
json.dashboard(with.defer(:manual)) do
|
|
461
530
|
sleep 10
|
|
462
531
|
json.someFancyMetric 42
|
|
463
532
|
end
|
|
@@ -465,7 +534,7 @@ end
|
|
|
465
534
|
|
|
466
535
|
# or you can explicitly pass a placeholder
|
|
467
536
|
|
|
468
|
-
json.dashboard(defer:
|
|
537
|
+
json.dashboard(with.defer(:manual, placeholder: {})) do
|
|
469
538
|
sleep 10
|
|
470
539
|
json.someFancyMetric 42
|
|
471
540
|
end
|
|
@@ -476,7 +545,7 @@ A auto option is available:
|
|
|
476
545
|
**Note** This is a [SuperglueJS][1] specific functionality.
|
|
477
546
|
|
|
478
547
|
```ruby
|
|
479
|
-
json.dashboard(defer:
|
|
548
|
+
json.dashboard(with.defer(:auto)) do
|
|
480
549
|
sleep 10
|
|
481
550
|
json.someFancyMetric 42
|
|
482
551
|
end
|
|
@@ -514,11 +583,11 @@ data = [
|
|
|
514
583
|
]
|
|
515
584
|
|
|
516
585
|
json.posts
|
|
517
|
-
json.array! data,
|
|
586
|
+
json.array! data, with.id_key(:some_id) do |item|
|
|
518
587
|
# By using :key, props_template will append `json.some_id item.some_id`
|
|
519
588
|
# automatically
|
|
520
589
|
|
|
521
|
-
json.contact(defer:
|
|
590
|
+
json.contact(with.defer(:auto)) do
|
|
522
591
|
json.address '123 example drive'
|
|
523
592
|
end
|
|
524
593
|
end
|
|
@@ -623,7 +692,10 @@ A single layout is supported. To use, create an `application.json.props` in
|
|
|
623
692
|
```ruby
|
|
624
693
|
json.data do
|
|
625
694
|
# template runs here.
|
|
626
|
-
|
|
695
|
+
_.call(json)
|
|
696
|
+
# NOTE: you can also use `yield json` instead, but prism sees this as
|
|
697
|
+
# a syntax error, so the `_.call(json)` is a workaround.
|
|
698
|
+
# See: https://github.com/thoughtbot/props_template/issues/58
|
|
627
699
|
end
|
|
628
700
|
|
|
629
701
|
json.header do
|
data/lib/props_template/base.rb
CHANGED
|
@@ -9,13 +9,17 @@ module Props
|
|
|
9
9
|
class InvalidScopeForChildError < StandardError; end
|
|
10
10
|
|
|
11
11
|
class Base
|
|
12
|
+
attr_accessor :item_context
|
|
13
|
+
|
|
12
14
|
def initialize(encoder = nil)
|
|
13
15
|
@stream = Oj::StringWriter.new(mode: :rails)
|
|
14
16
|
@scope = nil
|
|
17
|
+
@item_context = nil
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
def
|
|
20
|
+
def set_content!(options = {})
|
|
18
21
|
@scope = nil
|
|
22
|
+
@item_context = nil
|
|
19
23
|
yield
|
|
20
24
|
if @scope.nil?
|
|
21
25
|
@stream.push_object
|
|
@@ -26,7 +30,7 @@ module Props
|
|
|
26
30
|
def handle_set_block(key, options)
|
|
27
31
|
key = format_key(key)
|
|
28
32
|
@stream.push_key(key)
|
|
29
|
-
|
|
33
|
+
set_content!(options) do
|
|
30
34
|
yield
|
|
31
35
|
end
|
|
32
36
|
end
|
|
@@ -59,30 +63,17 @@ module Props
|
|
|
59
63
|
nil
|
|
60
64
|
end
|
|
61
65
|
|
|
62
|
-
def refine_item_options(item, options)
|
|
63
|
-
options
|
|
64
|
-
end
|
|
65
|
-
|
|
66
66
|
def handle_collection_item(collection, item, index, options)
|
|
67
|
-
|
|
67
|
+
@item_context = item
|
|
68
|
+
|
|
69
|
+
set_content!(options) do
|
|
68
70
|
yield
|
|
69
71
|
end
|
|
70
72
|
end
|
|
71
73
|
|
|
72
|
-
def refine_all_item_options(all_options)
|
|
73
|
-
all_options
|
|
74
|
-
end
|
|
75
|
-
|
|
76
74
|
def handle_collection(collection, options)
|
|
77
|
-
all_opts = collection.map do |item|
|
|
78
|
-
refine_item_options(item, options.clone)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
all_opts = refine_all_item_options(all_opts)
|
|
82
|
-
|
|
83
75
|
collection.each_with_index do |item, index|
|
|
84
|
-
|
|
85
|
-
handle_collection_item(collection, item, index, pass_opts) do
|
|
76
|
+
handle_collection_item(collection, item, index, options) do
|
|
86
77
|
# todo: remove index?
|
|
87
78
|
yield item, index
|
|
88
79
|
end
|
|
@@ -97,13 +88,20 @@ module Props
|
|
|
97
88
|
raise InvalidScopeForArrayError.new("array! expects exclusive use of this block")
|
|
98
89
|
end
|
|
99
90
|
|
|
100
|
-
if
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
if block_given?
|
|
92
|
+
if collection.nil?
|
|
93
|
+
@child_index = nil
|
|
94
|
+
yield
|
|
95
|
+
else
|
|
96
|
+
handle_collection(collection, options) do |item, index|
|
|
97
|
+
yield item, index
|
|
98
|
+
end
|
|
106
99
|
end
|
|
100
|
+
elsif options.is_a?(Props::Options)
|
|
101
|
+
options.valid_for_set!
|
|
102
|
+
handle_collection(collection, options) {}
|
|
103
|
+
else
|
|
104
|
+
raise ArgumentError.new("array! requires a block when no Props::Options object is given")
|
|
107
105
|
end
|
|
108
106
|
|
|
109
107
|
@scope = :array
|
|
@@ -147,7 +145,7 @@ module Props
|
|
|
147
145
|
child_index += 1
|
|
148
146
|
|
|
149
147
|
# this changes the scope to nil so child in a child will break
|
|
150
|
-
|
|
148
|
+
set_content!(options) do
|
|
151
149
|
yield
|
|
152
150
|
end
|
|
153
151
|
|
|
@@ -26,10 +26,10 @@ module Props
|
|
|
26
26
|
@traveled_path.join(".")
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def
|
|
29
|
+
def set_content!(options = {})
|
|
30
30
|
return super if !@em.has_extensions(options)
|
|
31
31
|
|
|
32
|
-
@em.handle(options) do
|
|
32
|
+
@em.handle(options, item_context) do
|
|
33
33
|
yield
|
|
34
34
|
end
|
|
35
35
|
end
|
|
@@ -51,11 +51,12 @@ module Props
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def set!(key, options = {}, &block)
|
|
54
|
-
if block
|
|
55
|
-
options
|
|
54
|
+
if !block && options.is_a?(Props::Options)
|
|
55
|
+
options.valid_for_set!
|
|
56
|
+
super {}
|
|
57
|
+
else
|
|
58
|
+
super
|
|
56
59
|
end
|
|
57
|
-
|
|
58
|
-
super
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
def handle_set_block(key, options)
|
|
@@ -73,16 +74,37 @@ module Props
|
|
|
73
74
|
nil
|
|
74
75
|
end
|
|
75
76
|
|
|
77
|
+
def handle_collection(collection, options)
|
|
78
|
+
if options[:cache]
|
|
79
|
+
key, rest = [*options[:cache]]
|
|
80
|
+
|
|
81
|
+
if ::Proc === key
|
|
82
|
+
cache_keys = collection.map do |item|
|
|
83
|
+
key.call(item)
|
|
84
|
+
end
|
|
85
|
+
@em.load_cache(cache_keys, rest || {})
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
super
|
|
90
|
+
end
|
|
91
|
+
|
|
76
92
|
def handle_collection_item(collection, item, index, options)
|
|
77
93
|
if !options[:key]
|
|
78
94
|
@traveled_path.push(index)
|
|
79
95
|
else
|
|
80
|
-
|
|
96
|
+
if (key = options[:key])
|
|
97
|
+
val = if item.respond_to? key
|
|
98
|
+
item.send(key)
|
|
99
|
+
elsif item.is_a? Hash
|
|
100
|
+
item[key] || item[key.to_sym]
|
|
101
|
+
end
|
|
102
|
+
end
|
|
81
103
|
|
|
82
|
-
if
|
|
104
|
+
if key.nil?
|
|
83
105
|
@traveled_path.push(index)
|
|
84
106
|
else
|
|
85
|
-
@traveled_path.push("#{
|
|
107
|
+
@traveled_path.push("#{key}=#{val}")
|
|
86
108
|
end
|
|
87
109
|
end
|
|
88
110
|
|
|
@@ -91,25 +113,5 @@ module Props
|
|
|
91
113
|
@traveled_path.pop
|
|
92
114
|
nil
|
|
93
115
|
end
|
|
94
|
-
|
|
95
|
-
def refine_all_item_options(all_options)
|
|
96
|
-
@em.refine_all_item_options(all_options)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def refine_item_options(item, options)
|
|
100
|
-
return options if options.empty?
|
|
101
|
-
|
|
102
|
-
if (key = options[:key])
|
|
103
|
-
val = if item.respond_to? key
|
|
104
|
-
item.send(key)
|
|
105
|
-
elsif item.is_a? Hash
|
|
106
|
-
item[key] || item[key.to_sym]
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
options[:key] = [options[:key], val]
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
@em.refine_options(options, item)
|
|
113
|
-
end
|
|
114
116
|
end
|
|
115
117
|
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module Props
|
|
2
2
|
class ExtensionManager
|
|
3
|
-
attr_reader :base, :builder, :context
|
|
3
|
+
attr_reader :base, :builder, :context, :cache, :partialer
|
|
4
|
+
|
|
5
|
+
delegate :load_cache, to: :cache
|
|
6
|
+
delegate :find_and_add_template, to: :partialer
|
|
4
7
|
|
|
5
8
|
def initialize(base, defered = [], fragments = [])
|
|
6
9
|
@base = base
|
|
@@ -16,22 +19,6 @@ module Props
|
|
|
16
19
|
@deferment.disable!
|
|
17
20
|
end
|
|
18
21
|
|
|
19
|
-
def refine_options(options, item = nil)
|
|
20
|
-
options = @partialer.refine_options(options, item)
|
|
21
|
-
if !@deferment.disabled
|
|
22
|
-
options = @deferment.refine_options(options, item)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
Cache.refine_options(options, item)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def refine_all_item_options(all_options)
|
|
29
|
-
return all_options if all_options.empty?
|
|
30
|
-
|
|
31
|
-
all_options = @partialer.find_and_add_template(all_options)
|
|
32
|
-
@cache.multi_fetch_and_add_results(all_options)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
22
|
def deferred
|
|
36
23
|
@deferment.deferred
|
|
37
24
|
end
|
|
@@ -44,26 +31,35 @@ module Props
|
|
|
44
31
|
options[:defer] || options[:cache] || options[:partial] || options[:key]
|
|
45
32
|
end
|
|
46
33
|
|
|
47
|
-
def handle(options)
|
|
34
|
+
def handle(options, item_context = nil)
|
|
48
35
|
return yield if !has_extensions(options)
|
|
49
36
|
|
|
50
|
-
if options[:
|
|
51
|
-
|
|
37
|
+
if (key = options[:key]) && item_context
|
|
38
|
+
val = if item_context.respond_to? key
|
|
39
|
+
item_context.send(key)
|
|
40
|
+
elsif item_context.is_a? Hash
|
|
41
|
+
item_context[key] || item_context[key.to_sym]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
deferment_type = @deferment.extract_deferment_type(options, item_context) if !@deferment.disabled
|
|
46
|
+
|
|
47
|
+
if deferment_type
|
|
48
|
+
placeholder = @deferment.handle(options, deferment_type, key, val)
|
|
52
49
|
base.stream.push_value(placeholder)
|
|
53
|
-
@fragment.handle(options)
|
|
50
|
+
@fragment.handle(options, item_context)
|
|
54
51
|
else
|
|
55
|
-
handle_cache(options) do
|
|
56
|
-
base.
|
|
52
|
+
handle_cache(options, item_context) do
|
|
53
|
+
base.set_content! do
|
|
57
54
|
if options[:partial]
|
|
58
|
-
@fragment.handle(options)
|
|
59
|
-
@partialer.handle(options)
|
|
55
|
+
@fragment.handle(options, item_context)
|
|
56
|
+
@partialer.handle(options, item_context)
|
|
60
57
|
else
|
|
61
58
|
yield
|
|
62
59
|
end
|
|
63
60
|
|
|
64
|
-
if
|
|
65
|
-
|
|
66
|
-
base.set!(id, val)
|
|
61
|
+
if key && val
|
|
62
|
+
base.set!(key, val)
|
|
67
63
|
end
|
|
68
64
|
end
|
|
69
65
|
end
|
|
@@ -72,11 +68,13 @@ module Props
|
|
|
72
68
|
|
|
73
69
|
private
|
|
74
70
|
|
|
75
|
-
def handle_cache(options)
|
|
71
|
+
def handle_cache(options, item)
|
|
76
72
|
if options[:cache]
|
|
77
73
|
recently_cached = false
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
key, rest = Cache
|
|
76
|
+
.normalize_options(options[:cache], item)
|
|
77
|
+
state = @cache.cache(key, rest) do
|
|
80
78
|
recently_cached = true
|
|
81
79
|
result = nil
|
|
82
80
|
start = base.stream.to_s.length
|
|
@@ -93,7 +91,7 @@ module Props
|
|
|
93
91
|
result
|
|
94
92
|
end
|
|
95
93
|
|
|
96
|
-
meta, raw_json = state.split("\n")
|
|
94
|
+
meta, raw_json = state.split("\n", 2)
|
|
97
95
|
next_deferred, next_fragments = Oj.load(meta)
|
|
98
96
|
deferred.push(*next_deferred)
|
|
99
97
|
fragments.push(*next_fragments)
|
|
@@ -2,23 +2,22 @@ module Props
|
|
|
2
2
|
class Cache
|
|
3
3
|
delegate :controller, :safe_concat, to: :@context
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
return options if !options[:cache]
|
|
5
|
+
attr_reader :results
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
def initialize(context)
|
|
8
|
+
@context = context
|
|
9
|
+
@results = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.normalize_options(options, item = nil)
|
|
13
|
+
key, rest = [*options]
|
|
10
14
|
rest ||= {}
|
|
11
15
|
|
|
12
16
|
if item && ::Proc === key
|
|
13
17
|
key = key.call(item)
|
|
14
18
|
end
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
pass_opts
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def initialize(context)
|
|
21
|
-
@context = context
|
|
20
|
+
[key, rest]
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
attr_reader :context
|
|
@@ -48,36 +47,21 @@ module Props
|
|
|
48
47
|
|
|
49
48
|
keys.each do |k|
|
|
50
49
|
ckey = key_to_ckey[k]
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
if read_caches[ckey]
|
|
52
|
+
result[k] = read_caches[ckey]
|
|
53
|
+
end
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
result
|
|
55
57
|
end
|
|
56
58
|
|
|
57
|
-
def
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if first_opts[:cache] && controller.perform_caching
|
|
61
|
-
keys = all_options.map { |i| i[:cache][0] }
|
|
62
|
-
c_opts = first_opts[:cache][1]
|
|
63
|
-
result = multi_fetch(keys, c_opts)
|
|
64
|
-
|
|
65
|
-
all_options.map do |opts|
|
|
66
|
-
key = opts[:cache][0]
|
|
67
|
-
|
|
68
|
-
if result.key? key
|
|
69
|
-
opts[:cache][1][:result] = result[key]
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
opts
|
|
73
|
-
end
|
|
74
|
-
else
|
|
75
|
-
all_options
|
|
76
|
-
end
|
|
59
|
+
def load_cache(keys, options = {})
|
|
60
|
+
@results = results.merge multi_fetch(keys, options)
|
|
77
61
|
end
|
|
78
62
|
|
|
79
|
-
#
|
|
80
|
-
#
|
|
63
|
+
# The below was copied from the wonderful jbuilder library Its also MIT
|
|
64
|
+
# licensed, so no issues there. Thanks to the jbuilder authors!
|
|
81
65
|
|
|
82
66
|
def cache(key = nil, options = {})
|
|
83
67
|
if controller.perform_caching
|
|
@@ -90,10 +74,9 @@ module Props
|
|
|
90
74
|
end
|
|
91
75
|
|
|
92
76
|
def cache_fragment_for(key, options, &block)
|
|
93
|
-
key
|
|
94
|
-
|
|
95
|
-
return options[:result] if options[:result]
|
|
77
|
+
return results[key] if results[key]
|
|
96
78
|
|
|
79
|
+
key = cache_key(key, options)
|
|
97
80
|
read_fragment_cache(key, options) || write_fragment_cache(key, options, &block)
|
|
98
81
|
end
|
|
99
82
|
|
|
@@ -13,37 +13,27 @@ module Props
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def refine_options(options, item = nil)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
type, rest = [*options[:defer]]
|
|
20
|
-
rest ||= {
|
|
21
|
-
placeholder: {}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if item
|
|
25
|
-
type = (Proc === type) ? type.call(item) : type
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
if type
|
|
29
|
-
pass_opts[:defer] = [type, rest]
|
|
30
|
-
else
|
|
31
|
-
pass_opts.delete(:defer)
|
|
32
|
-
end
|
|
16
|
+
options.clone
|
|
17
|
+
end
|
|
33
18
|
|
|
34
|
-
|
|
19
|
+
def extract_deferment_type(options, item)
|
|
20
|
+
type, _ = [*options[:defer]]
|
|
21
|
+
(Proc === type) ? type.call(item) : type
|
|
35
22
|
end
|
|
36
23
|
|
|
37
|
-
def handle(options)
|
|
24
|
+
def handle(options, type, key, val)
|
|
38
25
|
return if !options[:defer]
|
|
39
26
|
|
|
40
|
-
|
|
27
|
+
_, rest = [*options[:defer]]
|
|
28
|
+
rest ||= {
|
|
29
|
+
placeholder: {}
|
|
30
|
+
}
|
|
31
|
+
|
|
41
32
|
placeholder = rest[:placeholder]
|
|
42
33
|
success_action = rest[:success_action]
|
|
43
34
|
fail_action = rest[:fail_action]
|
|
44
35
|
|
|
45
|
-
if type.to_sym == :auto &&
|
|
46
|
-
key, val = options[:key]
|
|
36
|
+
if type.to_sym == :auto && key && val
|
|
47
37
|
placeholder = {}
|
|
48
38
|
placeholder[key] = val
|
|
49
39
|
end
|
|
@@ -7,7 +7,7 @@ module Props
|
|
|
7
7
|
@fragments = fragments
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def self.fragment_name_from_options(options)
|
|
10
|
+
def self.fragment_name_from_options(options, item = nil)
|
|
11
11
|
return if !options[:partial]
|
|
12
12
|
|
|
13
13
|
_, partial_opts = [*options[:partial]]
|
|
@@ -15,13 +15,17 @@ module Props
|
|
|
15
15
|
|
|
16
16
|
fragment = partial_opts[:fragment]
|
|
17
17
|
|
|
18
|
+
if item && ::Proc === fragment
|
|
19
|
+
fragment = fragment.call(item)
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
if String === fragment || Symbol === fragment
|
|
19
23
|
fragment.to_s
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
26
|
|
|
23
|
-
def handle(options)
|
|
24
|
-
fragment_name = self.class.fragment_name_from_options(options)
|
|
27
|
+
def handle(options, item_context = nil)
|
|
28
|
+
fragment_name = self.class.fragment_name_from_options(options, item_context)
|
|
25
29
|
path = @base.traveled_path
|
|
26
30
|
.map { |item| item.is_a?(Array) ? item[0] : item }
|
|
27
31
|
.join(".")
|
|
@@ -45,22 +45,6 @@ module Props
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def find_and_add_template(all_options)
|
|
49
|
-
first_opts = all_options[0]
|
|
50
|
-
|
|
51
|
-
if first_opts[:partial]
|
|
52
|
-
partial_opts = block_opts_to_render_opts(@builder, first_opts)
|
|
53
|
-
template = find_template(partial_opts)
|
|
54
|
-
|
|
55
|
-
all_options.map do |opts|
|
|
56
|
-
opts[:_template] = template
|
|
57
|
-
opts
|
|
58
|
-
end
|
|
59
|
-
else
|
|
60
|
-
all_options
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
48
|
def find_template(partial_opts)
|
|
65
49
|
partial = partial_opts[:partial]
|
|
66
50
|
template_keys = retrieve_template_keys(partial_opts)
|
|
@@ -78,7 +62,7 @@ module Props
|
|
|
78
62
|
|
|
79
63
|
def block_opts_to_render_opts(builder, options)
|
|
80
64
|
partial, pass_opts = [*options[:partial]]
|
|
81
|
-
pass_opts
|
|
65
|
+
pass_opts = pass_opts&.clone || {}
|
|
82
66
|
pass_opts[:locals] ||= {}
|
|
83
67
|
pass_opts[:partial] = partial
|
|
84
68
|
pass_opts[:formats] = [:json]
|
|
@@ -91,9 +75,17 @@ module Props
|
|
|
91
75
|
pass_opts
|
|
92
76
|
end
|
|
93
77
|
|
|
94
|
-
def handle(options)
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
def handle(options, item = nil)
|
|
79
|
+
return options if !options[:partial]
|
|
80
|
+
|
|
81
|
+
normalized_options = normalize_options(options, item)
|
|
82
|
+
partial_opts = block_opts_to_render_opts(@builder, normalized_options)
|
|
83
|
+
template = if options[:_template]
|
|
84
|
+
options[:_template]
|
|
85
|
+
else
|
|
86
|
+
# mutate the original options to bypass find_template a second time.
|
|
87
|
+
options[:_template] = find_template(partial_opts)
|
|
88
|
+
end
|
|
97
89
|
|
|
98
90
|
render_partial(template, @context, partial_opts)
|
|
99
91
|
end
|
|
@@ -133,8 +125,10 @@ module Props
|
|
|
133
125
|
end
|
|
134
126
|
|
|
135
127
|
def refine_options(options, item = nil)
|
|
136
|
-
|
|
128
|
+
options.clone
|
|
129
|
+
end
|
|
137
130
|
|
|
131
|
+
def normalize_options(options, item = nil)
|
|
138
132
|
partial, rest = [*options[:partial]]
|
|
139
133
|
rest = (rest || {}).clone
|
|
140
134
|
locals = (rest[:locals] || {}).clone
|
|
@@ -150,21 +144,9 @@ module Props
|
|
|
150
144
|
raise_invalid_option_as(as) unless /\A[a-z_]\w*\z/.match?(as.to_s)
|
|
151
145
|
|
|
152
146
|
locals[as] = item
|
|
153
|
-
|
|
154
|
-
if (fragment_name = rest[:fragment])
|
|
155
|
-
if item && ::Proc === fragment_name
|
|
156
|
-
fragment_name = fragment_name.call(item)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
rest[:fragment] = fragment_name.to_s
|
|
160
|
-
end
|
|
161
147
|
end
|
|
162
148
|
|
|
163
|
-
|
|
164
|
-
pass_opts[:partial] = [partial, rest]
|
|
165
|
-
|
|
166
|
-
pass_opts
|
|
149
|
+
{partial: [partial, rest]}
|
|
167
150
|
end
|
|
168
151
|
end
|
|
169
152
|
end
|
|
170
|
-
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Props
|
|
2
|
+
class Options < Hash
|
|
3
|
+
class InvalidOptionError < StandardError; end
|
|
4
|
+
|
|
5
|
+
def partial(partial_name, opts = {})
|
|
6
|
+
self[:partial] = [partial_name, opts]
|
|
7
|
+
self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def defer(type, placeholder: {}, **opts)
|
|
11
|
+
self[:defer] = [type, {placeholder: placeholder}.merge(opts)]
|
|
12
|
+
self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def fragment(fragment)
|
|
16
|
+
raise "Fragment can't be defined without a partial. Please use `partial` first" if !self[:partial]
|
|
17
|
+
|
|
18
|
+
self[:partial][1][:fragment] = fragment
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def cache(id_or_block)
|
|
23
|
+
return unless id_or_block
|
|
24
|
+
|
|
25
|
+
self[:cache] = id_or_block
|
|
26
|
+
self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def id_key(key_name)
|
|
30
|
+
self[:key] = key_name
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def valid_for_set!
|
|
35
|
+
raise InvalidOptionError.new("Props::Options can't be empty") if empty?
|
|
36
|
+
raise InvalidOptionError.new("The partial option must be used with an inline `set!`") if !key?(:partial)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -6,6 +6,7 @@ module Props
|
|
|
6
6
|
initializer :props_template do
|
|
7
7
|
ActiveSupport.on_load :action_view do
|
|
8
8
|
ActionView::Template.register_template_handler :props, Props::Handler
|
|
9
|
+
ActionView::Base.include Props::Helper
|
|
9
10
|
require "props_template/dependency_tracker"
|
|
10
11
|
require "props_template/layout_patch"
|
|
11
12
|
require "props_template/partial_patch"
|
|
@@ -12,6 +12,7 @@ module Props
|
|
|
12
12
|
@traveled_path = []
|
|
13
13
|
@partialer = Partialer.new(self, context, builder)
|
|
14
14
|
@fragment_name = nil
|
|
15
|
+
@found_item = nil
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def deferred!
|
|
@@ -30,7 +31,7 @@ module Props
|
|
|
30
31
|
pass_opts[:path_suffix] = traveled_path
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
fragment_name = Fragment.fragment_name_from_options(pass_opts)
|
|
34
|
+
fragment_name = Fragment.fragment_name_from_options(pass_opts, @found_item)
|
|
34
35
|
if fragment_name
|
|
35
36
|
@fragment_name = fragment_name
|
|
36
37
|
@fragment_path = @traveled_path.clone
|
|
@@ -38,15 +39,15 @@ module Props
|
|
|
38
39
|
|
|
39
40
|
fragment_context = @fragment_name
|
|
40
41
|
|
|
41
|
-
[@found_block, @traveled_path, pass_opts, @fragment_path, fragment_context]
|
|
42
|
+
[@found_block, @traveled_path, pass_opts, @fragment_path, fragment_context, @found_item]
|
|
42
43
|
end
|
|
43
44
|
|
|
44
|
-
def
|
|
45
|
+
def set_content!(*args)
|
|
45
46
|
yield
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
def set!(key, options = {}, &block)
|
|
49
|
-
return if @found_block || !block
|
|
50
|
+
return if @found_block || !block && !options.is_a?(Props::Options)
|
|
50
51
|
|
|
51
52
|
if @search_path[@depth] == key.to_s
|
|
52
53
|
@traveled_path.push(key)
|
|
@@ -97,21 +98,11 @@ module Props
|
|
|
97
98
|
|
|
98
99
|
if item
|
|
99
100
|
pass_opts = @partialer.refine_options(options, item)
|
|
100
|
-
|
|
101
|
-
if (key = pass_opts[:key])
|
|
102
|
-
val = if item.respond_to? key
|
|
103
|
-
item.send(key)
|
|
104
|
-
elsif item.is_a? Hash
|
|
105
|
-
item[key] || item[key.to_sym]
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
pass_opts[:key] = [pass_opts[:key], val]
|
|
109
|
-
end
|
|
110
|
-
|
|
111
101
|
@traveled_path.push(key_index)
|
|
112
102
|
|
|
113
103
|
if @depth == @search_path.size - 1
|
|
114
104
|
@found_options = pass_opts
|
|
105
|
+
@found_item = item
|
|
115
106
|
@found_block = proc {
|
|
116
107
|
yield item, 0
|
|
117
108
|
}
|
|
@@ -120,7 +111,7 @@ module Props
|
|
|
120
111
|
|
|
121
112
|
@depth += 1
|
|
122
113
|
if pass_opts[:partial]
|
|
123
|
-
fragment_name = Fragment.fragment_name_from_options(pass_opts)
|
|
114
|
+
fragment_name = Fragment.fragment_name_from_options(pass_opts, item)
|
|
124
115
|
if fragment_name
|
|
125
116
|
@fragment_name = fragment_name
|
|
126
117
|
@fragment_path = @traveled_path.clone
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
array
|
|
2
|
+
handle_collection
|
|
3
|
+
all_opts = collection.map do |item|
|
|
4
|
+
refine_item_options(item, options)
|
|
5
|
+
end
|
|
6
|
+
creates clone of the opts using
|
|
7
|
+
refine_item_options clones original options
|
|
8
|
+
then subsequently the ext refine_item_options
|
|
9
|
+
gets called first,
|
|
10
|
+
|
|
11
|
+
refine_all_item_options <- operates on the entire collection
|
|
12
|
+
|
|
13
|
+
handle_collection_item
|
|
14
|
+
set_content options
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
base with ExtensionManager
|
|
19
|
+
refine_all_item_options - overrided with ext manager
|
|
20
|
+
- which attahes a _template with partialer
|
|
21
|
+
to it AND multifetch and attaches it to cache
|
|
22
|
+
as [key, result]
|
|
23
|
+
|
|
24
|
+
refine_item_options
|
|
25
|
+
- transforms key: :id to key = [key, val]
|
|
26
|
+
- passes to refine_options
|
|
27
|
+
which is then asks the searcher the cache and
|
|
28
|
+
deferment to mutate the option
|
data/lib/props_template.rb
CHANGED
|
@@ -9,6 +9,8 @@ require "active_support/core_ext/string/output_safety"
|
|
|
9
9
|
require "active_support/core_ext/array"
|
|
10
10
|
require "props_template/searcher"
|
|
11
11
|
require "props_template/handler"
|
|
12
|
+
require "props_template/options"
|
|
13
|
+
require "props_template/helper"
|
|
12
14
|
require "props_template/version"
|
|
13
15
|
|
|
14
16
|
require "active_support"
|
|
@@ -28,7 +30,7 @@ module Props
|
|
|
28
30
|
:deferred!,
|
|
29
31
|
:fragments!,
|
|
30
32
|
:disable_deferments!,
|
|
31
|
-
:
|
|
33
|
+
:set_content!,
|
|
32
34
|
:traveled_path!,
|
|
33
35
|
:fragment_context!,
|
|
34
36
|
to: :builder!
|
|
@@ -51,13 +53,14 @@ module Props
|
|
|
51
53
|
options.delete(:dig)
|
|
52
54
|
|
|
53
55
|
@builder.set!(key, options, &block)
|
|
54
|
-
found_block, found_path, found_options, fragment_path, fragment_context = @builder.found!
|
|
56
|
+
found_block, found_path, found_options, fragment_path, fragment_context, found_item = @builder.found!
|
|
55
57
|
@found_path = found_path || []
|
|
56
58
|
@fragment_context = fragment_context
|
|
57
59
|
@builder = prev_builder
|
|
58
60
|
@fragment_path = fragment_path
|
|
59
61
|
|
|
60
62
|
if found_block
|
|
63
|
+
@builder.item_context = found_item
|
|
61
64
|
set!(key, found_options, &found_block)
|
|
62
65
|
end
|
|
63
66
|
else
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: props_template
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Johny Ho
|
|
@@ -83,10 +83,13 @@ files:
|
|
|
83
83
|
- lib/props_template/extensions/fragment.rb
|
|
84
84
|
- lib/props_template/extensions/partial_renderer.rb
|
|
85
85
|
- lib/props_template/handler.rb
|
|
86
|
+
- lib/props_template/helper.rb
|
|
86
87
|
- lib/props_template/layout_patch.rb
|
|
88
|
+
- lib/props_template/options.rb
|
|
87
89
|
- lib/props_template/partial_patch.rb
|
|
88
90
|
- lib/props_template/railtie.rb
|
|
89
91
|
- lib/props_template/searcher.rb
|
|
92
|
+
- lib/props_template/test.md
|
|
90
93
|
- lib/props_template/version.rb
|
|
91
94
|
homepage: https://github.com/thoughtbot/props_template/
|
|
92
95
|
licenses:
|
|
@@ -99,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
99
102
|
requirements:
|
|
100
103
|
- - ">="
|
|
101
104
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '
|
|
105
|
+
version: '3.3'
|
|
103
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
107
|
requirements:
|
|
105
108
|
- - ">="
|