view_component 4.1.0 → 4.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 819e2fcc432b7272d23885e2ea361725b7eae87f4aeb216b2100500cadfd1ffc
4
- data.tar.gz: 3958ff12852ee60b017ddeea924073bf7a787efe70d47929e692726fcd791adb
3
+ metadata.gz: 761d9451b4af2b617182339d3a356985d119be9ff490018815d9affd6ede89dc
4
+ data.tar.gz: 508b8e0699e11bbed4f649cebc9df0015e08e45b1cf92c1c528f13d566422c79
5
5
  SHA512:
6
- metadata.gz: ef854e693634333b5843a3cfb13f02271775c05856af79e439335f6154b2be9b4781fd4fa0a931eaad7f928048e9232cbd764dffc87fd64ee1730ec3c3af169c
7
- data.tar.gz: 15300b4f6d30eaa481210993b6ff17cdfb5647498af89a25d951a961bbc6fe48c400dff287574ccf51f0c742d8dc753fd7ae6b753fe278af67b29bb95e0c315d
6
+ metadata.gz: 4820e68ab750d1c89901c2244527e8896d42a270afb20d8add4c0437fab80d7f4623e9da3817baafda390d94c77c0d5e79959f95772fedc571b132565fcd8bca
7
+ data.tar.gz: 1a3118de2ce98910b40ba370b13618083c396565a7b2db128eea39de7263c2d17240865caf2f94c7e83ee9113537cd5d18f6b6c3c80e137d5f5e15f1f823ba17
data/docs/CHANGELOG.md CHANGED
@@ -10,15 +10,131 @@ nav_order: 6
10
10
 
11
11
  ## main
12
12
 
