view_component 3.23.2 → 4.12.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/view_component/preview_actions.rb +11 -14
  3. data/app/controllers/view_components_system_test_controller.rb +25 -19
  4. data/app/views/test_mailer/test_asset_email.html.erb +1 -0
  5. data/app/views/test_mailer/test_url_email.html.erb +1 -0
  6. data/app/views/view_components/preview.html.erb +1 -9
  7. data/docs/CHANGELOG.md +612 -108
  8. data/lib/{rails/generators → generators/view_component}/abstract_generator.rb +2 -2
  9. data/lib/{rails/generators → generators/view_component}/component/component_generator.rb +17 -4
  10. data/lib/{rails/generators → generators/view_component}/component/templates/component.rb.tt +6 -1
  11. data/lib/{rails/generators/erb/component_generator.rb → generators/view_component/erb/erb_generator.rb} +4 -3
  12. data/lib/{rails/generators/haml/component_generator.rb → generators/view_component/haml/haml_generator.rb} +3 -3
  13. data/lib/{rails/generators/locale/component_generator.rb → generators/view_component/locale/locale_generator.rb} +3 -3
  14. data/lib/{rails/generators/preview/component_generator.rb → generators/view_component/preview/preview_generator.rb} +3 -3
  15. data/lib/{rails/generators/rspec/component_generator.rb → generators/view_component/rspec/rspec_generator.rb} +3 -3
  16. data/lib/{rails/generators/slim/component_generator.rb → generators/view_component/slim/slim_generator.rb} +3 -3
  17. data/lib/{rails/generators/stimulus/component_generator.rb → generators/view_component/stimulus/stimulus_generator.rb} +3 -3
  18. data/lib/generators/view_component/tailwindcss/tailwindcss_generator.rb +11 -0
  19. data/lib/{rails/generators/test_unit/component_generator.rb → generators/view_component/test_unit/test_unit_generator.rb} +2 -2
  20. data/lib/view_component/base.rb +252 -163
  21. data/lib/view_component/collection.rb +33 -35
  22. data/lib/view_component/compiler.rb +55 -80
  23. data/lib/view_component/config.rb +55 -85
  24. data/lib/view_component/configurable.rb +19 -3
  25. data/lib/view_component/deprecation.rb +1 -1
  26. data/lib/view_component/engine.rb +46 -106
  27. data/lib/view_component/errors.rb +16 -34
  28. data/lib/view_component/inline_template.rb +4 -4
  29. data/lib/view_component/instrumentation.rb +21 -14
  30. data/lib/view_component/preview.rb +7 -12
  31. data/lib/view_component/request_details.rb +30 -0
  32. data/lib/view_component/slot.rb +7 -15
  33. data/lib/view_component/slotable.rb +94 -80
  34. data/lib/view_component/system_spec_helpers.rb +11 -0
  35. data/lib/view_component/system_test_helpers.rb +2 -2
  36. data/lib/view_component/template.rb +159 -83
  37. data/lib/view_component/test_helpers.rb +67 -50
  38. data/lib/view_component/translatable.rb +33 -32
  39. data/lib/view_component/version.rb +3 -3
  40. data/lib/view_component.rb +9 -6
  41. metadata +36 -556
  42. data/app/assets/vendor/prism.css +0 -4
  43. data/app/assets/vendor/prism.min.js +0 -12
  44. data/app/helpers/preview_helper.rb +0 -85
  45. data/app/views/view_components/_preview_source.html.erb +0 -17
  46. data/lib/rails/generators/tailwindcss/component_generator.rb +0 -11
  47. data/lib/view_component/capture_compatibility.rb +0 -44
  48. data/lib/view_component/component_error.rb +0 -6
  49. data/lib/view_component/rails/tasks/view_component.rake +0 -20
  50. data/lib/view_component/render_component_helper.rb +0 -10
  51. data/lib/view_component/render_component_to_string_helper.rb +0 -9
  52. data/lib/view_component/render_monkey_patch.rb +0 -13
  53. data/lib/view_component/render_to_string_monkey_patch.rb +0 -13
  54. data/lib/view_component/rendering_component_helper.rb +0 -9
  55. data/lib/view_component/rendering_monkey_patch.rb +0 -13
  56. data/lib/view_component/slotable_default.rb +0 -20
  57. data/lib/view_component/use_helpers.rb +0 -42
  58. /data/lib/{rails/generators → generators/view_component}/erb/templates/component.html.erb.tt +0 -0
  59. /data/lib/{rails/generators → generators/view_component}/haml/templates/component.html.haml.tt +0 -0
  60. /data/lib/{rails/generators → generators/view_component}/preview/templates/component_preview.rb.tt +0 -0
  61. /data/lib/{rails/generators → generators/view_component}/rspec/templates/component_spec.rb.tt +0 -0
  62. /data/lib/{rails/generators → generators/view_component}/slim/templates/component.html.slim.tt +0 -0
  63. /data/lib/{rails/generators → generators/view_component}/stimulus/templates/component_controller.js.tt +0 -0
  64. /data/lib/{rails/generators → generators/view_component}/stimulus/templates/component_controller.ts.tt +0 -0
  65. /data/lib/{rails/generators → generators/view_component}/tailwindcss/templates/component.html.erb.tt +0 -0
  66. /data/lib/{rails/generators → generators/view_component}/test_unit/templates/component_test.rb.tt +0 -0
@@ -8,159 +8,109 @@ module ViewComponent
8
8
  class Engine < Rails::Engine # :nodoc:
9
9
  config.view_component = ViewComponent::Config.current
10
10
 
11
- if Rails.version.to_f < 8.0
12
- rake_tasks do
13
- load "view_component/rails/tasks/view_component.rake"
14
- end
15
- else
16
- initializer "view_component.stats_directories" do |app|
17
- require "rails/code_statistics"
18
-
19
- if Rails.root.join(ViewComponent::Base.view_component_path).directory?
20
- Rails::CodeStatistics.register_directory("ViewComponents", ViewComponent::Base.view_component_path)
21
- end
22
-
23
- if Rails.root.join("test/components").directory?
24
- Rails::CodeStatistics.register_directory("ViewComponent tests", "test/components", test_directory: true)
25
- end
26
- end
27
- end
28
-
29
11
  initializer "view_component.set_configs" do |app|
30
12
  options = app.config.view_component
31
13
 
32
- %i[generate preview_controller preview_route show_previews_source].each do |config_option|
14
+ %i[generate previews].each do |config_option|
33
15
  options[config_option] ||= ViewComponent::Base.public_send(config_option)
34
16
  end
35
17
  options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
36
- options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
37
- options.show_previews = (Rails.env.development? || Rails.env.test?) if options.show_previews.nil?
18
+ options.previews.enabled = (Rails.env.development? || Rails.env.test?) if options.previews.enabled.nil?
38
19
 
39
- if options.show_previews
20
+ if options.previews.enabled
40
21
  # This is still necessary because when `config.view_component` is declared, `Rails.root` is unspecified.
41
- options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
22
+ options.previews.paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
42
23
  "#{Rails.root}/test/components/previews"
43
24
  )
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
25
  end
53
26
  end
54
27
 
55
28
  initializer "view_component.enable_instrumentation" do |app|
56
29
  ActiveSupport.on_load(:view_component) do
57
30
  if app.config.view_component.instrumentation_enabled.present?
58
- # :nocov: Re-executing the below in tests duplicates initializers and causes order-dependent failures.
59
31
  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
32
  end
68
33
  end
69
34
  end
70
35
 
71
- # :nocov:
72
- initializer "view_component.enable_capture_patch" do |app|
73
- ActiveSupport.on_load(:view_component) do
74
- ActionView::Base.include(ViewComponent::CaptureCompatibility) if app.config.view_component.capture_compatibility_patch_enabled
75
- end
76
- end
77
- # :nocov:
78
-
79
36
  initializer "view_component.set_autoload_paths" do |app|
80
37
  options = app.config.view_component
81
38
 
82
- if options.show_previews && !options.preview_paths.empty?
83
- paths_to_add = options.preview_paths - ActiveSupport::Dependencies.autoload_paths
39
+ if options.previews.enabled && !options.previews.paths.empty?
40
+ paths_to_add = options.previews.paths - ActiveSupport::Dependencies.autoload_paths
84
41
  ActiveSupport::Dependencies.autoload_paths.concat(paths_to_add) if paths_to_add.any?
85
42
  end
86
43
  end
87
44
 
88
- initializer "view_component.eager_load_actions" do
89
- ActiveSupport.on_load(:after_initialize) do
90
- ViewComponent::Base.descendants.each(&:compile) if Rails.application.config.eager_load
45
+ initializer "view_component.propshaft_support" do |_app|
46
+ ActiveSupport.on_load(:view_component) do
47
+ if defined?(Propshaft)
48
+ include Propshaft::Helper
49
+ end
91
50
  end
92
51
  end
93
52
 
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
53
+ config.after_routes_loaded do
54
+ ActiveSupport.on_load(:view_component) do
55
+ if defined?(Sprockets::Rails)
56
+ include Sprockets::Rails::Helper
104
57
 
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
58
+ app = Rails.application
113
59
 
114
- initializer "view_component.include_render_component" do |_app|
115
- next if Rails.version.to_f >= 6.1
60
+ # Copy relevant config to VC context
61
+ # See: https://github.com/rails/sprockets-rails/blob/266ec49f3c7c96018dd75f9dc4f9b62fe3f7eecf/lib/sprockets/railtie.rb#L245
62
+ self.debug_assets = app.config.assets.debug
63
+ self.digest_assets = app.config.assets.digest
64
+ self.assets_prefix = app.config.assets.prefix
65
+ self.assets_precompile = app.config.assets.precompile
116
66
 
117
- # :nocov:
118
- ViewComponent::Deprecation.deprecation_warning("using `render_component`", "ViewComponent 4.0 will remove `render_component`")
67
+ self.assets_environment = app.assets
68
+ self.assets_manifest = app.assets_manifest
119
69
 
120
- ActiveSupport.on_load(:action_view) do
121
- require "view_component/render_component_helper"
122
- ActionView::Base.include ViewComponent::RenderComponentHelper
123
- end
70
+ self.resolve_assets_with = app.config.assets.resolve_with
124
71
 
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
72
+ self.check_precompiled_asset = app.config.assets.check_precompiled_asset
73
+ self.unknown_asset_fallback = app.config.assets.unknown_asset_fallback
74
+ # Expose the app precompiled asset check to the view
75
+ self.precompiled_asset_checker = ->(logical_path) { app.asset_precompiled? logical_path }
76
+ end
130
77
  end
131
- # :nocov:
132
78
  end
133
79
 
134
- initializer "static assets" do |app|
135
- if serve_static_preview_assets?(app.config)
136
- app.middleware.use(::ActionDispatch::Static, "#{root}/app/assets/vendor")
137
- end
138
- end
80
+ initializer "view_component.eager_load_actions" do
81
+ ActiveSupport.on_load(:after_initialize) do
82
+ if Rails.application.config.eager_load
83
+ ActiveSupport::Notifications.instrument("compile.view_component") do
84
+ ViewComponent::Base.descendants.each do |component|
85
+ next if component.anonymous?
139
86
 
140
- def serve_static_preview_assets?(app_config)
141
- app_config.view_component.show_previews && app_config.public_file_server.enabled
87
+ component.__vc_compile
88
+ end
89
+ end
90
+ end
91
+ end
142
92
  end
143
93
 
144
94
  initializer "compiler mode" do |_app|
145
- ViewComponent::Compiler.development_mode = (Rails.env.development? || Rails.env.test?)
95
+ ViewComponent::Compiler.__vc_development_mode = (Rails.env.development? || Rails.env.test?)
146
96
  end
147
97
 
148
98
  config.after_initialize do |app|
149
99
  options = app.config.view_component
150
100
 
151
- if options.show_previews
101
+ if options.previews.enabled
152
102
  app.routes.prepend do
153
- preview_controller = options.preview_controller.sub(/Controller$/, "").underscore
103
+ preview_controller = options.previews.controller.sub(/Controller$/, "").underscore
154
104
 
155
105
  get(
156
- options.preview_route,
106
+ options.previews.route,
157
107
  to: "#{preview_controller}#index",
158
108
  as: :preview_view_components,
159
109
  internal: true
160
110
  )
161
111
 
162
112
  get(
163
- "#{options.preview_route}/*path",
113
+ "#{options.previews.route}/*path",
164
114
  to: "#{preview_controller}#previews",
165
115
  as: :preview_view_component,
166
116
  internal: true
@@ -174,16 +124,6 @@ module ViewComponent
174
124
  end
175
125
  end
176
126
 
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
127
  app.executor.to_run :before do
188
128
  CompileCache.invalidate! unless ActionView::Base.cache_template_loading
189
129
  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, " \
@@ -49,18 +65,6 @@ module ViewComponent
49
65
  end
50
66
  end
51
67
 
52
- class EmptyOrInvalidInitializerError < StandardError
53
- MESSAGE =
54
- "The COMPONENT initializer is empty or invalid. " \
55
- "It must accept the parameter `PARAMETER` to render it as a collection.\n\n" \
56
- "To fix this issue, update the initializer to accept `PARAMETER`.\n\n" \
57
- "See [the collections docs](https://viewcomponent.org/guide/collections.html) for more information on rendering collections."
58
-
59
- def initialize(klass_name, parameter)
60
- super(MESSAGE.gsub("COMPONENT", klass_name.to_s).gsub("PARAMETER", parameter.to_s))
61
- end
62
- end
63
-
64
68
  class MissingCollectionArgumentError < StandardError
65
69
  MESSAGE =
66
70
  "The initializer for COMPONENT doesn't accept the parameter `PARAMETER`, " \
@@ -202,28 +206,6 @@ module ViewComponent
202
206
  "`#controller` to a [`#before_render` method](https://viewcomponent.org/api.html#before_render--void)."
203
207
  end
204
208
 
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
209
  class SystemTestControllerNefariousPathError < BaseError
228
210
  MESSAGE = "ViewComponent SystemTest controller attempted to load a file outside of the expected directory."
229
211
  end
@@ -3,6 +3,7 @@
3
3
  module ViewComponent # :nodoc:
4
4
  module InlineTemplate
5
5
  extend ActiveSupport::Concern
6
+
6
7
  Template = Struct.new(:source, :language, :path, :lineno)
7
8
 
8
9
  class_methods do
@@ -32,23 +33,22 @@ module ViewComponent # :nodoc:
32
33
 
33
34
  @__vc_inline_template_defined = true
34
35
  end
35
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
36
36
 
37
37
  def respond_to_missing?(method, include_all = false)
38
38
  method.end_with?("_template") || super
39
39
  end
40
40
 
41
- def inline_template
41
+ def __vc_inline_template
42
42
  @__vc_inline_template if defined?(@__vc_inline_template)
43
43
  end
44
44
 
45
- def inline_template_language
45
+ def __vc_inline_template_language
46
46
  @__vc_inline_template_language if defined?(@__vc_inline_template_language)
47
47
  end
48
48
 
49
49
  def inherited(subclass)
50
50
  super
51
- subclass.instance_variable_set(:@__vc_inline_template_language, inline_template_language)
51
+ subclass.instance_variable_set(:@__vc_inline_template_language, __vc_inline_template_language)
52
52
  end
53
53
  end
54
54
  end
@@ -5,27 +5,34 @@ require "active_support/notifications"
5
5
  module ViewComponent # :nodoc:
6
6
  module Instrumentation
7
7
  def self.included(mod)
8
- mod.prepend(self) unless ancestors.include?(ViewComponent::Instrumentation)
8
+ mod.prepend(self) unless self <= ViewComponent::Instrumentation
9
9
  end
10
10
 
11
- def render_in(view_context, &block)
11
+ def render_in(view_context, **_, &block)
12
+ return super if !Rails.application.config.view_component.instrumentation_enabled.present?
13
+
14
+ payload = {
15
+ name: self.class.name,
16
+ identifier: self.class.identifier,
17
+ view_identifier: nil
18
+ }
19
+
12
20
  ActiveSupport::Notifications.instrument(
13
- notification_name,
14
- {
15
- name: self.class.name,
16
- identifier: self.class.identifier
17
- }
21
+ "render.view_component",
22
+ payload
18
23
  ) do
19
- super
24
+ result = super
25
+ payload[:view_identifier] = @__vc_instrumentation_view_identifier
26
+ result
20
27
  end
28
+ ensure
29
+ @__vc_instrumentation_view_identifier = nil
21
30
  end
22
31
 
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"
32
+ def around_render
33
+ result = super
34
+ @__vc_instrumentation_view_identifier = current_template&.path
35
+ result
29
36
  end
30
37
  end
31
38
  end
@@ -30,18 +30,18 @@ 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
- load_previews
36
+ __vc_load_previews
39
37
 
40
38
  descendants
41
39
  end
42
40
 
43
41
  # Returns the arguments for rendering of the component in its layout
44
42
  def render_args(example, params: {})
43
+ raise AbstractController::ActionNotFound, "#{example} is not a valid preview example" unless examples.include?(example.to_s)
44
+
45
45
  example_params_names = instance_method(example).parameters.map(&:last)
46
46
  provided_params = params.slice(*example_params_names).to_h.symbolize_keys
47
47
  result = provided_params.empty? ? new.public_send(example) : new.public_send(example, **provided_params)
@@ -94,22 +94,17 @@ module ViewComponent # :nodoc:
94
94
  .sub(/\..*$/, "")
95
95
  end
96
96
 
97
- # Returns the method body for the example from the preview file.
98
- def preview_source(example)
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
97
+ # @private
98
+ def __vc_load_previews
104
99
  Array(preview_paths).each do |preview_path|
105
- Dir["#{preview_path}/**/*preview.rb"].sort.each { |file| require_dependency file }
100
+ Dir["#{preview_path}/**/*preview.rb"].sort.each { |file| require file }
106
101
  end
107
102
  end
108
103
 
109
104
  private
110
105
 
111
106
  def preview_paths
112
- Base.preview_paths
107
+ Base.previews.paths
113
108
  end
114
109
  end
115
110
  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
@@ -6,7 +6,7 @@ module ViewComponent
6
6
  class Slot
7
7
  include ViewComponent::WithContentHelper
8
8
 
9
- attr_writer :__vc_component_instance, :__vc_content_block, :__vc_content
9
+ attr_writer :__vc_component_instance, :__vc_content_block, :__vc_content, :__vc_content_block_virtual_path
10
10
 
11
11
  def initialize(parent)
12
12
  @parent = parent
@@ -58,13 +58,7 @@ module ViewComponent
58
58
  if defined?(@__vc_content_block)
59
59
  # render_in is faster than `parent.render`
60
60
  @__vc_component_instance.render_in(view_context) do |*args|
61
- return @__vc_content_block.call(*args) if @__vc_content_block&.source_location.nil?
62
-
63
- block_context = @__vc_content_block.binding.receiver
64
-
65
- if block_context.class < ActionView::Base
66
- block_context.capture(*args, &@__vc_content_block)
67
- else
61
+ @parent.with_captured_virtual_path(@__vc_content_block_virtual_path) do
68
62
  @__vc_content_block.call(*args)
69
63
  end
70
64
  end
@@ -74,7 +68,9 @@ module ViewComponent
74
68
  elsif defined?(@__vc_content)
75
69
  @__vc_content
76
70
  elsif defined?(@__vc_content_block)
77
- view_context.capture(&@__vc_content_block)
71
+ @parent.with_captured_virtual_path(@__vc_content_block_virtual_path) do
72
+ view_context.capture(&@__vc_content_block)
73
+ end
78
74
  elsif defined?(@__vc_content_set_by_with_content)
79
75
  @__vc_content_set_by_with_content
80
76
  end
@@ -100,16 +96,12 @@ module ViewComponent
100
96
  # end
101
97
  # end
102
98
  # end
103
- #
104
- def method_missing(symbol, *args, &block)
105
- @__vc_component_instance.public_send(symbol, *args, &block)
99
+ def method_missing(symbol, *args, **kwargs, &block)
100
+ @__vc_component_instance.public_send(symbol, *args, **kwargs, &block)
106
101
  end
107
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
108
102
 
109
103
  def html_safe?
110
- # :nocov:
111
104
  to_s.html_safe?
112
- # :nocov:
113
105
  end
114
106
 
115
107
  def respond_to_missing?(symbol, include_all = false)