view_component 4.0.0.alpha5 → 4.0.0.alpha7
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/app/controllers/concerns/view_component/preview_actions.rb +9 -5
- data/app/controllers/view_components_system_test_controller.rb +1 -3
- data/app/views/test_mailer/test_url_email.html.erb +1 -0
- data/docs/CHANGELOG.md +86 -4
- data/lib/view_component/base.rb +91 -143
- data/lib/view_component/compiler.rb +14 -7
- data/lib/view_component/config.rb +41 -46
- data/lib/view_component/configurable.rb +1 -1
- data/lib/view_component/engine.rb +10 -10
- data/lib/view_component/errors.rb +0 -12
- data/lib/view_component/inline_template.rb +4 -4
- data/lib/view_component/preview.rb +1 -1
- data/lib/view_component/slot.rb +10 -15
- data/lib/view_component/slotable.rb +49 -45
- data/lib/view_component/template.rb +3 -3
- data/lib/view_component/test_helpers.rb +15 -2
- data/lib/view_component/translatable.rb +7 -7
- data/lib/view_component/version.rb +1 -1
- data/lib/view_component.rb +7 -5
- metadata +2 -410
- data/lib/view_component/component_local_config.rb +0 -60
- data/lib/view_component/slotable_default.rb +0 -18
- data/lib/view_component/use_helpers.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8be3a213c479ad3bc1cb82fad0a04b6b9a3f424a4995e0162e447c50cd6b0ef9
|
4
|
+
data.tar.gz: a7744949cc46b57628a55e78bb0bd766f048f140c8ca1769c271032e9d648176
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13776ebd6447652ce0ad682a40bc70a4141b6b2db8690c32d7191828adbe9fd16ec8d30775007b29ff4c71bc559317cc56b60c94ab2af67ef4d259ea89ec3220
|
7
|
+
data.tar.gz: 2463587d1336f2b30e17e51f728526157c27752adb66bbc3703d20b68326d20eb734ee2990c7583866723ba3d927564d22ea6ddd9c0a70e515264043ce1d08d6
|
@@ -8,7 +8,7 @@ module ViewComponent
|
|
8
8
|
prepend_view_path File.expand_path("../../../views", __dir__)
|
9
9
|
|
10
10
|
around_action :set_locale, only: :previews
|
11
|
-
before_action :require_local!, unless: :
|
11
|
+
before_action :require_local!, unless: :previews_enabled?
|
12
12
|
|
13
13
|
content_security_policy(false)
|
14
14
|
|
@@ -47,12 +47,12 @@ module ViewComponent
|
|
47
47
|
|
48
48
|
# :doc:
|
49
49
|
def default_preview_layout
|
50
|
-
ViewComponent::Base.config.
|
50
|
+
ViewComponent::Base.config.previews.default_layout
|
51
51
|
end
|
52
52
|
|
53
53
|
# :doc:
|
54
|
-
def
|
55
|
-
ViewComponent::Base.config.
|
54
|
+
def previews_enabled?
|
55
|
+
ViewComponent::Base.config.previews.enabled
|
56
56
|
end
|
57
57
|
|
58
58
|
# :doc:
|
@@ -64,7 +64,11 @@ module ViewComponent
|
|
64
64
|
if preview
|
65
65
|
@preview = ViewComponent::Preview.find(preview)
|
66
66
|
else
|
67
|
+
# TODO: This branch is covered in #test_returns_404_when_preview_does_not_exist,
|
68
|
+
# but Simplecov doesn't always mark it as covered.
|
69
|
+
# :nocov:
|
67
70
|
raise AbstractController::ActionNotFound, "Component preview '#{params[:path]}' not found."
|
71
|
+
# :nocov:
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
@@ -95,7 +99,7 @@ module ViewComponent
|
|
95
99
|
end
|
96
100
|
|
97
101
|
def prepend_preview_examples_view_path
|
98
|
-
prepend_view_path(ViewComponent::Base.
|
102
|
+
prepend_view_path(ViewComponent::Base.previews.paths)
|
99
103
|
end
|
100
104
|
end
|
101
105
|
end
|
@@ -19,9 +19,7 @@ class ViewComponentsSystemTestController < ActionController::Base # :nodoc:
|
|
19
19
|
def validate_file_path
|
20
20
|
base_path = ::File.realpath(self.class.temp_dir)
|
21
21
|
@path = ::File.realpath(params.permit(:file)[:file], base_path)
|
22
|
-
unless @path.start_with?(base_path)
|
23
|
-
raise ViewComponent::SystemTestControllerNefariousPathError
|
24
|
-
end
|
22
|
+
raise ViewComponent::SystemTestControllerNefariousPathError unless @path.start_with?(base_path)
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render(UrlForMailerComponent.new) %>
|
data/docs/CHANGELOG.md
CHANGED
@@ -10,6 +10,70 @@ nav_order: 6
|
|
10
10
|
|
11
11
|
## main
|
12
12
|
|
13
|
+
## 4.0.0.alpha7
|
14
|
+
|
15
|
+
* BREAKING: Remove deprecated `use_helper(s)`. Use `include MyHelper` or `helpers.` proxy instead.
|
16
|
+
|
17
|
+
*Joel Hawksley*
|
18
|
+
|
19
|
+
* BREAKING: Support compatibility with `Dry::Initializer`. As a result, `EmptyOrInvalidInitializerError` will no longer be raised.
|
20
|
+
|
21
|
+
*Joel Hawksley*
|
22
|
+
|
23
|
+
* BREAKING: Rename `config.generate.component_parent_class` to `config.generate.parent_class`.
|
24
|
+
|
25
|
+
*Joel Hawksley*
|
26
|
+
|
27
|
+
* Fix bug where `config.previews.enabled` did not function properly in production environments.
|
28
|
+
|
29
|
+
*Joel Hawksley*
|
30
|
+
|
31
|
+
* `config.previews.default_layout` should default to nil.
|
32
|
+
|
33
|
+
*Joel Hawksley*
|
34
|
+
|
35
|
+
* Add test case for absolute URL path helpers in mailers.
|
36
|
+
|
37
|
+
*Joel Hawksley*
|
38
|
+
|
39
|
+
* Fix bug where response format wasn't set, which caused issues with Turbo Frames.
|
40
|
+
|
41
|
+
*Joel Hawksley*
|
42
|
+
|
43
|
+
## 4.0.0.alpha6
|
44
|
+
|
45
|
+
* BREAKING: Remove `config.test_controller` in favor of `vc_test_controller_class` test helper method.
|
46
|
+
|
47
|
+
*Joel Hawksley*
|
48
|
+
|
49
|
+
* BREAKING: `config.component_parent_class` is now `config.generate.component_parent_class`, moving the generator-specific option to the generator configuration namespace.
|
50
|
+
|
51
|
+
*Joel Hawksley*
|
52
|
+
|
53
|
+
* BREAKING: Move previews-related configuration (`enabled`, `route`, `paths`, `default_layout`, `controller`) to under `previews` namespace.
|
54
|
+
|
55
|
+
*Joel Hawksley*
|
56
|
+
|
57
|
+
* Add template annotations for components with `def call`.
|
58
|
+
|
59
|
+
*Joel Hawksley*
|
60
|
+
|
61
|
+
* Add support for including Turbo::StreamsHelper.
|
62
|
+
|
63
|
+
*Stephen Nelson*
|
64
|
+
|
65
|
+
* Update documentation on performance to reflect more representative benchmark showing 2-3x speed increase over partials.
|
66
|
+
|
67
|
+
*Joel Hawksley*
|
68
|
+
|
69
|
+
* Add documentation note about instrumentation negatively affecting performance.
|
70
|
+
|
71
|
+
*Joel Hawksley*
|
72
|
+
|
73
|
+
* Revert object shapes optimization due to lack of evidence of improvement.
|
74
|
+
|
75
|
+
*Joel Hawksley*
|
76
|
+
|
13
77
|
## 4.0.0.alpha5
|
14
78
|
|
15
79
|
* BREAKING: `config.view_component_path` is now `config.generate.path`, as components have long since been able to exist in any directory.
|
@@ -20,10 +84,6 @@ nav_order: 6
|
|
20
84
|
|
21
85
|
*Joel Hawksley*
|
22
86
|
|
23
|
-
* Add internal optimization for Ruby object shapes.
|
24
|
-
|
25
|
-
*Adam Hess*, *Joel Hawksley*
|
26
|
-
|
27
87
|
## 4.0.0.alpha4
|
28
88
|
|
29
89
|
* BREAKING: Remove default initializer from `ViewComponent::Base`. Previously, `ViewComponent::Base` defined a catch-all initializer that allowed components without an initializer defined to be passed arbitrary arguments.
|
@@ -156,6 +216,28 @@ This release makes the following breaking changes:
|
|
156
216
|
|
157
217
|
*Simon Fish*
|
158
218
|
|
219
|
+
* Deprecate `use_helper(s)`. Use `include MyHelper` or `helpers.` proxy instead.
|
220
|
+
|
221
|
+
*Joel Hawksley*
|
222
|
+
|
223
|
+
* Reduce string allocations during compilation.
|
224
|
+
|
225
|
+
*Jonathan del Strother*
|
226
|
+
|
227
|
+
## 3.23.2
|
228
|
+
|
229
|
+
* Include .tt files in published gem. Fixes templates not being available when using generators.
|
230
|
+
|
231
|
+
*Florian Aßmann*
|
232
|
+
|
233
|
+
## 3.23.1
|
234
|
+
|
235
|
+
* Restore Rake tasks in published gem.
|
236
|
+
|
237
|
+
*Franz Liedke*
|
238
|
+
|
239
|
+
## 3.23.0
|
240
|
+
|
159
241
|
* Add docs about Slack channel in Ruby Central workspace. (Join us! #oss-view-component). Email joelhawksley@github.com for an invite.
|
160
242
|
|
161
243
|
*Joel Hawksley
|
data/lib/view_component/base.rb
CHANGED
@@ -5,7 +5,6 @@ require "active_support/configurable"
|
|
5
5
|
require "view_component/collection"
|
6
6
|
require "view_component/compile_cache"
|
7
7
|
require "view_component/compiler"
|
8
|
-
require "view_component/component_local_config"
|
9
8
|
require "view_component/config"
|
10
9
|
require "view_component/errors"
|
11
10
|
require "view_component/inline_template"
|
@@ -15,7 +14,6 @@ require "view_component/slotable"
|
|
15
14
|
require "view_component/template"
|
16
15
|
require "view_component/translatable"
|
17
16
|
require "view_component/with_content_helper"
|
18
|
-
require "view_component/use_helpers"
|
19
17
|
|
20
18
|
module ActionView
|
21
19
|
class OutputBuffer
|
@@ -35,15 +33,6 @@ module ViewComponent
|
|
35
33
|
class << self
|
36
34
|
delegate(*ViewComponent::Config.defaults.keys, to: :config)
|
37
35
|
|
38
|
-
# Redefine `new` so we can pre-allocate instance variables to optimize
|
39
|
-
# for Ruby object shapes.
|
40
|
-
def new(...)
|
41
|
-
instance = allocate
|
42
|
-
instance.__vc_pre_allocate_instance_variables
|
43
|
-
instance.send(:initialize, ...)
|
44
|
-
instance
|
45
|
-
end
|
46
|
-
|
47
36
|
# Returns the current config.
|
48
37
|
#
|
49
38
|
# @return [ActiveSupport::OrderedOptions]
|
@@ -57,39 +46,15 @@ module ViewComponent
|
|
57
46
|
end
|
58
47
|
end
|
59
48
|
|
60
|
-
def __vc_pre_allocate_instance_variables
|
61
|
-
@__vc_parent_render_level = 0
|
62
|
-
@__vc_set_slots = {}
|
63
|
-
@__vc_content_evaluated = false
|
64
|
-
@current_template = nil
|
65
|
-
@output_buffer = nil
|
66
|
-
@lookup_context = nil
|
67
|
-
@view_flow = nil
|
68
|
-
@view_context = nil
|
69
|
-
@virtual_path = nil
|
70
|
-
@__vc_ancestor_calls = nil
|
71
|
-
@__vc_controller = nil
|
72
|
-
@__vc_content = :unset # some behaviors depend on checking for nil
|
73
|
-
@__vc_content_set_by_with_content = nil
|
74
|
-
@__vc_helpers = nil
|
75
|
-
@__vc_inline_template = nil
|
76
|
-
@__vc_inline_template_defined = nil
|
77
|
-
@__vc_render_in_block = nil
|
78
|
-
@__vc_request = nil
|
79
|
-
@__vc_requested_details = nil
|
80
|
-
@__vc_original_view_context = nil
|
81
|
-
end
|
82
|
-
|
83
49
|
include ActionView::Helpers
|
50
|
+
include Rails.application.routes.url_helpers if defined?(Rails) && Rails.application
|
84
51
|
include ERB::Escape
|
85
52
|
include ActiveSupport::CoreExt::ERBUtil
|
86
53
|
|
87
54
|
include ViewComponent::InlineTemplate
|
88
|
-
include ViewComponent::UseHelpers
|
89
55
|
include ViewComponent::Slotable
|
90
56
|
include ViewComponent::Translatable
|
91
57
|
include ViewComponent::WithContentHelper
|
92
|
-
include ViewComponent::ComponentLocalConfig
|
93
58
|
|
94
59
|
# For CSRF authenticity tokens in forms
|
95
60
|
delegate :form_authenticity_token, :protect_against_forgery?, :config, to: :helpers
|
@@ -97,9 +62,17 @@ module ViewComponent
|
|
97
62
|
# HTML construction methods
|
98
63
|
delegate :output_buffer, :lookup_context, :view_renderer, :view_flow, to: :helpers
|
99
64
|
|
65
|
+
# For Turbo::StreamsHelper
|
66
|
+
delegate :formats, :formats=, to: :helpers
|
67
|
+
|
100
68
|
# For Content Security Policy nonces
|
101
69
|
delegate :content_security_policy_nonce, to: :helpers
|
102
70
|
|
71
|
+
# Config option that strips trailing whitespace in templates before compiling them.
|
72
|
+
class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false, default: false
|
73
|
+
|
74
|
+
class_attribute :__vc_response_format, instance_accessor: false, instance_predicate: false, default: nil
|
75
|
+
|
103
76
|
attr_accessor :__vc_original_view_context
|
104
77
|
attr_reader :current_template
|
105
78
|
|
@@ -118,6 +91,11 @@ module ViewComponent
|
|
118
91
|
|
119
92
|
using RequestDetails
|
120
93
|
|
94
|
+
# Including `Rails.application.routes.url_helpers` defines an initializer that accepts (...),
|
95
|
+
# so we have to define our own empty initializer to overwrite it.
|
96
|
+
def initialize
|
97
|
+
end
|
98
|
+
|
121
99
|
# Entrypoint for rendering components.
|
122
100
|
#
|
123
101
|
# - `view_context`: ActionView context from calling view
|
@@ -146,12 +124,14 @@ module ViewComponent
|
|
146
124
|
@__vc_requested_details ||= @lookup_context.vc_requested_details
|
147
125
|
|
148
126
|
# For caching, such as #cache_if
|
127
|
+
@current_template = nil unless defined?(@current_template)
|
149
128
|
old_current_template = @current_template
|
150
129
|
|
151
|
-
if block && __vc_content_set_by_with_content
|
130
|
+
if block && defined?(@__vc_content_set_by_with_content)
|
152
131
|
raise DuplicateContentError.new(self.class.name)
|
153
132
|
end
|
154
133
|
|
134
|
+
@__vc_content_evaluated = false
|
155
135
|
@__vc_render_in_block = block
|
156
136
|
|
157
137
|
before_render
|
@@ -166,10 +146,15 @@ module ViewComponent
|
|
166
146
|
value = if output_preamble.blank? && output_postamble.blank?
|
167
147
|
rendered_template
|
168
148
|
else
|
169
|
-
|
149
|
+
__vc_safe_output_preamble + rendered_template + __vc_safe_output_postamble
|
170
150
|
end
|
171
151
|
end
|
172
152
|
|
153
|
+
if ActionView::Base.annotate_rendered_view_with_filenames && current_template.inline_call? && request&.format == :html
|
154
|
+
identifier = defined?(Rails.root) ? self.class.identifier.sub("#{Rails.root}/", "") : self.class.identifier
|
155
|
+
value = "<!-- BEGIN #{identifier} -->".html_safe + value + "<!-- END #{identifier} -->".html_safe
|
156
|
+
end
|
157
|
+
|
173
158
|
value
|
174
159
|
else
|
175
160
|
""
|
@@ -205,12 +190,16 @@ module ViewComponent
|
|
205
190
|
#
|
206
191
|
# When rendering the parent inside an .erb template, use `#render_parent` instead.
|
207
192
|
def render_parent_to_string
|
208
|
-
|
209
|
-
@__vc_parent_render_level += 1
|
193
|
+
@__vc_parent_render_level ||= 0 # ensure a good starting value
|
210
194
|
|
211
|
-
|
212
|
-
|
213
|
-
|
195
|
+
begin
|
196
|
+
target_render = self.class.instance_variable_get(:@__vc_ancestor_calls)[@__vc_parent_render_level]
|
197
|
+
@__vc_parent_render_level += 1
|
198
|
+
|
199
|
+
target_render.bind_call(self, @__vc_requested_details)
|
200
|
+
ensure
|
201
|
+
@__vc_parent_render_level -= 1
|
202
|
+
end
|
214
203
|
end
|
215
204
|
|
216
205
|
# Optional content to be returned before the rendered template.
|
@@ -333,12 +322,12 @@ module ViewComponent
|
|
333
322
|
# @return [String]
|
334
323
|
def content
|
335
324
|
@__vc_content_evaluated = true
|
336
|
-
return @__vc_content if @__vc_content
|
325
|
+
return @__vc_content if defined?(@__vc_content)
|
337
326
|
|
338
327
|
@__vc_content =
|
339
328
|
if __vc_render_in_block_provided?
|
340
329
|
view_context.capture(self, &@__vc_render_in_block)
|
341
|
-
elsif
|
330
|
+
elsif __vc_content_set_by_with_content_defined?
|
342
331
|
@__vc_content_set_by_with_content
|
343
332
|
end
|
344
333
|
end
|
@@ -347,7 +336,11 @@ module ViewComponent
|
|
347
336
|
#
|
348
337
|
# @return [Boolean]
|
349
338
|
def content?
|
350
|
-
__vc_render_in_block_provided? ||
|
339
|
+
__vc_render_in_block_provided? || __vc_content_set_by_with_content_defined?
|
340
|
+
end
|
341
|
+
|
342
|
+
def format
|
343
|
+
self.class.__vc_response_format
|
351
344
|
end
|
352
345
|
|
353
346
|
private
|
@@ -355,18 +348,14 @@ module ViewComponent
|
|
355
348
|
attr_reader :view_context
|
356
349
|
|
357
350
|
def __vc_render_in_block_provided?
|
358
|
-
@view_context && @__vc_render_in_block
|
359
|
-
end
|
360
|
-
|
361
|
-
def __vc_content_set_by_with_content?
|
362
|
-
!@__vc_content_set_by_with_content.nil?
|
351
|
+
defined?(@view_context) && @view_context && @__vc_render_in_block
|
363
352
|
end
|
364
353
|
|
365
|
-
def
|
366
|
-
@
|
354
|
+
def __vc_content_set_by_with_content_defined?
|
355
|
+
defined?(@__vc_content_set_by_with_content)
|
367
356
|
end
|
368
357
|
|
369
|
-
def
|
358
|
+
def __vc_maybe_escape_html(text)
|
370
359
|
return text if @current_template && !@current_template.html?
|
371
360
|
return text if text.blank?
|
372
361
|
|
@@ -378,38 +367,18 @@ module ViewComponent
|
|
378
367
|
end
|
379
368
|
end
|
380
369
|
|
381
|
-
def
|
382
|
-
|
370
|
+
def __vc_safe_output_preamble
|
371
|
+
__vc_maybe_escape_html(output_preamble) do
|
383
372
|
Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe preamble. The preamble will be automatically escaped, but you may want to investigate.")
|
384
373
|
end
|
385
374
|
end
|
386
375
|
|
387
|
-
def
|
388
|
-
|
376
|
+
def __vc_safe_output_postamble
|
377
|
+
__vc_maybe_escape_html(output_postamble) do
|
389
378
|
Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe postamble. The postamble will be automatically escaped, but you may want to investigate.")
|
390
379
|
end
|
391
380
|
end
|
392
381
|
|
393
|
-
# Set the controller used for testing components:
|
394
|
-
#
|
395
|
-
# ```ruby
|
396
|
-
# config.view_component.test_controller = "MyTestController"
|
397
|
-
# ```
|
398
|
-
#
|
399
|
-
# Defaults to `nil`. If this is falsy, `"ApplicationController"` is used. Can also be
|
400
|
-
# configured on a per-test basis using `with_controller_class`.
|
401
|
-
#
|
402
|
-
|
403
|
-
# Parent class for generated components
|
404
|
-
#
|
405
|
-
# ```ruby
|
406
|
-
# config.view_component.component_parent_class = "MyBaseComponent"
|
407
|
-
# ```
|
408
|
-
#
|
409
|
-
# Defaults to nil. If this is falsy, generators will use
|
410
|
-
# "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
|
411
|
-
#
|
412
|
-
|
413
382
|
# Configuration for generators.
|
414
383
|
#
|
415
384
|
# All options under this namespace default to `false` unless otherwise
|
@@ -467,6 +436,18 @@ module ViewComponent
|
|
467
436
|
# ```
|
468
437
|
#
|
469
438
|
# Defaults to `false`.
|
439
|
+
#
|
440
|
+
# #### ßparent_class
|
441
|
+
#
|
442
|
+
# Parent class for generated components
|
443
|
+
#
|
444
|
+
# ```ruby
|
445
|
+
# config.view_component.generate.parent_class = "MyBaseComponent"
|
446
|
+
# ```
|
447
|
+
#
|
448
|
+
# Defaults to nil. If this is falsy, generators will use
|
449
|
+
# "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
|
450
|
+
#
|
470
451
|
|
471
452
|
class << self
|
472
453
|
# The file path of the component Ruby file.
|
@@ -535,6 +516,11 @@ module ViewComponent
|
|
535
516
|
Collection.new(self, collection, spacer_component, **args)
|
536
517
|
end
|
537
518
|
|
519
|
+
# @private
|
520
|
+
def __vc_compile(raise_errors: false, force: false)
|
521
|
+
__vc_compiler.compile(raise_errors: raise_errors, force: force)
|
522
|
+
end
|
523
|
+
|
538
524
|
# @private
|
539
525
|
def inherited(child)
|
540
526
|
# Compile so child will inherit compiled `call_*` template methods that
|
@@ -557,12 +543,6 @@ module ViewComponent
|
|
557
543
|
RUBY
|
558
544
|
end
|
559
545
|
|
560
|
-
# If Rails application is loaded, add application url_helpers to the component context
|
561
|
-
# we need to check this to use this gem as a dependency
|
562
|
-
if defined?(Rails) && Rails.application && !(child < Rails.application.routes.url_helpers)
|
563
|
-
child.include Rails.application.routes.url_helpers
|
564
|
-
end
|
565
|
-
|
566
546
|
# Derive the source location of the component Ruby file from the call stack.
|
567
547
|
# We need to ignore `inherited` frames here as they indicate that `inherited`
|
568
548
|
# has been re-defined by the consuming application, likely in ApplicationComponent.
|
@@ -572,10 +552,10 @@ module ViewComponent
|
|
572
552
|
child.virtual_path = child.name&.underscore
|
573
553
|
|
574
554
|
# Set collection parameter to the extended component
|
575
|
-
child.with_collection_parameter
|
555
|
+
child.with_collection_parameter(__vc_provided_collection_parameter)
|
576
556
|
|
577
557
|
if instance_methods(false).include?(:render_template_for)
|
578
|
-
vc_ancestor_calls = (
|
558
|
+
vc_ancestor_calls = defined?(@__vc_ancestor_calls) ? @__vc_ancestor_calls.dup : []
|
579
559
|
|
580
560
|
vc_ancestor_calls.unshift(instance_method(:render_template_for))
|
581
561
|
child.instance_variable_set(:@__vc_ancestor_calls, vc_ancestor_calls)
|
@@ -594,11 +574,6 @@ module ViewComponent
|
|
594
574
|
__vc_compile unless __vc_compiled?
|
595
575
|
end
|
596
576
|
|
597
|
-
# @private
|
598
|
-
def __vc_compile(raise_errors: false, force: false)
|
599
|
-
__vc_compiler.compile(raise_errors: raise_errors, force: force)
|
600
|
-
end
|
601
|
-
|
602
577
|
# @private
|
603
578
|
def __vc_compiler
|
604
579
|
@__vc_compiler ||= Compiler.new(self)
|
@@ -612,8 +587,8 @@ module ViewComponent
|
|
612
587
|
#
|
613
588
|
# @param parameter [Symbol] The parameter name used when rendering elements of a collection.
|
614
589
|
def with_collection_parameter(parameter)
|
615
|
-
@
|
616
|
-
@
|
590
|
+
@__vc_provided_collection_parameter = parameter
|
591
|
+
@__vc_initialize_parameters = nil
|
617
592
|
end
|
618
593
|
|
619
594
|
# Strips trailing whitespace from templates before compiling them.
|
@@ -624,38 +599,16 @@ module ViewComponent
|
|
624
599
|
# end
|
625
600
|
# ```
|
626
601
|
#
|
627
|
-
# @deprecated Use the new component-local configuration option instead.
|
628
|
-
#
|
629
|
-
# ```ruby
|
630
|
-
# class MyComponent < ViewComponent::Base
|
631
|
-
# configure_view_component do |config|
|
632
|
-
# config.strip_trailing_whitespace = true
|
633
|
-
# end
|
634
|
-
# end
|
635
|
-
# ```
|
636
|
-
#
|
637
602
|
# @param value [Boolean] Whether to strip newlines.
|
638
603
|
def strip_trailing_whitespace(value = true)
|
639
|
-
|
640
|
-
"strip_trailing_whitespace",
|
641
|
-
<<~DOC
|
642
|
-
Use the new component-local configuration option instead:
|
643
|
-
|
644
|
-
class #{self.class.name} < ViewComponent::Base
|
645
|
-
configure_view_component do |config|
|
646
|
-
config.strip_trailing_whitespace = #{value}
|
647
|
-
end
|
648
|
-
end
|
649
|
-
DOC
|
650
|
-
)
|
651
|
-
view_component_config.strip_trailing_whitespace = value
|
604
|
+
self.__vc_strip_trailing_whitespace = value
|
652
605
|
end
|
653
606
|
|
654
607
|
# Whether trailing whitespace will be stripped before compilation.
|
655
608
|
#
|
656
609
|
# @return [Boolean]
|
657
610
|
def strip_trailing_whitespace?
|
658
|
-
|
611
|
+
__vc_strip_trailing_whitespace
|
659
612
|
end
|
660
613
|
|
661
614
|
# Ensure the component initializer accepts the
|
@@ -665,17 +618,10 @@ module ViewComponent
|
|
665
618
|
# rendering is optional.
|
666
619
|
# @private
|
667
620
|
def __vc_validate_collection_parameter!(validate_default: false)
|
668
|
-
parameter = validate_default ? __vc_collection_parameter :
|
621
|
+
parameter = validate_default ? __vc_collection_parameter : __vc_provided_collection_parameter
|
669
622
|
|
670
623
|
return unless parameter
|
671
|
-
return if
|
672
|
-
|
673
|
-
# If Ruby can't parse the component class, then the initialize
|
674
|
-
# parameters will be empty and ViewComponent will not be able to render
|
675
|
-
# the component.
|
676
|
-
if initialize_parameters.empty?
|
677
|
-
raise EmptyOrInvalidInitializerError.new(name, parameter)
|
678
|
-
end
|
624
|
+
return if __vc_initialize_parameter_names.include?(parameter) || __vc_splatted_keyword_argument_present?
|
679
625
|
|
680
626
|
raise MissingCollectionArgumentError.new(name, parameter)
|
681
627
|
end
|
@@ -685,55 +631,57 @@ module ViewComponent
|
|
685
631
|
# methods.
|
686
632
|
# @private
|
687
633
|
def __vc_validate_initialization_parameters!
|
688
|
-
return unless
|
634
|
+
return unless __vc_initialize_parameter_names.include?(:content)
|
689
635
|
|
690
636
|
raise ReservedParameterError.new(name, :content)
|
691
637
|
end
|
692
638
|
|
693
639
|
# @private
|
694
640
|
def __vc_collection_parameter
|
695
|
-
|
641
|
+
@__vc_provided_collection_parameter ||= name && name.demodulize.underscore.chomp("_component").to_sym
|
696
642
|
end
|
697
643
|
|
698
644
|
# @private
|
699
645
|
def __vc_collection_counter_parameter
|
700
|
-
:"#{__vc_collection_parameter}_counter"
|
646
|
+
@__vc_collection_counter_parameter ||= :"#{__vc_collection_parameter}_counter"
|
701
647
|
end
|
702
648
|
|
703
649
|
# @private
|
704
650
|
def __vc_counter_argument_present?
|
705
|
-
|
651
|
+
__vc_initialize_parameter_names.include?(__vc_collection_counter_parameter)
|
706
652
|
end
|
707
653
|
|
708
654
|
# @private
|
709
655
|
def __vc_collection_iteration_parameter
|
710
|
-
:"#{__vc_collection_parameter}_iteration"
|
656
|
+
@__vc_collection_iteration_parameter ||= :"#{__vc_collection_parameter}_iteration"
|
711
657
|
end
|
712
658
|
|
713
659
|
# @private
|
714
660
|
def __vc_iteration_argument_present?
|
715
|
-
|
661
|
+
__vc_initialize_parameter_names.include?(__vc_collection_iteration_parameter)
|
716
662
|
end
|
717
663
|
|
718
664
|
private
|
719
665
|
|
720
|
-
def
|
721
|
-
|
722
|
-
!initialize_parameters.include?([:keyrest, :**]) # Un-named splatted keyword args don't count!
|
666
|
+
def __vc_splatted_keyword_argument_present?
|
667
|
+
__vc_initialize_parameters.flatten.include?(:keyrest)
|
723
668
|
end
|
724
669
|
|
725
|
-
def
|
726
|
-
|
727
|
-
|
728
|
-
|
670
|
+
def __vc_initialize_parameter_names
|
671
|
+
@__vc_initialize_parameter_names ||=
|
672
|
+
if respond_to?(:attribute_names)
|
673
|
+
attribute_names.map(&:to_sym)
|
674
|
+
else
|
675
|
+
__vc_initialize_parameters.map(&:last)
|
676
|
+
end
|
729
677
|
end
|
730
678
|
|
731
|
-
def
|
732
|
-
@
|
679
|
+
def __vc_initialize_parameters
|
680
|
+
@__vc_initialize_parameters ||= instance_method(:initialize).parameters
|
733
681
|
end
|
734
682
|
|
735
|
-
def
|
736
|
-
@
|
683
|
+
def __vc_provided_collection_parameter
|
684
|
+
@__vc_provided_collection_parameter ||= nil
|
737
685
|
end
|
738
686
|
end
|
739
687
|
|
@@ -48,7 +48,16 @@ module ViewComponent
|
|
48
48
|
|
49
49
|
define_render_template_for
|
50
50
|
|
51
|
-
|
51
|
+
# Set the format if the component only responds to a single format.
|
52
|
+
# Unfortunately we cannot determine which format a multi-format
|
53
|
+
# component will respond to until render time, so those components
|
54
|
+
# will not set the response format.
|
55
|
+
#
|
56
|
+
# TODO: Investigate upstream changes necessary to support multi-format renderables
|
57
|
+
unique_formats = templates.map(&:format).uniq
|
58
|
+
@component.__vc_response_format = unique_formats.last if unique_formats.one?
|
59
|
+
|
60
|
+
@component.__vc_register_default_slots
|
52
61
|
@component.__vc_build_i18n_backend
|
53
62
|
|
54
63
|
CompileCache.register(@component)
|
@@ -108,10 +117,8 @@ module ViewComponent
|
|
108
117
|
|
109
118
|
errors << "Couldn't find a template file or inline render method for #{@component}." if @templates.empty?
|
110
119
|
|
111
|
-
|
112
|
-
|
113
|
-
# raise an error.
|
114
|
-
@templates.reject(&:inline_call?)
|
120
|
+
@templates
|
121
|
+
.reject { |template| template.inline_call? && !template.defined_on_self? }
|
115
122
|
.map { |template| [template.variant, template.format] }
|
116
123
|
.tally
|
117
124
|
.select { |_, count| count > 1 }
|
@@ -170,10 +177,10 @@ module ViewComponent
|
|
170
177
|
|
171
178
|
def gather_templates
|
172
179
|
@templates ||=
|
173
|
-
if @component.
|
180
|
+
if @component.__vc_inline_template.present?
|
174
181
|
[Template::Inline.new(
|
175
182
|
component: @component,
|
176
|
-
inline_template: @component.
|
183
|
+
inline_template: @component.__vc_inline_template
|
177
184
|
)]
|
178
185
|
else
|
179
186
|
path_parser = ActionView::Resolver::PathParser.new
|