13
+ ## 4.6.0
14
+
15
+ * Add `view_identifier` to the `render.view_component` instrumentation event payload, containing the path to the component's template file (e.g. `app/components/my_component.html.erb`). For components using inline render methods, `view_identifier` will be `nil`.
16
+
17
+ *GitHub Copilot*
18
+
19
+ * Replace deprecated `require_dependency` with `require` in preview loading.
20
+
21
+ *GitHub Copilot*
22
+
23
+ * Return `html_safe` empty string from `render_in` when `render?` is false.
24
+
25
+ *Copilot*
26
+
27
+ ## 4.5.0
28
+
29
+ * Fix initialization ordering issue causing missing asset errors in Sprockets.
30
+
31
+ *Cameron Dutro*
32
+
33
+ ## 4.4.0
34
+
35
+ * Fix segfaults when Ruby coverage is enabled.
36
+
37
+ *George Holborn*, *Joel Hawksley*
38
+
39
+ * Add `protocol` parameter to `with_request_url` test helper to enable testing with HTTPS protocol.
40
+
41
+ *Joel Hawksley*
42
+
43
+ ## 4.3.0
44
+
45
+ * Fix load order issues for 3rd-party template handlers.
46
+
47
+ *Cameron Dutro*
48
+
49
+ * Fix segfault when Ruby coverage is enabled with Rails 8.1 ERB templates.
50
+
51
+ *George Holborn*
52
+
53
+ * Automatically merge dependabot PRs.
54
+
55
+ *Joel Hawksley*
56
+
57
+ * Use Ruby 4.0.0 in CI and dev.
58
+
59
+ *Joel Hawksley*
60
+
61
+ ## 4.2.0
62
+
63
+ * Fix translation scope resolution in deeply nested component blocks (3+ levels). Translations called inside deeply nested slot blocks using `renders_many`/`renders_one` were incorrectly resolving to an intermediate component's scope instead of the partial's scope where the block was defined. The fix captures the virtual path at block definition time and restores it during block execution, ensuring translations always resolve relative to where the block was created regardless of nesting depth.
64
+
65
+ *Nathaniel Watts*
66
+
67
+ * Allow `render_inline` with Nokogiri::HTML5 to parse more arbitrary content including bare table content otherwise illegal fragments like `<td>`.
68
+
69
+ *Jonathan Rochkind*
70
+
71
+ * Remove known issue from docs as ActiveScaffold is [now compatible](https://github.com/activescaffold/active_scaffold/pull/743) with ViewComponent.
72
+
73
+ *David Löwenfels*
74
+
75
+ * Add test to document the current behavior for resolving relative translation keys within partial blocks. When rendering a partial, relative translation keys are resolved relative to the partial's own path rather than the caller’s path. This test ensures that this behavior remains consistent.
76
+
77
+ *Oussama Hilal*
78
+
79
+ * Allow I18n calls in `render?`.
80
+
81
+ *23tux*
82
+
83
+ * ViewComponent now works without `rails` and `railties` gems loaded, enabling compatibility with Bridgetown 2.0.
84
+
85
+ *Tom Lord*
86
+
87
+ * Capture partial block in the component's context, allowing access to the component instance inside the block.
88
+
89
+ *23tux*
90
+
91
+ * Add `after_compile` class method hook to enable extensions to run logic after component compilation.
92
+
93
+ *Jose Solás*
94
+
95
+ * Fix outdated reference to preview layout configuration in docs.
96
+
97
+ *Lucas Geron*
98
+
99
+ * Allow ruby-head CI job to fail without failing workflow.
100
+
101
+ *Hakan Ensari*
102
+
103
+ * Fix bug where error line numbers were incorrect in Rails 8.1.
104
+
105
+ *Joel Hawksley*
106
+
107
+ * Remove `< 8.2` upper bound for `activesupport` and `actionview` dependencies.
108
+
109
+ *Hans Lemuet*
110
+
111
+ * Test compatibility with Herb/ReActionView.
112
+
113
+ *Joel Hawksley*
114
+
115
+ * Remove Who Uses ViewComponent section from docs.
116
+
117
+ *Joel Hawksley*
118
+
119
+ ## 4.1.1
120
+
121
+ * Resolve deprecation warning for `ActiveSupport::Configurable`.
122
+
123
+ *Simon Fish*
124
+
125
+ * Make `ViewComponent::VERSION` accessible to other gems by default.
126
+
127
+ *Hans Lemuet*
128
+
13
129
  ## 4.1.0
14
130
 
15
131
  * Add Rails 8.1 support.
16
132
 
17
133
  *Hans Lemuet*
18
134
 
19
- * Add Carwow to list of companies using ViewComponent.
135
+ * Declare `actionview` as a `view_component` gem dependency.
20
136
 
21
- *Tom Lord*
137
+ *Michal Cichra*
22
138
 
23
139
  ## 4.0.2
24
140
 
@@ -498,10 +614,6 @@ This release makes the following breaking changes:
498
614
 
499
615
  *Martin Meyerhoff*, *Joel Hawksley*
500
616
 
501
- * Add Content Harmony & Learn To Be to list of companies using ViewComponent.
502
-
503
- *Kane Jamison*
504
-
505
617
  * Clarify error message about render-dependent logic.
506
618
 
507
619
  Error messages about render-dependent logic were sometimes inaccurate, saying `during initialization` despite also being raised after a component had been initialized but before it was rendered.
@@ -520,10 +632,6 @@ This release makes the following breaking changes:
520
632
 
521
633
  *Reegan Viljoen*
522
634
 
523
- * Add HomeStyler AI to list of companies using ViewComponent.
524
-
525
- *JP Balarini*
526
-
527
635
  ## 3.21.0
528
636
 
529
637
  * Updates testing docs to include an example of how to use with RSpec.
@@ -534,10 +642,6 @@ This release makes the following breaking changes:
534
642
 
535
643
  *KAWAKAMI Moeki*
536
644
 
537
- * Add FreeATS to list of companies using ViewComponent.
538
-
539
- *Ilia Liamshin*
540
-
541
645
  * Ensure HTML output safety wrapper is used for all inline templates.
542
646
 
543
647
  *Joel Hawksley*
@@ -588,10 +692,6 @@ This release makes the following breaking changes:
588
692
 
589
693
  *Blake Williams*
590
694
 
591
- * Add [Niva]([niva.co](https://www.niva.co/)) to companies who use `ViewComponent`.
592
-
593
- *Daniel Vu Dao*
594
-
595
695
  * Fix `preview_paths` in docs.
596
696
 
597
697
  *Javier Aranda*
@@ -656,10 +756,6 @@ This release makes the following breaking changes:
656
756
 
657
757
  *Joel Hawksley*
658
758
 
659
- * Add Kicksite to list of companies using ViewComponent.
660
-
661
- *Adil Lari*
662
-
663
759
  * Allow overridden slot methods to use `super`.
664
760
 
665
761
  *Andrew Schwartz*
@@ -899,10 +995,6 @@ This release makes the following breaking changes:
899
995
 
900
996
  *Simon Fish*
901
997
 
902
- * Add Simundia to list of companies using ViewComponent.
903
-
904
- *Alexandre Ignjatovic*
905
-
906
998
  * Reduce UnboundMethod objects by memoizing initialize_parameters.
907
999
 
908
1000
  *Rainer Borene*
@@ -953,10 +1045,6 @@ This release makes the following breaking changes:
953
1045
 
954
1046
  *milk1000cc*
955
1047
 
956
- * Add PeopleForce to list of companies using ViewComponent.
957
-
958
- *Volodymyr Khandiuk*
959
-
960
1048
  ## 3.5.0
961
1049
 
962
1050
  * Add Skroutz to users list.
@@ -1031,14 +1119,6 @@ This release makes the following breaking changes:
1031
1119
 
1032
1120
  *Joel Hawksley*
1033
1121
 
1034
- * Add Ophelos to list of companies using ViewComponent.
1035
-
1036
- *Graham Rogers*
1037
-
1038
- * Add FlightLogger to list of companies using ViewComponent.
1039
-
1040
- *Joseph Carpenter*
1041
-
1042
1122
  * Fix coverage reports overwriting each other when running locally.
1043
1123
 
1044
1124
  *Jonathan del Strother*
@@ -1278,14 +1358,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1278
1358
 
1279
1359
  *Graham Rogers*
1280
1360
 
1281
- * Add Krystal to list of companies using ViewComponent.
1282
-
1283
- *Matt Bearman*
1284
-
1285
- * Add Mon Ami to list of companies using ViewComponent.
1286
-
1287
- *Ethan Lee-Tyson*
1288
-
1289
1361
  ## 3.0.0.rc1
1290
1362
 
1291
1363
  1,000+ days and 100+ releases later, the 200+ contributors to ViewComponent are proud to ship v3.0.0!
@@ -1434,10 +1506,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1434
1506
 
1435
1507
  *Hans Lemuet*
1436
1508
 
1437
- * Add Startup Jobs to list of companies using ViewComponent.
1438
-
1439
- *Marc Köhlbrugge*
1440
-
1441
1509
  * Run PVC's accessibility tests in a single process to avoid resource contention in CI.
1442
1510
 
1443
1511
  *Cameron Dutro*
@@ -1478,10 +1546,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1478
1546
 
1479
1547
  ## 2.74.0
1480
1548
 
1481
- * Add Avo to list of companies using ViewComponent.
1482
-
1483
- *Adrian Marin*
1484
-
1485
1549
  * Promote experimental `_output_postamble` method to public API as `output_postamble`.
1486
1550
 
1487
1551
  *Joel Hawksley*
@@ -1508,10 +1572,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1508
1572
 
1509
1573
  *Erinna Chen*
1510
1574
 
1511
- * Add PrintReleaf to list of companies using ViewComponent.
1512
-
1513
- *Ry Kulp*
1514
-
1515
1575
  * Simplify CI configuration to a single build per Ruby/Rails version.
1516
1576
 
1517
1577
  *Joel Hawksley*
@@ -1520,10 +1580,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1520
1580
 
1521
1581
  *Ruben Smit*
1522
1582
 
1523
- * Add Yobbers to list of companies using ViewComponent.
1524
-
1525
- *Anton Prins*
1526
-
1527
1583
  ## 2.72.0
1528
1584
 
1529
1585
  * Deprecate support for Ruby < 2.7 for removal in v3.0.0.
@@ -1538,10 +1594,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1538
1594
 
1539
1595
  *Joel Hawksley.
1540
1596
 
1541
- * Add Aluuno to list of companies using ViewComponent.
1542
-
1543
- *Daniel Naves de Carvalho*
1544
-
1545
1597
  * Add `source_code_uri` to gemspec.
1546
1598
 
1547
1599
  *Yoshiyuki Hirano*
@@ -1576,22 +1628,10 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1576
1628
 
1577
1629
  *Joel Hawksley*
1578
1630
 
1579
- * Add Arrows to list of companies using ViewComponent.
1580
-
1581
- *Matt Swanson*
1582
-
1583
- * Add WIP to list of companies using ViewComponent.
1584
-
1585
- *Marc Köhlbrugge*
1586
-
1587
1631
  * Update slots documentation to include how to reference slots.
1588
1632
 
1589
1633
  *Brittany Ellich*
1590
1634
 
1591
- * Add Clio to list of companies using ViewComponent.
1592
-
1593
- *Mike Buckley*
1594
-
1595
1635
  ## 2.69.0
1596
1636
 
1597
1637
  * Add missing `require` to fix `pvc` build.
@@ -1709,10 +1749,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1709
1749
 
1710
1750
  *Vikram Dighe*
1711
1751
 
1712
- * Add HappyCo to list of companies using ViewComponent.
1713
-
1714
- *Josh Clayton*
1715
-
1716
1752
  * Add predicate method support to polymorphic slots.
1717
1753
 
1718
1754
  *Graham Rogers*
@@ -1823,10 +1859,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1823
1859
 
1824
1860
  *Thomas Hutterer*
1825
1861
 
1826
- * Add FreeAgent to list of companies using ViewComponent.
1827
-
1828
- *Simon Fish*
1829
-
1830
1862
  * Include polymorphic slots in `ViewComponent::Base` by default.
1831
1863
 
1832
1864
  *Cameron Dutro*
@@ -1882,18 +1914,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1882
1914
 
1883
1915
  *Joel Hawksley*
1884
1916
 
1885
- * Add G2 to list of companies that use ViewComponent.
1886
-
1887
- *Jack Shuff*
1888
-
1889
- * Add Within3 to list of companies that use ViewComponent.
1890
-
1891
- *Drew Bragg*
1892
-
1893
- * Add Mission Met to list of companies that use ViewComponent.
1894
-
1895
- *Nick Smith*
1896
-
1897
1917
  * Fix `#with_request_url` test helper not parsing nested query parameters into nested hashes.
1898
1918
 
1899
1919
  *Richard Marbach*
@@ -1933,10 +1953,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1933
1953
 
1934
1954
  *Blake Williams*
1935
1955
 
1936
- * Add QuickNode to list of companies that use ViewComponent.
1937
-
1938
- *Luc Castera*
1939
-
1940
1956
  * Include the `Translatable` module by default.
1941
1957
 
1942
1958
  *Elia Schito*
@@ -1967,10 +1983,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
1967
1983
 
1968
1984
  *Jason Swett*
1969
1985
 
1970
- * Add Bearer to list of companies that use ViewComponent.
1971
-
1972
- *Yaroslav Shmarov*
1973
-
1974
1986
  * Add articles to resources page.
1975
1987
 
1976
1988
  *Joel Hawksley*
@@ -2000,10 +2012,6 @@ Run into an issue with this release? [Let us know](https://github.com/ViewCompon
2000
2012
 
2001
2013
  *Hans Lemuet*
2002
2014
 
2003
- * Alphabetize companies using ViewComponent and add Brightline to the list.
2004
-
2005
- *Jack Schuss*
2006
-
2007
2015
  * Add CMYK value for ViewComponent Red color on logo page.
2008
2016
 
2009
2017
  *Dylan Smith*
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "action_view"
4
- require "active_support/configurable"
4
+ require "action_view/base"
5
5
  require "view_component/collection"
6
6
  require "view_component/compile_cache"
7
7
  require "view_component/compiler"
@@ -47,7 +47,7 @@ module ViewComponent
47
47
  end
48
48
 
49
49
  include ActionView::Helpers
50
- include Rails.application.routes.url_helpers if defined?(Rails) && Rails.application
50
+ include Rails.application.routes.url_helpers if defined?(Rails.application.routes)
51
51
  include ERB::Escape
52
52
  include ActiveSupport::CoreExt::ERBUtil
53
53
 
@@ -132,6 +132,7 @@ module ViewComponent
132
132
 
133
133
  @__vc_content_evaluated = false
134
134
  @__vc_render_in_block = block
135
+ @view_context.instance_variable_set(:@virtual_path, virtual_path)
135
136
 
136
137
  before_render
137
138
 
@@ -139,8 +140,6 @@ module ViewComponent
139
140
  value = nil
140
141
 
141
142
  @output_buffer.with_buffer do
142
- @view_context.instance_variable_set(:@virtual_path, virtual_path)
143
-
144
143
  rendered_template =
145
144
  around_render do
146
145
  render_template_for(@__vc_requested_details).to_s
@@ -161,7 +160,7 @@ module ViewComponent
161
160
 
162
161
  value
163
162
  else
164
- ""
163
+ "".html_safe
165
164
  end
166
165
  ensure
167
166
  view_context.instance_variable_set(:@virtual_path, @old_virtual_path)
@@ -261,6 +260,9 @@ module ViewComponent
261
260
  @view_context.render(options, args, &block)
262
261
  elsif block
263
262
  __vc_original_view_context.render(options, args) do
263
+ # capture the block output in the view context of the component
264
+ output = capture(&block)
265
+
264
266
  # Partials are rendered to their own buffer and do not append to the
265
267
  # original @output_buffer we retain a reference to in #render_in. This
266
268
  # is a problem since the block passed to us here in the #render method
@@ -268,7 +270,7 @@ module ViewComponent
268
270
  # appends to the original @output_buffer. To avoid this, we evaluate the
269
271
  # block in the view context instead, which will append to the output buffer
270
272
  # created for the partial.
271
- __vc_original_view_context.instance_exec(&block)
273
+ __vc_original_view_context.capture { output }
272
274
  end
273
275
  else
274
276
  __vc_original_view_context.render(options, args)
@@ -302,7 +304,7 @@ module ViewComponent
302
304
  @__vc_helpers ||= __vc_original_view_context || controller.view_context
303
305
  end
304
306
 
305
- if ::Rails.env.development? || ::Rails.env.test?
307
+ if defined?(Rails.env) && (::Rails.env.development? || ::Rails.env.test?)
306
308
  # @private
307
309
  def method_missing(method_name, *args) # rubocop:disable Style/MissingRespondToMissing
308
310
  super
@@ -331,7 +333,7 @@ module ViewComponent
331
333
  []
332
334
  end
333
335
 
334
- if Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR == 1
336
+ if defined?(Rails::VERSION) && Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR == 1
335
337
  # Rails expects us to define `format` on all renderables,
336
338
  # but we do not know the `format` of a ViewComponent until runtime.
337
339
  def format
@@ -362,7 +364,7 @@ module ViewComponent
362
364
 
363
365
  @__vc_content =
364
366
  if __vc_render_in_block_provided?
365
- with_original_virtual_path do
367
+ with_captured_virtual_path(@old_virtual_path) do
366
368
  view_context.capture(self, &@__vc_render_in_block)
367
369
  end
368
370
  elsif __vc_content_set_by_with_content_defined?
@@ -378,11 +380,14 @@ module ViewComponent
378
380
  end
379
381
 
380
382
  # @private
381
- def with_original_virtual_path
382
- @view_context.instance_variable_set(:@virtual_path, @old_virtual_path)
383
+ # Temporarily sets the virtual path to the captured value, then restores it.
384
+ # This ensures translations and other path-dependent code execute with the correct scope.
385
+ def with_captured_virtual_path(captured_path)
386
+ old_virtual_path = @view_context.instance_variable_get(:@virtual_path)
387
+ @view_context.instance_variable_set(:@virtual_path, captured_path)
383
388
  yield
384
389
  ensure
385
- @view_context.instance_variable_set(:@virtual_path, virtual_path)
390
+ @view_context.instance_variable_set(:@virtual_path, old_virtual_path)
386
391
  end
387
392
 
388
393
  private
@@ -573,7 +578,7 @@ module ViewComponent
573
578
  # eager loading is disabled and the parent component is rendered before the child. In
574
579
  # such a scenario, the parent will override ViewComponent::Base#render_template_for,
575
580
  # meaning it will not be called for any children and thus not compile their templates.
576
- if !child.instance_methods(false).include?(:render_template_for) && !child.__vc_compiled?
581
+ if !child.method_defined?(:render_template_for, false) && !child.__vc_compiled?
577
582
  child.class_eval <<~RUBY, __FILE__, __LINE__ + 1
578
583
  def render_template_for(requested_details)
579
584
  # Force compilation here so the compiler always redefines render_template_for.
@@ -596,7 +601,7 @@ module ViewComponent
596
601
  # Set collection parameter to the extended component
597
602
  child.with_collection_parameter(__vc_provided_collection_parameter)
598
603
 
599
- if instance_methods(false).include?(:render_template_for)
604
+ if method_defined?(:render_template_for, false)
600
605
  vc_ancestor_calls = defined?(@__vc_ancestor_calls) ? @__vc_ancestor_calls.dup : []
601
606
 
602
607
  vc_ancestor_calls.unshift(instance_method(:render_template_for))
@@ -611,6 +616,16 @@ module ViewComponent
611
616
  __vc_compiler.compiled?
612
617
  end
613
618
 
619
+ # Hook called by the compiler after a component is compiled.
620
+ #
621
+ # Extensions can override this class method to run logic after
622
+ # compilation (e.g., generate helpers, register metadata, etc.).
623
+ #
624
+ # By default, this is a no-op.
625
+ def after_compile
626
+ # no-op by default
627
+ end
628
+
614
629
  # @private
615
630
  def __vc_ensure_compiled
616
631
  __vc_compile unless __vc_compiled?
@@ -20,7 +20,7 @@ module ViewComponent
20
20
  components.each(&block)
21
21
  end
22
22
 
23
- if Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR == 1
23
+ if defined?(Rails::VERSION) && Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR == 1
24
24
  # Rails expects us to define `format` on all renderables,
25
25
  # but we do not know the `format` of a ViewComponent until runtime.
26
26
  def format
@@ -52,6 +52,8 @@ module ViewComponent
52
52
  @component.__vc_build_i18n_backend
53
53
 
54
54
  CompileCache.register(@component)
55
+
56
+ @component.after_compile
55
57
  end
56
58
  end
57
59
 
@@ -113,11 +115,11 @@ module ViewComponent
113
115
  .tally
114
116
  .select { |_, count| count > 1 }
115
117
  .each do |tally|
116
- variant, this_format = tally.first
118
+ variant, this_format = tally.first
117
119
 
118
- variant_string = " for variant `#{variant}`" if variant.present?
120
+ variant_string = " for variant `#{variant}`" if variant.present?
119
121
 
120
- errors << "More than one #{this_format.upcase} template found#{variant_string} for #{@component}. "
122
+ errors << "More than one #{this_format.upcase} template found#{variant_string} for #{@component}. "
121
123
  end
122
124
 
123
125
  default_template_types = @templates.each_with_object(Set.new) do |template, memo|
@@ -188,11 +190,11 @@ module ViewComponent
188
190
  ).flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) }
189
191
  .uniq
190
192
  .each do |method_name|
191
- templates << Template::InlineCall.new(
192
- component: @component,
193
- method_name: method_name,
194
- defined_on_self: component_instance_methods_on_self.include?(method_name)
195
- )
193
+ templates << Template::InlineCall.new(
194
+ component: @component,
195
+ method_name: method_name,
196
+ defined_on_self: component_instance_methods_on_self.include?(method_name)
197
+ )
196
198
  end
197
199
 
198
200
  templates
@@ -163,7 +163,7 @@ module ViewComponent
163
163
  options = ActiveSupport::OrderedOptions.new
164
164
  options.controller = "ViewComponentsController"
165
165
  options.route = "/rails/view_components"
166
- options.enabled = Rails.env.development? || Rails.env.test?
166
+ options.enabled = defined?(Rails.env) && (Rails.env.development? || Rails.env.test?)
167
167
  options.default_layout = nil
168
168
  options.paths = default_preview_paths
169
169
  options
@@ -4,14 +4,30 @@ module ViewComponent
4
4
  module Configurable
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ class_methods do
8
+ def config
9
+ @_config ||= if respond_to?(:superclass) && superclass.respond_to?(:config)
10
+ superclass.config.inheritable_copy
11
+ else
12
+ ActiveSupport::OrderedOptions.new
13
+ end
14
+ end
15
+
16
+ def configure
17
+ yield config
18
+ end
19
+ end
20
+
7
21
  included do
8
22
  next if respond_to?(:config) && config.respond_to?(:view_component) && config.respond_to_missing?(:instrumentation_enabled)
9
23
 
10
- include ActiveSupport::Configurable
11
-
12
24
  configure do |config|
13
25
  config.view_component ||= ActiveSupport::InheritableOptions.new
14
26
  end
27
+
28
+ def config
29
+ self.class.config
30
+ end
15
31
  end
16
32
  end
17
33
  end
@@ -50,11 +50,13 @@ module ViewComponent
50
50
  end
51
51
  end
52
52
 
53
- config.after_initialize do |app|
53
+ config.after_routes_loaded do
54
54
  ActiveSupport.on_load(:view_component) do
55
55
  if defined?(Sprockets::Rails)
56
56
  include Sprockets::Rails::Helper
57
57
 
58
+ app = Rails.application
59
+
58
60
  # Copy relevant config to VC context
59
61
  # See: https://github.com/rails/sprockets-rails/blob/266ec49f3c7c96018dd75f9dc4f9b62fe3f7eecf/lib/sprockets/railtie.rb#L245
60
62
  self.debug_assets = app.config.assets.debug
@@ -11,15 +11,28 @@ module ViewComponent # :nodoc:
11
11
  def render_in(view_context, &block)
12
12
  return super if !Rails.application.config.view_component.instrumentation_enabled.present?
13
13
 
14
+ payload = {
15
+ name: self.class.name,
16
+ identifier: self.class.identifier,
17
+ view_identifier: nil
18
+ }
19
+
14
20
  ActiveSupport::Notifications.instrument(
15
21
  "render.view_component",
16
- {
17
- name: self.class.name,
18
- identifier: self.class.identifier
19
- }
22
+ payload
20
23
  ) do
21
- super
24
+ result = super
25
+ payload[:view_identifier] = @__vc_instrumentation_view_identifier
26
+ result
22
27
  end
28
+ ensure
29
+ @__vc_instrumentation_view_identifier = nil
30
+ end
31
+
32
+ def around_render
33
+ result = super
34
+ @__vc_instrumentation_view_identifier = current_template&.path
35
+ result
23
36
  end
24
37
  end
25
38
  end
@@ -95,7 +95,7 @@ module ViewComponent # :nodoc:
95
95
  # @private
96
96
  def __vc_load_previews
97
97
  Array(preview_paths).each do |preview_path|
98
- Dir["#{preview_path}/**/*preview.rb"].sort.each { |file| require_dependency file }
98
+ Dir["#{preview_path}/**/*preview.rb"].sort.each { |file| require file }
99
99
  end
100
100
  end
101
101
 
@@ -6,7 +6,7 @@ module ViewComponent
6
6
  class Slot
7
7
  include ViewComponent::WithContentHelper
8
8
 
9
- attr_writer :__vc_component_instance, :__vc_content_block, :__vc_content
9
+ attr_writer :__vc_component_instance, :__vc_content_block, :__vc_content, :__vc_content_block_virtual_path
10
10
 
11
11
  def initialize(parent)
12
12
  @parent = parent
@@ -58,7 +58,7 @@ module ViewComponent
58
58
  if defined?(@__vc_content_block)
59
59
  # render_in is faster than `parent.render`
60
60
  @__vc_component_instance.render_in(view_context) do |*args|
61
- @parent.with_original_virtual_path do
61
+ @parent.with_captured_virtual_path(@__vc_content_block_virtual_path) do
62
62
  @__vc_content_block.call(*args)
63
63
  end
64
64
  end
@@ -68,7 +68,7 @@ module ViewComponent
68
68
  elsif defined?(@__vc_content)
69
69
  @__vc_content
70
70
  elsif defined?(@__vc_content_block)
71
- @parent.with_original_virtual_path do
71
+ @parent.with_captured_virtual_path(@__vc_content_block_virtual_path) do
72
72
  view_context.capture(&@__vc_content_block)
73
73
  end
74
74
  elsif defined?(@__vc_content_set_by_with_content)
@@ -259,7 +259,7 @@ module ViewComponent
259
259
 
260
260
  setter_method_name = :"with_#{poly_slot_name}"
261
261
 
262
- if instance_methods.include?(setter_method_name)
262
+ if method_defined?(setter_method_name)
263
263
  raise AlreadyDefinedPolymorphicSlotSetterError.new(setter_method_name, poly_slot_name)
264
264
  end
265
265
 
@@ -390,7 +390,12 @@ module ViewComponent
390
390
  # 2. Since we have to pass block content to components when calling
391
391
  # `render`, evaluating the block here would require us to call
392
392
  # `view_context.capture` twice, which is slower
393
- slot.__vc_content_block = block if block
393
+ if block
394
+ slot.__vc_content_block = block
395
+ # Capture the virtual path at the time the block is defined, so that
396
+ # translations resolve relative to where the block was created, not where it's rendered
397
+ slot.__vc_content_block_virtual_path = view_context.instance_variable_get(:@virtual_path)
398
+ end
394
399
 
395
400
  # If class
396
401
  if slot_definition[:renderable]
@@ -408,7 +413,9 @@ module ViewComponent
408
413
  renderable_value =
409
414
  if block
410
415
  renderable_function.call(*args, **kwargs) do |*rargs|
411
- view_context.capture(*rargs, &block)
416
+ with_captured_virtual_path(@old_virtual_path) do
417
+ view_context.capture(*rargs, &block)
418
+ end
412
419
  end
413
420
  else
414
421
  renderable_function.call(*args, **kwargs)
@@ -21,11 +21,32 @@ module ViewComponent
21
21
 
22
22
  class File < Template
23
23
  def initialize(component:, details:, path:)
24
+ @strip_annotation_line = false
25
+
26
+ # Rails 8.1 added a newline to compiled ERB output (rails/rails#53731).
27
+ # Use -1 to compensate for correct line numbers in stack traces.
28
+ # However, negative line numbers cause segfaults when Ruby's coverage
29
+ # is enabled (bugs.ruby-lang.org/issues/19363). In that case, strip the
30
+ # annotation line from compiled source instead.
31
+ lineno =
32
+ if Rails::VERSION::MAJOR >= 8 && Rails::VERSION::MINOR > 0 && details.handler == :erb
33
+ if coverage_running?
34
+ # Can't use negative lineno with coverage (causes segfault on Linux).
35
+ # Strip annotation line if enabled to preserve correct line numbers.
36
+ @strip_annotation_line = ActionView::Base.annotate_rendered_view_with_filenames
37
+ 0
38
+ else
39
+ -1
40
+ end
41
+ else
42
+ 0
43
+ end
44
+
24
45
  super(
25
46
  component: component,
26
47
  details: details,
27
48
  path: path,
28
- lineno: 0
49
+ lineno: lineno
29
50
  )
30
51
  end
31
52
 
@@ -37,6 +58,16 @@ module ViewComponent
37
58
  def source
38
59
  ::File.read(@path)
39
60
  end
61
+
62
+ private
63
+
64
+ def compiled_source
65
+ result = super
66
+ # Strip the annotation line to maintain correct line numbers when coverage
67
+ # is running (avoids segfault from negative lineno)
68
+ result = result.partition(";").last if @strip_annotation_line
69
+ result
70
+ end
40
71
  end
41
72
 
42
73
  class Inline < Template
@@ -45,11 +76,22 @@ module ViewComponent
45
76
  def initialize(component:, inline_template:)
46
77
  details = ActionView::TemplateDetails.new(nil, inline_template.language.to_sym, nil, nil)
47
78
 
79
+ # Rails 8.1 added a newline to compiled ERB output (rails/rails#53731).
80
+ # Subtract 1 to compensate for correct line numbers in stack traces.
81
+ # Inline templates start at line 2+ (defined inside a class), so this
82
+ # won't result in negative line numbers that cause segfaults with coverage.
83
+ lineno =
84
+ if Rails::VERSION::MAJOR >= 8 && Rails::VERSION::MINOR > 0 && details.handler == :erb
85
+ inline_template.lineno - 1
86
+ else
87
+ inline_template.lineno
88
+ end
89
+
48
90
  super(
49
91
  component: component,
50
92
  details: details,
51
93
  path: inline_template.path,
52
- lineno: inline_template.lineno,
94
+ lineno: lineno,
53
95
  )
54
96
 
55
97
  @source = inline_template.source.dup
@@ -108,6 +150,10 @@ module ViewComponent
108
150
  @component.define_method(safe_method_name, @component.instance_method(@call_method_name))
109
151
  end
110
152
 
153
+ def coverage_running?
154
+ defined?(Coverage) && Coverage.running?
155
+ end
156
+
111
157
  def safe_method_name_call
112
158
  m = safe_method_name
113
159
  proc { send(m) }
@@ -40,7 +40,7 @@ module ViewComponent
40
40
  @page = nil
41
41
  @rendered_content = vc_test_view_context.render(component, args, &block)
42
42
 
43
- fragment = Nokogiri::HTML5.fragment(@rendered_content)
43
+ fragment = Nokogiri::HTML5.fragment(@rendered_content, context: "template")
44
44
  @vc_test_view_context = nil
45
45
  fragment
46
46
  end
@@ -196,10 +196,19 @@ module ViewComponent
196
196
  # end
197
197
  # ```
198
198
  #
199
+ # To specify a protocol, pass the protocol param:
200
+ #
201
+ # ```ruby
202
+ # with_request_url("/users/42", protocol: :https) do
203
+ # render_inline(MyComponent.new)
204
+ # end
205
+ # ```
206
+ #
199
207
  # @param full_path [String] The path to set for the current request.
200
208
  # @param host [String] The host to set for the current request.
201
209
  # @param method [String] The request method to set for the current request.
202
- def with_request_url(full_path, host: nil, method: nil)
210
+ # @param protocol [Symbol] The protocol to set for the current request (e.g., `:http` or `:https`).
211
+ def with_request_url(full_path, host: nil, method: nil, protocol: nil)
203
212
  old_request_host = vc_test_request.host
204
213
  old_request_method = vc_test_request.request_method
205
214
  old_request_path_info = vc_test_request.path_info
@@ -207,6 +216,7 @@ module ViewComponent
207
216
  old_request_query_parameters = vc_test_request.query_parameters
208
217
  old_request_query_string = vc_test_request.query_string
209
218
  old_request_format = vc_test_request.format.symbol
219
+ old_request_scheme = vc_test_request.scheme
210
220
  old_controller = defined?(@vc_test_controller) && @vc_test_controller
211
221
 
212
222
  path, query = full_path.split("?", 2)
@@ -214,6 +224,7 @@ module ViewComponent
214
224
  vc_test_request.instance_variable_set(:@original_fullpath, full_path)
215
225
  vc_test_request.host = host if host
216
226
  vc_test_request.request_method = method if method
227
+ vc_test_request.set_header(Rack::RACK_URL_SCHEME, protocol.to_s) if protocol
217
228
  vc_test_request.path_info = path
218
229
  vc_test_request.path_parameters = Rails.application.routes.recognize_path_with_request(vc_test_request, path, {})
219
230
  vc_test_request.set_header("action_dispatch.request.query_parameters",
@@ -223,6 +234,7 @@ module ViewComponent
223
234
  ensure
224
235
  vc_test_request.host = old_request_host
225
236
  vc_test_request.request_method = old_request_method
237
+ vc_test_request.set_header(Rack::RACK_URL_SCHEME, old_request_scheme)
226
238
  vc_test_request.path_info = old_request_path_info
227
239
  vc_test_request.path_parameters = old_request_path_parameters
228
240
  vc_test_request.set_header("action_dispatch.request.query_parameters", old_request_query_parameters)
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 4
6
- MINOR = 1
6
+ MINOR = 6
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "action_view"
4
4
  require "active_support/dependencies/autoload"
5
+ require "view_component/version"
5
6
 
6
7
  module ViewComponent
7
8
  extend ActiveSupport::Autoload
@@ -16,7 +17,7 @@ module ViewComponent
16
17
  autoload :Preview
17
18
  autoload :Translatable
18
19
 
19
- if Rails.env.test?
20
+ if defined?(Rails.env) && Rails.env.test?
20
21
  autoload :TestHelpers
21
22
  autoload :SystemSpecHelpers
22
23
  autoload :SystemTestHelpers
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ViewComponent Team
@@ -16,9 +16,6 @@ dependencies:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: 7.1.0
19
- - - "<"
20
- - !ruby/object:Gem::Version
21
- version: '8.2'
22
19
  type: :runtime
23
20
  prerelease: false
24
21
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,9 +23,20 @@ dependencies:
26
23
  - - ">="
27
24
  - !ruby/object:Gem::Version
28
25
  version: 7.1.0
29
- - - "<"
26
+ - !ruby/object:Gem::Dependency
27
+ name: actionview
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
30
31
  - !ruby/object:Gem::Version
31
- version: '8.2'
32
+ version: 7.1.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 7.1.0
32
40
  - !ruby/object:Gem::Dependency
33
41
  name: concurrent-ruby
34
42
  requirement: !ruby/object:Gem::Requirement
@@ -127,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
135
  - !ruby/object:Gem::Version
128
136
  version: '0'
129
137
  requirements: []
130
- rubygems_version: 3.6.9
138
+ rubygems_version: 4.0.6
131
139
  specification_version: 4
132
140
  summary: A framework for building reusable, testable & encapsulated view components
133
141
  in Ruby on Rails.