view_component 3.22.0 → 4.0.0.alpha2
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 +2 -9
- data/app/controllers/view_components_system_test_controller.rb +17 -20
- data/app/views/test_mailer/test_asset_email.html.erb +1 -0
- data/app/views/view_components/preview.html.erb +1 -9
- data/docs/CHANGELOG.md +133 -1
- data/lib/view_component/base.rb +42 -61
- data/lib/view_component/collection.rb +11 -17
- data/lib/view_component/compiler.rb +50 -74
- data/lib/view_component/config.rb +0 -21
- data/lib/view_component/deprecation.rb +1 -1
- data/lib/view_component/engine.rb +3 -82
- data/lib/view_component/errors.rb +16 -22
- data/lib/view_component/inline_template.rb +2 -3
- data/lib/view_component/instrumentation.rb +4 -10
- data/lib/view_component/preview.rb +3 -10
- data/lib/view_component/request_details.rb +30 -0
- data/lib/view_component/slot.rb +2 -5
- data/lib/view_component/slotable.rb +31 -39
- data/lib/view_component/system_test_helpers.rb +1 -2
- data/lib/view_component/template.rb +106 -83
- data/lib/view_component/test_helpers.rb +22 -42
- data/lib/view_component/translatable.rb +24 -23
- data/lib/view_component/use_helpers.rb +3 -4
- data/lib/view_component/version.rb +3 -3
- data/lib/view_component.rb +0 -1
- metadata +73 -220
- data/app/assets/vendor/prism.css +0 -4
- data/app/assets/vendor/prism.min.js +0 -12
- data/app/helpers/preview_helper.rb +0 -85
- data/app/views/view_components/_preview_source.html.erb +0 -17
- data/lib/rails/generators/abstract_generator.rb +0 -56
- data/lib/rails/generators/component/USAGE +0 -13
- data/lib/rails/generators/component/component_generator.rb +0 -67
- data/lib/rails/generators/component/templates/component.rb.tt +0 -16
- data/lib/rails/generators/erb/component_generator.rb +0 -33
- data/lib/rails/generators/erb/templates/component.html.erb.tt +0 -1
- data/lib/rails/generators/haml/component_generator.rb +0 -22
- data/lib/rails/generators/haml/templates/component.html.haml.tt +0 -1
- data/lib/rails/generators/locale/component_generator.rb +0 -46
- data/lib/rails/generators/preview/component_generator.rb +0 -39
- data/lib/rails/generators/preview/templates/component_preview.rb.tt +0 -9
- data/lib/rails/generators/rspec/component_generator.rb +0 -31
- data/lib/rails/generators/rspec/templates/component_spec.rb.tt +0 -15
- data/lib/rails/generators/slim/component_generator.rb +0 -22
- data/lib/rails/generators/slim/templates/component.html.slim.tt +0 -1
- data/lib/rails/generators/stimulus/component_generator.rb +0 -44
- data/lib/rails/generators/stimulus/templates/component_controller.js.tt +0 -7
- data/lib/rails/generators/stimulus/templates/component_controller.ts.tt +0 -9
- data/lib/rails/generators/tailwindcss/component_generator.rb +0 -11
- data/lib/rails/generators/tailwindcss/templates/component.html.erb.tt +0 -1
- data/lib/rails/generators/test_unit/component_generator.rb +0 -20
- data/lib/rails/generators/test_unit/templates/component_test.rb.tt +0 -12
- data/lib/view_component/component_error.rb +0 -6
- data/lib/view_component/docs_builder_component.html.erb +0 -22
- data/lib/view_component/docs_builder_component.rb +0 -96
- data/lib/view_component/rails/tasks/view_component.rake +0 -20
- data/lib/view_component/render_component_helper.rb +0 -10
- data/lib/view_component/render_component_to_string_helper.rb +0 -9
- data/lib/view_component/render_monkey_patch.rb +0 -13
- data/lib/view_component/render_to_string_monkey_patch.rb +0 -13
- data/lib/view_component/rendering_component_helper.rb +0 -9
- data/lib/view_component/rendering_monkey_patch.rb +0 -13
- data/lib/yard/mattr_accessor_handler.rb +0 -19
@@ -8,7 +8,7 @@ module ViewComponent
|
|
8
8
|
# * true (a blocking mode which ensures thread safety when redefining the `call` method for components,
|
9
9
|
# default in Rails development and test mode)
|
10
10
|
# * false(a non-blocking mode, default in Rails production mode)
|
11
|
-
class_attribute :
|
11
|
+
class_attribute :__vc_development_mode, default: false
|
12
12
|
|
13
13
|
def initialize(component)
|
14
14
|
@component = component
|
@@ -30,8 +30,8 @@ module ViewComponent
|
|
30
30
|
|
31
31
|
gather_templates
|
32
32
|
|
33
|
-
if self.class.
|
34
|
-
@component.superclass.
|
33
|
+
if self.class.__vc_development_mode && @templates.any?(&:requires_compiled_superclass?)
|
34
|
+
@component.superclass.__vc_compile(raise_errors: raise_errors)
|
35
35
|
end
|
36
36
|
|
37
37
|
if template_errors.present?
|
@@ -42,19 +42,36 @@ module ViewComponent
|
|
42
42
|
end
|
43
43
|
|
44
44
|
if raise_errors
|
45
|
-
@component.
|
46
|
-
@component.
|
45
|
+
@component.__vc_validate_initialization_parameters!
|
46
|
+
@component.__vc_validate_collection_parameter!
|
47
47
|
end
|
48
48
|
|
49
49
|
define_render_template_for
|
50
50
|
|
51
51
|
@component.register_default_slots
|
52
|
-
@component.
|
52
|
+
@component.__vc_build_i18n_backend
|
53
53
|
|
54
54
|
CompileCache.register(@component)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
# @return all matching compiled templates, in priority order based on the requested details from LookupContext
|
59
|
+
#
|
60
|
+
# @param [ActionView::TemplateDetails::Requested] requested_details i.e. locales, formats, variants
|
61
|
+
def find_templates_for(requested_details)
|
62
|
+
filtered_templates = @templates.select do |template|
|
63
|
+
template.details.matches?(requested_details)
|
64
|
+
end
|
65
|
+
|
66
|
+
if filtered_templates.count > 1
|
67
|
+
filtered_templates.sort_by! do |template|
|
68
|
+
template.details.sort_key_for(requested_details)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
filtered_templates
|
73
|
+
end
|
74
|
+
|
58
75
|
private
|
59
76
|
|
60
77
|
attr_reader :templates
|
@@ -64,40 +81,25 @@ module ViewComponent
|
|
64
81
|
template.compile_to_component
|
65
82
|
end
|
66
83
|
|
67
|
-
|
68
|
-
if @templates.one?
|
69
|
-
@templates.first.safe_method_name_call
|
70
|
-
elsif (template = @templates.find(&:inline?))
|
71
|
-
template.safe_method_name_call
|
72
|
-
else
|
73
|
-
branches = []
|
74
|
-
|
75
|
-
@templates.each do |template|
|
76
|
-
conditional =
|
77
|
-
if template.inline_call?
|
78
|
-
"variant&.to_sym == #{template.variant.inspect}"
|
79
|
-
else
|
80
|
-
[
|
81
|
-
template.default_format? ? "(format == #{ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT.inspect} || format.nil?)" : "format == #{template.format.inspect}",
|
82
|
-
template.variant.nil? ? "variant.nil?" : "variant&.to_sym == #{template.variant.inspect}"
|
83
|
-
].join(" && ")
|
84
|
-
end
|
85
|
-
|
86
|
-
branches << [conditional, template.safe_method_name_call]
|
87
|
-
end
|
84
|
+
@component.silence_redefinition_of_method(:render_template_for)
|
88
85
|
|
89
|
-
|
90
|
-
|
86
|
+
if @templates.one?
|
87
|
+
template = @templates.first
|
88
|
+
safe_call = template.safe_method_name_call
|
89
|
+
@component.define_method(:render_template_for) do |_|
|
90
|
+
@current_template = template
|
91
|
+
instance_exec(&safe_call)
|
92
|
+
end
|
93
|
+
else
|
94
|
+
compiler = self
|
95
|
+
@component.define_method(:render_template_for) do |details|
|
96
|
+
if (@current_template = compiler.find_templates_for(details).first)
|
97
|
+
instance_exec(&@current_template.safe_method_name_call)
|
98
|
+
else
|
99
|
+
raise MissingTemplateError.new(self.class.name, details)
|
91
100
|
end
|
92
|
-
out << "else\n #{templates.find { _1.variant.nil? && _1.default_format? }.safe_method_name_call}\nend"
|
93
101
|
end
|
94
|
-
|
95
|
-
@component.silence_redefinition_of_method(:render_template_for)
|
96
|
-
@component.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
97
|
-
def render_template_for(variant = nil, format = nil)
|
98
|
-
#{method_body}
|
99
102
|
end
|
100
|
-
RUBY
|
101
103
|
end
|
102
104
|
|
103
105
|
def template_errors
|
@@ -168,30 +170,18 @@ module ViewComponent
|
|
168
170
|
|
169
171
|
def gather_templates
|
170
172
|
@templates ||=
|
171
|
-
|
173
|
+
if @component.inline_template.present?
|
174
|
+
[Template::Inline.new(
|
175
|
+
component: @component,
|
176
|
+
inline_template: @component.inline_template
|
177
|
+
)]
|
178
|
+
else
|
179
|
+
path_parser = ActionView::Resolver::PathParser.new
|
172
180
|
templates = @component.sidecar_files(
|
173
181
|
ActionView::Template.template_handler_extensions
|
174
182
|
).map do |path|
|
175
|
-
|
176
|
-
|
177
|
-
File
|
178
|
-
.basename(path) # "variants_component.html+mini.watch.erb"
|
179
|
-
.split(".")[1..-2] # ["html+mini", "watch"]
|
180
|
-
.join(".") # "html+mini.watch"
|
181
|
-
.split("+") # ["html", "mini.watch"]
|
182
|
-
.map(&:to_sym) # [:html, :"mini.watch"]
|
183
|
-
|
184
|
-
out = Template.new(
|
185
|
-
component: @component,
|
186
|
-
type: :file,
|
187
|
-
path: path,
|
188
|
-
lineno: 0,
|
189
|
-
extension: path.split(".").last,
|
190
|
-
this_format: this_format.to_s.split(".").last&.to_sym, # strip locale from this_format, see #2113
|
191
|
-
variant: variant
|
192
|
-
)
|
193
|
-
|
194
|
-
out
|
183
|
+
details = path_parser.parse(path).details
|
184
|
+
Template::File.new(component: @component, path: path, details: details)
|
195
185
|
end
|
196
186
|
|
197
187
|
component_instance_methods_on_self = @component.instance_methods(false)
|
@@ -201,24 +191,10 @@ module ViewComponent
|
|
201
191
|
).flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) }
|
202
192
|
.uniq
|
203
193
|
.each do |method_name|
|
204
|
-
|
205
|
-
component: @component,
|
206
|
-
type: :inline_call,
|
207
|
-
this_format: ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT,
|
208
|
-
variant: method_name.to_s.include?("call_") ? method_name.to_s.sub("call_", "").to_sym : nil,
|
209
|
-
method_name: method_name,
|
210
|
-
defined_on_self: component_instance_methods_on_self.include?(method_name)
|
211
|
-
)
|
212
|
-
end
|
213
|
-
|
214
|
-
if @component.inline_template.present?
|
215
|
-
templates << Template.new(
|
194
|
+
templates << Template::InlineCall.new(
|
216
195
|
component: @component,
|
217
|
-
|
218
|
-
|
219
|
-
lineno: @component.inline_template.lineno,
|
220
|
-
source: @component.inline_template.source.dup,
|
221
|
-
extension: @component.inline_template.language
|
196
|
+
method_name: method_name,
|
197
|
+
defined_on_self: component_instance_methods_on_self.include?(method_name)
|
222
198
|
)
|
223
199
|
end
|
224
200
|
|
@@ -15,10 +15,7 @@ module ViewComponent
|
|
15
15
|
generate: default_generate_options,
|
16
16
|
preview_controller: "ViewComponentsController",
|
17
17
|
preview_route: "/rails/view_components",
|
18
|
-
show_previews_source: false,
|
19
18
|
instrumentation_enabled: false,
|
20
|
-
use_deprecated_instrumentation_name: true,
|
21
|
-
render_monkey_patch_enabled: true,
|
22
19
|
view_component_path: "app/components",
|
23
20
|
component_parent_class: nil,
|
24
21
|
show_previews: Rails.env.development? || Rails.env.test?,
|
@@ -109,29 +106,11 @@ module ViewComponent
|
|
109
106
|
# The entry route for component previews.
|
110
107
|
# Defaults to `"/rails/view_components"`.
|
111
108
|
|
112
|
-
# @!attribute show_previews_source
|
113
|
-
# @return [Boolean]
|
114
|
-
# Whether to display source code previews in component previews.
|
115
|
-
# Defaults to `false`.
|
116
|
-
|
117
109
|
# @!attribute instrumentation_enabled
|
118
110
|
# @return [Boolean]
|
119
111
|
# Whether ActiveSupport notifications are enabled.
|
120
112
|
# Defaults to `false`.
|
121
113
|
|
122
|
-
# @!attribute use_deprecated_instrumentation_name
|
123
|
-
# @return [Boolean]
|
124
|
-
# Whether ActiveSupport Notifications use the private name `"!render.view_component"`
|
125
|
-
# or are made more publicly available via `"render.view_component"`.
|
126
|
-
# Will default to `false` in next major version.
|
127
|
-
# Defaults to `true`.
|
128
|
-
|
129
|
-
# @!attribute render_monkey_patch_enabled
|
130
|
-
# @return [Boolean] Whether the #render method should be monkey patched.
|
131
|
-
# If this is disabled, use `#render_component` or
|
132
|
-
# `#render_component_to_string` instead.
|
133
|
-
# Defaults to `true`.
|
134
|
-
|
135
114
|
# @!attribute view_component_path
|
136
115
|
# @return [String]
|
137
116
|
# The path in which components, their templates, and their sidecars should
|
@@ -29,11 +29,10 @@ module ViewComponent
|
|
29
29
|
initializer "view_component.set_configs" do |app|
|
30
30
|
options = app.config.view_component
|
31
31
|
|
32
|
-
%i[generate preview_controller preview_route
|
32
|
+
%i[generate preview_controller preview_route].each do |config_option|
|
33
33
|
options[config_option] ||= ViewComponent::Base.public_send(config_option)
|
34
34
|
end
|
35
35
|
options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
|
36
|
-
options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
|
37
36
|
options.show_previews = (Rails.env.development? || Rails.env.test?) if options.show_previews.nil?
|
38
37
|
|
39
38
|
if options.show_previews
|
@@ -41,40 +40,22 @@ module ViewComponent
|
|
41
40
|
options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
|
42
41
|
"#{Rails.root}/test/components/previews"
|
43
42
|
)
|
44
|
-
|
45
|
-
if options.show_previews_source
|
46
|
-
require "method_source"
|
47
|
-
|
48
|
-
app.config.to_prepare do
|
49
|
-
MethodSource.instance_variable_set(:@lines_for_file, {})
|
50
|
-
end
|
51
|
-
end
|
52
43
|
end
|
53
44
|
end
|
54
45
|
|
55
46
|
initializer "view_component.enable_instrumentation" do |app|
|
56
47
|
ActiveSupport.on_load(:view_component) do
|
57
48
|
if app.config.view_component.instrumentation_enabled.present?
|
58
|
-
# :nocov: Re-executing the below in tests duplicates initializers and causes order-dependent failures.
|
59
49
|
ViewComponent::Base.prepend(ViewComponent::Instrumentation)
|
60
|
-
if app.config.view_component.use_deprecated_instrumentation_name
|
61
|
-
ViewComponent::Deprecation.deprecation_warning(
|
62
|
-
"!render.view_component",
|
63
|
-
"Use the new instrumentation key `render.view_component` instead. See https://viewcomponent.org/guide/instrumentation.html"
|
64
|
-
)
|
65
|
-
end
|
66
|
-
# :nocov:
|
67
50
|
end
|
68
51
|
end
|
69
52
|
end
|
70
53
|
|
71
|
-
# :nocov:
|
72
54
|
initializer "view_component.enable_capture_patch" do |app|
|
73
55
|
ActiveSupport.on_load(:view_component) do
|
74
56
|
ActionView::Base.include(ViewComponent::CaptureCompatibility) if app.config.view_component.capture_compatibility_patch_enabled
|
75
57
|
end
|
76
58
|
end
|
77
|
-
# :nocov:
|
78
59
|
|
79
60
|
initializer "view_component.set_autoload_paths" do |app|
|
80
61
|
options = app.config.view_component
|
@@ -87,62 +68,12 @@ module ViewComponent
|
|
87
68
|
|
88
69
|
initializer "view_component.eager_load_actions" do
|
89
70
|
ActiveSupport.on_load(:after_initialize) do
|
90
|
-
ViewComponent::Base.descendants.each(&:
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
initializer "view_component.monkey_patch_render" do |app|
|
95
|
-
next if Rails.version.to_f >= 6.1 || !app.config.view_component.render_monkey_patch_enabled
|
96
|
-
|
97
|
-
# :nocov:
|
98
|
-
ViewComponent::Deprecation.deprecation_warning("Monkey patching `render`", "ViewComponent 4.0 will remove the `render` monkey patch")
|
99
|
-
|
100
|
-
ActiveSupport.on_load(:action_view) do
|
101
|
-
require "view_component/render_monkey_patch"
|
102
|
-
ActionView::Base.prepend ViewComponent::RenderMonkeyPatch
|
103
|
-
end
|
104
|
-
|
105
|
-
ActiveSupport.on_load(:action_controller) do
|
106
|
-
require "view_component/rendering_monkey_patch"
|
107
|
-
require "view_component/render_to_string_monkey_patch"
|
108
|
-
ActionController::Base.prepend ViewComponent::RenderingMonkeyPatch
|
109
|
-
ActionController::Base.prepend ViewComponent::RenderToStringMonkeyPatch
|
110
|
-
end
|
111
|
-
# :nocov:
|
112
|
-
end
|
113
|
-
|
114
|
-
initializer "view_component.include_render_component" do |_app|
|
115
|
-
next if Rails.version.to_f >= 6.1
|
116
|
-
|
117
|
-
# :nocov:
|
118
|
-
ViewComponent::Deprecation.deprecation_warning("using `render_component`", "ViewComponent 4.0 will remove `render_component`")
|
119
|
-
|
120
|
-
ActiveSupport.on_load(:action_view) do
|
121
|
-
require "view_component/render_component_helper"
|
122
|
-
ActionView::Base.include ViewComponent::RenderComponentHelper
|
123
|
-
end
|
124
|
-
|
125
|
-
ActiveSupport.on_load(:action_controller) do
|
126
|
-
require "view_component/rendering_component_helper"
|
127
|
-
require "view_component/render_component_to_string_helper"
|
128
|
-
ActionController::Base.include ViewComponent::RenderingComponentHelper
|
129
|
-
ActionController::Base.include ViewComponent::RenderComponentToStringHelper
|
130
|
-
end
|
131
|
-
# :nocov:
|
132
|
-
end
|
133
|
-
|
134
|
-
initializer "static assets" do |app|
|
135
|
-
if serve_static_preview_assets?(app.config)
|
136
|
-
app.middleware.use(::ActionDispatch::Static, "#{root}/app/assets/vendor")
|
71
|
+
ViewComponent::Base.descendants.each(&:__vc_compile) if Rails.application.config.eager_load
|
137
72
|
end
|
138
73
|
end
|
139
74
|
|
140
|
-
def serve_static_preview_assets?(app_config)
|
141
|
-
app_config.view_component.show_previews && app_config.public_file_server.enabled
|
142
|
-
end
|
143
|
-
|
144
75
|
initializer "compiler mode" do |_app|
|
145
|
-
ViewComponent::Compiler.
|
76
|
+
ViewComponent::Compiler.__vc_development_mode = (Rails.env.development? || Rails.env.test?)
|
146
77
|
end
|
147
78
|
|
148
79
|
config.after_initialize do |app|
|
@@ -174,16 +105,6 @@ module ViewComponent
|
|
174
105
|
end
|
175
106
|
end
|
176
107
|
|
177
|
-
# :nocov:
|
178
|
-
if RUBY_VERSION < "3.2.0"
|
179
|
-
ViewComponent::Deprecation.deprecation_warning("Support for Ruby versions < 3.2.0", "ViewComponent v4 will remove support for Ruby versions < 3.2.0 no earlier than April 1, 2025")
|
180
|
-
end
|
181
|
-
|
182
|
-
if Rails.version.to_f < 7.1
|
183
|
-
ViewComponent::Deprecation.deprecation_warning("Support for Rails versions < 7.1", "ViewComponent v4 will remove support for Rails versions < 7.1 no earlier than April 1, 2025")
|
184
|
-
end
|
185
|
-
# :nocov:
|
186
|
-
|
187
108
|
app.executor.to_run :before do
|
188
109
|
CompileCache.invalidate! unless ActionView::Base.cache_template_loading
|
189
110
|
end
|
@@ -38,6 +38,22 @@ module ViewComponent
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
class MissingTemplateError < StandardError
|
42
|
+
MESSAGE =
|
43
|
+
"No templates for COMPONENT match the request DETAIL.\n\n" \
|
44
|
+
"To fix this issue, provide a suitable template."
|
45
|
+
|
46
|
+
def initialize(component, request_detail)
|
47
|
+
detail = {
|
48
|
+
locale: request_detail.locale,
|
49
|
+
formats: request_detail.formats,
|
50
|
+
variants: request_detail.variants,
|
51
|
+
handlers: request_detail.handlers
|
52
|
+
}
|
53
|
+
super(MESSAGE.gsub("COMPONENT", component).gsub("DETAIL", detail.inspect))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
41
57
|
class DuplicateContentError < StandardError
|
42
58
|
MESSAGE =
|
43
59
|
"It looks like a block was provided after calling `with_content` on COMPONENT, " \
|
@@ -202,28 +218,6 @@ module ViewComponent
|
|
202
218
|
"`#controller` to a [`#before_render` method](https://viewcomponent.org/api.html#before_render--void)."
|
203
219
|
end
|
204
220
|
|
205
|
-
# :nocov:
|
206
|
-
class NoMatchingTemplatesForPreviewError < StandardError
|
207
|
-
MESSAGE = "Found 0 matches for templates for TEMPLATE_IDENTIFIER."
|
208
|
-
|
209
|
-
def initialize(template_identifier)
|
210
|
-
super(MESSAGE.gsub("TEMPLATE_IDENTIFIER", template_identifier))
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
class MultipleMatchingTemplatesForPreviewError < StandardError
|
215
|
-
MESSAGE = "Found multiple templates for TEMPLATE_IDENTIFIER."
|
216
|
-
|
217
|
-
def initialize(template_identifier)
|
218
|
-
super(MESSAGE.gsub("TEMPLATE_IDENTIFIER", template_identifier))
|
219
|
-
end
|
220
|
-
end
|
221
|
-
# :nocov:
|
222
|
-
|
223
|
-
class SystemTestControllerOnlyAllowedInTestError < BaseError
|
224
|
-
MESSAGE = "ViewComponent SystemTest controller must only be called in a test environment for security reasons."
|
225
|
-
end
|
226
|
-
|
227
221
|
class SystemTestControllerNefariousPathError < BaseError
|
228
222
|
MESSAGE = "ViewComponent SystemTest controller attempted to load a file outside of the expected directory."
|
229
223
|
end
|
@@ -32,7 +32,6 @@ module ViewComponent # :nodoc:
|
|
32
32
|
|
33
33
|
@__vc_inline_template_defined = true
|
34
34
|
end
|
35
|
-
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
36
35
|
|
37
36
|
def respond_to_missing?(method, include_all = false)
|
38
37
|
method.end_with?("_template") || super
|
@@ -42,13 +41,13 @@ module ViewComponent # :nodoc:
|
|
42
41
|
@__vc_inline_template if defined?(@__vc_inline_template)
|
43
42
|
end
|
44
43
|
|
45
|
-
def
|
44
|
+
def __vc_inline_template_language
|
46
45
|
@__vc_inline_template_language if defined?(@__vc_inline_template_language)
|
47
46
|
end
|
48
47
|
|
49
48
|
def inherited(subclass)
|
50
49
|
super
|
51
|
-
subclass.instance_variable_set(:@__vc_inline_template_language,
|
50
|
+
subclass.instance_variable_set(:@__vc_inline_template_language, __vc_inline_template_language)
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
@@ -5,12 +5,14 @@ require "active_support/notifications"
|
|
5
5
|
module ViewComponent # :nodoc:
|
6
6
|
module Instrumentation
|
7
7
|
def self.included(mod)
|
8
|
-
mod.prepend(self) unless
|
8
|
+
mod.prepend(self) unless self <= ViewComponent::Instrumentation
|
9
9
|
end
|
10
10
|
|
11
11
|
def render_in(view_context, &block)
|
12
|
+
return super if !Rails.application.config.view_component.instrumentation_enabled.present?
|
13
|
+
|
12
14
|
ActiveSupport::Notifications.instrument(
|
13
|
-
|
15
|
+
"render.view_component",
|
14
16
|
{
|
15
17
|
name: self.class.name,
|
16
18
|
identifier: self.class.identifier
|
@@ -19,13 +21,5 @@ module ViewComponent # :nodoc:
|
|
19
21
|
super
|
20
22
|
end
|
21
23
|
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def notification_name
|
26
|
-
return "!render.view_component" if ViewComponent::Base.config.use_deprecated_instrumentation_name
|
27
|
-
|
28
|
-
"render.view_component"
|
29
|
-
end
|
30
24
|
end
|
31
25
|
end
|
@@ -30,12 +30,10 @@ module ViewComponent # :nodoc:
|
|
30
30
|
}
|
31
31
|
end
|
32
32
|
|
33
|
-
alias_method :render_component, :render
|
34
|
-
|
35
33
|
class << self
|
36
34
|
# Returns all component preview classes.
|
37
35
|
def all
|
38
|
-
|
36
|
+
__vc_load_previews
|
39
37
|
|
40
38
|
descendants
|
41
39
|
end
|
@@ -94,13 +92,8 @@ module ViewComponent # :nodoc:
|
|
94
92
|
.sub(/\..*$/, "")
|
95
93
|
end
|
96
94
|
|
97
|
-
#
|
98
|
-
def
|
99
|
-
source = instance_method(example.to_sym).source.split("\n")
|
100
|
-
source[1...(source.size - 1)].join("\n")
|
101
|
-
end
|
102
|
-
|
103
|
-
def load_previews
|
95
|
+
# @private
|
96
|
+
def __vc_load_previews
|
104
97
|
Array(preview_paths).each do |preview_path|
|
105
98
|
Dir["#{preview_path}/**/*preview.rb"].sort.each { |file| require_dependency file }
|
106
99
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
# LookupContext computes and encapsulates @details for each request
|
5
|
+
# so that it doesn't need to be recomputed on each partial render.
|
6
|
+
# This data is wrapped in ActionView::TemplateDetails::Requested and
|
7
|
+
# used by instances of ActionView::Resolver to choose which template
|
8
|
+
# best matches the request.
|
9
|
+
#
|
10
|
+
# ActionView considers this logic internal to template/partial resolution.
|
11
|
+
# We're exposing it to the compiler via `refine` so that ViewComponent
|
12
|
+
# can match Rails' template picking logic.
|
13
|
+
module RequestDetails
|
14
|
+
refine ActionView::LookupContext do
|
15
|
+
# Return an abstraction for matching and sorting available templates
|
16
|
+
# based on the current lookup context details.
|
17
|
+
#
|
18
|
+
# @return ActionView::TemplateDetails::Requested
|
19
|
+
# @see ActionView::LookupContext#detail_args_for
|
20
|
+
# @see ActionView::FileSystemResolver#_find_all
|
21
|
+
def vc_requested_details(user_details = {})
|
22
|
+
# The hash `user_details` would normally be the standard arguments that
|
23
|
+
# `render` accepts, but there's currently no mechanism for users to
|
24
|
+
# provide these when calling render on a ViewComponent.
|
25
|
+
details, cached = detail_args_for(user_details)
|
26
|
+
cached || ActionView::TemplateDetails::Requested.new(**details)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/view_component/slot.rb
CHANGED
@@ -101,15 +101,12 @@ module ViewComponent
|
|
101
101
|
# end
|
102
102
|
# end
|
103
103
|
#
|
104
|
-
def method_missing(symbol, *args, &block)
|
105
|
-
@__vc_component_instance.public_send(symbol, *args, &block)
|
104
|
+
def method_missing(symbol, *args, **kwargs, &block)
|
105
|
+
@__vc_component_instance.public_send(symbol, *args, **kwargs, &block)
|
106
106
|
end
|
107
|
-
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
108
107
|
|
109
108
|
def html_safe?
|
110
|
-
# :nocov:
|
111
109
|
to_s.html_safe?
|
112
|
-
# :nocov:
|
113
110
|
end
|
114
111
|
|
115
112
|
def respond_to_missing?(symbol, include_all = false)
|