view_component 2.19.1 → 2.23.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +4 -1106
- data/lib/rails/generators/component/templates/component.rb.tt +2 -0
- data/lib/rails/generators/test_unit/templates/component_test.rb.tt +1 -1
- data/lib/view_component.rb +1 -0
- data/lib/view_component/base.rb +26 -199
- data/lib/view_component/compiler.rb +229 -0
- data/lib/view_component/engine.rb +10 -5
- data/lib/view_component/preview.rb +4 -1
- data/lib/view_component/previewable.rb +10 -0
- data/lib/view_component/slot_v2.rb +65 -0
- data/lib/view_component/slotable.rb +14 -0
- data/lib/view_component/slotable_v2.rb +249 -0
- data/lib/view_component/version.rb +2 -2
- metadata +19 -2
@@ -1,7 +1,7 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class <%= class_name %>ComponentTest < ViewComponent::TestCase
|
4
|
-
|
4
|
+
def test_component_renders_something_useful
|
5
5
|
# assert_equal(
|
6
6
|
# %(<span>Hello, components!</span>),
|
7
7
|
# render_inline(<%= class_name %>Component.new(message: "Hello, components!")).css("span").to_html
|
data/lib/view_component.rb
CHANGED
data/lib/view_component/base.rb
CHANGED
@@ -6,6 +6,7 @@ require "view_component/collection"
|
|
6
6
|
require "view_component/compile_cache"
|
7
7
|
require "view_component/previewable"
|
8
8
|
require "view_component/slotable"
|
9
|
+
require "view_component/slotable_v2"
|
9
10
|
|
10
11
|
module ViewComponent
|
11
12
|
class Base < ActionView::Base
|
@@ -20,10 +21,6 @@ module ViewComponent
|
|
20
21
|
class_attribute :content_areas
|
21
22
|
self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
|
22
23
|
|
23
|
-
# Hash of registered Slots
|
24
|
-
class_attribute :slots
|
25
|
-
self.slots = {}
|
26
|
-
|
27
24
|
# Entrypoint for rendering components.
|
28
25
|
#
|
29
26
|
# view_context: ActionView context from calling view
|
@@ -64,7 +61,7 @@ module ViewComponent
|
|
64
61
|
@virtual_path ||= virtual_path
|
65
62
|
|
66
63
|
# For template variants (+phone, +desktop, etc.)
|
67
|
-
@variant
|
64
|
+
@variant ||= @lookup_context.variants.first
|
68
65
|
|
69
66
|
# For caching, such as #cache_if
|
70
67
|
@current_template = nil unless defined?(@current_template)
|
@@ -77,7 +74,7 @@ module ViewComponent
|
|
77
74
|
before_render
|
78
75
|
|
79
76
|
if render?
|
80
|
-
|
77
|
+
render_template_for(@variant)
|
81
78
|
else
|
82
79
|
""
|
83
80
|
end
|
@@ -99,13 +96,16 @@ module ViewComponent
|
|
99
96
|
|
100
97
|
def initialize(*); end
|
101
98
|
|
102
|
-
#
|
103
|
-
#
|
99
|
+
# Re-use original view_context if we're not rendering a component.
|
100
|
+
#
|
101
|
+
# This prevents an exception when rendering a partial inside of a component that has also been rendered outside
|
102
|
+
# of the component. This is due to the partials compiled template method existing in the parent `view_context`,
|
103
|
+
# and not the component's `view_context`.
|
104
104
|
def render(options = {}, args = {}, &block)
|
105
|
-
if options.is_a?
|
106
|
-
view_context.render(options, args, &block)
|
107
|
-
else
|
105
|
+
if options.is_a? ViewComponent::Base
|
108
106
|
super
|
107
|
+
else
|
108
|
+
view_context.render(options, args, &block)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -132,7 +132,10 @@ module ViewComponent
|
|
132
132
|
|
133
133
|
# For caching, such as #cache_if
|
134
134
|
def format
|
135
|
-
|
135
|
+
# Ruby 2.6 throws a warning without checking `defined?`, 2.7 does not
|
136
|
+
if defined?(@variant)
|
137
|
+
@variant
|
138
|
+
end
|
136
139
|
end
|
137
140
|
|
138
141
|
# Assign the provided content to the content area accessor
|
@@ -149,6 +152,12 @@ module ViewComponent
|
|
149
152
|
nil
|
150
153
|
end
|
151
154
|
|
155
|
+
def with_variant(variant)
|
156
|
+
@variant = variant
|
157
|
+
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
152
161
|
private
|
153
162
|
|
154
163
|
# Exposes the current request to the component.
|
@@ -201,23 +210,11 @@ module ViewComponent
|
|
201
210
|
# Removes the first part of the path and the extension.
|
202
211
|
child.virtual_path = child.source_location.gsub(%r{(.*app/components)|(\.rb)}, "")
|
203
212
|
|
204
|
-
# Clone slot configuration into child class
|
205
|
-
# see #test_slots_pollution
|
206
|
-
child.slots = self.slots.clone
|
207
|
-
|
208
213
|
super
|
209
214
|
end
|
210
215
|
|
211
|
-
def call_method_name(variant)
|
212
|
-
if variant.present? && variants.include?(variant)
|
213
|
-
"call_#{variant}"
|
214
|
-
else
|
215
|
-
"call"
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
216
|
def compiled?
|
220
|
-
|
217
|
+
template_compiler.compiled?
|
221
218
|
end
|
222
219
|
|
223
220
|
# Compile templates to instance methods, assuming they haven't been compiled already.
|
@@ -225,75 +222,11 @@ module ViewComponent
|
|
225
222
|
# Do as much work as possible in this step, as doing so reduces the amount
|
226
223
|
# of work done each time a component is rendered.
|
227
224
|
def compile(raise_errors: false)
|
228
|
-
|
229
|
-
|
230
|
-
if template_errors.present?
|
231
|
-
raise ViewComponent::TemplateError.new(template_errors) if raise_errors
|
232
|
-
return false
|
233
|
-
end
|
234
|
-
|
235
|
-
if instance_methods(false).include?(:before_render_check)
|
236
|
-
ActiveSupport::Deprecation.warn(
|
237
|
-
"`before_render_check` will be removed in v3.0.0. Use `before_render` instead."
|
238
|
-
)
|
239
|
-
end
|
240
|
-
|
241
|
-
# Remove any existing singleton methods,
|
242
|
-
# as Ruby warns when redefining a method.
|
243
|
-
remove_possible_singleton_method(:variants)
|
244
|
-
remove_possible_singleton_method(:collection_parameter)
|
245
|
-
remove_possible_singleton_method(:collection_counter_parameter)
|
246
|
-
remove_possible_singleton_method(:counter_argument_present?)
|
247
|
-
|
248
|
-
define_singleton_method(:variants) do
|
249
|
-
templates.map { |template| template[:variant] } + variants_from_inline_calls(inline_calls)
|
250
|
-
end
|
251
|
-
|
252
|
-
define_singleton_method(:collection_parameter) do
|
253
|
-
if provided_collection_parameter
|
254
|
-
provided_collection_parameter
|
255
|
-
else
|
256
|
-
name.demodulize.underscore.chomp("_component").to_sym
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
define_singleton_method(:collection_counter_parameter) do
|
261
|
-
"#{collection_parameter}_counter".to_sym
|
262
|
-
end
|
263
|
-
|
264
|
-
define_singleton_method(:counter_argument_present?) do
|
265
|
-
instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
|
266
|
-
end
|
267
|
-
|
268
|
-
validate_collection_parameter! if raise_errors
|
269
|
-
|
270
|
-
# If template name annotations are turned on, a line is dynamically
|
271
|
-
# added with a comment. In this case, we want to return a different
|
272
|
-
# starting line number so errors that are raised will point to the
|
273
|
-
# correct line in the component template.
|
274
|
-
line_number =
|
275
|
-
if ActionView::Base.respond_to?(:annotate_rendered_view_with_filenames) &&
|
276
|
-
ActionView::Base.annotate_rendered_view_with_filenames
|
277
|
-
-2
|
278
|
-
else
|
279
|
-
-1
|
280
|
-
end
|
281
|
-
|
282
|
-
templates.each do |template|
|
283
|
-
# Remove existing compiled template methods,
|
284
|
-
# as Ruby warns when redefining a method.
|
285
|
-
method_name = call_method_name(template[:variant])
|
286
|
-
undef_method(method_name.to_sym) if instance_methods.include?(method_name.to_sym)
|
287
|
-
|
288
|
-
class_eval <<-RUBY, template[:path], line_number
|
289
|
-
def #{method_name}
|
290
|
-
@output_buffer = ActionView::OutputBuffer.new
|
291
|
-
#{compiled_template(template[:path])}
|
292
|
-
end
|
293
|
-
RUBY
|
294
|
-
end
|
225
|
+
template_compiler.compile(raise_errors: raise_errors)
|
226
|
+
end
|
295
227
|
|
296
|
-
|
228
|
+
def template_compiler
|
229
|
+
@_template_compiler ||= Compiler.new(self)
|
297
230
|
end
|
298
231
|
|
299
232
|
# we'll eventually want to update this to support other types
|
@@ -357,112 +290,6 @@ module ViewComponent
|
|
357
290
|
def provided_collection_parameter
|
358
291
|
@provided_collection_parameter ||= nil
|
359
292
|
end
|
360
|
-
|
361
|
-
def compiled_template(file_path)
|
362
|
-
handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
|
363
|
-
template = File.read(file_path)
|
364
|
-
|
365
|
-
if handler.method(:call).parameters.length > 1
|
366
|
-
handler.call(self, template)
|
367
|
-
else
|
368
|
-
handler.call(OpenStruct.new(source: template, identifier: identifier, type: type))
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
def inline_calls
|
373
|
-
@inline_calls ||=
|
374
|
-
begin
|
375
|
-
# Fetch only ViewComponent ancestor classes to limit the scope of
|
376
|
-
# finding inline calls
|
377
|
-
view_component_ancestors =
|
378
|
-
ancestors.take_while { |ancestor| ancestor != ViewComponent::Base } - included_modules
|
379
|
-
|
380
|
-
view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call/) }.uniq
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
def inline_calls_defined_on_self
|
385
|
-
@inline_calls_defined_on_self ||= instance_methods(false).grep(/^call/)
|
386
|
-
end
|
387
|
-
|
388
|
-
def matching_views_in_source_location
|
389
|
-
return [] unless source_location
|
390
|
-
|
391
|
-
location_without_extension = source_location.chomp(File.extname(source_location))
|
392
|
-
|
393
|
-
extensions = ActionView::Template.template_handler_extensions.join(",")
|
394
|
-
|
395
|
-
# view files in the same directory as the component
|
396
|
-
sidecar_files = Dir["#{location_without_extension}.*{#{extensions}}"]
|
397
|
-
|
398
|
-
# view files in a directory named like the component
|
399
|
-
directory = File.dirname(source_location)
|
400
|
-
filename = File.basename(source_location, ".rb")
|
401
|
-
component_name = name.demodulize.underscore
|
402
|
-
|
403
|
-
sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
|
404
|
-
|
405
|
-
(sidecar_files - [source_location] + sidecar_directory_files)
|
406
|
-
end
|
407
|
-
|
408
|
-
def templates
|
409
|
-
@templates ||=
|
410
|
-
matching_views_in_source_location.each_with_object([]) do |path, memo|
|
411
|
-
pieces = File.basename(path).split(".")
|
412
|
-
|
413
|
-
memo << {
|
414
|
-
path: path,
|
415
|
-
variant: pieces.second.split("+").second&.to_sym,
|
416
|
-
handler: pieces.last
|
417
|
-
}
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
def template_errors
|
422
|
-
@template_errors ||=
|
423
|
-
begin
|
424
|
-
errors = []
|
425
|
-
|
426
|
-
if (templates + inline_calls).empty?
|
427
|
-
errors << "Could not find a template file or inline render method for #{self}."
|
428
|
-
end
|
429
|
-
|
430
|
-
if templates.count { |template| template[:variant].nil? } > 1
|
431
|
-
errors << "More than one template found for #{self}. There can only be one default template file per component."
|
432
|
-
end
|
433
|
-
|
434
|
-
invalid_variants = templates
|
435
|
-
.group_by { |template| template[:variant] }
|
436
|
-
.map { |variant, grouped| variant if grouped.length > 1 }
|
437
|
-
.compact
|
438
|
-
.sort
|
439
|
-
|
440
|
-
unless invalid_variants.empty?
|
441
|
-
errors << "More than one template found for #{'variant'.pluralize(invalid_variants.count)} #{invalid_variants.map { |v| "'#{v}'" }.to_sentence} in #{self}. There can only be one template file per variant."
|
442
|
-
end
|
443
|
-
|
444
|
-
if templates.find { |template| template[:variant].nil? } && inline_calls_defined_on_self.include?(:call)
|
445
|
-
errors << "Template file and inline render method found for #{self}. There can only be a template file or inline render method per component."
|
446
|
-
end
|
447
|
-
|
448
|
-
duplicate_template_file_and_inline_variant_calls =
|
449
|
-
templates.pluck(:variant) & variants_from_inline_calls(inline_calls_defined_on_self)
|
450
|
-
|
451
|
-
unless duplicate_template_file_and_inline_variant_calls.empty?
|
452
|
-
count = duplicate_template_file_and_inline_variant_calls.count
|
453
|
-
|
454
|
-
errors << "Template #{'file'.pluralize(count)} and inline render #{'method'.pluralize(count)} found for #{'variant'.pluralize(count)} #{duplicate_template_file_and_inline_variant_calls.map { |v| "'#{v}'" }.to_sentence} in #{self}. There can only be a template file or inline render method per variant."
|
455
|
-
end
|
456
|
-
|
457
|
-
errors
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
def variants_from_inline_calls(calls)
|
462
|
-
calls.reject { |call| call == :call }.map do |variant_call|
|
463
|
-
variant_call.to_s.sub("call_", "").to_sym
|
464
|
-
end
|
465
|
-
end
|
466
293
|
end
|
467
294
|
|
468
295
|
ActiveSupport.run_load_hooks(:view_component, self)
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
class Compiler
|
5
|
+
def initialize(component_class)
|
6
|
+
@component_class = component_class
|
7
|
+
end
|
8
|
+
|
9
|
+
def compiled?
|
10
|
+
CompileCache.compiled?(component_class)
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile(raise_errors: false)
|
14
|
+
return if compiled?
|
15
|
+
|
16
|
+
if template_errors.present?
|
17
|
+
raise ViewComponent::TemplateError.new(template_errors) if raise_errors
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
if component_class.instance_methods(false).include?(:before_render_check)
|
22
|
+
ActiveSupport::Deprecation.warn(
|
23
|
+
"`before_render_check` will be removed in v3.0.0. Use `before_render` instead."
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Remove any existing singleton methods,
|
28
|
+
# as Ruby warns when redefining a method.
|
29
|
+
component_class.remove_possible_singleton_method(:collection_parameter)
|
30
|
+
component_class.remove_possible_singleton_method(:collection_counter_parameter)
|
31
|
+
component_class.remove_possible_singleton_method(:counter_argument_present?)
|
32
|
+
|
33
|
+
component_class.define_singleton_method(:collection_parameter) do
|
34
|
+
if provided_collection_parameter
|
35
|
+
provided_collection_parameter
|
36
|
+
else
|
37
|
+
name.demodulize.underscore.chomp("_component").to_sym
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
component_class.define_singleton_method(:collection_counter_parameter) do
|
42
|
+
"#{collection_parameter}_counter".to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
component_class.define_singleton_method(:counter_argument_present?) do
|
46
|
+
instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
|
47
|
+
end
|
48
|
+
|
49
|
+
component_class.validate_collection_parameter! if raise_errors
|
50
|
+
|
51
|
+
templates.each do |template|
|
52
|
+
# Remove existing compiled template methods,
|
53
|
+
# as Ruby warns when redefining a method.
|
54
|
+
method_name = call_method_name(template[:variant])
|
55
|
+
component_class.send(:undef_method, method_name.to_sym) if component_class.instance_methods.include?(method_name.to_sym)
|
56
|
+
|
57
|
+
component_class.class_eval <<-RUBY, template[:path], -1
|
58
|
+
def #{method_name}
|
59
|
+
@output_buffer = ActionView::OutputBuffer.new
|
60
|
+
#{compiled_template(template[:path])}
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
end
|
64
|
+
|
65
|
+
define_render_template_for
|
66
|
+
|
67
|
+
CompileCache.register(component_class)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
attr_reader :component_class
|
73
|
+
|
74
|
+
def define_render_template_for
|
75
|
+
component_class.send(:undef_method, :render_template_for) if component_class.instance_methods.include?(:render_template_for)
|
76
|
+
|
77
|
+
variant_elsifs = variants.compact.uniq.map do |variant|
|
78
|
+
"elsif variant.to_sym == :#{variant}\n #{call_method_name(variant)}"
|
79
|
+
end.join("\n")
|
80
|
+
|
81
|
+
component_class.class_eval <<-RUBY
|
82
|
+
def render_template_for(variant = nil)
|
83
|
+
if variant.nil?
|
84
|
+
call
|
85
|
+
#{variant_elsifs}
|
86
|
+
else
|
87
|
+
call
|
88
|
+
end
|
89
|
+
end
|
90
|
+
RUBY
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def template_errors
|
95
|
+
@_template_errors ||= begin
|
96
|
+
errors = []
|
97
|
+
|
98
|
+
if (templates + inline_calls).empty?
|
99
|
+
errors << "Could not find a template file or inline render method for #{component_class}."
|
100
|
+
end
|
101
|
+
|
102
|
+
if templates.count { |template| template[:variant].nil? } > 1
|
103
|
+
errors << "More than one template found for #{component_class}. There can only be one default template file per component."
|
104
|
+
end
|
105
|
+
|
106
|
+
invalid_variants = templates
|
107
|
+
.group_by { |template| template[:variant] }
|
108
|
+
.map { |variant, grouped| variant if grouped.length > 1 }
|
109
|
+
.compact
|
110
|
+
.sort
|
111
|
+
|
112
|
+
unless invalid_variants.empty?
|
113
|
+
errors << "More than one template found for #{'variant'.pluralize(invalid_variants.count)} #{invalid_variants.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. There can only be one template file per variant."
|
114
|
+
end
|
115
|
+
|
116
|
+
if templates.find { |template| template[:variant].nil? } && inline_calls_defined_on_self.include?(:call)
|
117
|
+
errors << "Template file and inline render method found for #{component_class}. There can only be a template file or inline render method per component."
|
118
|
+
end
|
119
|
+
|
120
|
+
duplicate_template_file_and_inline_variant_calls =
|
121
|
+
templates.pluck(:variant) & variants_from_inline_calls(inline_calls_defined_on_self)
|
122
|
+
|
123
|
+
unless duplicate_template_file_and_inline_variant_calls.empty?
|
124
|
+
count = duplicate_template_file_and_inline_variant_calls.count
|
125
|
+
|
126
|
+
errors << "Template #{'file'.pluralize(count)} and inline render #{'method'.pluralize(count)} found for #{'variant'.pluralize(count)} #{duplicate_template_file_and_inline_variant_calls.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. There can only be a template file or inline render method per variant."
|
127
|
+
end
|
128
|
+
|
129
|
+
errors
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def templates
|
134
|
+
@templates ||= matching_views_in_source_location.each_with_object([]) do |path, memo|
|
135
|
+
pieces = File.basename(path).split(".")
|
136
|
+
|
137
|
+
memo << {
|
138
|
+
path: path,
|
139
|
+
variant: pieces.second.split("+").second&.to_sym,
|
140
|
+
handler: pieces.last
|
141
|
+
}
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def matching_views_in_source_location
|
146
|
+
source_location = component_class.source_location
|
147
|
+
return [] unless source_location
|
148
|
+
|
149
|
+
extensions = ActionView::Template.template_handler_extensions.join(",")
|
150
|
+
|
151
|
+
# view files in a directory named like the component
|
152
|
+
directory = File.dirname(source_location)
|
153
|
+
filename = File.basename(source_location, ".rb")
|
154
|
+
component_name = component_class.name.demodulize.underscore
|
155
|
+
|
156
|
+
# Add support for nested components defined in the same file.
|
157
|
+
#
|
158
|
+
# e.g.
|
159
|
+
#
|
160
|
+
# class MyComponent < ViewComponent::Base
|
161
|
+
# class MyOtherComponent < ViewComponent::Base
|
162
|
+
# end
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
|
166
|
+
nested_component_files = if component_class.name.include?("::")
|
167
|
+
nested_component_path = component_class.name.deconstantize.underscore
|
168
|
+
Dir["#{directory}/#{nested_component_path}/#{component_name}.*{#{extensions}}"]
|
169
|
+
else
|
170
|
+
[]
|
171
|
+
end
|
172
|
+
|
173
|
+
# view files in the same directory as the component
|
174
|
+
sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
|
175
|
+
|
176
|
+
sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
|
177
|
+
|
178
|
+
(sidecar_files - [source_location] + sidecar_directory_files + nested_component_files)
|
179
|
+
end
|
180
|
+
|
181
|
+
def inline_calls
|
182
|
+
@inline_calls ||= begin
|
183
|
+
# Fetch only ViewComponent ancestor classes to limit the scope of
|
184
|
+
# finding inline calls
|
185
|
+
view_component_ancestors =
|
186
|
+
component_class.ancestors.take_while { |ancestor| ancestor != ViewComponent::Base } - component_class.included_modules
|
187
|
+
|
188
|
+
view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call/) }.uniq
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def inline_calls_defined_on_self
|
193
|
+
@inline_calls_defined_on_self ||= component_class.instance_methods(false).grep(/^call/)
|
194
|
+
end
|
195
|
+
|
196
|
+
def variants
|
197
|
+
@_variants = (
|
198
|
+
templates.map { |template| template[:variant] } + variants_from_inline_calls(inline_calls)
|
199
|
+
).compact.uniq
|
200
|
+
end
|
201
|
+
|
202
|
+
def variants_from_inline_calls(calls)
|
203
|
+
calls.reject { |call| call == :call }.map do |variant_call|
|
204
|
+
variant_call.to_s.sub("call_", "").to_sym
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# :nocov:
|
209
|
+
def compiled_template(file_path)
|
210
|
+
handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
|
211
|
+
template = File.read(file_path)
|
212
|
+
|
213
|
+
if handler.method(:call).parameters.length > 1
|
214
|
+
handler.call(component_class, template)
|
215
|
+
else
|
216
|
+
handler.call(OpenStruct.new(source: template, identifier: component_class.identifier, type: component_class.type))
|
217
|
+
end
|
218
|
+
end
|
219
|
+
# :nocov:
|
220
|
+
|
221
|
+
def call_method_name(variant)
|
222
|
+
if variant.present? && variants.include?(variant)
|
223
|
+
"call_#{variant}"
|
224
|
+
else
|
225
|
+
"call"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|