view_component 3.2.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.

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: e505722b47ce320345cbb123e06e5138362a3b9abc5fe8cc77c5849a71e8baf5
4
- data.tar.gz: c9f053e92c067b2743ae64d8135334518a14933710c81ad68e058d0cd076b610
3
+ metadata.gz: ce590ddce7011ae4362dde0733f78ba65992c31add6bac215555515d02ae1dc6
4
+ data.tar.gz: df4867599a61d2757e2f226a3c6b187981772e2d225fc442f9184484c0423e64
5
5
  SHA512:
6
- metadata.gz: 3e3aab08e8665557c94e0f8df5c7f0f484b056bc9e0a85247a7d718cedfc3ff8aa3a2a6875fd4660626b15c0f6e002ac50797fdcce822f610ca91581afff8c9e
7
- data.tar.gz: 2f25ccc3bcfefb4e3096a5c9289922b648353ba42c333ad963d59cc95f8bd1cf4d1db0f178494ad6cb4a59af6832a852b3b15f34f80dc3c2ebfa6cf78d65b445
6
+ metadata.gz: 0a39d71f089c0f4285dc1eecd324e44afc73f55565002a45c2d37292cc4fa8b05713f7237f04b530617ddc0bb2ccd08fab0c7d010400790dc00daf2d6c9c0546
7
+ data.tar.gz: 252a63a4ed7eefd7db529dc93081d3ccfb78555ac1d051540f7a69829a41d4d22fd94557fa2fe9eb88c012bd8dccfd2ceb813aae2582877e387a2df347e2d915
@@ -59,7 +59,7 @@ module ViewComponent
59
59
  def find_preview
60
60
  candidates = []
61
61
  params[:path].to_s.scan(%r{/|$}) { candidates << Regexp.last_match.pre_match }
62
- preview = candidates.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
62
+ preview = candidates.sort_by(&:length).reverse_each.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
63
63
 
64
64
  if preview
65
65
  @preview = ViewComponent::Preview.find(preview)
data/docs/CHANGELOG.md CHANGED
@@ -10,6 +10,44 @@ nav_order: 5
10
10
 
11
11
  ## main
12
12
 
13
+ ## 3.5.0
14
+
15
+ * Add Skroutz to users list.
16
+
17
+ *Chris Nitsas*
18
+
19
+ * Improve implementation of `#render_parent` so it respects variants and deep inheritance hierarchies.
20
+
21
+ *Cameron Dutro*
22
+
23
+ * Add CharlieHR to users list.
24
+
25
+ *Alex Balhatchet*
26
+
27
+ ## 3.4.0
28
+
29
+ * Avoid including Rails `url_helpers` into `Preview` class when they're not defined.
30
+
31
+ *Richard Macklin*
32
+
33
+ * Allow instrumentation to be automatically included in Server-Timing headers generated by Rails. To enable this set the config `config.use_deprecated_instrumentation_name = false`. The old key `!render.view_component` is deprecated: update ActiveSupport::Notification subscriptions to `render.view_component`.
34
+
35
+ *Travis Gaff*
36
+
37
+ ## 3.3.0
38
+
39
+ * Include InlineTemplate by default in Base. **Note:** It's no longer necessary to include `ViewComponent::InlineTemplate` to use inline templates.
40
+
41
+ *Joel Hawksley*
42
+
43
+ * Allow Setting host when using the `with_request_url` test helper.
44
+
45
+ *Daniel Alfaro*
46
+
47
+ * Resolve ambiguous preview paths when using components without the Component suffix.
48
+
49
+ *Reed Law*
50
+
13
51
  ## 3.2.0
14
52
 
15
53
  * Fix viewcomponent.org Axe violations.
@@ -7,6 +7,7 @@ require "view_component/compile_cache"
7
7
  require "view_component/compiler"
8
8
  require "view_component/config"
9
9
  require "view_component/errors"
