view_component 2.33.0 → 2.37.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.

Potentially problematic release.


This version of view_component might be problematic. Click here for more details.

Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/vendor/prism.css +196 -0
  4. data/app/assets/vendor/prism.min.js +12 -0
  5. data/app/controllers/view_components_controller.rb +1 -1
  6. data/app/helpers/preview_helper.rb +19 -0
  7. data/app/views/test_mailer/test_email.html.erb +1 -0
  8. data/app/views/view_components/_preview_source.html.erb +17 -0
  9. data/app/views/view_components/preview.html.erb +6 -2
  10. data/{CHANGELOG.md → docs/CHANGELOG.md} +151 -1
  11. data/lib/rails/generators/abstract_generator.rb +29 -0
  12. data/lib/rails/generators/component/component_generator.rb +5 -5
  13. data/lib/rails/generators/erb/component_generator.rb +7 -16
  14. data/lib/rails/generators/haml/component_generator.rb +6 -16
  15. data/lib/rails/generators/slim/component_generator.rb +6 -16
  16. data/lib/view_component.rb +2 -0
  17. data/lib/view_component/base.rb +144 -85
  18. data/lib/view_component/collection.rb +6 -2
  19. data/lib/view_component/compile_cache.rb +1 -0
  20. data/lib/view_component/compiler.rb +87 -53
  21. data/lib/view_component/content_areas.rb +57 -0
  22. data/lib/view_component/engine.rb +31 -3
  23. data/lib/view_component/instrumentation.rb +21 -0
  24. data/lib/view_component/preview.rb +19 -8
  25. data/lib/view_component/previewable.rb +16 -18
  26. data/lib/view_component/slot_v2.rb +34 -27
  27. data/lib/view_component/slotable.rb +2 -1
  28. data/lib/view_component/slotable_v2.rb +58 -24
  29. data/lib/view_component/test_helpers.rb +7 -1
  30. data/lib/view_component/translatable.rb +6 -5
  31. data/lib/view_component/version.rb +1 -1
  32. data/lib/view_component/with_content_helper.rb +5 -2
  33. data/lib/yard/mattr_accessor_handler.rb +19 -0
  34. metadata +76 -39
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module AbstractGenerator
5
+ def copy_view_file
6
+ unless options["inline"]
7
+ template "component.html.#{engine_name}", destination
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def destination
14
+ if options["sidecar"]
15
+ File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component.html.#{engine_name}")
16
+ else
17
+ File.join(component_path, class_path, "#{file_name}_component.html.#{engine_name}")
18
+ end
19
+ end
20
+
21
+ def file_name
22
+ @_file_name ||= super.sub(/_component\z/i, "")
23
+ end
24
+
25
+ def component_path
26
+ ViewComponent::Base.view_component_path
27
+ end
28
+ end
29
+ end
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rails/generators/abstract_generator"
4
+
3
5
  module Rails
4
6
  module Generators
5
7
  class ComponentGenerator < Rails::Generators::NamedBase
8
+ include ViewComponent::AbstractGenerator
9
+
6
10
  source_root File.expand_path("templates", __dir__)
7
11
 
8
12
  argument :attributes, type: :array, default: [], banner: "attribute"
@@ -10,7 +14,7 @@ module Rails
10
14
  class_option :inline, type: :boolean, default: false
11
15
 
12
16
  def create_component_file
13
- template "component.rb", File.join("app/components", class_path, "#{file_name}_component.rb")
17
+ template "component.rb", File.join(component_path, class_path, "#{file_name}_component.rb")
14
18
  end
15
19
 
16
20
  hook_for :test_framework
@@ -23,10 +27,6 @@ module Rails
23
27
 
24
28
  private
25
29
 
26
- def file_name
27
- @_file_name ||= super.sub(/_component\z/i, "")
28
- end
29
-
30
30
  def parent_class
31
31
  defined?(ApplicationComponent) ? "ApplicationComponent" : "ViewComponent::Base"
32
32
  end
@@ -1,32 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/generators/erb"
4
+ require "rails/generators/abstract_generator"
4
5
 
5
6
  module Erb
6
7
  module Generators
7
8
  class ComponentGenerator < Base
9
+ include ViewComponent::AbstractGenerator
10
+
8
11
  source_root File.expand_path("templates", __dir__)
9
12
  class_option :sidecar, type: :boolean, default: false
10
13
  class_option :inline, type: :boolean, default: false
11
14
 
12
- def copy_view_file
13
- unless options["inline"]
14
- template "component.html.erb", destination
15
- end
16
- end
17
-
18
- private
19
-
20
- def destination
21
- if options["sidecar"]
22
- File.join("app/components", class_path, "#{file_name}_component", "#{file_name}_component.html.erb")
23
- else
24
- File.join("app/components", class_path, "#{file_name}_component.html.erb")
25
- end
15
+ def engine_name
16
+ "erb"
26
17
  end
27
18
 
28
- def file_name
29
- @_file_name ||= super.sub(/_component\z/i, "")
19
+ def copy_view_file
20
+ super
30
21
  end
31
22
  end
32
23
  end
@@ -5,27 +5,17 @@ require "rails/generators/erb/component_generator"
5
5
  module Haml
6
6
  module Generators
7
7
  class ComponentGenerator < Erb::Generators::ComponentGenerator
8
+ include ViewComponent::AbstractGenerator
9
+
8
10
  source_root File.expand_path("templates", __dir__)
9
11
  class_option :sidecar, type: :boolean, default: false
10
12
 
11
- def copy_view_file
12
- if !options["inline"]
13
- template "component.html.haml", destination
14
- end
15
- end
16
-
17
- private
18
-
19
- def destination
20
- if options["sidecar"]
21
- File.join("app/components", class_path, "#{file_name}_component", "#{file_name}_component.html.haml")
22
- else
23
- File.join("app/components", class_path, "#{file_name}_component.html.haml")
24
- end
13
+ def engine_name
14
+ "haml"
25
15
  end
26
16
 
27
- def file_name
28
- @_file_name ||= super.sub(/_component\z/i, "")
17
+ def copy_view_file
18
+ super
29
19
  end
30
20
  end
31
21
  end
@@ -5,27 +5,17 @@ require "rails/generators/erb/component_generator"
5
5
  module Slim
6
6
  module Generators
7
7
  class ComponentGenerator < Erb::Generators::ComponentGenerator
8
+ include ViewComponent::AbstractGenerator
9
+
8
10
  source_root File.expand_path("templates", __dir__)
9
11
  class_option :sidecar, type: :boolean, default: false
10
12
 
11
- def copy_view_file
12
- if !options["inline"]
13
- template "component.html.slim", destination
14
- end
15
- end
16
-
17
- private
18
-
19
- def destination
20
- if options["sidecar"]
21
- File.join("app/components", class_path, "#{file_name}_component", "#{file_name}_component.html.slim")
22
- else
23
- File.join("app/components", class_path, "#{file_name}_component.html.slim")
24
- end
13
+ def engine_name
14
+ "slim"
25
15
  end
26
16
 
27
- def file_name
28
- @_file_name ||= super.sub(/_component\z/i, "")
17
+ def copy_view_file
18
+ super
29
19
  end
30
20
  end
31
21
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "action_view"
3
4
  require "active_support/dependencies/autoload"
4
5
 
@@ -8,6 +9,7 @@ module ViewComponent
8
9
  autoload :Base
9
10
  autoload :Compiler
10
11
  autoload :ComponentError
12
+ autoload :Instrumentation
11
13
  autoload :Preview
12
14
  autoload :PreviewTemplateError
13
15
  autoload :TestHelpers
@@ -4,6 +4,7 @@ require "action_view"
4
4
  require "active_support/configurable"
5
5
  require "view_component/collection"
6
6
  require "view_component/compile_cache"
7
+ require "view_component/content_areas"
7
8
  require "view_component/previewable"
8
9
  require "view_component/slotable"
9
10
  require "view_component/slotable_v2"
@@ -12,6 +13,7 @@ require "view_component/with_content_helper"
12
13
  module ViewComponent
13
14
  class Base < ActionView::Base
14
15
  include ActiveSupport::Configurable
16
+ include ViewComponent::ContentAreas
15
17
  include ViewComponent::Previewable
16
18
  include ViewComponent::SlotableV2
17
19
  include ViewComponent::WithContentHelper
@@ -76,22 +78,28 @@ module ViewComponent
76
78
  @virtual_path ||= virtual_path
