view_component 3.4.0 → 3.6.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: fda2b08a3a0e713feb6e1fc6c1fef238f886cc4ab1ddd23e3d181bda02ad9c27
4
- data.tar.gz: e405fabfc3f12543caf45207f7222fdb9efcf9963dad10d3d37e47c131427e8b
3
+ metadata.gz: e24f482306b48f037310ce13c9fd25a35ad809a1b3cc536f5b496cf4f4e17ebc
4
+ data.tar.gz: b403755a43c062e591b2b6cce09422a7148a22d263ff15ca0f2395086df965b2
5
5
  SHA512:
6
- metadata.gz: 2a8be926941021f58d66f8b8c29893e5bd682426483914f16f431783c2e230029755e137a434f535fd081f51d3d9a63c219174ce68af9202f8f5f42f0f7087bd
7
- data.tar.gz: 4da3a061e16a87cc13440b4c1bf621da4d34a0b2443f28c34a132df0f4a85822b9f9ba12bea9b85c950e8b7991553c85a130eee75e1d7c84865feb30f66f17b5
6
+ metadata.gz: 8cac599cdbad5dfaf4bdf9e02cc3ca34bf45be4fd8832745fe00bd3487127f360e144cc746f5a975a55f1beded97193a3d5abaa42ce161c8d88535e4547fb21b
7
+ data.tar.gz: d7e4d742329eec00ac562e5cd02ca7a1cd206af87dd4544649ab8790697511fb400a2175d70c6fff39fbed9124810a97db8e4e4d92ec8f6a7735247042140417
data/docs/CHANGELOG.md CHANGED
@@ -10,6 +10,58 @@ nav_order: 5
10
10
 
11
11
  ## main
12
12
 
13
+ ## 3.6.0
14
+
15
+ * Refer to `helpers` in `NameError` message in development and test environments.
16
+
17
+ *Simon Fish*
18
+
19
+ * Fix API documentation and revert unnecessary change in `preview.rb`.
20
+
21
+ *Richard Macklin*
22
+
23
+ * Initialize ViewComponent::Config with defaults before framework load.
24
+
25
+ *Simon Fish*
26
+
27
+ * Add 3.2 to the list of Ruby CI versions
28
+
29
+ *Igor Drozdov*
30
+
31
+ * Stop running PVC's `docs:preview` rake task in CI, as the old docsite has been removed.
32
+
33
+ *Cameron Dutro*
34
+
35
+ * Minor testing documentation improvement.
36
+
37
+ *Travis Gaff*
38
+
39
+ * Add SearchApi to users list.
40
+
41
+ *Sebastjan Prachovskij*
42
+
43
+ * Fix `#with_request_url` to ensure `request.query_parameters` is an instance of ActiveSupport::HashWithIndifferentAccess.
44
+
45
+ *milk1000cc*
46
+
47
+ * Add PeopleForce to list of companies using ViewComponent.
48
+
49
+ *Volodymyr Khandiuk*
50
+
51
+ ## 3.5.0
52
+
53
+ * Add Skroutz to users list.
54
+
55
+ *Chris Nitsas*
56
+
57
+ * Improve implementation of `#render_parent` so it respects variants and deep inheritance hierarchies.
58
+
59
+ *Cameron Dutro*
60
+
61
+ * Add CharlieHR to users list.
62
+
63
+ *Alex Balhatchet*
64
+
13
65
  ## 3.4.0
14
66
 
15
67
  * Avoid including Rails `url_helpers` into `Preview` class when they're not defined.
@@ -22,12 +22,8 @@ module ViewComponent
22
22
  #
23
23
  # @return [ActiveSupport::OrderedOptions]
24
24
  def config
25
- @config ||= ActiveSupport::OrderedOptions.new
25
+ ViewComponent::Config.current
26
26
  end
27
-
28
- # Replaces the entire config. You shouldn't need to use this directly
29
- # unless you're building a `ViewComponent::Config` elsewhere.
30
- attr_writer :config
31
27
  end
32
28
 
33
29
  include ViewComponent::InlineTemplate
@@ -116,20 +112,44 @@ module ViewComponent
116
112
  end
117
113
 
118
114
  # Subclass components that call `super` inside their template code will cause a
119
- # double render if they emit the result:
115
+ # double render if they emit the result.
120
116
  #
121
117
  # ```erb
122
118
  # <%= super %> # double-renders
123
- # <% super %> # does not double-render
119
+ # <% super %> # doesn't double-render
124
120
  # ```
125
121
  #
126
- # Calls `super`, returning `nil` to avoid rendering the result twice.
122
+ # `super` also doesn't consider the current variant. `render_parent` renders the
123
+ # parent template considering the current variant and emits the result without
124
+ # double-rendering.
127
125
  def render_parent
128
- mtd = @__vc_variant ? "call_#{@__vc_variant}" : "call"
129
- method(mtd).super_method.call
126
+ render_parent_to_string
130
127
  nil
131
128
  end
132
129
 
130
+ # Renders the parent component to a string and returns it. This method is meant
131
+ # to be used inside custom #call methods when a string result is desired, eg.
132
+ #
133
+ # ```ruby
134
+ # def call
135
+ # "<div>#{render_parent_to_string}</div>"
136
+ # end
137
+ # ```
138
+ #
139
+ # When rendering the parent inside an .erb template, use `#render_parent` instead.
140
+ def render_parent_to_string
141
+ @__vc_parent_render_level ||= 0 # ensure a good starting value
142
+
143
+ begin
144
+ target_render = self.class.instance_variable_get(:@__vc_ancestor_calls)[@__vc_parent_render_level]
145
+ @__vc_parent_render_level += 1
146
+
147
+ target_render.bind_call(self, @__vc_variant)
148
+ ensure
149
+ @__vc_parent_render_level -= 1
150
+ end
151
+ end
152
+
133
153
  # Optional content to be returned after the rendered template.
134
154
  #
135
155
  # @return [String]
@@ -199,6 +219,21 @@ module ViewComponent
199
219
  @__vc_helpers ||= __vc_original_view_context || controller.view_context
200
220
  end
201
221
 
222
+ if Rails.env.development? || Rails.env.test?
223
+ def method_missing(method_name, *args) # rubocop:disable Style/MissingRespondToMissing
224
+ super
225
+ rescue => e # rubocop:disable Style/RescueStandardError
226
+ e.set_backtrace e.backtrace.tap(&:shift)
227
+ raise e, <<~MESSAGE.chomp if view_context && e.is_a?(NameError) && helpers.respond_to?(method_name)
228
+ #{e.message}
229
+
230
+ You may be trying to call a method provided as a view helper. Did you mean `helpers.#{method_name}'?
231
+ MESSAGE
232
+
233
+ raise
234
+ end
235
+ end
236
+
202
237
  # Exposes .virtual_path as an instance method
203
238
  #
204
239
  # @private
@@ -459,6 +494,13 @@ module ViewComponent
459
494
  # Set collection parameter to the extended component
460
495
  child.with_collection_parameter provided_collection_parameter
461
496
 
497
+ if instance_methods(false).include?(:render_template_for)
498
+ vc_ancestor_calls = defined?(@__vc_ancestor_calls) ? @__vc_ancestor_calls.dup : []
499
+
500
+ vc_ancestor_calls.unshift(instance_method(:render_template_for))
501
+ child.instance_variable_set(:@__vc_ancestor_calls, vc_ancestor_calls)
502
+ end
503
+
462
504
  super
463
505
  end
464
506
 
@@ -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
@@ -167,6 +167,14 @@ module ViewComponent
167
167
  end
168
168
  end
169
169
 
170
+ # @!attribute current
171
+ # @return [ViewComponent::Config]
172
+ # Returns the current ViewComponent::Config. This is persisted against this
173
+ # class so that config options remain accessible before the rest of
174
+ # ViewComponent has loaded. Defaults to an instance of ViewComponent::Config
175
+ # with all other documented defaults set.
176
+ class_attribute :current, default: defaults, instance_predicate: false
177
+
170
178
  def initialize
171
179
  @config = self.class.defaults
172
180
  end
@@ -6,7 +6,7 @@ require "view_component/deprecation"
6
6
 
7
7
  module ViewComponent
8
8
  class Engine < Rails::Engine # :nodoc:
9
- config.view_component = ViewComponent::Config.defaults
9
+ config.view_component = ViewComponent::Config.current
10
10
 
11
11
  rake_tasks do
12
12
  load "view_component/rails/tasks/view_component.rake"
@@ -15,6 +15,9 @@ module ViewComponent
15
15
  initializer "view_component.set_configs" do |app|
16
16
  options = app.config.view_component
17
17
 
18
+ %i[generate preview_controller preview_route show_previews_source].each do |config_option|
19
+ options[config_option] ||= ViewComponent::Base.public_send(config_option)
20
+ end
18
21
  options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
19
22
  options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
20
23
  options.show_previews = (Rails.env.development? || Rails.env.test?) if options.show_previews.nil?
@@ -37,8 +40,6 @@ module ViewComponent
37
40
 
38
41
  initializer "view_component.enable_instrumentation" do |app|
39
42
  ActiveSupport.on_load(:view_component) do
40
- Base.config = app.config.view_component
41
-
42
43
  if app.config.view_component.instrumentation_enabled.present?
43
44
  # :nocov: Re-executing the below in tests duplicates initializers and causes order-dependent failures.
44
45
  ViewComponent::Base.prepend(ViewComponent::Instrumentation)
@@ -177,7 +177,8 @@ module ViewComponent
177
177
  vc_test_request.host = host if host
178
178
  vc_test_request.path_info = path
179
179
  vc_test_request.path_parameters = Rails.application.routes.recognize_path_with_request(vc_test_request, path, {})
180
- vc_test_request.set_header("action_dispatch.request.query_parameters", Rack::Utils.parse_nested_query(query))
180
+ vc_test_request.set_header("action_dispatch.request.query_parameters",
181
+ Rack::Utils.parse_nested_query(query).with_indifferent_access)
181
182
  vc_test_request.set_header(Rack::QUERY_STRING, query)
182
183
  yield
183
184
  ensure
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 3
6
- MINOR = 4
6
+ MINOR = 6
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.4.0
4
+ version: 3.6.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-07-11 00:00:00.000000000 Z
11
+ date: 2023-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport