props_template 1.0.0.alpha.4 → 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 +58 -0
- data/lib/props_template/base.rb +7 -16
- data/lib/props_template/base_with_extensions.rb +25 -28
- data/lib/props_template/extension_manager.rb +28 -30
- 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 -33
- data/lib/props_template/searcher.rb +5 -14
- data/lib/props_template/test.md +28 -0
- data/lib/props_template/version.rb +1 -1
- data/lib/props_template.rb +2 -1
- metadata +3 -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,
|
|
@@ -105,6 +148,12 @@ json.authorDetails, with.some_option do
|
|
|
105
148
|
json.firstName 'David'
|
|
106
149
|
end
|
|
107
150
|
|
|
151
|
+
# or with hash options
|
|
152
|
+
|
|
153
|
+
json.authorDetails, {...options} do
|
|
154
|
+
json.firstName 'David'
|
|
155
|
+
end
|
|
156
|
+
|
|
108
157
|
|
|
109
158
|
# => {"authorDetails": { "firstName": "David" }}
|
|
110
159
|
```
|
|
@@ -125,6 +174,10 @@ json.set! :firstName, 'David'
|
|
|
125
174
|
json.firstName 'David'
|
|
126
175
|
|
|
127
176
|
# => { "firstName": "David" }
|
|
177
|
+
|
|
178
|
+
# or
|
|
179
|
+
|
|
180
|
+
json.postDetails with.partial("blog_post")
|
|
128
181
|
```
|
|
129
182
|
|
|
130
183
|
The block form defines key and structure
|
|
@@ -340,6 +393,11 @@ with @post, which you can use inside the partial.
|
|
|
340
393
|
|
|
341
394
|
```ruby
|
|
342
395
|
json.one_post(with.partial("posts/blog_post", locals: {post: @post}))
|
|
396
|
+
|
|
397
|
+
# or with hash options
|
|
398
|
+
|
|
399
|
+
json.one_post partial: ["posts/blog_post", locals: {post: @post}] do
|
|
400
|
+
end
|
|
343
401
|
```
|
|
344
402
|
|
|
345
403
|
Usage with arrays:
|
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
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
|
|
@@ -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
|
+
@item_context = item
|
|
68
|
+
|
|
67
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
|
|
@@ -29,7 +29,7 @@ module Props
|
|
|
29
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,10 +51,6 @@ module Props
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def set!(key, options = {}, &block)
|
|
54
|
-
if block || options.is_a?(Props::Options)
|
|
55
|
-
options = @em.refine_options(options)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
54
|
if !block && options.is_a?(Props::Options)
|
|
59
55
|
options.valid_for_set!
|
|
60
56
|
super {}
|
|
@@ -78,16 +74,37 @@ module Props
|
|
|
78
74
|
nil
|
|
79
75
|
end
|
|
80
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
|
+
|
|
81
92
|
def handle_collection_item(collection, item, index, options)
|
|
82
93
|
if !options[:key]
|
|
83
94
|
@traveled_path.push(index)
|
|
84
95
|
else
|
|
85
|
-
|
|
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
|
|
86
103
|
|
|
87
|
-
if
|
|
104
|
+
if key.nil?
|
|
88
105
|
@traveled_path.push(index)
|
|
89
106
|
else
|
|
90
|
-
@traveled_path.push("#{
|
|
107
|
+
@traveled_path.push("#{key}=#{val}")
|
|
91
108
|
end
|
|
92
109
|
end
|
|
93
110
|
|
|
@@ -96,25 +113,5 @@ module Props
|
|
|
96
113
|
@traveled_path.pop
|
|
97
114
|
nil
|
|
98
115
|
end
|
|
99
|
-
|
|
100
|
-
def refine_all_item_options(all_options)
|
|
101
|
-
@em.refine_all_item_options(all_options)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def refine_item_options(item, options)
|
|
105
|
-
return options if options.empty?
|
|
106
|
-
|
|
107
|
-
if (key = options[:key])
|
|
108
|
-
val = if item.respond_to? key
|
|
109
|
-
item.send(key)
|
|
110
|
-
elsif item.is_a? Hash
|
|
111
|
-
item[key] || item[key.to_sym]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
options[:key] = [options[:key], val]
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
@em.refine_options(options, item)
|
|
118
|
-
end
|
|
119
116
|
end
|
|
120
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
|
|
52
|
+
handle_cache(options, item_context) do
|
|
56
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,20 +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
|
|
@@ -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,7 +39,7 @@ 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
45
|
def set_content!(*args)
|
|
@@ -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
|
@@ -53,13 +53,14 @@ module Props
|
|
|
53
53
|
options.delete(:dig)
|
|
54
54
|
|
|
55
55
|
@builder.set!(key, options, &block)
|
|
56
|
-
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!
|
|
57
57
|
@found_path = found_path || []
|
|
58
58
|
@fragment_context = fragment_context
|
|
59
59
|
@builder = prev_builder
|
|
60
60
|
@fragment_path = fragment_path
|
|
61
61
|
|
|
62
62
|
if found_block
|
|
63
|
+
@builder.item_context = found_item
|
|
63
64
|
set!(key, found_options, &found_block)
|
|
64
65
|
end
|
|
65
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
|
|
@@ -89,6 +89,7 @@ files:
|
|
|
89
89
|
- lib/props_template/partial_patch.rb
|
|
90
90
|
- lib/props_template/railtie.rb
|
|
91
91
|
- lib/props_template/searcher.rb
|
|
92
|
+
- lib/props_template/test.md
|
|
92
93
|
- lib/props_template/version.rb
|
|
93
94
|
homepage: https://github.com/thoughtbot/props_template/
|
|
94
95
|
licenses:
|
|
@@ -101,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
101
102
|
requirements:
|
|
102
103
|
- - ">="
|
|
103
104
|
- !ruby/object:Gem::Version
|
|
104
|
-
version: '
|
|
105
|
+
version: '3.3'
|
|
105
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
107
|
requirements:
|
|
107
108
|
- - ">="
|