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.
@@ -34,6 +34,14 @@ 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]
39
+
40
+ if type.to_sym == :auto && options[:key]
41
+ key, val = options[:key]
42
+ placeholder = {}
43
+ placeholder[key] = val
44
+ end
37
45
 
38
46
  request_path = @base.context.controller.request.fullpath
39
47
  path = @base.traveled_path.join('.')
@@ -44,11 +52,17 @@ module Props
44
52
 
45
53
  uri.query = ::URI.encode_www_form(qry)
46
54
 
47
- @deferred.push(
55
+ deferral = {
48
56
  url: uri.to_s,
49
57
  path: path,
50
- type: type.to_s
51
- )
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)
52
66
 
53
67
  placeholder
54
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
- identity = {}
31
- locals
32
- .clone
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
- renderer = PartialRenderer.new(@context, partial_opts)
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] = renderer.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 < ActionView::AbstractRenderer
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
- fragment_name = Proc === fragment_name ? fragment_name.call(item) : fragment_name.to_s
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
- @context_prefix = @lookup_context.prefixes.first
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
- # Sets up instance variables needed for rendering a partial. This method
165
- # finds the options and details and extracts them. The method also contains
166
- # logic that handles the type of object passed in as the partial.
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)
@@ -18,9 +18,9 @@ module Props
18
18
  def render_props_template(view, template, path, locals)
19
19
  layout_locals = locals.dup
20
20
  layout_locals.delete(:json)
21
+ layout_locals[:virtual_path_of_template] = template.virtual_path
21
22
 
22
- layout = resolve_props_layout(path, layout_locals, [formats.first])
23
-
23
+ layout = resolve_props_layout(path, layout_locals.keys, [formats.first])
24
24
  body = layout.render(view, layout_locals) do |json|
25
25
  locals[:json] = json
26
26
  template.render(view, locals)
@@ -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
@@ -23,9 +23,6 @@ module Props
23
23
  []
24
24
  end
25
25
 
26
- def fragment_digest!
27
- end
28
-
29
26
  def found!
30
27
  pass_opts = @found_options.clone || {}
31
28
  pass_opts.delete(:defer)
@@ -1,16 +1,24 @@
1
- require_relative './support/helper'
2
- require_relative './support/rails_helper'
3
- require 'props_template/layout_patch'
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 'Props::Template' do
6
- it 'uses a layout to render' do
7
- view_path = File.join(File.dirname(__FILE__),'./fixtures')
8
- controller = ActionView::TestCase::TestController.new
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.render('200', layout: 'application')
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.13.0
4
+ version: 0.17.1
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: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2021-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -52,30 +52,18 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.9'
55
- - !ruby/object:Gem::Dependency
56
- name: concurrent-ruby
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
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
55
  description: A JSON builder for your React props
70
56
  email: jho406@gmail.com
71
57
  executables: []
72
58
  extensions: []
73
59
  extra_rdoc_files: []
74
60
  files:
61
+ - README.md
75
62
  - lib/props_template.rb
76
63
  - lib/props_template/base.rb
77
64
  - lib/props_template/base_with_extensions.rb
78
65
  - lib/props_template/core_ext.rb
66
+ - lib/props_template/debug_writer.rb
79
67
  - lib/props_template/dependency_tracker.rb
80
68
  - lib/props_template/extension_manager.rb
81
69
  - lib/props_template/extensions/cache.rb
@@ -83,7 +71,6 @@ files:
83
71
  - lib/props_template/extensions/fragment.rb
84
72
  - lib/props_template/extensions/partial_renderer.rb
85
73
  - lib/props_template/handler.rb
86
- - lib/props_template/key_formatter.rb
87
74
  - lib/props_template/layout_patch.rb
88
75
  - lib/props_template/railtie.rb
89
76
  - lib/props_template/searcher.rb
@@ -94,7 +81,7 @@ homepage: https://github.com/jho406/breezy/
94
81
  licenses:
95
82
  - MIT
96
83
  metadata: {}
97
- post_install_message:
84
+ post_install_message:
98
85
  rdoc_options: []
99
86
  require_paths:
100
87
  - lib
@@ -109,8 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
96
  - !ruby/object:Gem::Version
110
97
  version: '0'
111
98
  requirements: []
112
- rubygems_version: 3.0.3
113
- signing_key:
99
+ rubygems_version: 3.1.2
100
+ signing_key:
114
101
  specification_version: 4
115
102
  summary: A JSON builder for your React props
116
103
  test_files:
@@ -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