view_component 2.56.2 → 2.58.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afe785add49fc05a089c0d317b73ab372489e85473fced3b8b4ae13d11271e78
4
- data.tar.gz: e52674e539ea4ee9bb147ac8394575d9b45f7096ed3f92503b47da7c63ba3b47
3
+ metadata.gz: 73dd7bae94ee1c5a5886e248924ccfea872df61e783e713c0744390d6729d128
4
+ data.tar.gz: e70c67571e32098ee5997b7912d07e65d427e265766c5caa398bcd47d06d3e55
5
5
  SHA512:
6
- metadata.gz: 0d6b9fc86ac35aa9cc1831d2b3eb4b1bf8f7197658342edfc6201ccf62e9f01abdca2a31226dd9a9b5d039a0af3d8b997ff38c7626e2da33841f0fc573254fc4
7
- data.tar.gz: 1efe944077b322fe594d7ef3b6a21ee7fa887efd4c237546c877de54b85be5b7bc5ba01a4e75b1d5518f645302ae6360c4c8aa1e2d519fa04b27bd80f622921c
6
+ metadata.gz: '080f91f8f3f6aa9e0db95a4b533643c627be1e31fe8fcd32cea979556e52a351f956a9b01000f0a4654039f2588d88fa6680107f5b94c1103fa4a5c0190953f3'
7
+ data.tar.gz: 7c4e322ca388053c13ad36ad8d79e706aede23d5a2e25d15cdadb2e2e8c6776c95a5981c5588134061534037fd89a11c859fe74110418072378ee4b14e10b8d6
@@ -37,21 +37,24 @@ module ViewComponent
37
37
  opts = {}
38
38
  opts[:layout] = layout if layout.present? || layout == false
39
39
  opts[:locals] = locals if locals.present?
40
- render "view_components/preview", opts # rubocop:disable GitHub/RailsControllerRenderLiteral
40
+ render "view_components/preview", opts
41
41
  end
42
42
  end
43
43
 
44
44
  private
45
45
 
46
- def default_preview_layout # :doc:
46
+ # :doc:
47
+ def default_preview_layout
47
48
  ViewComponent::Base.default_preview_layout
48
49
  end
49
50
 
50
- def show_previews? # :doc:
51
+ # :doc:
52
+ def show_previews?
51
53
  ViewComponent::Base.show_previews
52
54
  end
53
55
 
54
- def find_preview # :doc:
56
+ # :doc:
57
+ def find_preview
55
58
  candidates = []
56
59
  params[:path].to_s.scan(%r{/|$}) { candidates << $` }
57
60
  preview = candidates.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
@@ -7,14 +7,14 @@ module PreviewHelper
7
7
  def preview_source
8
8
  return if @render_args.nil?
9
9
 
10
- render "preview_source" # rubocop:disable GitHub/RailsViewRenderPathsExist
10
+ render "preview_source"
11
11
  end
12
12
 
13
13
  def find_template_data(lookup_context:, template_identifier:)
14
14
  template = lookup_context.find_template(template_identifier)
15
15
 
16
16
  if Rails.version.to_f >= 6.1 || template.source.present?
17
- return {
17
+ {
18
18
  source: template.source,
19
19
  prism_language_name: prism_language_name_by_template(template: template)
20
20
  }
@@ -40,7 +40,7 @@ module PreviewHelper
40
40
  template_source = File.read(template_file_path)
41
41
  prism_language_name = prism_language_name_by_template_path(template_file_path: template_file_path)
42
42
 
43
- return {
43
+ {
44
44
  source: template_source,
45
45
  prism_language_name: prism_language_name
46
46
  }
data/docs/CHANGELOG.md CHANGED
@@ -9,6 +9,74 @@ title: Changelog
9
9
 
10
10
  ## main
11
11
 
12
+ ## 2.58.0
13
+
14
+ * Switch to `standardrb`.
15
+
16
+ *Joel Hawksley*
17
+
18
+ * Add BootrAils article to resources.
19
+
20
+ *Joel Hawksley*
21
+
22
+ * Add @boardfish and @spone as maintainers.
23
+
24
+ *Joel Hawksley*, *Cameron Dutro*, *Blake Williams*
25
+
26
+ * Re-compile updated, inherited templates when class caching is disabled.
27
+
28
+ *Patrick Arnett*
29
+
30
+ * Add the latest version to the docs index.
31
+ * Improve the docs: add the versions various features were introduced in.
32
+
33
+ *Hans Lemuet*
34
+
35
+ * Update docs to reflect lack of block content support in controllers.
36
+
37
+ *Joel Hawksley*
38
+
39
+ * Prevent adding duplicates to `autoload_paths`.
40
+
41
+ *Thomas Hutterer*
42
+
43
+ * Add FreeAgent to list of companies using ViewComponent.
44
+
45
+ *Simon Fish*
46
+
47
+ * Include polymorphic slots in `ViewComponent::Base` by default.
48
+
49
+ *Cameron Dutro*
50
+
51
+ * Add per-component config option for stripping newlines from templates before compilation.
52
+
53
+ *Cameron Dutro*
54
+
55
+ * Add link to article by Matouš Borák.
56
+
57
+ *Joel Hawksley*
58
+
59
+ ## 2.57.1
60
+
61
+ * Fix issue causing `NoMethodError`s when calling helper methods from components rendered as part of a collection.
62
+ * Fix syntax error in the ERB example in the polymorphic slots docs.
63
+
64
+ *Cameron Dutro*
65
+
66
+ ## 2.57.0
67
+
68
+ * Add missing `require` for `Translatable` module in `Base`.
69
+
70
+ *Hans Lemuet*
71
+
72
+ * Allow anything that responds to `#render_in` to be rendered in the parent component's view context.
73
+
74
+ *Cameron Dutro*
75
+
76
+ * Fix script/release so it honors semver.
77
+
78
+ *Cameron Dutro*
79
+
12
80
  ## 2.56.2
13
81
 
14
82
  * Restore removed `rendered_component`, marking it for deprecation in v3.0.0.
@@ -36,10 +36,10 @@ module ViewComponent
36
36
 
37
37
  def stimulus_controller
38
38
  if options["stimulus"]
39
- File.join(destination_directory, destination_file_name).
40
- sub("#{component_path}/", "").
41
- gsub("_", "-").
42
- gsub("/", "--")
39
+ File.join(destination_directory, destination_file_name)
40
+ .sub("#{component_path}/", "")
41
+ .tr("_", "-")
42
+ .gsub("/", "--")
43
43
  end
44
44
  end
45
45
 
@@ -9,12 +9,14 @@ require "view_component/polymorphic_slots"
9
9
  require "view_component/previewable"
10
10
  require "view_component/slotable"
11
11
  require "view_component/slotable_v2"
12
+ require "view_component/translatable"
12
13
  require "view_component/with_content_helper"
13
14
 
14
15
  module ViewComponent
15
16
  class Base < ActionView::Base
16
17
  include ActiveSupport::Configurable
17
18
  include ViewComponent::ContentAreas
19
+ include ViewComponent::PolymorphicSlots
18
20
  include ViewComponent::Previewable
19
21
  include ViewComponent::SlotableV2
20
22
  include ViewComponent::Translatable
@@ -30,8 +32,25 @@ module ViewComponent
30
32
  class_attribute :content_areas
31
33
  self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
32
34
 
35
+ # Config option that strips trailing whitespace in templates before compiling them.
36
+ class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false
37
+ self.__vc_strip_trailing_whitespace = false # class_attribute:default doesn't work until Rails 5.2
38
+
33
39
  attr_accessor :__vc_original_view_context
34
40
 
41
+ # Components render in their own view context. Helpers and other functionality
42
+ # require a reference to the original Rails view context, an instance of
43
+ # `ActionView::Base`. Use this method to set a reference to the original
44
+ # view context. Objects that implement this method will render in the component's
45
+ # view context, while objects that don't will render in the original view context
46
+ # so helpers, etc work as expected.
47
+ #
48
+ # @param view_context [ActionView::Base] The original view context.
49
+ # @return [void]
50
+ def set_original_view_context(view_context)
51
+ self.__vc_original_view_context = view_context
52
+ end
53
+
35
54
  # EXPERIMENTAL: This API is experimental and may be removed at any time.
36
55
  # Hook for allowing components to do work as part of the compilation process.
37
56
  #
@@ -113,24 +132,27 @@ module ViewComponent
113
132
  @current_template = old_current_template
114
133
  end
115
134
 
135
+ # @private
116
136
  def perform_render
117
137
  render_template_for(@__vc_variant).to_s + _output_postamble
118
138
  end
119
139
 
120
140
  # Subclass components that call `super` inside their template code will cause a
121
- # double render if they accidentally emit the result:
141
+ # double render if they emit the result:
122
142
  #
143
+ # ```erb
123
144
  # <%= super %> # double-renders
124
- #
125
145
  # <% super %> # does not double-render
146
+ # ```
126
147
  #
127
- # Calls `super`, returning nil to avoid rendering the result twice.
148
+ # Calls `super`, returning `nil` to avoid rendering the result twice.
128
149
  def render_parent
129
150
  mtd = @__vc_variant ? "call_#{@__vc_variant}" : "call"
130
151
  method(mtd).super_method.call
131
152
  nil
132
153
  end
133
154
 
155
+ # @private
134
156
  # :nocov:
135
157
  def render_template_for(variant = nil)
136
158
  # Force compilation here so the compiler always redefines render_template_for.
@@ -172,7 +194,8 @@ module ViewComponent
172
194
  end
173
195
 
174
196
  # @private
175
- def initialize(*); end
197
+ def initialize(*)
198
+ end
176
199
 
177
200
  # Re-use original view_context if we're not rendering a component.
178
201
  #
@@ -182,8 +205,8 @@ module ViewComponent
182
205
  #
183
206
  # @private
184
207
  def render(options = {}, args = {}, &block)
185
- if options.is_a? ViewComponent::Base
186
- options.__vc_original_view_context = __vc_original_view_context
208
+ if options.respond_to?(:set_original_view_context)
209
+ options.set_original_view_context(self.__vc_original_view_context)
187
210
  super
188
211
  else
189
212
  __vc_original_view_context.render(options, args, &block)
@@ -300,7 +323,9 @@ module ViewComponent
300
323
 
301
324
  # Set the controller used for testing components:
302
325
  #
303
- # config.view_component.test_controller = "MyTestController"
326
+ # ```ruby
327
+ # config.view_component.test_controller = "MyTestController"
328
+ # ```
304
329
  #
305
330
  # Defaults to ApplicationController. Can also be configured on a per-test
306
331
  # basis using `with_controller_class`.
@@ -310,13 +335,17 @@ module ViewComponent
310
335
 
311
336
  # Set if render monkey patches should be included or not in Rails <6.1:
312
337
  #
313
- # config.view_component.render_monkey_patch_enabled = false
338
+ # ```ruby
339
+ # config.view_component.render_monkey_patch_enabled = false
340
+ # ```
314
341
  #
315
342
  mattr_accessor :render_monkey_patch_enabled, instance_writer: false, default: true
316
343
 
317
344
  # Path for component files
318
345
  #
319
- # config.view_component.view_component_path = "app/my_components"
346
+ # ```ruby
347
+ # config.view_component.view_component_path = "app/my_components"
348
+ # ```
320
349
  #
321
350
  # Defaults to `app/components`.
322
351
  #
@@ -324,7 +353,9 @@ module ViewComponent
324
353
 
325
354
  # Parent class for generated components
326
355
  #
327
- # config.view_component.component_parent_class = "MyBaseComponent"
356
+ # ```ruby
357
+ # config.view_component.component_parent_class = "MyBaseComponent"
358
+ # ```
328
359
  #
329
360
  # Defaults to nil. If this is falsy, generators will use
330
361
  # "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
@@ -340,25 +371,33 @@ module ViewComponent
340
371
  #
341
372
  # Always generate a component with a sidecar directory:
342
373
  #
343
- # config.view_component.generate.sidecar = true
374
+ # ```ruby
375
+ # config.view_component.generate.sidecar = true
376
+ # ```
344
377
  #
345
378
  # #### #stimulus_controller
346
379
  #
347
380
  # Always generate a Stimulus controller alongside the component:
348
381
  #
349
- # config.view_component.generate.stimulus_controller = true
382
+ # ```ruby
383
+ # config.view_component.generate.stimulus_controller = true
384
+ # ```
350
385
  #
351
386
  # #### #locale
352
387
  #
353
388
  # Always generate translations file alongside the component:
354
389
  #
355
- # config.view_component.generate.locale = true
390
+ # ```ruby
391
+ # config.view_component.generate.locale = true
392
+ # ```
356
393
  #
357
394
  # #### #distinct_locale_files
358
395
  #
359
396
  # Always generate as many translations files as available locales:
360
397
  #
361
- # config.view_component.generate.distinct_locale_files = true
398
+ # ```ruby
399
+ # config.view_component.generate.distinct_locale_files = true
400
+ # ```
362
401
  #
363
402
  # One file will be generated for each configured `I18n.available_locales`,
364
403
  # falling back to `[:en]` when no `available_locales` is defined.
@@ -367,7 +406,9 @@ module ViewComponent
367
406
  #
368
407
  # Always generate preview alongside the component:
369
408
  #
370
- # config.view_component.generate.preview = true
409
+ # ```ruby
410
+ # config.view_component.generate.preview = true
411
+ # ```
371
412
  #
372
413
  # Defaults to `false`.
373
414
  mattr_accessor :generate, instance_writer: false, default: ActiveSupport::OrderedOptions.new(false)
@@ -421,7 +462,9 @@ module ViewComponent
421
462
 
422
463
  # Render a component for each element in a collection ([documentation](/guide/collections)):
423
464
  #
424
- # render(ProductsComponent.with_collection(@products, foo: :bar))
465
+ # ```ruby
466
+ # render(ProductsComponent.with_collection(@products, foo: :bar))
467
+ # ```
425
468
  #
426
469
  # @param collection [Enumerable] A list of items to pass the ViewComponent one at a time.
427
470
  # @param args [Arguments] Arguments to pass to the ViewComponent every time.
@@ -517,13 +560,35 @@ module ViewComponent
517
560
 
518
561
  # Set the parameter name used when rendering elements of a collection ([documentation](/guide/collections)):
519
562
  #
520
- # with_collection_parameter :item
563
+ # ```ruby
564
+ # with_collection_parameter :item
565
+ # ```
521
566
  #
522
567
  # @param parameter [Symbol] The parameter name used when rendering elements of a collection.
523
568
  def with_collection_parameter(parameter)
524
569
  @provided_collection_parameter = parameter
525
570
  end
526
571
 
572
+ # Strips trailing whitespace from templates before compiling them.
573
+ #
574
+ # ```ruby
575
+ # class MyComponent < ViewComponent::Base
576
+ # strip_trailing_whitespace
577
+ # end
578
+ # ```
579
+ #
580
+ # @param value [Boolean] Whether or not to strip newlines.
581
+ def strip_trailing_whitespace(value = true)
582
+ self.__vc_strip_trailing_whitespace = value
583
+ end
584
+
585
+ # Whether trailing whitespace will be stripped before compilation.
586
+ #
587
+ # @return [Boolean]
588
+ def strip_trailing_whitespace?
589
+ __vc_strip_trailing_whitespace
590
+ end
591
+
527
592
  # Ensure the component initializer accepts the
528
593
  # collection parameter. By default, we don't
529
594
  # validate that the default parameter name
@@ -571,11 +636,7 @@ module ViewComponent
571
636
 
572
637
  # @private
573
638
  def collection_parameter
574
- if provided_collection_parameter
575
- provided_collection_parameter
576
- else
577
- name && name.demodulize.underscore.chomp("_component").to_sym
578
- end
639
+ provided_collection_parameter || name && name.demodulize.underscore.chomp("_component").to_sym
579
640
  end
580
641
 
581
642
  # @private
@@ -10,10 +10,17 @@ module ViewComponent
10
10
  delegate :format, to: :component
11
11
  delegate :size, to: :@collection
12
12
 
13
+ attr_accessor :__vc_original_view_context
14
+
15
+ def set_original_view_context(view_context)
16
+ self.__vc_original_view_context = view_context
17
+ end
18
+
13
19
  def render_in(view_context, &block)
14
20
  components.map do |component|
21
+ component.set_original_view_context(__vc_original_view_context)
15
22
  component.render_in(view_context, &block)
16
- end.join.html_safe # rubocop:disable Rails/OutputSafety
23
+ end.join.html_safe
17
24
  end
18
25
 
19
26
  def components
@@ -54,7 +61,7 @@ module ViewComponent
54
61
  end
55
62
 
56
63
  def component_options(item, iterator)
57
- item_options = { component.collection_parameter => item }
64
+ item_options = {component.collection_parameter => item}
58
65
  item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
59
66
  item_options[component.collection_iteration_parameter] = iterator.dup if component.iteration_argument_present?
60
67
 
@@ -31,6 +31,8 @@ module ViewComponent
31
31
  return if compiled? && !force
32
32
  return if component_class == ViewComponent::Base
33
33
 
34
+ component_class.superclass.compile(raise_errors: raise_errors) if should_compile_superclass?
35
+
34
36
  with_lock do
35
37
  subclass_instance_methods = component_class.instance_methods(false)
36
38
 
@@ -68,11 +70,13 @@ module ViewComponent
68
70
  component_class.send(:remove_method, method_name.to_sym)
69
71
  end
70
72
 
73
+ # rubocop:disable Style/EvalWithLocation
71
74
  component_class.class_eval <<-RUBY, template[:path], 0
72
75
  def #{method_name}
73
76
  #{compiled_template(template[:path])}
74
77
  end
75
78
  RUBY
79
+ # rubocop:enable Style/EvalWithLocation
76
80
  end
77
81
 
78
82
  define_render_template_for
@@ -151,15 +155,15 @@ module ViewComponent
151
155
  end
152
156
 
153
157
  invalid_variants =
154
- templates.
155
- group_by { |template| template[:variant] }.
156
- map { |variant, grouped| variant if grouped.length > 1 }.
157
- compact.
158
- sort
158
+ templates
159
+ .group_by { |template| template[:variant] }
160
+ .map { |variant, grouped| variant if grouped.length > 1 }
161
+ .compact
162
+ .sort
159
163
 
160
164
  unless invalid_variants.empty?
161
165
  errors <<
162
- "More than one template found for #{'variant'.pluralize(invalid_variants.count)} " \
166
+ "More than one template found for #{"variant".pluralize(invalid_variants.count)} " \
163
167
  "#{invalid_variants.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. " \
164
168
  "There can only be one template file per variant."
165
169
  end
@@ -177,8 +181,8 @@ module ViewComponent
177
181
  count = duplicate_template_file_and_inline_variant_calls.count
178
182
 
179
183
  errors <<
180
- "Template #{'file'.pluralize(count)} and inline render #{'method'.pluralize(count)} " \
181
- "found for #{'variant'.pluralize(count)} " \
184
+ "Template #{"file".pluralize(count)} and inline render #{"method".pluralize(count)} " \
185
+ "found for #{"variant".pluralize(count)} " \
182
186
  "#{duplicate_template_file_and_inline_variant_calls.map { |v| "'#{v}'" }.to_sentence} " \
183
187
  "in #{component_class}. " \
184
188
  "There can only be a template file or inline render method per variant."
@@ -236,8 +240,9 @@ module ViewComponent
236
240
  end
237
241
 
238
242
  def compiled_template(file_path)
239
- handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
243
+ handler = ActionView::Template.handler_for_extension(File.extname(file_path).delete("."))
240
244
  template = File.read(file_path)
245
+ template.rstrip! if component_class.strip_trailing_whitespace?
241
246
 
242
247
  if handler.method(:call).parameters.length > 1
243
248
  handler.call(component_class, template)
@@ -259,5 +264,14 @@ module ViewComponent
259
264
  "call"
260
265
  end
261
266
  end
267
+
268
+ def should_compile_superclass?
269
+ development? &&
270
+ templates.empty? &&
271
+ !(
272
+ component_class.instance_methods(false).include?(:call) ||
273
+ component_class.private_instance_methods(false).include?(:call)
274
+ )
275
+ end
262
276
  end
263
277
  end
@@ -21,7 +21,7 @@ module ViewComponent
21
21
  )
22
22
  end
23
23
 
24
- if block_given?
24
+ if block
25
25
  content = view_context.capture(&block)
26
26
  end
27
27
 
@@ -28,7 +28,7 @@ module ViewComponent
28
28
  end
29
29
 
30
30
  def types
31
- " → [#{@method.tag(:return).types.join(',')}]" if @method.tag(:return)&.types && show_types?
31
+ " → [#{@method.tag(:return).types.join(",")}]" if @method.tag(:return)&.types && show_types?
32
32
  end
33
33
 
34
34
  def signature_or_name
@@ -77,7 +77,8 @@ module ViewComponent
77
77
  options = app.config.view_component
78
78
 
79
79
  if options.show_previews && !options.preview_paths.empty?
80
- ActiveSupport::Dependencies.autoload_paths.concat(options.preview_paths)
80
+ paths_to_add = options.preview_paths - ActiveSupport::Dependencies.autoload_paths
81
+ ActiveSupport::Dependencies.autoload_paths.concat(paths_to_add) if paths_to_add.any?
81
82
  end
82
83
  end
83
84
 
@@ -133,10 +134,10 @@ module ViewComponent
133
134
 
134
135
  initializer "compiler mode" do |app|
135
136
  ViewComponent::Compiler.mode = if Rails.env.development? || Rails.env.test?
136
- ViewComponent::Compiler::DEVELOPMENT_MODE
137
- else
138
- ViewComponent::Compiler::PRODUCTION_MODE
139
- end
137
+ ViewComponent::Compiler::DEVELOPMENT_MODE
138
+ else
139
+ ViewComponent::Compiler::PRODUCTION_MODE
140
+ end
140
141
  end
141
142
 
142
143
  config.after_initialize do |app|
@@ -34,13 +34,14 @@ module ViewComponent
34
34
  def with_output_buffer(buf = nil)
35
35
  unless buf
36
36
  buf = ActionView::OutputBuffer.new
37
+ # rubocop:disable Style/SafeNavigation
37
38
  if output_buffer && output_buffer.respond_to?(:encoding)
38
39
  buf.force_encoding(output_buffer.encoding)
39
40
  end
41
+ # rubocop:enable Style/SafeNavigation
40
42
  end
41
43
 
42
44
  output_buffer.push(buf)
43
- result = nil
44
45
 
45
46
  begin
46
47
  yield
@@ -65,13 +66,13 @@ module ViewComponent
65
66
  def with_output_buffer(buf = nil)
66
67
  unless buf
67
68
  buf = ActionView::OutputBuffer.new
69
+ # rubocop:disable Style/SafeNavigation
68
70
  if @output_buffer && @output_buffer.respond_to?(:encoding)
69
71
  buf.force_encoding(@output_buffer.encoding)
70
72
  end
73
+ # rubocop:enable Style/SafeNavigation
71
74
  end
72
75
 
73
- result = nil
74
-
75
76
  if @output_buffer.is_a?(OutputBufferStack)
76
77
  @output_buffer.push(buf)
77
78
 
@@ -37,9 +37,7 @@ module ViewComponent
37
37
  end
38
38
 
39
39
  def safe_concat(arg)
40
- # rubocop:disable Rails/OutputSafety
41
40
  @current_buffer.safe_concat(arg)
42
- # rubocop:enable Rails/OutputSafety
43
41
  end
44
42
 
45
43
  def length
@@ -5,6 +5,17 @@ module ViewComponent
5
5
  # In older rails versions, using a concern isn't a good idea here because they appear to not work with
6
6
  # Module#prepend and class methods.
7
7
  def self.included(base)
8
+ if base != ViewComponent::Base
9
+ # :nocov:
10
+ location = Kernel.caller_locations(1, 1)[0]
11
+
12
+ warn(
13
+ "warning: ViewComponent::PolymorphicSlots is now included in ViewComponent::Base by default "\
14
+ "and can be removed from #{location.path}:#{location.lineno}"
15
+ )
16
+ # :nocov:
17
+ end
18
+
8
19
  base.singleton_class.prepend(ClassMethods)
9
20
  base.include(InstanceMethods)
10
21
  end
@@ -45,8 +56,12 @@ module ViewComponent
45
56
  "#{slot_name}_#{poly_type}"
46
57
  end
47
58
 
48
- # Deprecated: Will be removed in 3.0
49
59
  define_method(setter_name) do |*args, &block|
60
+ ViewComponent::Deprecation.warn(
61
+ "polymorphic slot setters like `#{setter_name}` are deprecated and will be removed in"\
62
+ "ViewComponent v3.0.0.\n\nUse `with_#{setter_name}` instead."
63
+ )
64
+
50
65
  set_polymorphic_slot(slot_name, poly_type, *args, &block)
51
66
  end
52
67
  ruby2_keywords(setter_name.to_sym) if respond_to?(:ruby2_keywords, true)
@@ -57,7 +72,7 @@ module ViewComponent
57
72
  ruby2_keywords(:"with_#{setter_name}") if respond_to?(:ruby2_keywords, true)
58
73
  end
59
74
 
60
- self.registered_slots[slot_name] = {
75
+ registered_slots[slot_name] = {
61
76
  collection: collection,
62
77
  renderable_hash: renderable_hash
63
78
  }
@@ -14,7 +14,7 @@ module ViewComponent # :nodoc:
14
14
  block: block,
15
15
  component: component,
16
16
  locals: {},
17
- template: "view_components/preview",
17
+ template: "view_components/preview"
18
18
  }
19
19
  end
20
20
 
@@ -66,10 +66,12 @@ module ViewComponent # :nodoc:
66
66
  name.chomp("Preview").underscore
67
67
  end
68
68
 
69
+ # rubocop:disable Style/TrivialAccessors
69
70
  # Setter for layout name.
70
71
  def layout(layout_name)
71
72
  @layout = layout_name
72
73
  end
74
+ # rubocop:enable Style/TrivialAccessors
73
75
 
74
76
  # Returns the relative path (from preview_path) to the preview example template if the template exists
75
77
  def preview_example_template_path(example)
@@ -87,15 +89,15 @@ module ViewComponent # :nodoc:
87
89
  end
88
90
 
89
91
  path = Dir["#{preview_path}/#{preview_name}_preview/#{example}.html.*"].first
90
- Pathname.new(path).
91
- relative_path_from(Pathname.new(preview_path)).
92
- to_s.
93
- sub(/\..*$/, "")
92
+ Pathname.new(path)
93
+ .relative_path_from(Pathname.new(preview_path))
94
+ .to_s
95
+ .sub(/\..*$/, "")
94
96
  end
95
97
 
96
98
  # Returns the method body for the example from the preview file.
97
99
  def preview_source(example)
98
- source = self.instance_method(example.to_sym).source.split("\n")
100
+ source = instance_method(example.to_sym).source.split("\n")
99
101
  source[1...(source.size - 1)].join("\n")
100
102
  end
101
103
 
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module RenderComponentToStringHelper # :nodoc:
5
5
  def render_component_to_string(component)
6
- component.render_in(self.view_context)
6
+ component.render_in(view_context)
7
7
  end
8
8
  end
9
9
  end
@@ -4,7 +4,7 @@ module ViewComponent
4
4
  module RenderToStringMonkeyPatch # :nodoc:
5
5
  def render_to_string(options = {}, args = {})
6
6
  if options.respond_to?(:render_in)
7
- options.render_in(self.view_context)
7
+ options.render_in(view_context)
8
8
  else
9
9
  super
10
10
  end
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module RenderingComponentHelper # :nodoc:
5
5
  def render_component(component)
6
- self.response_body = component.render_in(self.view_context)
6
+ self.response_body = component.render_in(view_context)
7
7
  end
8
8
  end
9
9
  end
@@ -4,7 +4,7 @@ module ViewComponent
4
4
  module RenderingMonkeyPatch # :nodoc:
5
5
  def render(options = {}, args = {})
6
6
  if options.respond_to?(:render_in)
7
- self.response_body = options.render_in(self.view_context)
7
+ self.response_body = options.render_in(view_context)
8
8
  else
9
9
  super
10
10
  end
@@ -30,7 +30,7 @@ module ViewComponent
30
30
 
31
31
  slot_names.each do |slot_name|
32
32
  # Ensure slot_name isn't already declared
33
- if self.slots.key?(slot_name)
33
+ if slots.key?(slot_name)
34
34
  raise ArgumentError.new("#{slot_name} slot declared multiple times")
35
35
  end
36
36
 
@@ -73,7 +73,7 @@ module ViewComponent
73
73
  class_name = "ViewComponent::Slot" unless class_name.present?
74
74
 
75
75
  # Register the slot on the component
76
- self.slots[slot_name] = {
76
+ slots[slot_name] = {
77
77
  class_name: class_name,
78
78
  instance_variable_name: instance_variable_name,
79
79
  collection: collection
@@ -84,7 +84,7 @@ module ViewComponent
84
84
  def inherited(child)
85
85
  # Clone slot configuration into child class
86
86
  # see #test_slots_pollution
87
- child.slots = self.slots.clone
87
+ child.slots = slots.clone
88
88
 
89
89
  super
90
90
  end
@@ -106,7 +106,7 @@ module ViewComponent
106
106
  #
107
107
  def slot(slot_name, **args, &block)
108
108
  # Raise ArgumentError if `slot` doesn't exist
109
- unless slots.keys.include?(slot_name)
109
+ unless slots.key?(slot_name)
110
110
  raise ArgumentError.new "Unknown slot '#{slot_name}' - expected one of '#{slots.keys}'"
111
111
  end
112
112
 
@@ -123,8 +123,7 @@ module ViewComponent
123
123
  slot_instance = args.present? ? slot_class.new(**args) : slot_class.new
124
124
 
125
125
  # Capture block and assign to slot_instance#content
126
- # rubocop:disable Rails/OutputSafety
127
- slot_instance.content = view_context.capture(&block).to_s.strip.html_safe if block_given?
126
+ slot_instance.content = view_context.capture(&block).to_s.strip.html_safe if block
128
127
 
129
128
  if slot[:collection]
130
129
  # Initialize instance variable as an empty array
@@ -9,7 +9,7 @@ module ViewComponent
9
9
 
10
10
  RESERVED_NAMES = {
11
11
  singular: %i[content render].freeze,
12
- plural: %i[contents renders].freeze,
12
+ plural: %i[contents renders].freeze
13
13
  }.freeze
14
14
 
15
15
  # Setup component slot state
@@ -190,20 +190,20 @@ module ViewComponent
190
190
  # Clone slot configuration into child class
191
191
  # see #test_slots_pollution
192
192
  def inherited(child)
193
- child.registered_slots = self.registered_slots.clone
193
+ child.registered_slots = registered_slots.clone
194
194
  super
195
195
  end
196
196
 
197
197
  private
198
198
 
199
199
  def register_slot(slot_name, **kwargs)
200
- self.registered_slots[slot_name] = define_slot(slot_name, **kwargs)
200
+ registered_slots[slot_name] = define_slot(slot_name, **kwargs)
201
201
  end
202
202
 
203
203
  def define_slot(slot_name, collection:, callable:)
204
204
  # Setup basic slot data
205
205
  slot = {
206
- collection: collection,
206
+ collection: collection
207
207
  }
208
208
  return slot unless callable
209
209
 
@@ -254,7 +254,7 @@ module ViewComponent
254
254
  end
255
255
 
256
256
  def raise_if_slot_registered(slot_name)
257
- if self.registered_slots.key?(slot_name)
257
+ if registered_slots.key?(slot_name)
258
258
  # TODO remove? This breaks overriding slots when slots are inherited
259
259
  raise ArgumentError.new(
260
260
  "#{self} declares the #{slot_name} slot multiple times.\n\n" \
@@ -287,8 +287,6 @@ module ViewComponent
287
287
 
288
288
  if slot[:collection]
289
289
  []
290
- else
291
- nil
292
290
  end
293
291
  end
294
292
 
@@ -305,7 +303,7 @@ module ViewComponent
305
303
  # 2. Since we've to pass block content to components when calling
306
304
  # `render`, evaluating the block here would require us to call
307
305
  # `view_context.capture` twice, which is slower
308
- slot.__vc_content_block = block if block_given?
306
+ slot.__vc_content_block = block if block
309
307
 
310
308
  # If class
311
309
  if slot_definition[:renderable]
@@ -321,7 +319,7 @@ module ViewComponent
321
319
  # methods like `content_tag` as well as parent component state.
322
320
  renderable_function = slot_definition[:renderable_function].bind(self)
323
321
  renderable_value =
324
- if block_given?
322
+ if block
325
323
  renderable_function.call(*args) do |*rargs|
326
324
  view_context.capture(*rargs, &block)
327
325
  end
@@ -32,6 +32,9 @@ module ViewComponent
32
32
  # @private
33
33
  attr_reader :rendered_content
34
34
 
35
+ # Returns the result of a render_inline call.
36
+ #
37
+ # @return [String]
35
38
  def rendered_component
36
39
  ViewComponent::Deprecation.warn(
37
40
  "`rendered_component` is deprecated and will be removed in v3.0.0. " \
@@ -9,7 +9,7 @@ module ViewComponent
9
9
  module Translatable
10
10
  extend ActiveSupport::Concern
11
11
 
12
- HTML_SAFE_TRANSLATION_KEY = /(?:_|\b)html\z/.freeze
12
+ HTML_SAFE_TRANSLATION_KEY = /(?:_|\b)html\z/
13
13
 
14
14
  included do
15
15
  class_attribute :i18n_backend, instance_writer: false, instance_predicate: false
@@ -23,14 +23,13 @@ module ViewComponent
23
23
  def build_i18n_backend
24
24
  return if CompileCache.compiled? self
25
25
 
26
- if (translation_files = _sidecar_files(%w[yml yaml])).any?
27
- self.i18n_backend = I18nBackend.new(
26
+ self.i18n_backend = if (translation_files = _sidecar_files(%w[yml yaml])).any?
27
+ # Returning nil cleans up if translations file has been removed since the last compilation
28
+
29
+ I18nBackend.new(
28
30
  i18n_scope: i18n_scope,
29
- load_paths: translation_files,
31
+ load_paths: translation_files
30
32
  )
31
- else
32
- # Cleanup if translations file has been removed since the last compilation
33
- self.i18n_backend = nil
34
33
  end
35
34
  end
36
35
  end
@@ -50,7 +49,7 @@ module ViewComponent
50
49
 
51
50
  def scope_data(data)
52
51
  @i18n_scope.reverse_each do |part|
53
- data = { part => data }
52
+ data = {part => data}
54
53
  end
55
54
  data
56
55
  end
@@ -95,7 +94,7 @@ module ViewComponent
95
94
  super(key, locale: locale, **options)
96
95
  end
97
96
  end
98
- alias :t :translate
97
+ alias_method :t, :translate
99
98
 
100
99
  # Exposes .i18n_scope as an instance method
101
100
  def i18n_scope
@@ -109,7 +108,7 @@ module ViewComponent
109
108
  # It's assumed here that objects loaded by the i18n backend will respond to `#html_safe?`.
110
109
  # It's reasonable that if we're in Rails, `active_support/core_ext/string/output_safety.rb`
111
110
  # will provide this to `Object`.
112
- translation.html_safe # rubocop:disable Rails/OutputSafety
111
+ translation.html_safe
113
112
  end
114
113
  end
115
114
 
@@ -3,8 +3,8 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 56
7
- PATCH = 2
6
+ MINOR = 58
7
+ PATCH = 0
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.56.2
4
+ version: 2.58.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-02 00:00:00.000000000 Z
11
+ date: 2022-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -185,19 +185,19 @@ dependencies:
185
185
  - !ruby/object:Gem::Version
186
186
  version: '13.0'
187
187
  - !ruby/object:Gem::Dependency
188
- name: rubocop-github
188
+ name: standard
189
189
  requirement: !ruby/object:Gem::Requirement
190
190
  requirements:
191
191
  - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: 0.16.1
193
+ version: '1'
194
194
  type: :development
195
195
  prerelease: false
196
196
  version_requirements: !ruby/object:Gem::Requirement
197
197
  requirements:
198
198
  - - "~>"
199
199
  - !ruby/object:Gem::Version
200
- version: 0.16.1
200
+ version: '1'
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: simplecov
203
203
  requirement: !ruby/object:Gem::Requirement