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
@@ -34,6 +34,8 @@ module Props
|
|
34
34
|
|
35
35
|
type, rest = options[:defer]
|
36
36
|
placeholder = rest[:placeholder]
|
37
|
+
success_action = rest[:success_action]
|
38
|
+
fail_action = rest[:fail_action]
|
37
39
|
|
38
40
|
if type.to_sym == :auto && options[:key]
|
39
41
|
key, val = options[:key]
|
@@ -50,11 +52,17 @@ module Props
|
|
50
52
|
|
51
53
|
uri.query = ::URI.encode_www_form(qry)
|
52
54
|
|
53
|
-
|
55
|
+
deferral = {
|
54
56
|
url: uri.to_s,
|
55
57
|
path: path,
|
56
|
-
type: type.to_s
|
57
|
-
|
58
|
+
type: type.to_s,
|
59
|
+
}
|
60
|
+
|
61
|
+
# camelize for JS land
|
62
|
+
deferral[:successAction] = success_action if success_action
|
63
|
+
deferral[:failAction] = fail_action if fail_action
|
64
|
+
|
65
|
+
@deferred.push(deferral)
|
58
66
|
|
59
67
|
placeholder
|
60
68
|
end
|
@@ -1,14 +1,10 @@
|
|
1
|
-
require 'digest'
|
2
|
-
|
3
1
|
module Props
|
4
2
|
class Fragment
|
5
3
|
attr_reader :fragments
|
6
|
-
attr_accessor :name
|
7
4
|
|
8
|
-
def initialize(base, fragments=
|
5
|
+
def initialize(base, fragments=[])
|
9
6
|
@base = base
|
10
7
|
@fragments = fragments
|
11
|
-
@digest = Digest::SHA2.new(256)
|
12
8
|
end
|
13
9
|
|
14
10
|
def handle(options)
|
@@ -20,30 +16,10 @@ module Props
|
|
20
16
|
fragment_name = fragment.to_s
|
21
17
|
path = @base.traveled_path.join('.')
|
22
18
|
@name = fragment_name
|
23
|
-
@fragments[fragment_name] ||= []
|
24
|
-
@fragments[fragment_name].push(path)
|
25
|
-
end
|
26
|
-
|
27
|
-
if fragment == true
|
28
|
-
locals = partial_opts[:locals]
|
29
19
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
.tap{|h| h.delete(:json)}
|
34
|
-
.each do |key, value|
|
35
|
-
if value.respond_to?(:to_global_id)
|
36
|
-
identity[key] = value.to_global_id.to_s
|
37
|
-
else
|
38
|
-
identity[key] = value
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
path = @base.traveled_path.join('.')
|
43
|
-
fragment_name = @digest.hexdigest("#{partial_name}#{identity.to_json}")
|
44
|
-
@name = fragment_name
|
45
|
-
@fragments[fragment_name] ||= []
|
46
|
-
@fragments[fragment_name].push(path)
|
20
|
+
@fragments.push(
|
21
|
+
{ type: fragment_name, partial: partial_name, path: path }
|
22
|
+
)
|
47
23
|
end
|
48
24
|
end
|
49
25
|
end
|
@@ -1,23 +1,56 @@
|
|
1
|
-
require "concurrent/map"
|
2
1
|
require 'action_view'
|
3
2
|
|
4
3
|
module Props
|
4
|
+
class RenderedTemplate
|
5
|
+
attr_reader :body, :layout, :template
|
6
|
+
|
7
|
+
def initialize(body, layout, template)
|
8
|
+
@body = body
|
9
|
+
@layout = layout
|
10
|
+
@template = template
|
11
|
+
end
|
12
|
+
|
13
|
+
def format
|
14
|
+
template.format
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
5
18
|
class Partialer
|
19
|
+
INVALID_PARTIAL_MESSAGE = "The partial name must be a string, but received (%s)."
|
20
|
+
|
6
21
|
def initialize(base, context, builder)
|
7
22
|
@context = context
|
8
23
|
@builder = builder
|
9
24
|
@base = base
|
10
25
|
end
|
11
26
|
|
27
|
+
def extract_details(options) # :doc:
|
28
|
+
@context.lookup_context.registered_details.each_with_object({}) do |key, details|
|
29
|
+
value = options[key]
|
30
|
+
|
31
|
+
details[key] = Array(value) if value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
12
35
|
def find_and_add_template(all_options)
|
13
36
|
first_opts = all_options[0]
|
14
37
|
|
15
38
|
if first_opts[:partial]
|
16
39
|
partial_opts = block_opts_to_render_opts(@builder, first_opts)
|
17
|
-
|
40
|
+
.merge(formats: [:json])
|
41
|
+
partial_opts.delete(:handlers)
|
42
|
+
partial = partial_opts[:partial]
|
43
|
+
|
44
|
+
if !(String === partial)
|
45
|
+
raise ArgumentError.new(INVALID_PARTIAL_MESSAGE % (partial.inspect))
|
46
|
+
end
|
47
|
+
|
48
|
+
template_keys = retrieve_template_keys(partial_opts)
|
49
|
+
details = extract_details(partial_opts)
|
50
|
+
template = find_template(partial, template_keys, details)
|
18
51
|
|
19
52
|
all_options.map do |opts|
|
20
|
-
opts[:_template] =
|
53
|
+
opts[:_template] = template
|
21
54
|
opts
|
22
55
|
end
|
23
56
|
else
|
@@ -25,6 +58,17 @@ module Props
|
|
25
58
|
end
|
26
59
|
end
|
27
60
|
|
61
|
+
def find_template(path, locals, details)
|
62
|
+
prefixes = path.include?(?/) ? [] : @context.lookup_context.prefixes
|
63
|
+
@context.lookup_context.find_template(path, prefixes, true, locals, details)
|
64
|
+
end
|
65
|
+
|
66
|
+
def retrieve_template_keys(options)
|
67
|
+
template_keys = options[:locals].keys
|
68
|
+
template_keys << options[:as] if options[:as]
|
69
|
+
template_keys
|
70
|
+
end
|
71
|
+
|
28
72
|
def block_opts_to_render_opts(builder, options)
|
29
73
|
partial, pass_opts = [*options[:partial]]
|
30
74
|
pass_opts ||= {}
|
@@ -46,9 +90,20 @@ module Props
|
|
46
90
|
|
47
91
|
renderer.render(template, pass_opts)
|
48
92
|
end
|
93
|
+
|
94
|
+
def render(template, options)
|
95
|
+
view = @context
|
96
|
+
instrument(:partial, identifier: template.identifier) do |payload|
|
97
|
+
locals = options[:locals]
|
98
|
+
content = template.render(view, locals)
|
99
|
+
|
100
|
+
payload[:cache_hit] = view.view_renderer.cache_hits[template.virtual_path]
|
101
|
+
build_rendered_template(content, template)
|
102
|
+
end
|
103
|
+
end
|
49
104
|
end
|
50
105
|
|
51
|
-
class PartialRenderer
|
106
|
+
class PartialRenderer
|
52
107
|
OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " \
|
53
108
|
"make sure it starts with lowercase letter, " \
|
54
109
|
"and is followed by any combination of letters, numbers and underscores."
|
@@ -57,21 +112,6 @@ module Props
|
|
57
112
|
|
58
113
|
INVALID_PARTIAL_MESSAGE = "The partial name must be a string, but received (%s)."
|
59
114
|
|
60
|
-
def self.find_and_add_template(builder, context, all_options)
|
61
|
-
first_opts = all_options[0]
|
62
|
-
|
63
|
-
if first_opts[:partial]
|
64
|
-
partial_opts = block_opts_to_render_opts(builder, first_opts)
|
65
|
-
renderer = new(context, partial_opts)
|
66
|
-
|
67
|
-
all_options.map do |opts|
|
68
|
-
opts[:_template] = renderer.template
|
69
|
-
opts
|
70
|
-
end
|
71
|
-
else
|
72
|
-
all_options
|
73
|
-
end
|
74
|
-
end
|
75
115
|
|
76
116
|
def self.raise_invalid_option_as(as)
|
77
117
|
raise ArgumentError.new(OPTION_AS_ERROR_MESSAGE % (as))
|
@@ -81,7 +121,6 @@ module Props
|
|
81
121
|
raise ArgumentError.new(IDENTIFIER_ERROR_MESSAGE % (path))
|
82
122
|
end
|
83
123
|
|
84
|
-
|
85
124
|
def self.retrieve_variable(path)
|
86
125
|
base = path[-1] == "/" ? "" : File.basename(path)
|
87
126
|
raise_invalid_identifier(path) unless base =~ /\A_?(.*?)(?:\.\w+)*\z/
|
@@ -108,8 +147,7 @@ module Props
|
|
108
147
|
locals[as] = item
|
109
148
|
|
110
149
|
if fragment_name = rest[:fragment]
|
111
|
-
|
112
|
-
rest[:fragment] = fragment_name
|
150
|
+
rest[:fragment] = fragment_name.to_s
|
113
151
|
end
|
114
152
|
end
|
115
153
|
|
@@ -123,7 +161,6 @@ module Props
|
|
123
161
|
|
124
162
|
def initialize(context, options)
|
125
163
|
@context = context
|
126
|
-
super(@context.lookup_context)
|
127
164
|
@options = options.merge(formats: [:json])
|
128
165
|
@options.delete(:handlers)
|
129
166
|
@details = extract_details(@options)
|
@@ -135,7 +172,7 @@ module Props
|
|
135
172
|
end
|
136
173
|
|
137
174
|
@path = partial
|
138
|
-
|
175
|
+
|
139
176
|
template_keys = retrieve_template_keys(@options)
|
140
177
|
@template = find_template(@path, template_keys)
|
141
178
|
end
|
@@ -147,6 +184,19 @@ module Props
|
|
147
184
|
end
|
148
185
|
|
149
186
|
private
|
187
|
+
def extract_details(options) # :doc:
|
188
|
+
@context.lookup_context.registered_details.each_with_object({}) do |key, details|
|
189
|
+
value = options[key]
|
190
|
+
|
191
|
+
details[key] = Array(value) if value
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def instrument(name, **options) # :doc:
|
196
|
+
ActiveSupport::Notifications.instrument("render_#{name}.action_view", options) do |payload|
|
197
|
+
yield payload
|
198
|
+
end
|
199
|
+
end
|
150
200
|
|
151
201
|
def render_partial(template, view, options)
|
152
202
|
template ||= @template
|
@@ -161,17 +211,13 @@ module Props
|
|
161
211
|
end
|
162
212
|
end
|
163
213
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
#
|
168
|
-
# If +options[:partial]+ is a string, then the <tt>@path</tt> instance variable is
|
169
|
-
# set to that string. Otherwise, the +options[:partial]+ object must
|
170
|
-
# respond to +to_partial_path+ in order to setup the path.
|
214
|
+
def build_rendered_template(content, template, layout = nil)
|
215
|
+
RenderedTemplate.new content, layout, template
|
216
|
+
end
|
171
217
|
|
172
218
|
def find_template(path, locals)
|
173
|
-
prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
|
174
|
-
@lookup_context.find_template(path, prefixes, true, locals, @details)
|
219
|
+
prefixes = path.include?(?/) ? [] : @context.lookup_context.prefixes
|
220
|
+
@context.lookup_context.find_template(path, prefixes, true, locals, @details)
|
175
221
|
end
|
176
222
|
|
177
223
|
def retrieve_template_keys(options)
|
@@ -10,13 +10,5 @@ module Props
|
|
10
10
|
require 'props_template/layout_patch'
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
14
|
-
# if Rails::VERSION::MAJOR >= 4
|
15
|
-
# generators do |app|
|
16
|
-
# Rails::Generators.configure! app.config.generators
|
17
|
-
# Rails::Generators.hidden_namespaces.uniq!
|
18
|
-
# require 'generators/rails/scaffold_controller_generator'
|
19
|
-
# end
|
20
|
-
# end
|
21
13
|
end
|
22
14
|
end
|
data/spec/layout_spec.rb
CHANGED
@@ -1,16 +1,24 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require
|
1
|
+
require_relative "./support/helper"
|
2
|
+
require_relative "./support/rails_helper"
|
3
|
+
require "props_template/layout_patch"
|
4
|
+
require "action_controller"
|
4
5
|
|
5
|
-
RSpec.describe
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
RSpec.describe "Props::Template" do
|
7
|
+
class TestController < ActionController::Base
|
8
|
+
protect_from_forgery
|
9
|
+
|
10
|
+
def self.controller_path
|
11
|
+
""
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "uses a layout to render" do
|
16
|
+
view_path = File.join(File.dirname(__FILE__), "./fixtures")
|
17
|
+
controller = TestController.new
|
9
18
|
controller.prepend_view_path(view_path)
|
10
|
-
controller.response.headers['Content-Type']='application/json'
|
11
|
-
controller.request.path = '/some_url'
|
12
19
|
|
13
|
-
json = controller.
|
20
|
+
json = controller.render_to_string("200", layout: "application")
|
21
|
+
|
14
22
|
expect(json.strip).to eql('{"data":{"success":"ok"}}')
|
15
23
|
end
|
16
24
|
end
|
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.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,22 +52,10 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.9'
|
55
|
-
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.1'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.1'
|
69
|
-
description: A JSON builder for your React props
|
70
|
-
email: jho406@gmail.com
|
55
|
+
description: PropsTemplate is a direct-to-Oj, JBuilder-like DSL for building JSON.
|
56
|
+
It has support for Russian-Doll caching, layouts, and can be queried by giving the
|
57
|
+
root a key path.
|
58
|
+
email: johny@thoughtbot.com
|
71
59
|
executables: []
|
72
60
|
extensions: []
|
73
61
|
extra_rdoc_files: []
|
@@ -77,6 +65,7 @@ files:
|
|
77
65
|
- lib/props_template/base.rb
|
78
66
|
- lib/props_template/base_with_extensions.rb
|
79
67
|
- lib/props_template/core_ext.rb
|
68
|
+
- lib/props_template/debug_writer.rb
|
80
69
|
- lib/props_template/dependency_tracker.rb
|
81
70
|
- lib/props_template/extension_manager.rb
|
82
71
|
- lib/props_template/extensions/cache.rb
|
@@ -84,18 +73,18 @@ files:
|
|
84
73
|
- lib/props_template/extensions/fragment.rb
|
85
74
|
- lib/props_template/extensions/partial_renderer.rb
|
86
75
|
- lib/props_template/handler.rb
|
87
|
-
- lib/props_template/key_formatter.rb
|
88
76
|
- lib/props_template/layout_patch.rb
|
89
77
|
- lib/props_template/railtie.rb
|
90
78
|
- lib/props_template/searcher.rb
|
79
|
+
- lib/props_template/version.rb
|
91
80
|
- spec/layout_spec.rb
|
92
81
|
- spec/props_template_spec.rb
|
93
82
|
- spec/searcher_spec.rb
|
94
|
-
homepage: https://github.com/
|
83
|
+
homepage: https://github.com/thoughtbot/props_template/
|
95
84
|
licenses:
|
96
85
|
- MIT
|
97
86
|
metadata: {}
|
98
|
-
post_install_message:
|
87
|
+
post_install_message:
|
99
88
|
rdoc_options: []
|
100
89
|
require_paths:
|
101
90
|
- lib
|
@@ -103,17 +92,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
92
|
requirements:
|
104
93
|
- - ">="
|
105
94
|
- !ruby/object:Gem::Version
|
106
|
-
version: '2.
|
95
|
+
version: '2.5'
|
107
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
97
|
requirements:
|
109
98
|
- - ">="
|
110
99
|
- !ruby/object:Gem::Version
|
111
100
|
version: '0'
|
112
101
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
114
|
-
signing_key:
|
102
|
+
rubygems_version: 3.1.6
|
103
|
+
signing_key:
|
115
104
|
specification_version: 4
|
116
|
-
summary: A JSON builder
|
105
|
+
summary: A fast JSON builder
|
117
106
|
test_files:
|
118
107
|
- spec/searcher_spec.rb
|
119
108
|
- spec/layout_spec.rb
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/array'
|
2
|
-
|
3
|
-
module Props
|
4
|
-
class KeyFormatter
|
5
|
-
def initialize(*args)
|
6
|
-
@format = {}
|
7
|
-
@cache = {}
|
8
|
-
|
9
|
-
options = args.extract_options!
|
10
|
-
args.each do |name|
|
11
|
-
@format[name] = []
|
12
|
-
end
|
13
|
-
options.each do |name, parameters|
|
14
|
-
@format[name] = parameters
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize_copy(original)
|
19
|
-
@cache = {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def format(key)
|
23
|
-
@cache[key] ||= @format.inject(key.to_s) do |result, args|
|
24
|
-
func, args = args
|
25
|
-
if ::Proc === func
|
26
|
-
func.call result, *args
|
27
|
-
else
|
28
|
-
result.send func, *args
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|