view_component 3.22.0 → 4.0.0.alpha1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/view_component/preview_actions.rb +2 -9
  3. data/app/controllers/view_components_system_test_controller.rb +17 -20
  4. data/app/views/test_mailer/test_asset_email.html.erb +1 -0
  5. data/app/views/view_components/preview.html.erb +1 -9
  6. data/docs/CHANGELOG.md +127 -1
  7. data/lib/view_component/base.rb +41 -61
  8. data/lib/view_component/collection.rb +11 -17
  9. data/lib/view_component/compiler.rb +50 -74
  10. data/lib/view_component/config.rb +0 -21
  11. data/lib/view_component/deprecation.rb +1 -1
  12. data/lib/view_component/engine.rb +3 -82
  13. data/lib/view_component/errors.rb +16 -22
  14. data/lib/view_component/inline_template.rb +2 -3
  15. data/lib/view_component/instrumentation.rb +4 -10
  16. data/lib/view_component/preview.rb +3 -10
  17. data/lib/view_component/request_details.rb +30 -0
  18. data/lib/view_component/slot.rb +2 -5
  19. data/lib/view_component/slotable.rb +31 -39
  20. data/lib/view_component/system_test_helpers.rb +1 -2
  21. data/lib/view_component/template.rb +106 -83
  22. data/lib/view_component/test_helpers.rb +22 -42
  23. data/lib/view_component/translatable.rb +24 -23
  24. data/lib/view_component/use_helpers.rb +3 -4
  25. data/lib/view_component/version.rb +3 -3
  26. data/lib/view_component.rb +0 -1
  27. metadata +73 -220
  28. data/app/assets/vendor/prism.css +0 -4
  29. data/app/assets/vendor/prism.min.js +0 -12
  30. data/app/helpers/preview_helper.rb +0 -85
  31. data/app/views/view_components/_preview_source.html.erb +0 -17
  32. data/lib/rails/generators/abstract_generator.rb +0 -56
  33. data/lib/rails/generators/component/USAGE +0 -13
  34. data/lib/rails/generators/component/component_generator.rb +0 -67
  35. data/lib/rails/generators/component/templates/component.rb.tt +0 -16
  36. data/lib/rails/generators/erb/component_generator.rb +0 -33
  37. data/lib/rails/generators/erb/templates/component.html.erb.tt +0 -1
  38. data/lib/rails/generators/haml/component_generator.rb +0 -22
  39. data/lib/rails/generators/haml/templates/component.html.haml.tt +0 -1
  40. data/lib/rails/generators/locale/component_generator.rb +0 -46
  41. data/lib/rails/generators/preview/component_generator.rb +0 -39
  42. data/lib/rails/generators/preview/templates/component_preview.rb.tt +0 -9
  43. data/lib/rails/generators/rspec/component_generator.rb +0 -31
  44. data/lib/rails/generators/rspec/templates/component_spec.rb.tt +0 -15
  45. data/lib/rails/generators/slim/component_generator.rb +0 -22
  46. data/lib/rails/generators/slim/templates/component.html.slim.tt +0 -1
  47. data/lib/rails/generators/stimulus/component_generator.rb +0 -44
  48. data/lib/rails/generators/stimulus/templates/component_controller.js.tt +0 -7
  49. data/lib/rails/generators/stimulus/templates/component_controller.ts.tt +0 -9
  50. data/lib/rails/generators/tailwindcss/component_generator.rb +0 -11
  51. data/lib/rails/generators/tailwindcss/templates/component.html.erb.tt +0 -1
  52. data/lib/rails/generators/test_unit/component_generator.rb +0 -20
  53. data/lib/rails/generators/test_unit/templates/component_test.rb.tt +0 -12
  54. data/lib/view_component/component_error.rb +0 -6
  55. data/lib/view_component/docs_builder_component.html.erb +0 -22
  56. data/lib/view_component/docs_builder_component.rb +0 -96
  57. data/lib/view_component/rails/tasks/view_component.rake +0 -20
  58. data/lib/view_component/render_component_helper.rb +0 -10
  59. data/lib/view_component/render_component_to_string_helper.rb +0 -9
  60. data/lib/view_component/render_monkey_patch.rb +0 -13
  61. data/lib/view_component/render_to_string_monkey_patch.rb +0 -13
  62. data/lib/view_component/rendering_component_helper.rb +0 -9
  63. data/lib/view_component/rendering_monkey_patch.rb +0 -13
  64. data/lib/yard/mattr_accessor_handler.rb +0 -19