77
79
 
78
80
  # For template variants (+phone, +desktop, etc.)
79
- @variant ||= @lookup_context.variants.first
81
+ @__vc_variant ||= @lookup_context.variants.first
80
82
 
81
83
  # For caching, such as #cache_if
82
84
  @current_template = nil unless defined?(@current_template)
83
85
  old_current_template = @current_template
84
86
  @current_template = self
85
87
 
86
- raise ArgumentError.new("Block provided after calling `with_content`. Use one or the other.") if block && defined?(@_content_set_by_with_content)
88
+ if block && defined?(@__vc_content_set_by_with_content)
89
+ raise ArgumentError.new(
90
+ "It looks like a block was provided after calling `with_content` on #{self.class.name}, " \
91
+ "which means that ViewComponent doesn't know which content to use.\n\n" \
92
+ "To fix this issue, use either `with_content` or a block."
93
+ )
94
+ end
87
95
 
88
- @_content_evaluated = false
89
- @_render_in_block = block
96
+ @__vc_content_evaluated = false
97
+ @__vc_render_in_block = block
90
98
 
91
99
  before_render
92
100
 
93
101
  if render?
94
- render_template_for(@variant).to_s + _output_postamble
102
+ render_template_for(@__vc_variant).to_s + _output_postamble
95
103
  else
96
104
  ""
97
105
  end
@@ -106,7 +114,8 @@ module ViewComponent
106
114
  ""
107
115
  end
108
116
 
109
- # Called before rendering the component. Override to perform operations that depend on having access to the view context, such as helpers.
117
+ # Called before rendering the component. Override to perform operations that
118
+ # depend on having access to the view context, such as helpers.
110
119
  #
111
120
  # @return [void]
112
121
  def before_render
@@ -115,7 +124,7 @@ module ViewComponent
115
124
 
116
125
  # Called after rendering the component.
117
126
  #
118
- # @deprecated Use `before_render` instead. Will be removed in v3.0.0.
127
+ # @deprecated Use `#before_render` instead. Will be removed in v3.0.0.
119
128
  # @return [void]
120
129
  def before_render_check
121
130
  # noop
@@ -136,6 +145,7 @@ module ViewComponent
136
145
  # This prevents an exception when rendering a partial inside of a component that has also been rendered outside
137
146
  # of the component. This is due to the partials compiled template method existing in the parent `view_context`,
138
147
  # and not the component's `view_context`.
148
+ #
139
149
  # @private
140
150
  def render(options = {}, args = {}, &block)
141
151
  if options.is_a? ViewComponent::Base
@@ -145,23 +155,46 @@ module ViewComponent
145
155
  end
146
156
  end
147
157
 
148
- # The current controller. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult.
158
+ # The current controller. Use sparingly as doing so introduces coupling
159
+ # that inhibits encapsulation & reuse, often making testing difficult.
149
160
  #
150
161
  # @return [ActionController::Base]
151
162
  def controller
152
- raise ViewContextCalledBeforeRenderError, "`controller` can only be called at render time." if view_context.nil?
153
- @controller ||= view_context.controller
163
+ if view_context.nil?
164
+ raise(
165
+ ViewContextCalledBeforeRenderError,
166
+ "`#controller` cannot be used during initialization, as it depends " \
167
+ "on the view context that only exists once a ViewComponent is passed to " \
168
+ "the Rails render pipeline.\n\n" \
169
+ "It's sometimes possible to fix this issue by moving code dependent on " \
170
+ "`#controller` to a `#before_render` method: https://viewcomponent.org/api.html#before_render--void."
171
+ )
172
+ end
173
+
174
+ @__vc_controller ||= view_context.controller
154
175
  end
155
176
 
156
- # A proxy through which to access helpers. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult.
177
+ # A proxy through which to access helpers. Use sparingly as doing so introduces
178
+ # coupling that inhibits encapsulation & reuse, often making testing difficult.
157
179
  #
158
180
  # @return [ActionView::Base]
159
181
  def helpers
