view_component 4.0.2 → 4.12.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.
@@ -21,11 +21,39 @@ module ViewComponent
21
21
 
22
22
  class File < Template
23
23
  def initialize(component:, details:, path:)
24
+ # If the template file has no format (e.g. .erb instead of .html.erb),
25
+ # assume the default format (html).
26
+ if details.format.nil?
27
+ Kernel.warn("WARNING: Template format for #{path} is missing, defaulting to :html.")
28
+ details = ActionView::TemplateDetails.new(details.locale, details.handler, DEFAULT_FORMAT, details.variant)
29
+ end
30
+
31
+ @strip_annotation_line = false
32
+
33
+ # Rails 8.1 added a newline to compiled ERB output (rails/rails#53731).
34
+ # Use -1 to compensate for correct line numbers in stack traces.
35
+ # However, negative line numbers cause segfaults when Ruby's coverage
36
+ # is enabled (bugs.ruby-lang.org/issues/19363). In that case, strip the
37
+ # annotation line from compiled source instead.
38
+ lineno =
39
+ if Rails::VERSION::MAJOR >= 8 && Rails::VERSION::MINOR > 0 && details.handler == :erb
40
+ if coverage_running?
41
+ # Can't use negative lineno with coverage (causes segfault on Linux).
42
+ # Strip annotation line if enabled to preserve correct line numbers.
43
+ @strip_annotation_line = ActionView::Base.annotate_rendered_view_with_filenames
44
+ 0
45
+ else
46
+ -1
47
+ end
48
+ else
49
+ 0
50
+ end
51
+
24
52
  super(
25
53
  component: component,
26
54
  details: details,
27
55
  path: path,
28
- lineno: 0
56
+ lineno: lineno
29
57
  )
30
58
  end
31
59
 
@@ -37,6 +65,16 @@ module ViewComponent
37
65
  def source
38
66
  ::File.read(@path)
39
67
  end
68
+
69
+ private
70
+
71
+ def compiled_source
72
+ result = super
73
+ # Strip the annotation line to maintain correct line numbers when coverage
74
+ # is running (avoids segfault from negative lineno)
75
+ result = result.partition(";").last if @strip_annotation_line
76
+ result
77
+ end
40
78
  end
41
79
 
42
80
  class Inline < Template
@@ -45,11 +83,22 @@ module ViewComponent
45
83
  def initialize(component:, inline_template:)
46
84
  details = ActionView::TemplateDetails.new(nil, inline_template.language.to_sym, nil, nil)
47
85
 
86
+ # Rails 8.1 added a newline to compiled ERB output (rails/rails#53731).
87
+ # Subtract 1 to compensate for correct line numbers in stack traces.
88
+ # Inline templates start at line 2+ (defined inside a class), so this
89
+ # won't result in negative line numbers that cause segfaults with coverage.
90
+ lineno =
91
+ if Rails::VERSION::MAJOR >= 8 && Rails::VERSION::MINOR > 0 && details.handler == :erb
92
+ inline_template.lineno - 1
93
+ else
94
+ inline_template.lineno
95
+ end
96
+
48
97
  super(
49
98
  component: component,
50
99
  details: details,
51
100
  path: inline_template.path,
52
- lineno: inline_template.lineno,
101
+ lineno: lineno,
53
102
  )
54
103
 
55
104
  @source = inline_template.source.dup
@@ -108,6 +157,10 @@ module ViewComponent
108
157
  @component.define_method(safe_method_name, @component.instance_method(@call_method_name))
109
158
  end
110
159
 
160
+ def coverage_running?
161
+ defined?(Coverage) && Coverage.running?
162
+ end
163
+
111
164
  def safe_method_name_call
112
165
  m = safe_method_name
113
166
  proc { send(m) }
@@ -35,12 +35,13 @@ module ViewComponent
35
35
  # ```
36
36
  #
37
37
  # @param component [ViewComponent::Base, ViewComponent::Collection] The instance of the component to be rendered.
38
+ #
38
39
  # @return [Nokogiri::HTML5]
39
40
  def render_inline(component, **args, &block)
40
41
  @page = nil
41
42
  @rendered_content = vc_test_view_context.render(component, args, &block)
42
43
 
43
- fragment = Nokogiri::HTML5.fragment(@rendered_content)
44
+ fragment = Nokogiri::HTML5.fragment(@rendered_content, context: "template")
44
45
  @vc_test_view_context = nil
45
46
  fragment
46
47
  end
@@ -71,17 +72,18 @@ module ViewComponent
71
72
  # assert_text("Hello, World!")
72
73
  # ```
73
74
  #