@@ -12,12 +12,10 @@ module ViewComponent
12
12
  singular: %i[content render].freeze,
13
13
  plural: %i[contents renders].freeze
14
14
  }.freeze
15
+ private_constant :RESERVED_NAMES
15
16
 
16
- # Setup component slot state
17
17
  included do
18
- # Hash of registered Slots
19
- class_attribute :registered_slots
20
- self.registered_slots = {}
18
+ class_attribute :registered_slots, default: {}
21
19
  end
22
20
 
23
21
  class_methods do
@@ -84,10 +82,9 @@ module ViewComponent
84
82
 
85
83
  setter_method_name = :"with_#{slot_name}"
86
84
 
87
- define_method setter_method_name do |*args, &block|
88
- set_slot(slot_name, nil, *args, &block)
85
+ define_method setter_method_name do |*args, **kwargs, &block|
86
+ set_slot(slot_name, nil, *args, **kwargs, &block)
89
87
  end
90
- ruby2_keywords(setter_method_name) if respond_to?(:ruby2_keywords, true)
91
88
 
92
89
  self::GeneratedSlotMethods.define_method slot_name do
93
90
  get_slot(slot_name)
@@ -155,10 +152,9 @@ module ViewComponent
155
152
 
156
153
  setter_method_name = :"with_#{singular_name}"
157
154
 
158
- define_method setter_method_name do |*args, &block|
159
- set_slot(slot_name, nil, *args, &block)
155
+ define_method setter_method_name do |*args, **kwargs, &block|
156
+ set_slot(slot_name, nil, *args, **kwargs, &block)
160
157
  end
161
- ruby2_keywords(setter_method_name) if respond_to?(:ruby2_keywords, true)
162
158
 
163
159
  define_method :"with_#{singular_name}_content" do |content|
164
160
  send(setter_method_name) { content.to_s }
@@ -215,6 +211,21 @@ module ViewComponent
215
211
  super
216
212
  end
217
213
 
214
+ # Called by the compiler, as instance methods are not defined when slots are first registered
215
+ def register_default_slots
216
+ registered_slots.each do |slot_name, config|
217
+ config[:default_method] = instance_methods.find { |method_name| method_name == :"default_#{slot_name}" }
218
+
219
+ registered_slots[slot_name] = config
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ def register_slot(slot_name, **kwargs)
226
+ registered_slots[slot_name] = define_slot(slot_name, **kwargs)
227
+ end
228
+
218
229
  def register_polymorphic_slot(slot_name, types, collection:)
219
230
  self::GeneratedSlotMethods.define_method(slot_name) do
220
231
  get_slot(slot_name)
@@ -250,10 +261,9 @@ module ViewComponent
250
261
  raise AlreadyDefinedPolymorphicSlotSetterError.new(setter_method_name, poly_slot_name)
251
262
  end
252
263
 
253
- define_method(setter_method_name) do |*args, &block|
254
- set_polymorphic_slot(slot_name, poly_type, *args, &block)
264
+ define_method(setter_method_name) do |*args, **kwargs, &block|
265
+ set_polymorphic_slot(slot_name, poly_type, *args, **kwargs, &block)
255
266
  end
256
- ruby2_keywords(setter_method_name) if respond_to?(:ruby2_keywords, true)
257
267
 
258
268
  define_method :"with_#{poly_slot_name}_content" do |content|
259
269
  send(setter_method_name) { content.to_s }
@@ -268,21 +278,6 @@ module ViewComponent
268
278
  }
269
279
  end
270
280
 
271
- # Called by the compiler, as instance methods are not defined when slots are first registered
272
- def register_default_slots
273
- registered_slots.each do |slot_name, config|
274
- config[:default_method] = instance_methods.find { |method_name| method_name == :"default_#{slot_name}" }
275
-
276
- registered_slots[slot_name] = config
277
- end
278
- end
279
-
280
- private
281
-
282
- def register_slot(slot_name, **kwargs)
283
- registered_slots[slot_name] = define_slot(slot_name, **kwargs)
284
- end
285
-
286
281
  def define_slot(slot_name, collection:, callable:)
287
282
  slot = {collection: collection}
288
283
  return slot unless callable
@@ -333,7 +328,6 @@ module ViewComponent
333
328
 
334
329
  def raise_if_slot_registered(slot_name)
335
330
  if registered_slots.key?(slot_name)
336
- # TODO remove? This breaks overriding slots when slots are inherited
337
331
  raise RedefinedSlotError.new(name, slot_name)
338
332
  end
339
333
  end
@@ -371,7 +365,7 @@ module ViewComponent
371
365
  end
372
366
  end
373
367
 
374
- def set_slot(slot_name, slot_definition = nil, *args, &block)
368
+ def set_slot(slot_name, slot_definition = nil, *args, **kwargs, &block)
375
369
  slot_definition ||= self.class.registered_slots[slot_name]
376
370
  slot = Slot.new(self)
377
371
 
@@ -388,11 +382,11 @@ module ViewComponent
388
382
 
389
383
  # If class
390
384
  if slot_definition[:renderable]
391
- slot.__vc_component_instance = slot_definition[:renderable].new(*args)
385
+ slot.__vc_component_instance = slot_definition[:renderable].new(*args, **kwargs)
392
386
  # If class name as a string
393
387
  elsif slot_definition[:renderable_class_name]
394
388
  slot.__vc_component_instance =
395
- self.class.const_get(slot_definition[:renderable_class_name]).new(*args)
389
+ self.class.const_get(slot_definition[:renderable_class_name]).new(*args, **kwargs)
396
390
  # If passed a lambda
397
391
  elsif slot_definition[:renderable_function]
398
392
  # Use `bind(self)` to ensure lambda is executed in the context of the
@@ -401,11 +395,11 @@ module ViewComponent
401
395
  renderable_function = slot_definition[:renderable_function].bind(self)
402
396
  renderable_value =
403
397
  if block
404
- renderable_function.call(*args) do |*rargs|
398
+ renderable_function.call(*args, **kwargs) do |*rargs|
405
399
  view_context.capture(*rargs, &block)
406
400
  end
407
401
  else
408
- renderable_function.call(*args)
402
+ renderable_function.call(*args, **kwargs)
409
403
  end
410
404
 
411
405
  # Function calls can return components, so if it's a component handle it specially
@@ -427,19 +421,17 @@ module ViewComponent
427
421
 
428
422
  slot
429
423
  end
430
- ruby2_keywords(:set_slot) if respond_to?(:ruby2_keywords, true)
431
424
 
432
- def set_polymorphic_slot(slot_name, poly_type = nil, *args, &block)
425
+ def set_polymorphic_slot(slot_name, poly_type = nil, *args, **kwargs, &block)
433
426
  slot_definition = self.class.registered_slots[slot_name]
434
427
 
435
- if !slot_definition[:collection] && (defined?(@__vc_set_slots) && @__vc_set_slots[slot_name])
428
+ if !slot_definition[:collection] && defined?(@__vc_set_slots) && @__vc_set_slots[slot_name]
436
429
  raise ContentAlreadySetForPolymorphicSlotError.new(slot_name)
437
430
  end
438
431
 
439
432
  poly_def = slot_definition[:renderable_hash][poly_type]
440
433
 
441
- set_slot(slot_name, poly_def, *args, &block)
434
+ set_slot(slot_name, poly_def, *args, **kwargs, &block)
442
435
  end
443
- ruby2_keywords(:set_polymorphic_slot) if respond_to?(:ruby2_keywords, true)
444
436
  end
445
437
  end
@@ -4,7 +4,6 @@ module ViewComponent
4
4
  module SystemTestHelpers
5
5
  include TestHelpers
6
6
 
7
- #
8
7
  # Returns a block that can be used to visit the path of the inline rendered component.
9
8
  # @param fragment [Nokogiri::Fragment] The fragment returned from `render_inline`.
10
9
  # @param layout [String] The (optional) layout to use.
@@ -18,7 +17,7 @@ module ViewComponent
18
17
  file.write(vc_test_controller.render_to_string(html: fragment.to_html.html_safe, layout: layout))
19
18
  file.rewind
20
19
 
21
- block.call("/_system_test_entrypoint?file=#{file.path.split("/").last}")
20
+ yield("/_system_test_entrypoint?file=#{file.path.split("/").last}")
22
21
  ensure
23
22
  file.unlink
24
23
  end
@@ -2,69 +2,115 @@
2
2
 
3
3
  module ViewComponent
4
4
  class Template
5
+ DEFAULT_FORMAT = :html
6
+ private_constant :DEFAULT_FORMAT
7
+
5
8
  DataWithSource = Struct.new(:format, :identifier, :short_identifier, :type, keyword_init: true)
6
- DataNoSource = Struct.new(:source, :identifier, :type, keyword_init: true)
7
-
8
- attr_reader :variant, :this_format, :type
9
-
10
- def initialize(
11
- component:,
12
- type:,
13
- this_format: nil,
14
- variant: nil,
15
- lineno: nil,
16
- path: nil,
17
- extension: nil,
18
- source: nil,
19
- method_name: nil,
20
- defined_on_self: true
21
- )
9
+
10
+ attr_reader :details
11
+
12
+ delegate :virtual_path, to: :@component
13
+ delegate :format, :variant, to: :@details
14
+
15
+ def initialize(component:, details:, lineno: nil, path: nil)
22
16
  @component = component
23
- @type = type
24
- @this_format = this_format
25
- @variant = variant&.to_sym
17
+ @details = details
26
18
  @lineno = lineno
27
19
  @path = path
28
- @extension = extension
29
- @source = source
30
- @method_name = method_name
31
- @defined_on_self = defined_on_self
32
-
33
- @source_originally_nil = @source.nil?
34
-
35
- @call_method_name =
36
- if @method_name
37
- @method_name
38
- else
39
- out = +"call"
40
- out << "_#{normalized_variant_name}" if @variant.present?
41
- out << "_#{@this_format}" if @this_format.present? && @this_format != ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT
42
- out
20
+ end
21
+
22
+ class File < Template
23
+ def initialize(component:, details:, path:)
24
+ super(
25
+ component: component,
26
+ details: details,
27
+ path: path,
28
+ lineno: 0
29
+ )
30
+ end
31
+
32
+ def type
33
+ :file
34
+ end
35
+
36
+ # Load file each time we look up #source in case the file has been modified
37
+ def source
38
+ ::File.read(@path)
39
+ end
40
+ end
41
+
42
+ class Inline < Template
43
+ attr_reader :source
44
+
45
+ def initialize(component:, inline_template:)
46
+ details = ActionView::TemplateDetails.new(nil, inline_template.language.to_sym, nil, nil)
47
+
48
+ super(
49
+ component: component,
50
+ details: details,
51
+ path: inline_template.path,
52
+ lineno: inline_template.lineno,
53
+ )
54
+
55
+ @source = inline_template.source.dup
56
+ end
57
+
58
+ def type
59
+ :inline
60
+ end
61
+ end
62
+
63
+ class InlineCall < Template
64
+ def initialize(component:, method_name:, defined_on_self:)
65
+ variant = method_name.to_s.include?("call_") ? method_name.to_s.sub("call_", "").to_sym : nil
66
+ details = ActionView::TemplateDetails.new(nil, nil, nil, variant)
67
+
68
+ super(component: component, details: details)
69
+
70
+ @call_method_name = method_name
71
+ @defined_on_self = defined_on_self
72
+ end
73
+
74
+ def type
75
+ :inline_call
76
+ end
77
+
78
+ def compile_to_component
79
+ @component.define_method(safe_method_name, @component.instance_method(@call_method_name))
80
+ end
81
+
82
+ def safe_method_name_call
83
+ m = safe_method_name
84
+ proc do
85
+ maybe_escape_html(send(m)) do
86
+ Kernel.warn("WARNING: The #{self.class} component rendered HTML-unsafe output. " \
87
+ "The output will be automatically escaped, but you may want to investigate.")
88
+ end
43
89
  end
90
+ end
91
+
92
+ def defined_on_self?
93
+ @defined_on_self
94
+ end
44
95
  end
45
96
 
46
97
  def compile_to_component
47
- if !inline_call?
48
- @component.silence_redefinition_of_method(@call_method_name)
98
+ @component.silence_redefinition_of_method(call_method_name)
49
99
 
50
- # rubocop:disable Style/EvalWithLocation
51
- @component.class_eval <<-RUBY, @path, @lineno
52
- def #{@call_method_name}
100
+ # rubocop:disable Style/EvalWithLocation
101
+ @component.class_eval <<~RUBY, @path, @lineno
102
+ def #{call_method_name}
53
103
  #{compiled_source}
54
104
  end
55
- RUBY
56
- # rubocop:enable Style/EvalWithLocation
57
- end
105
+ RUBY
106
+ # rubocop:enable Style/EvalWithLocation
58
107
 
59
108
  @component.define_method(safe_method_name, @component.instance_method(@call_method_name))
60
109
  end
61
110
 
62
111
  def safe_method_name_call
63
- return safe_method_name unless inline_call?
64
-
65
- "maybe_escape_html(#{safe_method_name}) " \
66
- "{ Kernel.warn(\"WARNING: The #{@component} component rendered HTML-unsafe output. " \
67
- "The output will be automatically escaped, but you may want to investigate.\") } "
112
+ m = safe_method_name
113
+ proc { send(m) }
68
114
  end
69
115
 
70
116
  def requires_compiled_superclass?
@@ -72,63 +118,40 @@ module ViewComponent
72
118
  end
73
119
 
74
120
  def inline_call?
75
- @type == :inline_call
76
- end
77
-
78
- def inline?
79
- @type == :inline
121
+ type == :inline_call
80
122
  end
81
123
 
82
124
  def default_format?
83
- @this_format == ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT
125
+ format.nil? || format == DEFAULT_FORMAT
84
126
  end
127
+ alias_method :html?, :default_format?
85
128
 
86
- def format
87
- @this_format
129
+ def call_method_name
130
+ @call_method_name ||=
131
+ ["call", (normalized_variant_name if variant.present?), (format unless default_format?)]
132
+ .compact.join("_").to_sym
88
133
  end
89
134
 
90
135
  def safe_method_name
91
- "_#{@call_method_name}_#{@component.name.underscore.gsub("/", "__")}"
136
+ "_#{call_method_name}_#{@component.name.underscore.gsub("/", "__")}"
92
137
  end
93
138
 
94
139
  def normalized_variant_name
95
- @variant.to_s.gsub("-", "__").gsub(".", "___")
96
- end
97
-
98
- def defined_on_self?
99
- @defined_on_self
140
+ variant.to_s.gsub("-", "__")
100
141
  end
101
142
 
102
143
  private
103
144
 
104
- def source
105
- if @source_originally_nil
106
- # Load file each time we look up #source in case the file has been modified
107
- File.read(@path)
108
- else
109
- @source
110
- end
111
- end
112
-
113
145
  def compiled_source
114
- handler = ActionView::Template.handler_for_extension(@extension)
146
+ handler = details.handler_class
115
147
  this_source = source
116
148
  this_source.rstrip! if @component.strip_trailing_whitespace?
117
149
 
118
150
  short_identifier = defined?(Rails.root) ? @path.sub("#{Rails.root}/", "") : @path
119
- type = ActionView::Template::Types[@this_format]
151
+ format = self.format || DEFAULT_FORMAT
152
+ type = ActionView::Template::Types[format]
120
153
 
121
- if handler.method(:call).parameters.length > 1
122
- handler.call(
123
- DataWithSource.new(format: @this_format, identifier: @path, short_identifier: short_identifier, type: type),
124
- this_source
125
- )
126
- # :nocov:
127
- # TODO: Remove in v4
128
- else
129
- handler.call(DataNoSource.new(source: this_source, identifier: @path, type: type))
130
- end
131
- # :nocov:
154
+ handler.call(DataWithSource.new(format:, identifier: @path, short_identifier:, type:), this_source)
132
155
  end
133
156
  end
134
157
  end
@@ -18,18 +18,7 @@ module ViewComponent
18
18
  def assert_component_rendered
19
19
  assert_selector("body")
20
20
  end
21
- rescue LoadError
22
- # We don't have a test case for running an application without capybara installed.
23
- # It's probably fine to leave this without coverage.
24
- # :nocov:
25
- if ENV["DEBUG"]
26
- warn(
27
- "WARNING in `ViewComponent::TestHelpers`: Add `capybara` " \
28
- "to Gemfile to use Capybara assertions."
29
- )
30
- end
31
-
32
- # :nocov:
21
+ rescue LoadError # We don't have a test case for running an application without capybara installed.
33
22
  end
34
23
 
35
24
  # Returns the result of a render_inline call.
@@ -46,21 +35,12 @@ module ViewComponent
46
35
  # ```
47
36
  #
48
37
  # @param component [ViewComponent::Base, ViewComponent::Collection] The instance of the component to be rendered.
49
- # @return [Nokogiri::HTML]
38
+ # @return [Nokogiri::HTML5]
50
39
  def render_inline(component, **args, &block)
51
40
  @page = nil
52
- @rendered_content =
53
- if Rails.version.to_f >= 6.1
54
- vc_test_controller.view_context.render(component, args, &block)
55
-
56
- # :nocov:
57
- else
58
- vc_test_controller.view_context.render_component(component, &block)
59
- end
41
+ @rendered_content = vc_test_controller.view_context.render(component, args, &block)
60
42
 
61
- # :nocov:
62
-
63
- Nokogiri::HTML.fragment(@rendered_content)
43
+ Nokogiri::HTML5.fragment(@rendered_content)
64
44
  end
65
45
 
66
46
  # `JSON.parse`-d component output.
@@ -91,7 +71,7 @@ module ViewComponent
91
71
  # @param name [String] The name of the preview to be rendered.
92
72
  # @param from [ViewComponent::Preview] The class of the preview to be rendered.
93
73
  # @param params [Hash] Parameters to be passed to the preview.
94
- # @return [Nokogiri::HTML]
74
+ # @return [Nokogiri::HTML5]
95
75
  def render_preview(name, from: __vc_test_helpers_preview_class, params: {})
96
76
  previews_controller = __vc_test_helpers_build_controller(Rails.application.config.view_component.preview_controller.constantize)
97
77
 
@@ -107,7 +87,7 @@ module ViewComponent
107
87
 
108
88
  @rendered_content = result
109
89
 
110
- Nokogiri::HTML.fragment(@rendered_content)
90
+ Nokogiri::HTML5.fragment(@rendered_content)
111
91
  end
112
92
 
113
93
  # Execute the given block in the view context (using `instance_exec`).
@@ -121,12 +101,11 @@ module ViewComponent
121
101
  #
