props_template 0.13.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +487 -0
- data/lib/props_template.rb +2 -9
- data/lib/props_template/base.rb +33 -24
- data/lib/props_template/base_with_extensions.rb +31 -30
- data/lib/props_template/debug_writer.rb +55 -0
- data/lib/props_template/extension_manager.rb +33 -32
- data/lib/props_template/extensions/cache.rb +2 -21
- data/lib/props_template/extensions/deferment.rb +17 -3
- data/lib/props_template/extensions/fragment.rb +4 -28
- data/lib/props_template/extensions/partial_renderer.rb +79 -33
- data/lib/props_template/layout_patch.rb +2 -2
- data/lib/props_template/railtie.rb +0 -8
- data/lib/props_template/searcher.rb +0 -3
- data/spec/layout_spec.rb +18 -10
- metadata +8 -21
- data/lib/props_template/key_formatter.rb +0 -33
data/lib/props_template.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require 'props_template/base_with_extensions'
|
4
2
|
require 'props_template/searcher'
|
5
3
|
require 'props_template/handler'
|
@@ -15,11 +13,9 @@ module Props
|
|
15
13
|
self.template_lookup_options = { handlers: [:props] }
|
16
14
|
|
17
15
|
delegate :result!, :array!,
|
18
|
-
:commands_to_json!,
|
19
16
|
:deferred!,
|
20
17
|
:fragments!,
|
21
18
|
:set_block_content!,
|
22
|
-
:fragment_digest!,
|
23
19
|
to: :builder!
|
24
20
|
|
25
21
|
def initialize(context = nil, options = {})
|
@@ -49,11 +45,8 @@ module Props
|
|
49
45
|
@builder
|
50
46
|
end
|
51
47
|
|
52
|
-
|
53
|
-
|
54
|
-
def method_missing(*args, &block)
|
55
|
-
set!(*args, &block)
|
56
|
-
end
|
48
|
+
alias_method :method_missing, :set!
|
49
|
+
private :method_missing
|
57
50
|
end
|
58
51
|
end
|
59
52
|
|
data/lib/props_template/base.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'oj'
|
2
2
|
require 'active_support'
|
3
|
-
|
4
3
|
#todo: active_support/core_ext/string/output_safety.rb
|
5
4
|
|
6
5
|
module Props
|
@@ -8,38 +7,49 @@ module Props
|
|
8
7
|
class InvalidScopeForObjError < StandardError; end
|
9
8
|
|
10
9
|
class Base
|
11
|
-
def initialize
|
12
|
-
@commands = [[:push_object]]
|
10
|
+
def initialize(encoder = nil)
|
13
11
|
@stream = Oj::StringWriter.new(mode: :rails)
|
14
12
|
@scope = nil
|
15
13
|
end
|
16
14
|
|
17
15
|
def set_block_content!(options = {})
|
18
|
-
@commands.push([:push_object])
|
19
16
|
@scope = nil
|
20
17
|
yield
|
21
|
-
@
|
18
|
+
if @scope.nil?
|
19
|
+
@stream.push_object
|
20
|
+
end
|
21
|
+
@stream.pop
|
22
22
|
end
|
23
23
|
|
24
24
|
def handle_set_block(key, options)
|
25
|
-
@
|
25
|
+
@stream.push_key(key)
|
26
26
|
set_block_content!(options) do
|
27
27
|
yield
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def format_key(key)
|
32
|
+
key.to_s
|
33
|
+
end
|
34
|
+
|
31
35
|
def set!(key, value = nil)
|
32
|
-
|
36
|
+
key = format_key(key)
|
37
|
+
|
33
38
|
if @scope == :array
|
34
39
|
raise InvalidScopeForObjError.new('Attempted to set! on an array! scope')
|
35
40
|
end
|
41
|
+
|
42
|
+
if @scope.nil?
|
43
|
+
@scope = :object
|
44
|
+
@stream.push_object
|
45
|
+
end
|
46
|
+
|
36
47
|
if block_given?
|
37
48
|
handle_set_block(key, value) do
|
38
49
|
yield
|
39
50
|
end
|
40
51
|
else
|
41
|
-
@
|
42
|
-
@commands.push([:push_value, value])
|
52
|
+
@stream.push_value(value, key)
|
43
53
|
end
|
44
54
|
|
45
55
|
@scope = :object
|
@@ -76,19 +86,18 @@ module Props
|
|
76
86
|
end
|
77
87
|
end
|
78
88
|
end
|
89
|
+
|
79
90
|
#todo, add ability to define contents of array
|
80
91
|
def array!(collection, options = {})
|
81
92
|
if @scope.nil?
|
82
93
|
@scope = :array
|
94
|
+
@stream.push_array
|
83
95
|
else
|
84
96
|
raise InvalidScopeForArrayError.new('array! expects exclusive use of this block')
|
85
97
|
end
|
86
|
-
@commands[-1] = [:push_array]
|
87
98
|
|
88
|
-
|
89
|
-
|
90
|
-
yield item, index
|
91
|
-
end
|
99
|
+
handle_collection(collection, options) do |item, index|
|
100
|
+
yield item, index
|
92
101
|
end
|
93
102
|
|
94
103
|
@scope = :array
|
@@ -96,18 +105,18 @@ module Props
|
|
96
105
|
nil
|
97
106
|
end
|
98
107
|
|
99
|
-
def
|
100
|
-
|
101
|
-
@stream.
|
108
|
+
def result!
|
109
|
+
if @scope.nil?
|
110
|
+
@stream.push_object
|
111
|
+
@stream.pop
|
112
|
+
else
|
113
|
+
@stream.pop
|
102
114
|
end
|
103
|
-
json = @stream.to_s
|
104
|
-
@stream.reset
|
105
|
-
json
|
106
|
-
end
|
107
115
|
|
108
|
-
|
109
|
-
@
|
110
|
-
|
116
|
+
json = @stream.raw_json
|
117
|
+
@scope = nil
|
118
|
+
@key_cache = {}
|
119
|
+
json
|
111
120
|
end
|
112
121
|
end
|
113
122
|
end
|
@@ -3,13 +3,12 @@ require 'props_template/extensions/partial_renderer'
|
|
3
3
|
require 'props_template/extensions/cache'
|
4
4
|
require 'props_template/extensions/deferment'
|
5
5
|
require 'props_template/extension_manager'
|
6
|
-
require 'props_template/key_formatter'
|
7
|
-
|
8
6
|
require 'active_support/core_ext/string/output_safety'
|
7
|
+
require 'active_support/core_ext/array'
|
9
8
|
|
10
9
|
module Props
|
11
10
|
class BaseWithExtensions < Base
|
12
|
-
attr_reader :builder, :context, :fragments, :traveled_path, :deferred, :
|
11
|
+
attr_reader :builder, :context, :fragments, :traveled_path, :deferred, :stream
|
13
12
|
|
14
13
|
def initialize(builder, context = nil, options = {})
|
15
14
|
@context = context
|
@@ -17,7 +16,7 @@ module Props
|
|
17
16
|
#todo: refactor so deferred can be its own class
|
18
17
|
@em = ExtensionManager.new(self)
|
19
18
|
@traveled_path = []
|
20
|
-
@
|
19
|
+
@key_cache = {}
|
21
20
|
super()
|
22
21
|
end
|
23
22
|
|
@@ -29,33 +28,32 @@ module Props
|
|
29
28
|
@em.fragments
|
30
29
|
end
|
31
30
|
|
32
|
-
def fragment_digest!
|
33
|
-
@em.fragment_digest
|
34
|
-
end
|
35
|
-
|
36
31
|
def set_block_content!(options = {})
|
37
32
|
return super if !@em.has_extensions(options)
|
38
33
|
|
39
|
-
@em.handle(
|
34
|
+
@em.handle(options) do
|
40
35
|
yield
|
41
36
|
end
|
42
37
|
end
|
43
38
|
|
44
39
|
def scoped_state
|
45
|
-
prev_state = [@
|
46
|
-
@
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@
|
40
|
+
prev_state = [@stream, @em.deferred, @em.fragments]
|
41
|
+
@em = ExtensionManager.new(self)
|
42
|
+
prev_scope = @scope
|
43
|
+
@scope = nil
|
44
|
+
|
45
|
+
yield @stream, @em.deferred, @em.fragments
|
46
|
+
|
47
|
+
@scope = prev_scope
|
51
48
|
@em = ExtensionManager.new(self, prev_state[1], prev_state[2])
|
49
|
+
end
|
52
50
|
|
53
|
-
|
51
|
+
def format_key(key)
|
52
|
+
@key_cache[key] ||= key.to_s.camelize(:lower)
|
53
|
+
@key_cache[key].dup
|
54
54
|
end
|
55
55
|
|
56
56
|
def set!(key, options = {}, &block)
|
57
|
-
key = @key_formatter.format(key)
|
58
|
-
|
59
57
|
if block_given?
|
60
58
|
options = @em.refine_options(options)
|
61
59
|
end
|
@@ -78,23 +76,15 @@ module Props
|
|
78
76
|
end
|
79
77
|
|
80
78
|
def handle_collection_item(collection, item, index, options)
|
81
|
-
if
|
82
|
-
member_key = collection.member_key
|
83
|
-
end
|
84
|
-
|
85
|
-
if !member_key
|
79
|
+
if !options[:key]
|
86
80
|
@traveled_path.push(index)
|
87
81
|
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
|
82
|
+
id, val = options[:key]
|
93
83
|
|
94
84
|
if id.nil?
|
95
85
|
@traveled_path.push(index)
|
96
86
|
else
|
97
|
-
@traveled_path.push("#{
|
87
|
+
@traveled_path.push("#{id.to_s}=#{val}")
|
98
88
|
end
|
99
89
|
end
|
100
90
|
|
@@ -108,8 +98,19 @@ module Props
|
|
108
98
|
@em.refine_all_item_options(all_options)
|
109
99
|
end
|
110
100
|
|
111
|
-
|
112
101
|
def refine_item_options(item, options)
|
102
|
+
return options if options.empty?
|
103
|
+
|
104
|
+
if key = options[:key]
|
105
|
+
val = if item.respond_to? key
|
106
|
+
item.send(key)
|
107
|
+
elsif item.is_a? Hash
|
108
|
+
item[key] || item[key.to_sym]
|
109
|
+
end
|
110
|
+
|
111
|
+
options[:key] = [options[:key], val]
|
112
|
+
end
|
113
|
+
|
113
114
|
@em.refine_options(options, item)
|
114
115
|
end
|
115
116
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'oj'
|
2
|
+
require 'active_support'
|
3
|
+
require 'byebug'
|
4
|
+
|
5
|
+
module Props
|
6
|
+
class DebugWriter
|
7
|
+
attr_accessor :commands
|
8
|
+
|
9
|
+
def initialize(opts)
|
10
|
+
@stream = Oj::StringWriter.new(opts)
|
11
|
+
@commands = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def push_object
|
15
|
+
@commands.push([:push_object])
|
16
|
+
end
|
17
|
+
|
18
|
+
def push_key(key)
|
19
|
+
@commands.push([:push_key, key])
|
20
|
+
end
|
21
|
+
|
22
|
+
def push_value(value, key = nil)
|
23
|
+
if key
|
24
|
+
@commands.push([:push_value, value, key])
|
25
|
+
else
|
26
|
+
@commands.push([:push_value, value])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def push_array
|
31
|
+
@commands.push([:push_array])
|
32
|
+
end
|
33
|
+
|
34
|
+
def pop
|
35
|
+
@commands.push([:pop])
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset
|
39
|
+
@commands = []
|
40
|
+
@stream.reset
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
@commands.each do |command|
|
45
|
+
begin
|
46
|
+
@stream.send(*command)
|
47
|
+
rescue => e
|
48
|
+
byebug
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@stream.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -7,7 +7,7 @@ module Props
|
|
7
7
|
class ExtensionManager
|
8
8
|
attr_reader :base, :builder, :context
|
9
9
|
|
10
|
-
def initialize(base, defered=[], fragments=
|
10
|
+
def initialize(base, defered=[], fragments=[])
|
11
11
|
@base = base
|
12
12
|
@context = base.context
|
13
13
|
@builder = base.builder
|
@@ -25,6 +25,8 @@ module Props
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def refine_all_item_options(all_options)
|
28
|
+
return all_options if all_options.empty?
|
29
|
+
|
28
30
|
all_options = @partialer.find_and_add_template(all_options)
|
29
31
|
all_options = @cache.multi_fetch_and_add_results(all_options)
|
30
32
|
all_options
|
@@ -34,36 +36,35 @@ module Props
|
|
34
36
|
@deferment.deferred
|
35
37
|
end
|
36
38
|
|
37
|
-
def fragment_digest
|
38
|
-
@fragment.name
|
39
|
-
end
|
40
|
-
|
41
39
|
def fragments
|
42
40
|
@fragment.fragments
|
43
41
|
end
|
44
42
|
|
45
43
|
def has_extensions(options)
|
46
|
-
options[:defer] || options[:cache] || options[:partial]
|
44
|
+
options[:defer] || options[:cache] || options[:partial] || options[:key]
|
47
45
|
end
|
48
46
|
|
49
|
-
def handle(
|
47
|
+
def handle(options)
|
50
48
|
return yield if !has_extensions(options)
|
51
49
|
|
52
50
|
if options[:defer]
|
53
51
|
placeholder = @deferment.handle(options)
|
54
|
-
|
52
|
+
base.stream.push_value(placeholder)
|
55
53
|
@fragment.handle(options)
|
56
54
|
else
|
57
55
|
handle_cache(options) do
|
58
56
|
base.set_block_content! do
|
59
57
|
if options[:partial]
|
60
|
-
current_digest = @fragment.name
|
61
58
|
@fragment.handle(options)
|
62
59
|
@partialer.handle(options)
|
63
|
-
@fragment.name = current_digest
|
64
60
|
else
|
65
61
|
yield
|
66
62
|
end
|
63
|
+
|
64
|
+
if options[:key]
|
65
|
+
id, val = options[:key]
|
66
|
+
base.set!(id, val)
|
67
|
+
end
|
67
68
|
end
|
68
69
|
end
|
69
70
|
end
|
@@ -71,33 +72,33 @@ module Props
|
|
71
72
|
|
72
73
|
private
|
73
74
|
|
74
|
-
def content_for_cache(commands, deferred_paths, fragment_paths)
|
75
|
-
suffix = [
|
76
|
-
[:push_value, deferred_paths],
|
77
|
-
[:push_value, fragment_paths],
|
78
|
-
[:pop]
|
79
|
-
]
|
80
|
-
|
81
|
-
[[:push_array]] + commands + suffix
|
82
|
-
end
|
83
|
-
|
84
75
|
def handle_cache(options)
|
85
76
|
if options[:cache]
|
77
|
+
recently_cached = false
|
78
|
+
|
86
79
|
state = @cache.cache(*options[:cache]) do
|
87
|
-
|
88
|
-
|
80
|
+
recently_cached = true
|
81
|
+
result = nil
|
82
|
+
start = base.stream.to_s.length
|
83
|
+
base.scoped_state { |stream, deferred_paths, fragment_paths|
|
84
|
+
yield
|
85
|
+
meta = Oj.dump([deferred_paths, fragment_paths]).strip
|
86
|
+
json_in_progress = base.stream.to_s
|
87
|
+
if json_in_progress[start] == ','
|
88
|
+
start += 1
|
89
|
+
end
|
90
|
+
raw = base.stream.to_s[start..-1].strip
|
91
|
+
result = "#{meta}\n#{raw}"
|
92
|
+
}
|
93
|
+
result
|
89
94
|
end
|
90
95
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
fragments[k].push(*v)
|
98
|
-
else
|
99
|
-
fragments[k] = v
|
100
|
-
end
|
96
|
+
if !recently_cached
|
97
|
+
meta, raw_json = state.split("\n")
|
98
|
+
next_deferred, next_fragments = Oj.load(meta)
|
99
|
+
base.stream.push_json(raw_json)
|
100
|
+
deferred.push(*next_deferred)
|
101
|
+
fragments.push(*next_fragments)
|
101
102
|
end
|
102
103
|
else
|
103
104
|
yield
|
@@ -25,12 +25,6 @@ module Props
|
|
25
25
|
@context
|
26
26
|
end
|
27
27
|
|
28
|
-
def instrument(name, **options)
|
29
|
-
ActiveSupport::Notifications.instrument(name, options) do |payload|
|
30
|
-
yield payload
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
28
|
def multi_fetch(keys, options = {})
|
35
29
|
result = {}
|
36
30
|
key_to_ckey = {}
|
@@ -49,7 +43,7 @@ module Props
|
|
49
43
|
|
50
44
|
read_caches = {}
|
51
45
|
|
52
|
-
instrument('read_multi_fragments.action_view', payload) do |payload|
|
46
|
+
ActiveSupport::Notifications.instrument('read_multi_fragments.action_view', payload) do |payload|
|
53
47
|
read_caches = ::Rails.cache.read_multi(*ckeys, options)
|
54
48
|
payload[:read_caches] = read_caches
|
55
49
|
end
|
@@ -122,7 +116,7 @@ module Props
|
|
122
116
|
|
123
117
|
def cache_key(key, options)
|
124
118
|
name_options = options.slice(:skip_digest, :virtual_path)
|
125
|
-
key =
|
119
|
+
key = @context.cache_fragment_name(key, **name_options)
|
126
120
|
|
127
121
|
if @context.respond_to?(:combined_fragment_cache_key)
|
128
122
|
key = @context.combined_fragment_cache_key(key)
|
@@ -132,19 +126,6 @@ module Props
|
|
132
126
|
|
133
127
|
::ActiveSupport::Cache.expand_cache_key(key, :props)
|
134
128
|
end
|
135
|
-
|
136
|
-
def fragment_name_with_digest(key, options)
|
137
|
-
if @context.respond_to?(:cache_fragment_name)
|
138
|
-
# Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
|
139
|
-
# should be used instead.
|
140
|
-
@context.cache_fragment_name(key, options)
|
141
|
-
elsif @context.respond_to?(:fragment_name_with_digest)
|
142
|
-
# Backwards compatibility for period of time when fragment_name_with_digest was made public.
|
143
|
-
@context.fragment_name_with_digest(key)
|
144
|
-
else
|
145
|
-
key
|
146
|
-
end
|
147
|
-
end
|
148
129
|
end
|
149
130
|
end
|
150
131
|
|