view_component 3.22.0 → 4.0.0.alpha2
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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/view_component/preview_actions.rb +2 -9
- data/app/controllers/view_components_system_test_controller.rb +17 -20
- data/app/views/test_mailer/test_asset_email.html.erb +1 -0
- data/app/views/view_components/preview.html.erb +1 -9
- data/docs/CHANGELOG.md +133 -1
- data/lib/view_component/base.rb +42 -61
- data/lib/view_component/collection.rb +11 -17
- data/lib/view_component/compiler.rb +50 -74
- data/lib/view_component/config.rb +0 -21
- data/lib/view_component/deprecation.rb +1 -1
- data/lib/view_component/engine.rb +3 -82
- data/lib/view_component/errors.rb +16 -22
- data/lib/view_component/inline_template.rb +2 -3
- data/lib/view_component/instrumentation.rb +4 -10
- data/lib/view_component/preview.rb +3 -10
- data/lib/view_component/request_details.rb +30 -0
- data/lib/view_component/slot.rb +2 -5
- data/lib/view_component/slotable.rb +31 -39
- data/lib/view_component/system_test_helpers.rb +1 -2
- data/lib/view_component/template.rb +106 -83
- data/lib/view_component/test_helpers.rb +22 -42
- data/lib/view_component/translatable.rb +24 -23
- data/lib/view_component/use_helpers.rb +3 -4
- data/lib/view_component/version.rb +3 -3
- data/lib/view_component.rb +0 -1
- metadata +73 -220
- data/app/assets/vendor/prism.css +0 -4
- data/app/assets/vendor/prism.min.js +0 -12
- data/app/helpers/preview_helper.rb +0 -85
- data/app/views/view_components/_preview_source.html.erb +0 -17
- data/lib/rails/generators/abstract_generator.rb +0 -56
- data/lib/rails/generators/component/USAGE +0 -13
- data/lib/rails/generators/component/component_generator.rb +0 -67
- data/lib/rails/generators/component/templates/component.rb.tt +0 -16
- data/lib/rails/generators/erb/component_generator.rb +0 -33
- data/lib/rails/generators/erb/templates/component.html.erb.tt +0 -1
- data/lib/rails/generators/haml/component_generator.rb +0 -22
- data/lib/rails/generators/haml/templates/component.html.haml.tt +0 -1
- data/lib/rails/generators/locale/component_generator.rb +0 -46
- data/lib/rails/generators/preview/component_generator.rb +0 -39
- data/lib/rails/generators/preview/templates/component_preview.rb.tt +0 -9
- data/lib/rails/generators/rspec/component_generator.rb +0 -31
- data/lib/rails/generators/rspec/templates/component_spec.rb.tt +0 -15
- data/lib/rails/generators/slim/component_generator.rb +0 -22
- data/lib/rails/generators/slim/templates/component.html.slim.tt +0 -1
- data/lib/rails/generators/stimulus/component_generator.rb +0 -44
- data/lib/rails/generators/stimulus/templates/component_controller.js.tt +0 -7
- data/lib/rails/generators/stimulus/templates/component_controller.ts.tt +0 -9
- data/lib/rails/generators/tailwindcss/component_generator.rb +0 -11
- data/lib/rails/generators/tailwindcss/templates/component.html.erb.tt +0 -1
- data/lib/rails/generators/test_unit/component_generator.rb +0 -20
- data/lib/rails/generators/test_unit/templates/component_test.rb.tt +0 -12
- data/lib/view_component/component_error.rb +0 -6
- data/lib/view_component/docs_builder_component.html.erb +0 -22
- data/lib/view_component/docs_builder_component.rb +0 -96
- data/lib/view_component/rails/tasks/view_component.rake +0 -20
- data/lib/view_component/render_component_helper.rb +0 -10
- data/lib/view_component/render_component_to_string_helper.rb +0 -9
- data/lib/view_component/render_monkey_patch.rb +0 -13
- data/lib/view_component/render_to_string_monkey_patch.rb +0 -13
- data/lib/view_component/rendering_component_helper.rb +0 -9
- data/lib/view_component/rendering_monkey_patch.rb +0 -13
- 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
|
-
|
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] &&
|
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
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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, :path
|
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
|
-
@
|
24
|
-
@this_format = this_format
|
25
|
-
@variant = variant&.to_sym
|
17
|
+
@details = details
|
26
18
|
@lineno = lineno
|
27
19
|
@path = path
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
48
|
-
@component.silence_redefinition_of_method(@call_method_name)
|
98
|
+
@component.silence_redefinition_of_method(call_method_name)
|
49
99
|
|
50
|
-
|
51
|
-
|
52
|
-
def #{
|
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
|
-
|
56
|
-
|
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
|
-
|
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
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
def inline?
|
79
|
-
@type == :inline
|
121
|
+
type == :inline_call
|
80
122
|
end
|
81
123
|
|
82
124
|
def default_format?
|
83
|
-
|
125
|
+
format.nil? || format == DEFAULT_FORMAT
|
84
126
|
end
|
127
|
+
alias_method :html?, :default_format?
|
85
128
|
|
86
|
-
def
|
87
|
-
@
|
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
|
-
"_#{
|
136
|
+
"_#{call_method_name}_#{@component.name.underscore.gsub("/", "__")}"
|
92
137
|
end
|
93
138
|
|
94
139
|
def normalized_variant_name
|
95
|
-
|
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 =
|
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
|
-
|
151
|
+
format = self.format || DEFAULT_FORMAT
|
152
|
+
type = ActionView::Template::Types[format]
|
120
153
|
|
121
|
-
|
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::
|
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
|
-
|
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::
|
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::
|
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(
|
104
|
+
def render_in_view_context(...)
|
125
105
|
@page = nil
|
126
|
-
@rendered_content = vc_test_controller.view_context.instance_exec(
|
127
|
-
Nokogiri::
|
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
|
140
|
-
def with_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
|
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
|
177
|
-
def with_format(
|
178
|
-
|
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
|
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
|
-
|
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
|