props_template 0.14.0 → 0.20.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 +205 -140
- data/lib/props_template.rb +3 -9
- data/lib/props_template/base.rb +33 -24
- data/lib/props_template/base_with_extensions.rb +18 -19
- data/lib/props_template/debug_writer.rb +55 -0
- data/lib/props_template/extension_manager.rb +27 -31
- data/lib/props_template/extensions/cache.rb +2 -21
- data/lib/props_template/extensions/deferment.rb +11 -3
- data/lib/props_template/extensions/fragment.rb +4 -28
- data/lib/props_template/extensions/partial_renderer.rb +79 -33
- data/lib/props_template/railtie.rb +0 -8
- data/lib/props_template/searcher.rb +0 -3
- data/lib/props_template/version.rb +3 -0
- data/spec/layout_spec.rb +18 -10
- metadata +15 -26
- data/lib/props_template/key_formatter.rb +0 -33
data/lib/props_template.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
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'
|
4
|
+
require 'props_template/version'
|
6
5
|
|
7
6
|
require 'active_support'
|
8
7
|
|
@@ -15,11 +14,9 @@ module Props
|
|
15
14
|
self.template_lookup_options = { handlers: [:props] }
|
16
15
|
|
17
16
|
delegate :result!, :array!,
|
18
|
-
:commands_to_json!,
|
19
17
|
:deferred!,
|
20
18
|
:fragments!,
|
21
19
|
:set_block_content!,
|
22
|
-
:fragment_digest!,
|
23
20
|
to: :builder!
|
24
21
|
|
25
22
|
def initialize(context = nil, options = {})
|
@@ -49,11 +46,8 @@ module Props
|
|
49
46
|
@builder
|
50
47
|
end
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
def method_missing(*args, &block)
|
55
|
-
set!(*args, &block)
|
56
|
-
end
|
49
|
+
alias_method :method_missing, :set!
|
50
|
+
private :method_missing
|
57
51
|
end
|
58
52
|
end
|
59
53
|
|
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
|
@@ -100,8 +98,9 @@ module Props
|
|
100
98
|
@em.refine_all_item_options(all_options)
|
101
99
|
end
|
102
100
|
|
103
|
-
|
104
101
|
def refine_item_options(item, options)
|
102
|
+
return options if options.empty?
|
103
|
+
|
105
104
|
if key = options[:key]
|
106
105
|
val = if item.respond_to? key
|
107
106
|
item.send(key)
|
@@ -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,10 +36,6 @@ 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
|
@@ -46,21 +44,19 @@ module Props
|
|
46
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
|
@@ -76,33 +72,33 @@ module Props
|
|
76
72
|
|
77
73
|
private
|
78
74
|
|
79
|
-
def content_for_cache(commands, deferred_paths, fragment_paths)
|
80
|
-
suffix = [
|
81
|
-
[:push_value, deferred_paths],
|
82
|
-
[:push_value, fragment_paths],
|
83
|
-
[:pop]
|
84
|
-
]
|
85
|
-
|
86
|
-
[[:push_array]] + commands + suffix
|
87
|
-
end
|
88
|
-
|
89
75
|
def handle_cache(options)
|
90
76
|
if options[:cache]
|
77
|
+
recently_cached = false
|
78
|
+
|
91
79
|
state = @cache.cache(*options[:cache]) do
|
92
|
-
|
93
|
-
|
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
|
94
94
|
end
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
fragments[k].push(*v)
|
103
|
-
else
|
104
|
-
fragments[k] = v
|
105
|
-
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)
|
106
102
|
end
|
107
103
|
else
|
108
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
|
|