74
- # Note: `#rendered_preview` expects a preview to be defined with the same class
75
- # name as the calling test, but with `Test` replaced with `Preview`:
76
- #
77
- # MyComponentTest -> MyComponentPreview etc.
78
- #
79
- # In RSpec, `Preview` is appended to `described_class`.
80
- #
81
75
  # @param name [String] The name of the preview to be rendered.
82
76
  # @param from [ViewComponent::Preview] The class of the preview to be rendered.
83
77
  # @param params [Hash] Parameters to be passed to the preview.
78
+ #
84
79
  # @return [Nokogiri::HTML5]
80
+ #
81
+ # @note `#rendered_preview` expects a preview to be defined with the same class
82
+ # name as the calling test, but with `Test` replaced with `Preview`:
83
+ #
84
+ # MyComponentTest -> MyComponentPreview etc.
85
+ #
86
+ # In RSpec, `Preview` is appended to `described_class`.
85
87
  def render_preview(name, from: __vc_test_helpers_preview_class, params: {})
86
88
  previews_controller = __vc_test_helpers_build_controller(Rails.application.config.view_component.previews.controller.constantize)
87
89
 
@@ -125,7 +127,7 @@ module ViewComponent
125
127
  # end
126
128
  # ```
127
129
  #
128
- # @param variants [Symbol[]] The variants to be set for the provided block.
130
+ # @param variants [Array<Symbol>] The variants to be set for the provided block.
129
131
  def with_variant(*variants)
130
132
  old_variants = vc_test_controller.view_context.lookup_context.variants
131
133
 
@@ -162,7 +164,7 @@ module ViewComponent
162
164
  # end
163
165
  # ```
164
166
  #
165
- # @param formats [Symbol[]] The format(s) to be set for the provided block.
167
+ # @param formats [Array<Symbol>] The format(s) to be set for the provided block.
166
168
  def with_format(*formats)
167
169
  old_formats = vc_test_controller.view_context.lookup_context.formats
168
170
 
@@ -196,10 +198,19 @@ module ViewComponent
196
198
  # end
197
199
  # ```
198
200
  #
201
+ # To specify a protocol, pass the protocol param:
202
+ #
203
+ # ```ruby
204
+ # with_request_url("/users/42", protocol: :https) do
205
+ # render_inline(MyComponent.new)
206
+ # end
207
+ # ```
208
+ #
199
209
  # @param full_path [String] The path to set for the current request.
200
210
  # @param host [String] The host to set for the current request.
201
211
  # @param method [String] The request method to set for the current request.
202
- def with_request_url(full_path, host: nil, method: nil)
212
+ # @param protocol [Symbol] The protocol to set for the current request (e.g., `:http` or `:https`).
213
+ def with_request_url(full_path, host: nil, method: nil, protocol: nil)
203
214
  old_request_host = vc_test_request.host
204
215
  old_request_method = vc_test_request.request_method
205
216
  old_request_path_info = vc_test_request.path_info
@@ -207,6 +218,7 @@ module ViewComponent
207
218
  old_request_query_parameters = vc_test_request.query_parameters
208
219
  old_request_query_string = vc_test_request.query_string
209
220
  old_request_format = vc_test_request.format.symbol
221
+ old_request_scheme = vc_test_request.scheme
210
222
  old_controller = defined?(@vc_test_controller) && @vc_test_controller
211
223
 
212
224
  path, query = full_path.split("?", 2)
@@ -214,6 +226,7 @@ module ViewComponent
214
226
  vc_test_request.instance_variable_set(:@original_fullpath, full_path)
215
227
  vc_test_request.host = host if host
216
228
  vc_test_request.request_method = method if method
229
+ vc_test_request.set_header(Rack::RACK_URL_SCHEME, protocol.to_s) if protocol
217
230
  vc_test_request.path_info = path
218
231
  vc_test_request.path_parameters = Rails.application.routes.recognize_path_with_request(vc_test_request, path, {})
219
232
  vc_test_request.set_header("action_dispatch.request.query_parameters",
@@ -223,6 +236,7 @@ module ViewComponent
223
236
  ensure
224
237
  vc_test_request.host = old_request_host
225
238
  vc_test_request.request_method = old_request_method
239
+ vc_test_request.set_header(Rack::RACK_URL_SCHEME, old_request_scheme)
226
240
  vc_test_request.path_info = old_request_path_info
227
241
  vc_test_request.path_parameters = old_request_path_parameters
228
242
  vc_test_request.set_header("action_dispatch.request.query_parameters", old_request_query_parameters)
@@ -3,8 +3,8 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 4
6
- MINOR = 0
7
- PATCH = 2
6
+ MINOR = 12
7
+ PATCH = 0
8
8
  PRE = nil
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
@@ -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.0.2
4
+ version: 4.12.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.1'
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.1'
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.10
131
139
  specification_version: 4
132
140
  summary: A framework for building reusable, testable & encapsulated view components
133
141
  in Ruby on Rails.