10
+ require "view_component/inline_template"
10
11
  require "view_component/preview"
11
12
  require "view_component/slotable"
12
13
  require "view_component/translatable"
@@ -29,6 +30,7 @@ module ViewComponent
29
30
  attr_writer :config
30
31
  end
31
32
 
33
+ include ViewComponent::InlineTemplate
32
34
  include ViewComponent::Slotable
33
35
  include ViewComponent::Translatable
34
36
  include ViewComponent::WithContentHelper
@@ -114,20 +116,44 @@ module ViewComponent
114
116
  end
115
117
 
116
118
  # Subclass components that call `super` inside their template code will cause a
117
- # double render if they emit the result:
119
+ # double render if they emit the result.
118
120
  #
119
121
  # ```erb
120
122
  # <%= super %> # double-renders
121
- # <% super %> # does not double-render
123
+ # <% super %> # doesn't double-render
122
124
  # ```
123
125
  #
124
- # Calls `super`, returning `nil` to avoid rendering the result twice.
126
+ # `super` also doesn't consider the current variant. `render_parent` renders the
127
+ # parent template considering the current variant and emits the result without
128
+ # double-rendering.
125
129
  def render_parent
126
- mtd = @__vc_variant ? "call_#{@__vc_variant}" : "call"
127
- method(mtd).super_method.call
130
+ render_parent_to_string
128
131
  nil
129
132
  end
130
133
 
134
+ # Renders the parent component to a string and returns it. This method is meant
135
+ # to be used inside custom #call methods when a string result is desired, eg.
136
+ #
137
+ # ```ruby
138
+ # def call
139
+ # "<div>#{render_parent_to_string}</div>"
140
+ # end
141
+ # ```
142
+ #
143
+ # When rendering the parent inside an .erb template, use `#render_parent` instead.
144
+ def render_parent_to_string
145
+ @__vc_parent_render_level ||= 0 # ensure a good starting value
146
+
147
+ begin
148
+ target_render = self.class.instance_variable_get(:@__vc_ancestor_calls)[@__vc_parent_render_level]
149
+ @__vc_parent_render_level += 1
150
+
151
+ target_render.bind_call(self, @__vc_variant)
152
+ ensure
153
+ @__vc_parent_render_level -= 1
154
+ end
155
+ end
156
+
131
157
  # Optional content to be returned after the rendered template.
132
158
  #
133
159
  # @return [String]
@@ -457,6 +483,13 @@ module ViewComponent
457
483
  # Set collection parameter to the extended component
458
484
  child.with_collection_parameter provided_collection_parameter
459
485
 
486
+ if instance_methods(false).include?(:render_template_for)
487
+ vc_ancestor_calls = defined?(@__vc_ancestor_calls) ? @__vc_ancestor_calls.dup : []
488
+
489
+ vc_ancestor_calls.unshift(instance_method(:render_template_for))
490
+ child.instance_variable_set(:@__vc_ancestor_calls, vc_ancestor_calls)
491
+ end
492
+
460
493
  super
461
494
  end
462
495
 
@@ -56,17 +56,17 @@ module ViewComponent
56
56
  RUBY
57
57
  # rubocop:enable Style/EvalWithLocation
58
58
 
59
+ component_class.define_method("_call_#{safe_class_name}", component_class.instance_method(:call))
60
+
59
61
  component_class.silence_redefinition_of_method("render_template_for")
60
62
  component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
61
63
  def render_template_for(variant = nil)
62
- call
64
+ _call_#{safe_class_name}
63
65
  end
64
66
  RUBY
65
67
  end
66
68
  else
67
69
  templates.each do |template|
68
- # Remove existing compiled template methods,
69
- # as Ruby warns when redefining a method.
70
70
  method_name = call_method_name(template[:variant])
71
71
 
72
72
  redefinition_lock.synchronize do
@@ -95,15 +95,20 @@ module ViewComponent
95
95
 
