view_component 2.82.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.

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