160
- raise ViewContextCalledBeforeRenderError, "`helpers` can only be called at render time." if view_context.nil?
161
- @helpers ||= controller.view_context
182
+ if view_context.nil?
183
+ raise(
184
+ ViewContextCalledBeforeRenderError,
185
+ "`#helpers` cannot be used during initialization, as it depends " \
186
+ "on the view context that only exists once a ViewComponent is passed to " \
187
+ "the Rails render pipeline.\n\n" \
188
+ "It's sometimes possible to fix this issue by moving code dependent on " \
189
+ "`#helpers` to a `#before_render` method: https://viewcomponent.org/api.html#before_render--void."
190
+ )
191
+ end
192
+
193
+ @__vc_helpers ||= controller.view_context
162
194
  end
163
195
 
164
196
  # Exposes .virtual_path as an instance method
197
+ #
165
198
  # @private
166
199
  def virtual_path
167
200
  self.class.virtual_path
@@ -174,41 +207,31 @@ module ViewComponent
174
207
  end
175
208
 
176
209
  # For caching, such as #cache_if
210
+ #
177
211
  # @private
178
212
  def format
179
213
  # Ruby 2.6 throws a warning without checking `defined?`, 2.7 does not
180
- if defined?(@variant)
181
- @variant
214
+ if defined?(@__vc_variant)
215
+ @__vc_variant
182
216
  end
183
217
  end
184
218
 
185
- # Assign the provided content to the content area accessor
186
- # @private
187
- def with(area, content = nil, &block)
188
- unless content_areas.include?(area)
189
- raise ArgumentError.new "Unknown content_area '#{area}' - expected one of '#{content_areas}'"
190
- end
191
-
192
- if block_given?
193
- content = view_context.capture(&block)
194
- end
195
-
196
- instance_variable_set("@#{area}".to_sym, content)
197
- nil
198
- end
199
-
200
- # @private TODO: add documentation
219
+ # Use the provided variant instead of the one determined by the current request.
220
+ #
221
+ # @param variant [Symbol] The variant to be used by the component.
222
+ # @return [self]
201
223
  def with_variant(variant)
202
- @variant = variant
224
+ @__vc_variant = variant
203
225
 
204
226
  self
205
227
  end
206
228
 
207
- # The current request. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult.
229
+ # The current request. Use sparingly as doing so introduces coupling that
230
+ # inhibits encapsulation & reuse, often making testing difficult.
208
231
  #
209
232
  # @return [ActionDispatch::Request]
210
233
  def request
211
- @request ||= controller.request
234
+ @request ||= controller.request if controller.respond_to?(:request)
212
235
  end
213
236
 
214
237
  private
@@ -216,31 +239,54 @@ module ViewComponent
216
239
  attr_reader :view_context
217
240
 
218
241
  def content
219
- return @_content if defined?(@_content)
220
- @_content_evaluated = true
221
-
222
- @_content = if @view_context && @_render_in_block
223
- view_context.capture(self, &@_render_in_block)
224
- elsif defined?(@_content_set_by_with_content)
225
- @_content_set_by_with_content
226
- end
242
+ @__vc_content_evaluated = true
243
+ return @__vc_content if defined?(@__vc_content)
244
+
245
+ @__vc_content =
246
+ if @view_context && @__vc_render_in_block
247
+ view_context.capture(self, &@__vc_render_in_block)
248
+ elsif defined?(@__vc_content_set_by_with_content)
249
+ @__vc_content_set_by_with_content
250
+ end
227
251
  end
228
252
 
229
253
  def content_evaluated?
230
- @_content_evaluated
254
+ @__vc_content_evaluated
231
255
  end
232
256
 
233
- # The controller used for testing components.
234
- # Defaults to ApplicationController, but can be configured
235
- # on a per-test basis using `with_controller_class`.
236
- # This should be set early in the initialization process and should be a string.
257
+ # Set the controller used for testing components:
258
+ #
259
+ # config.view_component.test_controller = "MyTestController"
260
+ #
261
+ # Defaults to ApplicationController. Can also be configured on a per-test
262
+ # basis using `with_controller_class`.
263
+ #
237
264
  mattr_accessor :test_controller
238
265
  @@test_controller = "ApplicationController"
239
266
 
240
- # Configure if render monkey patches should be included or not in Rails <6.1.
267
+ # Set if render monkey patches should be included or not in Rails <6.1:
268
+ #
269
+ # config.view_component.render_monkey_patch_enabled = false
270
+ #
241
271
  mattr_accessor :render_monkey_patch_enabled, instance_writer: false, default: true
242
272
 
273
+ # Enable or disable source code previews in component previews:
274
+ #
275
+ # config.view_component.show_previews_source = true
276
+ #
277
+ # Defaults to `false`.
278
+ #
279
+ mattr_accessor :show_previews_source, instance_writer: false, default: false
280
+
281
+ # Path for component files
282
+ #
283
+ # config.view_component.view_component_path = "app/my_components"
284
+ #
285
+ # Defaults to "app/components".
286
+ mattr_accessor :view_component_path, instance_writer: false, default: "app/components"
287
+
243
288
  class << self
289
+ # @private
244
290
  attr_accessor :source_location, :virtual_path
245
291
 
246
292
  # EXPERIMENTAL: This API is experimental and may be removed at any time.
@@ -250,6 +296,7 @@ module ViewComponent
250
296
  # strings starting without the "dot", example: `["erb", "haml"]`.
251
297
  #
252
298
  # For example, one might collect sidecar CSS files that need to be compiled.
299
+ # @private TODO: add documentation
253
300
  def _sidecar_files(extensions)
254
301
  return [] unless source_location
255
302
 
@@ -270,11 +317,12 @@ module ViewComponent
270
317
  # end
271
318
  #
272
319
  # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
273
- nested_component_files = if name.include?("::") && component_name != filename
274
- Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
275
- else
276
- []
277
- end
320
+ nested_component_files =
321
+ if name.include?("::") && component_name != filename
322
+ Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
323
+ else
324
+ []
325
+ end
278
326
 
279
327
  # view files in the same directory as the component
280
328
  sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
@@ -284,16 +332,24 @@ module ViewComponent
284
332
  (sidecar_files - [source_location] + sidecar_directory_files + nested_component_files).uniq
285
333
  end
286
334
 
287
- # Render a component collection.
335
+ # Render a component for each element in a collection ([documentation](/guide/collections)):
336
+ #
337
+ # render(ProductsComponent.with_collection(@products, foo: :bar))
338
+ #
339
+ # @param collection [Enumerable] A list of items to pass the ViewComponent one at a time.
340
+ # @param args [Arguments] Arguments to pass to the ViewComponent every time.
288
341
  def with_collection(collection, **args)
289
342
  Collection.new(self, collection, **args)
290
343
  end
291
344
 
292
345
  # Provide identifier for ActionView template annotations
346
+ #
347
+ # @private
293
348
  def short_identifier
294
349
  @short_identifier ||= defined?(Rails.root) ? source_location.sub("#{Rails.root}/", "") : source_location
295
350
  end
296
351
 
352
+ # @private
297
353
  def inherited(child)
298
354
  # Compile so child will inherit compiled `call_*` template methods that
299
355
  # `compile` defines
@@ -311,11 +367,14 @@ module ViewComponent
311
367
  child.source_location = caller_locations(1, 10).reject { |l| l.label == "inherited" }[0].absolute_path
312
368
 
313
369
  # Removes the first part of the path and the extension.
314
- child.virtual_path = child.source_location.gsub(%r{(.*app/components)|(\.rb)}, "")
370
+ child.virtual_path = child.source_location.gsub(
371
+ %r{(.*#{Regexp.quote(ViewComponent::Base.view_component_path)})|(\.rb)}, ""
372
+ )
315
373
 
316
374
  super
317
375
  end
318
376
 
377
+ # @private
319
378
  def compiled?
320
379
  compiler.compiled?
321
380
  end
@@ -324,50 +383,39 @@ module ViewComponent
324
383
  #
325
384
  # Do as much work as possible in this step, as doing so reduces the amount
326
385
  # of work done each time a component is rendered.
386
+ # @private
327
387
  def compile(raise_errors: false)
328
388
  compiler.compile(raise_errors: raise_errors)
329
389
  end
330
390
 
391
+ # @private
331
392
  def compiler
332
- @_compiler ||= Compiler.new(self)
393
+ @__vc_compiler ||= Compiler.new(self)
333
394
  end
334
395
 
335
396
  # we'll eventually want to update this to support other types
397
+ # @private
336
398
  def type
337
399
  "text/html"
338
400
  end
339
401
 
402
+ # @private
340
403
  def format
341
404
  :html
342
405
  end
343
406
 
407
+ # @private
344
408
  def identifier
345
409
  source_location
346
410
  end
347
411
 
348
- def with_content_areas(*areas)
349
- ActiveSupport::Deprecation.warn(
350
- "`with_content_areas` is deprecated and will be removed in ViewComponent v3.0.0.\n" \
351
- "Use slots (https://viewcomponent.org/guide/slots.html) instead."
352
- )
353
-
354
- if areas.include?(:content)
355
- raise ArgumentError.new ":content is a reserved content area name. Please use another name, such as ':body'"
356
- end
357
-
358
- areas.each do |area|
359
- define_method area.to_sym do
360
- content unless content_evaluated? # ensure content is loaded so content_areas will be defined
361
- instance_variable_get(:"@#{area}") if instance_variable_defined?(:"@#{area}")
362
- end
363
- end
364
-
365
- self.content_areas = areas
366
- end
367
-
368
- # Support overriding collection parameter name
369
- def with_collection_parameter(param)
370
- @provided_collection_parameter = param
412
+ # Set the parameter name used when rendering elements of a collection ([documentation](/guide/collections)):
413
+ #
414
+ # with_collection_parameter :item
415
+ #
416
+ # @param parameter [Symbol] The parameter name used when rendering elements of a collection.
417
+ def with_collection_parameter(parameter)
418
+ @provided_collection_parameter = parameter
371
419
  end
372
420
 
373
421
  # Ensure the component initializer accepts the
@@ -375,6 +423,7 @@ module ViewComponent
375
423
  # validate that the default parameter name
376
424
  # is accepted, as support for collection
377
425
  # rendering is optional.
426
+ # @private TODO: add documentation
378
427
  def validate_collection_parameter!(validate_default: false)
379
428
  parameter = validate_default ? collection_parameter : provided_collection_parameter
380
429
 
@@ -386,29 +435,35 @@ module ViewComponent
386
435
  # the component.
387
436
  if initialize_parameters.empty?
388
437
  raise ArgumentError.new(
389
- "#{self} initializer is empty or invalid."
438
+ "The #{self} initializer is empty or invalid." \
439
+ "It must accept the parameter `#{parameter}` to render it as a collection.\n\n" \
440
+ "To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
441
+ "See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
390
442
  )
391
443
  end
392
444
 
393
445
  raise ArgumentError.new(
394
- "#{self} initializer must accept " \
395
- "`#{parameter}` collection parameter."
446
+ "The initializer for #{self} does not accept the parameter `#{parameter}`, " \
447
+ "which is required in order to render it as a collection.\n\n" \
448
+ "To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
449
+ "See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
396
450
  )
397
451
  end
398
452
 
399
453
  # Ensure the component initializer does not define
400
454
  # invalid parameters that could override the framework's
401
455
  # methods.
456
+ # @private TODO: add documentation
402
457
  def validate_initialization_parameters!
403
458
  return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
404
459
 
405
460
  raise ViewComponent::ComponentError.new(
406
- "#{self} initializer cannot contain " \
407
- "`#{RESERVED_PARAMETER}` since it will override a " \
408
- "public ViewComponent method."
461
+ "#{self} initializer cannot accept the parameter `#{RESERVED_PARAMETER}`, as it will override a " \
462
+ "public ViewComponent method. To fix this issue, rename the parameter."
409
463
  )
410
464
  end
411
465
 
466
+ # @private
412
467
  def collection_parameter
413
468
  if provided_collection_parameter
414
469
  provided_collection_parameter
@@ -417,18 +472,22 @@ module ViewComponent
417
472
  end
418
473
  end
419
474
 
475
+ # @private
420
476
  def collection_counter_parameter
421
477
  "#{collection_parameter}_counter".to_sym
422
478
  end
423
479
 
480
+ # @private
424
481
  def counter_argument_present?
425
482
  initialize_parameter_names.include?(collection_counter_parameter)
426
483
  end
427
484
 
485
+ # @private
428
486
  def collection_iteration_parameter
429
487
  "#{collection_parameter}_iteration".to_sym
430
488
  end
431
489
 
490
+ # @private
432
491
  def iteration_argument_present?
433
492
  initialize_parameter_names.include?(collection_iteration_parameter)
434
493
  end