122
102
  # assert_text("Hello, World!")
123
103
  # ```
124
- def render_in_view_context(*args, &block)
104
+ def render_in_view_context(...)
125
105
  @page = nil
126
- @rendered_content = vc_test_controller.view_context.instance_exec(*args, &block)
127
- Nokogiri::HTML.fragment(@rendered_content)
106
+ @rendered_content = vc_test_controller.view_context.instance_exec(...)
107
+ Nokogiri::HTML5.fragment(@rendered_content)
128
108
  end
129
- ruby2_keywords(:render_in_view_context) if respond_to?(:ruby2_keywords, true)
130
109
 
131
110
  # Set the Action Pack request variant for the given block:
132
111
  #
@@ -136,11 +115,11 @@ module ViewComponent
136
115
  # end
137
116
  # ```
138
117
  #
139
- # @param variant [Symbol] The variant to be set for the provided block.
140
- def with_variant(variant)
118
+ # @param variants [Symbol[]] The variants to be set for the provided block.
119
+ def with_variant(*variants)
141
120
  old_variants = vc_test_controller.view_context.lookup_context.variants
142
121
 
143
- vc_test_controller.view_context.lookup_context.variants = variant
122
+ vc_test_controller.view_context.lookup_context.variants += variants
144
123
  yield
145
124
  ensure
146
125
  vc_test_controller.view_context.lookup_context.variants = old_variants
@@ -173,9 +152,14 @@ module ViewComponent
173
152
  # end
174
153
  # ```
175
154
  #
176
- # @param format [Symbol] The format to be set for the provided block.
177
- def with_format(format)
178
- with_request_url("/", format: format) { yield }
155
+ # @param formats [Symbol[]] The format(s) to be set for the provided block.
156
+ def with_format(*formats)
157
+ old_formats = vc_test_controller.view_context.lookup_context.formats
158
+
159
+ vc_test_controller.view_context.lookup_context.formats = formats
160
+ yield
161
+ ensure
162
+ vc_test_controller.view_context.lookup_context.formats = old_formats
179
163
  end
180
164
 
181
165
  # Set the URL of the current request (such as when using request-dependent path helpers):
@@ -205,7 +189,7 @@ module ViewComponent
205
189
  # @param full_path [String] The path to set for the current request.
206
190
  # @param host [String] The host to set for the current request.
207
191
  # @param method [String] The request method to set for the current request.
208
- def with_request_url(full_path, host: nil, method: nil, format: ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT)
192
+ def with_request_url(full_path, host: nil, method: nil)
209
193
  old_request_host = vc_test_request.host
210
194
  old_request_method = vc_test_request.request_method
211
195
  old_request_path_info = vc_test_request.path_info
@@ -225,7 +209,6 @@ module ViewComponent
225
209
  vc_test_request.set_header("action_dispatch.request.query_parameters",
226
210
  Rack::Utils.parse_nested_query(query).with_indifferent_access)
227
211
  vc_test_request.set_header(Rack::QUERY_STRING, query)
228
- vc_test_request.format = format
229
212
  yield
230
213
  ensure
231
214
  vc_test_request.host = old_request_host
@@ -284,11 +267,9 @@ module ViewComponent
284
267
 
285
268
  def __vc_test_helpers_preview_class
286
269
  result = if respond_to?(:described_class)
287
- # :nocov:
288
- raise "`render_preview` expected a described_class, but it is nil." if described_class.nil?
270
+ raise ArgumentError.new("`render_preview` expected a described_class, but it is nil.") if described_class.nil?
289
271
 
290
272
  "#{described_class}Preview"
291
- # :nocov:
292
273
  else
293
274
  self.class.name.gsub("Test", "Preview")
294
275
  end
@@ -296,6 +277,5 @@ module ViewComponent
296
277
  rescue NameError
297
278
  raise NameError, "`render_preview` expected to find #{result}, but it does not exist."
298
279
  end
299
- # :nocov:
300
280
  end
301
281
  end