96
96
  def define_render_template_for
97
97
  variant_elsifs = variants.compact.uniq.map do |variant|
98
- "elsif variant.to_sym == :'#{variant}'\n #{call_method_name(variant)}"
98
+ safe_name = "_call_variant_#{normalized_variant_name(variant)}_#{safe_class_name}"
99
+ component_class.define_method(safe_name, component_class.instance_method(call_method_name(variant)))
100
+
101
+ "elsif variant.to_sym == :'#{variant}'\n #{safe_name}"
99
102
  end.join("\n")
100
103
 
104
+ component_class.define_method("_call_#{safe_class_name}", component_class.instance_method(:call))
105
+
101
106
  body = <<-RUBY
102
107
  if variant.nil?
103
- call
108
+ _call_#{safe_class_name}
104
109
  #{variant_elsifs}
105
110
  else
106
- call
111
+ _call_#{safe_class_name}
107
112
  end
108
113
  RUBY
109
114
 
@@ -276,12 +281,17 @@ module ViewComponent
276
281
  variant.to_s.gsub("-", "__").gsub(".", "___")
277
282
  end
278
283
 
284
+ def safe_class_name
285
+ @safe_class_name ||= component_class.name.underscore.gsub("/", "__")
286
+ end
287
+
279
288
  def should_compile_superclass?
280
- development? && templates.empty? && !has_inline_template? &&
281
- !(
282
- component_class.instance_methods(false).include?(:call) ||
283
- component_class.private_instance_methods(false).include?(:call)
284
- )
289
+ development? && templates.empty? && !has_inline_template? && !call_defined?
290
+ end
291
+
292
+ def call_defined?
293
+ component_class.instance_methods(false).include?(:call) ||
294
+ component_class.private_instance_methods(false).include?(:call)
285
295
  end
286
296
  end
287
297
  end
@@ -17,6 +17,7 @@ module ViewComponent
17
17
  preview_route: "/rails/view_components",
18
18
  show_previews_source: false,
19
19
  instrumentation_enabled: false,
20
+ use_deprecated_instrumentation_name: true,
20
21
  render_monkey_patch_enabled: true,
21
22
  view_component_path: "app/components",
22
23
  component_parent_class: nil,
@@ -99,6 +100,13 @@ module ViewComponent
99
100
  # Whether ActiveSupport notifications are enabled.
100
101
  # Defaults to `false`.
101
102
 
103
+ # @!attribute use_deprecated_instrumentation_name
104
+ # @return [Boolean]
105
+ # Whether ActiveSupport Notifications use the private name `"!render.view_component"`
106
+ # or are made more publicly available via `"render.view_component"`.
107
+ # Will default to `false` in next major version.
108
+ # Defaults to `true`.
109
+
102
110
  # @!attribute render_monkey_patch_enabled
103
111
  # @return [Boolean] Whether the #render method should be monkey patched.
104
112
  # If this is disabled, use `#render_component` or
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "rails"
4
4
  require "view_component/config"
5
+ require "view_component/deprecation"
5
6
 
6
7
  module ViewComponent
7
8
  class Engine < Rails::Engine # :nodoc:
@@ -39,8 +40,14 @@ module ViewComponent
39
40
  Base.config = app.config.view_component
40
41
 
41
42
  if app.config.view_component.instrumentation_enabled.present?
42
- # :nocov:
43
+ # :nocov: Re-executing the below in tests duplicates initializers and causes order-dependent failures.
43
44
  ViewComponent::Base.prepend(ViewComponent::Instrumentation)
45
+ if app.config.view_component.use_deprecated_instrumentation_name
46
+ ViewComponent::Deprecation.deprecation_warning(
47
+ "!render.view_component",
48
+ "Use the new instrumentation key `render.view_component` instead. See https://viewcomponent.org/guide/instrumentation.html"
49
+ )
50
+ end
44
51
  # :nocov:
45
52
  end
46
53
  end
@@ -39,7 +39,7 @@ module ViewComponent # :nodoc:
39
39
  end
40
40
 
41
41
  def inline_template
42
- @__vc_inline_template
42
+ @__vc_inline_template if defined?(@__vc_inline_template)
43
43
  end
44
44
 
45
45
  def inline_template_language
@@ -10,7 +10,7 @@ module ViewComponent # :nodoc:
10
10
 
11
11
  def render_in(view_context, &block)
12
12
  ActiveSupport::Notifications.instrument(
13
- "!render.view_component",
13
+ notification_name,
14
14
  {
15
15
  name: self.class.name,
16
16
  identifier: self.class.identifier
@@ -19,5 +19,13 @@ module ViewComponent # :nodoc:
19
19
  super(view_context, &block)
20
20
  end
21
21
  end
22
+
23
+ private
24
+
25
+ def notification_name
26
+ return "!render.view_component" if ViewComponent::Base.config.use_deprecated_instrumentation_name
27
+
28
+ "render.view_component"
29
+ end
22
30
  end
23
31
  end
@@ -4,7 +4,7 @@ require "active_support/descendants_tracker"
4
4
 
5
5
  module ViewComponent # :nodoc:
6
6
  class Preview
7
- include Rails.application.routes.url_helpers
7
+ include Rails.application.routes.url_helpers if defined?(Rails.application.routes.url_helpers)
8
8
  include ActionView::Helpers::TagHelper
9
9
  include ActionView::Helpers::AssetTagHelper
10
10
  extend ActiveSupport::DescendantsTracker
@@ -4,8 +4,10 @@ task stats: "view_component:statsetup"
4
4
 
5
5
  namespace :view_component do
6
6
  task :statsetup do
7
+ # :nocov:
7
8
  require "rails/code_statistics"
8
9
 
9
10
  ::STATS_DIRECTORIES << ["ViewComponents", ViewComponent::Base.view_component_path]
11
+ # :nocov:
10
12
  end
11
13
  end
@@ -155,8 +155,18 @@ module ViewComponent
155
155
  # end
156
156
  # ```
157
157
  #
158
+ # To use a specific host, pass the host param:
159
+ #
160
+ # ```ruby
161
+ # with_request_url("/users/42", host: "app.example.com") do
162
+ # render_inline(MyComponent.new)
163
+ # end
164
+ # ```
165
+ #
158
166
  # @param path [String] The path to set for the current request.
159
- def with_request_url(path)
167
+ # @param host [String] The host to set for the current request.
168
+ def with_request_url(path, host: nil)
169
+ old_request_host = vc_test_request.host
160
170
  old_request_path_info = vc_test_request.path_info
161
171
  old_request_path_parameters = vc_test_request.path_parameters
162
172
  old_request_query_parameters = vc_test_request.query_parameters
@@ -164,12 +174,14 @@ module ViewComponent
164
174
  old_controller = defined?(@vc_test_controller) && @vc_test_controller
165
175
 
166
176
  path, query = path.split("?", 2)
177
+ vc_test_request.host = host if host
167
178
  vc_test_request.path_info = path
168
179
  vc_test_request.path_parameters = Rails.application.routes.recognize_path_with_request(vc_test_request, path, {})
169
180
  vc_test_request.set_header("action_dispatch.request.query_parameters", Rack::Utils.parse_nested_query(query))
170
181
  vc_test_request.set_header(Rack::QUERY_STRING, query)
171
182
  yield
172
183
  ensure
184
+ vc_test_request.host = old_request_host
173
185
  vc_test_request.path_info = old_request_path_info
174
186
  vc_test_request.path_parameters = old_request_path_parameters
175
187
  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 = 3
6
- MINOR = 2
6
+ MINOR = 5
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
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: 3.2.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ViewComponent Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-12 00:00:00.000000000 Z
11
+ date: 2023-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport