view_component 2.82.0 → 3.1.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/view_component/preview_actions.rb +4 -0
  3. data/app/controllers/view_components_system_test_controller.rb +24 -1
  4. data/app/helpers/preview_helper.rb +2 -4
  5. data/docs/CHANGELOG.md +320 -0
  6. data/lib/view_component/base.rb +50 -96
  7. data/lib/view_component/capture_compatibility.rb +44 -0
  8. data/lib/view_component/collection.rb +2 -5
  9. data/lib/view_component/compiler.rb +51 -28
  10. data/lib/view_component/config.rb +9 -13
  11. data/lib/view_component/deprecation.rb +1 -1
  12. data/lib/view_component/docs_builder_component.html.erb +5 -1
  13. data/lib/view_component/docs_builder_component.rb +28 -9
  14. data/lib/view_component/engine.rb +12 -22
  15. data/lib/view_component/errors.rb +223 -0
  16. data/lib/view_component/inline_template.rb +55 -0
  17. data/lib/view_component/preview.rb +1 -7
  18. data/lib/view_component/rails/tasks/view_component.rake +1 -1
  19. data/lib/view_component/slot.rb +109 -1
  20. data/lib/view_component/slotable.rb +364 -96
  21. data/lib/view_component/system_test_helpers.rb +5 -5
  22. data/lib/view_component/test_helpers.rb +67 -54
  23. data/lib/view_component/translatable.rb +35 -23
  24. data/lib/view_component/version.rb +4 -3
  25. data/lib/view_component/with_content_helper.rb +3 -8
  26. data/lib/view_component.rb +3 -12
  27. metadata +45 -34
  28. data/lib/view_component/content_areas.rb +0 -56
  29. data/lib/view_component/polymorphic_slots.rb +0 -103
  30. data/lib/view_component/preview_template_error.rb +0 -6
  31. data/lib/view_component/slot_v2.rb +0 -98
  32. data/lib/view_component/slotable_v2.rb +0 -391
  33. data/lib/view_component/template_error.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb20706245c43b9c5fa4d11087a2e98332bda53d659f7065874a3c0b8545547
4
- data.tar.gz: 13821a1e91da8a8dce8270962b99aa3b84fddb9731f99c2e2acfd143ad017836
3
+ metadata.gz: ca112c2d340e4ade9bd258d515edafbd1cc66e0b19097acd12d3eab53b9ae4a4
4
+ data.tar.gz: 173223c31abaf369bbfb455eff47137dfa6b7ac98485b17ba58c8317d6f5c3e5
5
5
  SHA512:
6
- metadata.gz: 5b0ebf7ac54fc2c82374b29f9cceadfe55af73516ad2e4c65dad69cd65a7c63de3e00ef9cdba8b359c1061309f9a0d2f90344374feec2b37211fbfb36282c96b
7
- data.tar.gz: 48e156dcc5fa1ac9a6cff64e4cb585d528103452938a515d1e3598b505b03188e89362c393c86c0a05437f9a8c28f22e937e3d706f3da17ae03a7c1371728505
6
+ metadata.gz: 7d63eac1f6f698a44ae621b107194d5ae2e0f4ef16da352e8fbb4ee5514f61fadd70e596582d6f78fcbc5738be3046013846a8541d0e845a85a4d1257262d8ad
7
+ data.tar.gz: f7a415d645e7dc45cbd0300fed91c3356d10c543ea9331a24b7beb8e67efe0f3f05d09148a66a4dbecd14149861c884ea0481c033c9c32da5f398b3744c02b60
@@ -11,6 +11,10 @@ module ViewComponent
11
11
  before_action :require_local!, unless: :show_previews?
12
12
 
13
13
  content_security_policy(false) if respond_to?(:content_security_policy)
14
+
15
+ # Including helpers here ensures that we're loading the
16
+ # latest version of helpers if code-reloading is enabled
17
+ helper :all if include_all_helpers
14
18
  end
15
19
 
16
20
  def index
@@ -1,7 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ViewComponentsSystemTestController < ActionController::Base # :nodoc:
4
+ before_action :validate_test_env
5
+ before_action :validate_file_path
6
+
7
+ def self.temp_dir
8
+ @_tmpdir ||= FileUtils.mkdir_p("./tmp/view_components/").first
9
+ end
10
+
4
11
  def system_test_entrypoint
5
- render file: "./tmp/view_components/#{params.permit(:file)[:file]}"
12
+ render file: @path
13
+ end
14
+
15
+ private
16
+
17
+ def validate_test_env
18
+ raise ViewComponent::SystemTestControllerOnlyAllowedInTestError unless Rails.env.test?
19
+ end
20
+
21
+ # Ensure that the file path is valid and doesn't target files outside
22
+ # the expected directory (e.g. via a path traversal or symlink attack)
23
+ def validate_file_path
24
+ base_path = ::File.realpath(self.class.temp_dir)
25
+ @path = ::File.realpath(params.permit(:file)[:file], base_path)
26
+ unless @path.start_with?(base_path)
27
+ raise ViewComponent::SystemTestControllerNefariousPathError
28
+ end
6
29
  end
7
30
  end
@@ -31,10 +31,8 @@ module PreviewHelper
31
31
  path =~ /#{template_identifier}*.(html)/
32
32
  end
33
33
 
34
- # In-case of a conflict due to multiple template files with
35
- # the same name
36
- raise "found 0 matches for templates for #{template_identifier}." if matching_templates.empty?
37
- raise "found multiple templates for #{template_identifier}." if matching_templates.size > 1
34
+ raise ViewComponent::NoMatchingTemplatesForPreviewError.new(template_identifier) if matching_templates.empty?
35
+ raise ViewComponent::MultipleMatchingTemplatesForPreviewError.new(template_identifier) if matching_templates.size > 1
38
36
 
39
37
  template_file_path = matching_templates.first
40
38
  template_source = File.read(template_file_path)
data/docs/CHANGELOG.md CHANGED
@@ -10,6 +10,326 @@ nav_order: 5
10
10
 
11
11
  ## main
12
12
 
13
+ ## 3.1.0
14
+
15
+ * Check `defined?(Rails) && Rails.application` before using `ViewComponent::Base.config.view_component_path`.
16
+
17
+ *Donapieppo*
18
+
19
+ * Allow customization of polymorphic slot setters.
20
+
21
+ *Cameron Dutro*
22
+
23
+ * Fix duplication in configuration docs.
24
+
25
+ *Tom Chen*
26
+
27
+ * Fix helpers not reloading in development.
28
+
29
+ *Jonathan del Strother*
30
+
31
+ * Add `SECURITY.md`.
32
+
33
+ *Joel Hawksley*
34
+
35
+ * Add Ophelos to list of companies using ViewComponent.
36
+
37
+ *Graham Rogers*
38
+
39
+ * Add FlightLogger to list of companies using ViewComponent.
40
+
41
+ *Joseph Carpenter*
42
+
43
+ * Fix coverage reports overwriting each other when running locally.
44
+
45
+ *Jonathan del Strother*
46
+
47
+ * Add @reeganviljoen to triage team.
48
+
49
+ *Reegan Viljoen*
50
+
51
+ ### v3.0.0
52
+
53
+ 1,000+ days and 100+ releases later, the 200+ contributors to ViewComponent are proud to ship v3.0.0!
54
+
55
+ We're so grateful for all the work of community members to get us to this release. Whether it’s filing bug reports, designing APIs in long-winded discussion threads, or writing code itself, ViewComponent is built by the community, for the community. We couldn’t be more proud of what we’re building together :heart:
56
+
57
+ This release makes the following breaking changes, many of which have long been deprecated:
58
+
59
+ * BREAKING: Remove deprecated slots setter methods. Use `with_SLOT_NAME` instead.
60
+
61
+ *Joel Hawksley*
62
+
63
+ * BREAKING: Remove deprecated SlotsV1 in favor of current SlotsV2.
64
+
65
+ *Joel Hawksley*
66
+
67
+ * BREAKING: Remove deprecated `content_areas` feature. Use Slots instead.
68
+
69
+ *Joel Hawksley*
70
+
71
+ * BREAKING: Remove deprecated support for loading ViewComponent engine manually. Make sure `require "view_component/engine"` is removed from `Gemfile`.
72
+
73
+ *Joel Hawksley*
74
+
75
+ * BREAKING: Remove deprecated `generate_*` methods. Use `generate.*` instead.
76
+
77
+ *Joel Hawksley*
78
+
79
+ * BREAKING: Remove deprecated `with_variant` method.
80
+
81
+ *Joel Hawksley*
82
+
83
+ * BREAKING: Remove deprecated `rendered_component` in favor of `rendered_content`.
84
+
85
+ *Joel Hawksley*
86
+
87
+ * BREAKING: Remove deprecated `config.preview_path` in favor of `config.preview_paths`.
88
+
89
+ *Joel Hawksley*
90
+
91
+ * BREAKING: Support Ruby 2.7+ instead of 2.4+
92
+
93
+ *Joel Hawksley*
94
+
95
+ * BREAKING: Remove deprecated `before_render_check`.
96
+
97
+ *Joel Hawksley*
98
+
99
+ * BREAKING: Change counter variable to start iterating from `0` instead of `1`.
100
+
101
+ *Frank S*
102
+
103
+ * BREAKING: `#SLOT_NAME` getter no longer accepts arguments. This change was missed as part of the earlier deprecation in `3.0.0.rc1`.
104
+
105
+ *Joel Hawksley*
106
+
107
+ * BREAKING: Raise `TranslateCalledBeforeRenderError`, `ControllerCalledBeforeRenderError`, or `HelpersCalledBeforeRenderError` instead of `ViewContextCalledBeforeRenderError`.
108
+
109
+ *Joel Hawksley*
110
+
111
+ * BREAKING: Raise `SlotPredicateNameError`, `RedefinedSlotError`, `ReservedSingularSlotNameError`, `ContentSlotNameError`, `InvalidSlotDefinitionError`, `ReservedPluralSlotNameError`, `ContentAlreadySetForPolymorphicSlotErrror`, `SystemTestControllerOnlyAllowedInTestError`, `SystemTestControllerNefariousPathError`, `NoMatchingTemplatesForPreviewError`, `MultipleMatchingTemplatesForPreviewError`, `DuplicateContentError`, `EmptyOrInvalidInitializerError`, `MissingCollectionArgumentError`, `ReservedParameterError`, `InvalidCollectionArgumentError`, `MultipleInlineTemplatesError`, `MissingPreviewTemplateError`, `DuplicateSlotContentError` or `NilWithContentError` instead of generic error classes.
112
+
113
+ *Joel Hawksley*
114
+
115
+ * BREAKING: Rename `SlotV2` to `Slot` and `SlotableV2` to `Slotable`.
116
+
117
+ *Joel Hawksley*
118
+
119
+ * BREAKING: Incorporate `PolymorphicSlots` into `Slotable`. To migrate, remove any references to `PolymorphicSlots` as they are no longer necessary.
120
+
121
+ *Joel Hawksley*
122
+
123
+ * BREAKING: Rename private TestHelpers#controller, #build_controller, #request, and #preview_class to avoid conflicts. Note: While these methods were undocumented and marked as private, they were accessible in tests. As such, we're considering this to be a breaking change.
124
+
125
+ *Joel Hawksley*
126
+
127
+ * Add support for CSP nonces inside of components.
128
+
129
+ *Reegan Viljoen*
130
+
131
+ ### v3.0.0.rc6
132
+
133
+ Run into an issue with this release candidate? [Let us know](https://github.com/ViewComponent/view_component/issues/1629). We hope to release v3.0.0 in the near future!
134
+
135
+ * BREAKING: `#SLOT_NAME` getter no longer accepts arguments. This change was missed as part of the earlier deprecation in `3.0.0.rc1`.
136
+
137
+ *Joel Hawksley*
138
+
139
+ * BREAKING: Raise `TranslateCalledBeforeRenderError`, `ControllerCalledBeforeRenderError`, or `HelpersCalledBeforeRenderError` instead of `ViewContextCalledBeforeRenderError`.
140
+
141
+ *Joel Hawksley*
142
+
143
+ * BREAKING: Raise `SlotPredicateNameError`, `RedefinedSlotError`, `ReservedSingularSlotNameError`, `ContentSlotNameError`, `InvalidSlotDefinitionError`, `ReservedPluralSlotNameError`, `ContentAlreadySetForPolymorphicSlotErrror`, `SystemTestControllerOnlyAllowedInTestError`, `SystemTestControllerNefariousPathError`, `NoMatchingTemplatesForPreviewError`, `MultipleMatchingTemplatesForPreviewError`, `DuplicateContentError`, `EmptyOrInvalidInitializerError`, `MissingCollectionArgumentError`, `ReservedParameterError`, `InvalidCollectionArgumentError`, `MultipleInlineTemplatesError`, `MissingPreviewTemplateError`, `DuplicateSlotContentError` or `NilWithContentError` instead of generic error classes.
144
+
145
+ *Joel Hawksley*
146
+
147
+ * Fix bug where `content?` and `with_content` didn't work reliably with slots.
148
+
149
+ *Derek Kniffin, Joel Hawksley*
150
+
151
+ * Add `with_SLOT_NAME_content` helper.
152
+
153
+ *Will Cosgrove*
154
+
155
+ * Allow ActiveRecord objects to be passed to `renders_many`.
156
+
157
+ *Leigh Halliday*
158
+
159
+ * Fix broken links in documentation.
160
+
161
+ *Ellen Keal*
162
+
163
+ * Run `standardrb` against markdown in docs.
164
+
165
+ *Joel Hawksley*
166
+
167
+ * Allow `.with_content` to be redefined by components.
168
+
169
+ *Joel Hawksley*
170
+
171
+ * Run `standardrb` against markdown in docs.
172
+
173
+ *Joel Hawksley*
174
+
175
+ * Raise error if translations are used in initializer.
176
+
177
+ *Joel Hawksley*
178
+
179
+ ## v3.0.0.rc5
180
+
181
+ Run into an issue with this release candidate? [Let us know](https://github.com/ViewComponent/view_component/issues/1629).
182
+
183
+ * Fix bug where `mkdir_p` failed due to incorrect permissions.
184
+
185
+ *Joel Hawksley*
186
+
187
+ * Check for inline `erb_template` calls when deciding whether to compile a component's superclass.
188
+
189
+ *Justin Kenyon*
190
+
191
+ * Protect against `SystemStackError` if `CaptureCompatibility` module is included more than once.
192
+
193
+ *Cameron Dutro*
194
+
195
+ ## v3.0.0.rc4
196
+
197
+ Run into an issue with this release candidate? [Let us know](https://github.com/ViewComponent/view_component/issues/1629).
198
+
199
+ * Add `TestHelpers#vc_test_request`.
200
+
201
+ *Joel Hawksley*
202
+
203
+ ## v3.0.0.rc3
204
+
205
+ Run into an issue with this release candidate? [Let us know](https://github.com/ViewComponent/view_component/issues/1629).
206
+
207
+ * Fix typos in generator docs.
208
+
209
+ *Sascha Karnatz*
210
+
211
+ * Add `TestHelpers#vc_test_controller`.
212
+
213
+ *Joel Hawksley*
214
+
215
+ * Document `config.view_component.capture_compatibility_patch_enabled` as option for the known incompatibilities with Rails form helpers.
216
+
217
+ *Tobias L. Maier*
218
+
219
+ * Add support for experimental inline templates.
220
+
221
+ *Blake Williams*
222
+
223
+ * Expose `translate` and `t` I18n methods on component classes.
224
+
225
+ *Elia Schito*
226
+
227
+ * Protect against Arbitrary File Read edge case in `ViewComponentsSystemTestController`.
228
+
229
+ *Nick Malcolm*
230
+
231
+ ## v3.0.0.rc2
232
+
233
+ Run into an issue with this release? [Let us know](https://github.com/ViewComponent/view_component/issues/1629).
234
+
235
+ * BREAKING: Rename `SlotV2` to `Slot` and `SlotableV2` to `Slotable`.
236
+
237
+ *Joel Hawksley*
238
+
239
+ * BREAKING: Incorporate `PolymorphicSlots` into `Slotable`. To migrate, remove any references to `PolymorphicSlots` as they are no longer necessary.
240
+
241
+ *Joel Hawksley*
242
+
243
+ * BREAKING: Rename private TestHelpers#controller, #build_controller, #request, and #preview_class to avoid conflicts. Note: While these methods were undocumented and marked as private, they were accessible in tests. As such, we're considering this to be a breaking change.
244
+
245
+ *Joel Hawksley*
246
+
247
+ * Avoid loading ActionView::Base during Rails initialization. Originally submitted in #1528.
248
+
249
+ *Jonathan del Strother*
250
+
251
+ * Improve documentation of known incompatibilities with Rails form helpers.
252
+
253
+ *Tobias L. Maier*
254
+
255
+ * Remove dependency on environment task from `view_component:statsetup`.
256
+
257
+ *Svetlin Simonyan*
258
+
259
+ * Add experimental `config.view_component.capture_compatibility_patch_enabled` option resolving rendering issues related to forms, capture, turbo frames, etc.
260
+
261
+ *Blake Williams*
262
+
263
+ * Add `#content?` method that indicates if content has been passed to component.
264
+
265
+ *Joel Hawksley*
266
+
267
+ * Added example of a custom preview controller.
268
+
269
+ *Graham Rogers*
270
+
271
+ * Add Krystal to list of companies using ViewComponent.
272
+
273
+ *Matt Bearman*
274
+
275
+ * Add Mon Ami to list of companies using ViewComponent.
276
+
277
+ *Ethan Lee-Tyson*
278
+
279
+ ## 3.0.0.rc1
280
+
281
+ 1,000+ days and 100+ releases later, the 200+ contributors to ViewComponent are proud to ship v3.0.0!
282
+
283
+ We're so grateful for all the work of community members to get us to this release. Whether it’s filing bug reports, designing APIs in long-winded discussion threads, or writing code itself, ViewComponent is built by the community, for the community. We couldn’t be more proud of what we’re building together :heart:
284
+
285
+ This release makes the following breaking changes, many of which have long been deprecated:
286
+
287
+ * BREAKING: Remove deprecated slots setter methods. Use `with_SLOT_NAME` instead.
288
+
289
+ *Joel Hawksley*
290
+
291
+ * BREAKING: Remove deprecated SlotsV1 in favor of current SlotsV2.
292
+
293
+ *Joel Hawksley*
294
+
295
+ * BREAKING: Remove deprecated `content_areas` feature. Use Slots instead.
296
+
297
+ *Joel Hawksley*
298
+
299
+ * BREAKING: Remove deprecated support for loading ViewComponent engine manually. Make sure `require "view_component/engine"` is removed from `Gemfile`.
300
+
301
+ *Joel Hawksley*
302
+
303
+ * BREAKING: Remove deprecated `generate_*` methods. Use `generate.*` instead.
304
+
305
+ *Joel Hawksley*
306
+
307
+ * BREAKING: Remove deprecated `with_variant` method.
308
+
309
+ *Joel Hawksley*
310
+
311
+ * BREAKING: Remove deprecated `rendered_component` in favor of `rendered_content`.
312
+
313
+ *Joel Hawksley*
314
+
315
+ * BREAKING: Remove deprecated `config.preview_path` in favor of `config.preview_paths`.
316
+
317
+ *Joel Hawksley*
318
+
319
+ * BREAKING: Support Ruby 2.7+ instead of 2.4+
320
+
321
+ *Joel Hawksley*
322
+
323
+ * BREAKING: Remove deprecated `before_render_check`.
324
+
325
+ *Joel Hawksley*
326
+
327
+ * BREAKING: Change counter variable to start iterating from `0` instead of `1`.
328
+
329
+ *Frank S*
330
+
331
+ Run into an issue with this release? [Let us know](https://github.com/ViewComponent/view_component/issues/1629).
332
+
13
333
  ## 2.82.0
14
334
 
15
335
  * Revert "Avoid loading ActionView::Base during initialization (#1528)"
@@ -6,11 +6,9 @@ require "view_component/collection"
6
6
  require "view_component/compile_cache"
7
7
  require "view_component/compiler"
8
8
  require "view_component/config"
9
- require "view_component/content_areas"
10
- require "view_component/polymorphic_slots"
9
+ require "view_component/errors"
11
10
  require "view_component/preview"
12
11
  require "view_component/slotable"
13
- require "view_component/slotable_v2"
14
12
  require "view_component/translatable"
15
13
  require "view_component/with_content_helper"
16
14
 
@@ -21,9 +19,9 @@ module ViewComponent
21
19
 
22
20
  # Returns the current config.
23
21
  #
24
- # @return [ViewComponent::Config]
22
+ # @return [ActiveSupport::OrderedOptions]
25
23
  def config
26
- @config ||= ViewComponent::Config.defaults
24
+ @config ||= ActiveSupport::OrderedOptions.new
27
25
  end
28
26
 
29
27
  # Replaces the entire config. You shouldn't need to use this directly
@@ -31,21 +29,17 @@ module ViewComponent
31
29
  attr_writer :config
32
30
  end
33
31
 
34
- include ViewComponent::ContentAreas
35
- include ViewComponent::PolymorphicSlots
36
- include ViewComponent::SlotableV2
32
+ include ViewComponent::Slotable
37
33
  include ViewComponent::Translatable
38
34
  include ViewComponent::WithContentHelper
39
35
 
40
- ViewContextCalledBeforeRenderError = Class.new(StandardError)
41
-
42
36
  RESERVED_PARAMETER = :content
43
37
 
44
38
  # For CSRF authenticity tokens in forms
45
39
  delegate :form_authenticity_token, :protect_against_forgery?, :config, to: :helpers
46
40
 
47
- class_attribute :content_areas
48
- self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
41
+ # For Content Security Policy nonces
42
+ delegate :content_security_policy_nonce, to: :helpers
49
43
 
50
44
  # Config option that strips trailing whitespace in templates before compiling them.
51
45
  class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false
@@ -66,23 +60,6 @@ module ViewComponent
66
60
  self.__vc_original_view_context = view_context
67
61
  end
68
62
 
69
- # @!macro [attach] deprecated_generate_mattr_accessor
70
- # @method generate_$1
71
- # @deprecated Use `#generate.$1` instead. Will be removed in v3.0.0.
72
- def self._deprecated_generate_mattr_accessor(name)
73
- define_singleton_method("generate_#{name}".to_sym) do
74
- generate.public_send(name)
75
- end
76
- define_singleton_method("generate_#{name}=".to_sym) do |value|
77
- generate.public_send("#{name}=".to_sym, value)
78
- end
79
- end
80
-
81
- _deprecated_generate_mattr_accessor :distinct_locale_files
82
- _deprecated_generate_mattr_accessor :locale
83
- _deprecated_generate_mattr_accessor :sidecar
84
- _deprecated_generate_mattr_accessor :stimulus_controller
85
-
86
63
  # Entrypoint for rendering components.
87
64
  #
88
65
  # - `view_context`: ActionView context from calling view
@@ -119,9 +96,7 @@ module ViewComponent
119
96
  @current_template = self
120
97
 
121
98
  if block && defined?(@__vc_content_set_by_with_content)
122
- raise ArgumentError, "It looks like a block was provided after calling `with_content` on #{self.class.name}, " \
123
- "which means that ViewComponent doesn't know which content to use.\n\n" \
124
- "To fix this issue, use either `with_content` or a block."
99
+ raise DuplicateContentError.new(self.class.name)
125
100
  end
126
101
 
127
102
  @__vc_content_evaluated = false
@@ -165,14 +140,6 @@ module ViewComponent
165
140
  #
166
141
  # @return [void]
167
142
  def before_render
168
- before_render_check
169
- end
170
-
171
- # Called after rendering the component.
172
- #
173
- # @deprecated Use `#before_render` instead. Will be removed in v3.0.0.
174
- # @return [void]
175
- def before_render_check
176
143
  # noop
177
144
  end
178
145
 
@@ -208,16 +175,7 @@ module ViewComponent
208
175
  #
209
176
  # @return [ActionController::Base]
210
177
  def controller
211
- if view_context.nil?
212
- raise(
213
- ViewContextCalledBeforeRenderError,
214
- "`#controller` can't be used during initialization, as it depends " \
215
- "on the view context that only exists once a ViewComponent is passed to " \
216
- "the Rails render pipeline.\n\n" \
217
- "It's sometimes possible to fix this issue by moving code dependent on " \
218
- "`#controller` to a `#before_render` method: https://viewcomponent.org/api.html#before_render--void."
219
- )
220
- end
178
+ raise ControllerCalledBeforeRenderError if view_context.nil?
221
179
 
222
180
  @__vc_controller ||= view_context.controller
223
181
  end
@@ -227,16 +185,7 @@ module ViewComponent
227
185
  #
228
186
  # @return [ActionView::Base]
229
187
  def helpers
230
- if view_context.nil?
231
- raise(
232
- ViewContextCalledBeforeRenderError,
233
- "`#helpers` can't be used during initialization, as it depends " \
234
- "on the view context that only exists once a ViewComponent is passed to " \
235
- "the Rails render pipeline.\n\n" \
236
- "It's sometimes possible to fix this issue by moving code dependent on " \
237
- "`#helpers` to a `#before_render` method: https://viewcomponent.org/api.html#before_render--void."
238
- )
239
- end
188
+ raise HelpersCalledBeforeRenderError if view_context.nil?
240
189
 
241
190
  # Attempt to re-use the original view_context passed to the first
242
191
  # component rendered in the rendering pipeline. This prevents the
@@ -265,22 +214,9 @@ module ViewComponent
265
214
  #
266
215
  # @private
267
216
  def format
268
- # Ruby 2.6 throws a warning without checking `defined?`, 2.7 doesn't
269
217
  @__vc_variant if defined?(@__vc_variant)
270
218
  end
271
219
 
272
- # Use the provided variant instead of the one determined by the current request.
273
- #
274
- # @deprecated Will be removed in v3.0.0.
275
- # @param variant [Symbol] The variant to be used by the component.
276
- # @return [self]
277
- def with_variant(variant)
278
- @__vc_variant = variant
279
-
280
- self
281
- end
282
- deprecate :with_variant, deprecator: ViewComponent::Deprecation
283
-
284
220
  # The current request. Use sparingly as doing so introduces coupling that
285
221
  # inhibits encapsulation & reuse, often making testing difficult.
286
222
  #
@@ -289,24 +225,42 @@ module ViewComponent
289
225
  @request ||= controller.request if controller.respond_to?(:request)
290
226
  end
291
227
 
292
- private
293
-
294
- attr_reader :view_context
295
-
228
+ # The content passed to the component instance as a block.
229
+ #
230
+ # @return [String]
296
231
  def content
297
232
  @__vc_content_evaluated = true
298
233
  return @__vc_content if defined?(@__vc_content)
299
234
 
300
235
  @__vc_content =
301
- if @view_context && @__vc_render_in_block
236
+ if __vc_render_in_block_provided?
302
237
  view_context.capture(self, &@__vc_render_in_block)
303
- elsif defined?(@__vc_content_set_by_with_content)
238
+ elsif __vc_content_set_by_with_content_defined?
304
239
  @__vc_content_set_by_with_content
305
240
  end
306
241
  end
307
242
 
243
+ # Whether `content` has been passed to the component.
244
+ #
245
+ # @return [Boolean]
246
+ def content?
247
+ __vc_render_in_block_provided? || __vc_content_set_by_with_content_defined?
248
+ end
249
+
250
+ private
251
+
252
+ attr_reader :view_context
253
+
254
+ def __vc_render_in_block_provided?
255
+ defined?(@view_context) && @view_context && @__vc_render_in_block
256
+ end
257
+
258
+ def __vc_content_set_by_with_content_defined?
259
+ defined?(@__vc_content_set_by_with_content)
260
+ end
261
+
308
262
  def content_evaluated?
309
- @__vc_content_evaluated
263
+ defined?(@__vc_content_evaluated) && @__vc_content_evaluated
310
264
  end
311
265
 
312
266
  # Set the controller used for testing components:
@@ -493,10 +447,12 @@ module ViewComponent
493
447
  # has been re-defined by the consuming application, likely in ApplicationComponent.
494
448
  child.source_location = caller_locations(1, 10).reject { |l| l.label == "inherited" }[0].path
495
449
 
496
- # Removes the first part of the path and the extension.
497
- child.virtual_path = child.source_location.gsub(
498
- /(.*#{Regexp.quote(ViewComponent::Base.config.view_component_path)})|(\.rb)/, ""
499
- )
450
+ # If Rails application is loaded, removes the first part of the path and the extension.
451
+ if defined?(Rails) && Rails.application
452
+ child.virtual_path = child.source_location.gsub(
453
+ /(.*#{Regexp.quote(ViewComponent::Base.config.view_component_path)})|(\.rb)/, ""
454
+ )
455
+ end
500
456
 
501
457
  # Set collection parameter to the extended component
502
458
  child.with_collection_parameter provided_collection_parameter
@@ -509,6 +465,11 @@ module ViewComponent
509
465
  compiler.compiled?
510
466
  end
511
467
 
468
+ # @private
469
+ def ensure_compiled
470
+ compile unless compiled?
471
+ end
472
+
512
473
  # Compile templates to instance methods, assuming they haven't been compiled already.
513
474
  #
514
475
  # Do as much work as possible in this step, as doing so reduces the amount
@@ -558,7 +519,7 @@ module ViewComponent
558
519
  # end
559
520
  # ```
560
521
  #
561
- # @param value [Boolean] Whether or not to strip newlines.
522
+ # @param value [Boolean] Whether to strip newlines.
562
523
  def strip_trailing_whitespace(value = true)
563
524
  self.__vc_strip_trailing_whitespace = value
564
525
  end
@@ -582,20 +543,14 @@ module ViewComponent
582
543
  return unless parameter
583
544
  return if initialize_parameter_names.include?(parameter) || splatted_keyword_argument_present?
584
545
 
585
- # If Ruby can't parse the component class, then the initalize
546
+ # If Ruby can't parse the component class, then the initialize
586
547
  # parameters will be empty and ViewComponent will not be able to render
587
548
  # the component.
588
549
  if initialize_parameters.empty?
589
- raise ArgumentError, "The #{self} initializer is empty or invalid." \
590
- "It must accept the parameter `#{parameter}` to render it as a collection.\n\n" \
591
- "To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
592
- "See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
550
+ raise EmptyOrInvalidInitializerError.new(name, parameter)
593
551
  end
594
552
 
595
- raise ArgumentError, "The initializer for #{self} doesn't accept the parameter `#{parameter}`, " \
596
- "which is required in order to render it as a collection.\n\n" \
597
- "To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
598
- "See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
553
+ raise MissingCollectionArgumentError.new(name, parameter)
599
554
  end
600
555
 
601
556
  # Ensure the component initializer doesn't define
@@ -605,8 +560,7 @@ module ViewComponent
605
560
  def validate_initialization_parameters!
606
561
  return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
607
562
 
608
- raise ViewComponent::ComponentError, "#{self} initializer can't accept the parameter `#{RESERVED_PARAMETER}`, as it will override a " \
609
- "public ViewComponent method. To fix this issue, rename the parameter."
563
+ raise ReservedParameterError.new(name, RESERVED_PARAMETER)
610
564
  end
611
565
 
612
566
  # @private