view_component 3.4.0 → 3.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.

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