view_component 2.60.0 → 2.62.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: b74cdfd2d8306224e0fc89d244d70f08fbf779ec9a892affd0fe766b16a4ac6d
4
- data.tar.gz: d401c34f06238713ba43d97e5b50b9db647f946f8937e964c57578918b3418fb
3
+ metadata.gz: e57d7d7eece678a577cf5f89f4b506fbe1026c79cc8b28d269e6984a01de29c7
4
+ data.tar.gz: e8fd167897e4bbcfaf0b4d657605acf26a5e1c6dc72e6fd5a868e0e0e76d232b
5
5
  SHA512:
6
- metadata.gz: a3c56fb2399e387fb57f6976264ea7aa3d3ce9e4490a741cf660876fe90fb5265bf80a865887a082cf282259a04b8477416546bdd21a2be08ac21744aa8316b5
7
- data.tar.gz: 71049fb1fcc3cd1a09404feb9ab7a5aee6b2c9e5dc88c377233472953ee3e498f4a95a973033d717413e8d128a0ea3e95d955885692581b9e62c26fb66a18d0f
6
+ metadata.gz: a6bae85903899c93cb78e11a49082c4e6c2393605c9b3e94cca98ecff1e790a97dd7acda4c5e13b11ad4e4591384d0d30e62d86831998577531b595378f9fcb7
7
+ data.tar.gz: 814913871cc0d5b4865a6864a0585f06d6c26088cdbab888e4c4d33787f7ab2e74c9dafffd52fe726999d03b9a453186b3f495afc1c0c9da5207b5edb3a89480
data/docs/CHANGELOG.md CHANGED
@@ -9,6 +9,42 @@ title: Changelog
9
9
 
10
10
  ## main
11
11
 
12
+ ## 2.62.0
13
+
14
+ * Remove the experimental global output buffer feature.
15
+ * Restore functionality that used to attempt to compile templates on each call to `#render_in`.
16
+ * Un-pin `rails` `main` dependency.
17
+
18
+ *Cameron Dutro*
19
+
20
+ * Add blank space between "in" and "ViewComponent" in a deprecation warning.
21
+
22
+ *Vikram Dighe*
23
+
24
+ * Add HappyCo to list of companies using ViewComponent.
25
+
26
+ *Josh Clayton*
27
+
28
+ ## 2.61.1
29
+
30
+ * Revert `Expose Capybara DSL methods directly inside tests.` This change unintentionally broke other Capybara methods and thus introduced a regression. We aren't confident that we can fail forward so we have decided to revert this change.
31
+
32
+ *Joel Hawksley*, *Blake Williams*
33
+
34
+ * Revert change making content evaluation consistent.
35
+
36
+ *Blake Williams*
37
+
38
+ * Pin `rails` `main` dependency due to incompatibility with Global Output Buffer.
39
+
40
+ *Joel Hawksley*
41
+
42
+ ## 2.61.0
43
+
44
+ * Ensure side-effects in `content` are consistently evaluated before components are rendered. This change effectively means that `content` is evaluated for every component render where `render?` returns true. As a result, code that is passed to a component via a block/content will now always be evaluated, before `#call`, which can reveal bugs in existing components.
45
+
46
+ *Blake Williams*
47
+
12
48
  ## 2.60.0
13
49
 
14
50
  * Add support for `render_preview` in RSpec tests.
@@ -86,10 +86,12 @@ module ViewComponent
86
86
  #
87
87
  # @return [String]
88
88
  def render_in(view_context, &block)
89
+ self.class.compile(raise_errors: true)
90
+
89
91
  @view_context = view_context
90
92
  self.__vc_original_view_context ||= view_context
91
93
 
92
- @output_buffer = ActionView::OutputBuffer.new unless defined?(@global_buffer_in_use) && @global_buffer_in_use
94
+ @output_buffer = ActionView::OutputBuffer.new
93
95
 
94
96
  @lookup_context ||= view_context.lookup_context
95
97
 
@@ -124,7 +126,7 @@ module ViewComponent
124
126
  before_render
125
127
 
126
128
  if render?
127
- perform_render
129
+ render_template_for(@__vc_variant).to_s + _output_postamble
128
130
  else
129
131
  ""
130
132
  end
@@ -132,11 +134,6 @@ module ViewComponent
132
134
  @current_template = old_current_template
133
135
  end
134
136
 
135
- # @private
136
- def perform_render
137
- render_template_for(@__vc_variant).to_s + _output_postamble
138
- end
139
-
140
137
  # Subclass components that call `super` inside their template code will cause a
141
138
  # double render if they emit the result:
142
139
  #
@@ -152,17 +149,6 @@ module ViewComponent
152
149
  nil
153
150
  end
154
151
 
155
- # @private
156
- # :nocov:
157
- def render_template_for(variant = nil)
158
- # Force compilation here so the compiler always redefines render_template_for.
159
- # This is mostly a safeguard to prevent infinite recursion.
160
- self.class.compile(raise_errors: true, force: true)
161
- # .compile replaces this method; call the new one
162
- render_template_for(variant)
163
- end
164
- # :nocov:
165
-
166
152
  # EXPERIMENTAL: Optional content to be returned after the rendered template.
167
153
  #
168
154
  # @return [String]
@@ -20,11 +20,10 @@ module ViewComponent
20
20
 
21
21
  def invalidate_class!(klass)
22
22
  cache.delete(klass)
23
- klass.compiler.reset_render_template_for
24
23
  end
25
24
 
26
25
  def invalidate!
27
- cache.each { |klass| invalidate_class!(klass) }
26
+ cache.clear
28
27
  end
29
28
  end
30
29
  end
@@ -34,6 +34,8 @@ module ViewComponent
34
34
  component_class.superclass.compile(raise_errors: raise_errors) if should_compile_superclass?
35
35
 
36
36
  with_lock do
37
+ CompileCache.invalidate_class!(component_class)
38
+
37
39
  subclass_instance_methods = component_class.instance_methods(false)
38
40
 
39
41
  if subclass_instance_methods.include?(:with_content) && raise_errors
@@ -66,8 +68,8 @@ module ViewComponent
66
68
  # as Ruby warns when redefining a method.
67
69
  method_name = call_method_name(template[:variant])
68
70
 
69
- if component_class.instance_methods(false).include?(method_name.to_sym)
70
- component_class.send(:remove_method, method_name.to_sym)
71
+ if component_class.instance_methods.include?(method_name.to_sym)
72
+ component_class.send(:undef_method, method_name.to_sym)
71
73
  end
72
74
 
73
75
  # rubocop:disable Style/EvalWithLocation
@@ -96,18 +98,14 @@ module ViewComponent
96
98
  end
97
99
  end
98
100
 
99
- def reset_render_template_for
100
- if component_class.instance_methods(false).include?(:render_template_for)
101
- component_class.send(:remove_method, :render_template_for)
102
- end
103
- end
104
-
105
101
  private
106
102
 
107
103
  attr_reader :component_class
108
104
 
109
105
  def define_render_template_for
110
- reset_render_template_for
106
+ if component_class.instance_methods.include?(:render_template_for)
107
+ component_class.send(:undef_method, :render_template_for)
108
+ end
111
109
 
112
110
  variant_elsifs = variants.compact.uniq.map do |variant|
113
111
  "elsif variant.to_sym == :#{variant}\n #{call_method_name(variant)}"
@@ -20,7 +20,6 @@ module ViewComponent
20
20
  options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
21
21
  options.preview_route ||= ViewComponent::Base.preview_route
22
22
  options.preview_controller ||= ViewComponent::Base.preview_controller
23
- options.use_global_output_buffer = false if options.use_global_output_buffer.nil?
24
23
 
25
24
  if options.show_previews
26
25
  options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
@@ -58,21 +57,6 @@ module ViewComponent
58
57
  end
59
58
  end
60
59
 
61
- initializer "view_component.enable_global_output_buffer" do |app|
62
- ActiveSupport.on_load(:view_component) do
63
- env_use_gob = ENV.fetch("VIEW_COMPONENT_USE_GLOBAL_OUTPUT_BUFFER", "false") == "true"
64
- config_use_gob = app.config.view_component.use_global_output_buffer
65
-
66
- if config_use_gob || env_use_gob
67
- # :nocov:
68
- app.config.view_component.use_global_output_buffer = true
69
- ViewComponent::Base.prepend(ViewComponent::GlobalOutputBuffer)
70
- ActionView::Base.prepend(ViewComponent::GlobalOutputBuffer::ActionViewMods)
71
- # :nocov:
72
- end
73
- end
74
- end
75
-
76
60
  initializer "view_component.set_autoload_paths" do |app|
77
61
  options = app.config.view_component
78
62
 
@@ -10,7 +10,7 @@ module ViewComponent
10
10
  location = Kernel.caller_locations(1, 1)[0]
11
11
 
12
12
  warn(
13
- "warning: ViewComponent::PolymorphicSlots is now included in ViewComponent::Base by default "\
13
+ "warning: ViewComponent::PolymorphicSlots is now included in ViewComponent::Base by default " \
14
14
  "and can be removed from #{location.path}:#{location.lineno}"
15
15
  )
16
16
  # :nocov:
@@ -58,7 +58,7 @@ module ViewComponent
58
58
 
59
59
  define_method(setter_name) do |*args, &block|
60
60
  ViewComponent::Deprecation.warn(
61
- "polymorphic slot setters like `#{setter_name}` are deprecated and will be removed in"\
61
+ "polymorphic slot setters like `#{setter_name}` are deprecated and will be removed in " \
62
62
  "ViewComponent v3.0.0.\n\nUse `with_#{setter_name}` instead."
63
63
  )
64
64
 
@@ -266,8 +266,8 @@ module ViewComponent
266
266
  def raise_if_slot_ends_with_question_mark(slot_name)
267
267
  if slot_name.to_s.ends_with?("?")
268
268
  raise ArgumentError.new(
269
- "#{self} declares a slot named #{slot_name}, which ends with a question mark.\n\n"\
270
- "This is not allowed because the ViewComponent framework already provides predicate "\
269
+ "#{self} declares a slot named #{slot_name}, which ends with a question mark.\n\n" \
270
+ "This is not allowed because the ViewComponent framework already provides predicate " \
271
271
  "methods ending in `?`.\n\n" \
272
272
  "To fix this issue, choose a different name."
273
273
  )
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "view_component/render_preview_helper"
4
- require "view_component/capybara_simple_session"
5
4
 
6
5
  module ViewComponent
7
6
  module TestHelpers
@@ -10,28 +9,8 @@ module ViewComponent
10
9
 
11
10
  include Capybara::Minitest::Assertions
12
11
 
13
- CapybaraSimpleSession::DSL_METHODS.each do |method|
14
- if RUBY_VERSION >= "2.7"
15
- class_eval <<~METHOD, __FILE__, __LINE__ + 1
16
- def #{method}(...)
17
- page.method("#{method}").call(...)
18
- end
19
- METHOD
20
- else
21
- define_method method do |*args, &block|
22
- page.send method, *args, &block
23
- end
24
- end
25
- end
26
-
27
- def self.included(mod)
28
- Capybara::Node::Simple.send(:define_method, :to_capybara_node) do
29
- self
30
- end
31
- end
32
-
33
12
  def page
34
- @page ||= CapybaraSimpleSession.new(rendered_content)
13
+ @page ||= Capybara::Node::Simple.new(rendered_content)
35
14
  end
36
15
 
37
16
  def refute_component_rendered
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 60
6
+ MINOR = 62
7
7
  PATCH = 0
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
@@ -7,14 +7,11 @@ module ViewComponent
7
7
  extend ActiveSupport::Autoload
8
8
 
9
9
  autoload :Base
10
- autoload :CapybaraSimpleSession
11
10
  autoload :Compiler
12
11
  autoload :CompileCache
13
12
  autoload :ComponentError
14
13
  autoload :Deprecation
15
- autoload :GlobalOutputBuffer
16
14
  autoload :Instrumentation
17
- autoload :OutputBufferStack
18
15
  autoload :Preview
19
16
  autoload :PreviewTemplateError
20
17
  autoload :TestHelpers
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: 2.60.0
4
+ version: 2.62.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-18 00:00:00.000000000 Z
11
+ date: 2022-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -325,7 +325,6 @@ files:
325
325
  - lib/rails/generators/test_unit/templates/component_test.rb.tt
326
326
  - lib/view_component.rb
327
327
  - lib/view_component/base.rb
328
- - lib/view_component/capybara_simple_session.rb
329
328
  - lib/view_component/collection.rb
330
329
  - lib/view_component/compile_cache.rb
331
330
  - lib/view_component/compiler.rb
@@ -335,9 +334,7 @@ files:
335
334
  - lib/view_component/docs_builder_component.html.erb
336
335
  - lib/view_component/docs_builder_component.rb
337
336
  - lib/view_component/engine.rb
338
- - lib/view_component/global_output_buffer.rb
339
337
  - lib/view_component/instrumentation.rb
340
- - lib/view_component/output_buffer_stack.rb
341
338
  - lib/view_component/polymorphic_slots.rb
342
339
  - lib/view_component/preview.rb
343
340
  - lib/view_component/preview_template_error.rb
@@ -1,132 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- # This is a simpler version of {Capybara::Session}.
5
- #
6
- # It only includes {Capybara::Node::Finders}, {Capybara::Node::Matchers},
7
- # {#within} and {#within_element}. It is useful in that it does not require a
8
- # session, an application or a driver, but can still use Capybara's finders
9
- # and matchers on any string that contains HTML.
10
- class CapybaraSimpleSession
11
- # Most of the code in this class is shamelessly stolen from the
12
- # {Capybara::Session} class in the Capybara gem
13
- # (https://github.com/teamcapybara/capybara/blob/e704d00879fb1d1e1a0cc01e04c101bcd8af4a68/lib/capybara/session.rb#L38).
14
-
15
- NODE_METHODS = %i[
16
- all
17
- first
18
- text
19
-
20
- find
21
- find_all
22
- find_button
23
- find_by_id
24
- find_field
25
- find_link
26
-
27
- has_content?
28
- has_text?
29
- has_css?
30
- has_no_content?
31
- has_no_text?
32
- has_no_css?
33
- has_no_xpath?
34
- has_xpath?
35
- has_link?
36
- has_no_link?
37
- has_button?
38
- has_no_button?
39
- has_field?
40
- has_no_field?
41
- has_checked_field?
42
- has_unchecked_field?
43
- has_no_table?
44
- has_table?
45
- has_select?
46
- has_no_select?
47
- has_selector?
48
- has_no_selector?
49
- has_no_checked_field?
50
- has_no_unchecked_field?
51
-
52
- assert_selector
53
- assert_no_selector
54
- assert_all_of_selectors
55
- assert_none_of_selectors
56
- assert_any_of_selectors
57
- assert_text
58
- assert_no_text
59
- ].freeze
60
-
61
- private_constant :NODE_METHODS
62
-
63
- SESSION_METHODS = %i[within within_element within_fieldset within_table].freeze
64
-
65
- private_constant :SESSION_METHODS
66
-
67
- DSL_METHODS = (NODE_METHODS + SESSION_METHODS).freeze
68
-
69
- # Stolen from: https://github.com/teamcapybara/capybara/blob/e704d00879fb1d1e1a0cc01e04c101bcd8af4a68/lib/capybara/session.rb#L767-L774.
70
- NODE_METHODS.each do |method|
71
- if RUBY_VERSION >= "2.7"
72
- class_eval <<~METHOD, __FILE__, __LINE__ + 1
73
- def #{method}(...)
74
- current_scope.#{method}(...)
75
- end
76
- METHOD
77
- else
78
- define_method method do |*args, &block|
79
- current_scope.send(method, *args, &block)
80
- end
81
- end
82
- end
83
-
84
- # Initializes the receiver with the given string of HTML.
85
- #
86
- # @param html [String] the HTML to create the session out of
87
- def initialize(html)
88
- @document = Capybara::Node::Simple.new(html)
89
- end
90
-
91
- # (see Capybara::Session#within)
92
- def within(*args, **kw_args)
93
- new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args, **kw_args)
94
- begin
95
- scopes.push(new_scope)
96
- yield if block_given?
97
- ensure
98
- scopes.pop
99
- end
100
- end
101
-
102
- # (see Capybara::Session#within_element)
103
- alias_method :within_element, :within
104
-
105
- # (see Capybara::Session#within_fieldset)
106
- def within_fieldset(locator, &block)
107
- within(:fieldset, locator, &block)
108
- end
109
-
110
- # (see Capybara::Session#within_table)
111
- def within_table(locator, &block)
112
- within(:table, locator, &block)
113
- end
114
-
115
- # (see Capybara::Node::Element#native)
116
- def native
117
- current_scope.native
118
- end
119
-
120
- private
121
-
122
- attr_reader :document
123
-
124
- def scopes
125
- @scopes ||= [nil]
126
- end
127
-
128
- def current_scope
129
- scopes.last.presence || document
130
- end
131
- end
132
- end
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- module GlobalOutputBuffer
5
- def render_in(view_context, &block)
6
- unless view_context.output_buffer.is_a?(OutputBufferStack)
7
- # use instance_variable_set here to avoid triggering the code in the #output_buffer= method below
8
- view_context.instance_variable_set(:@output_buffer, OutputBufferStack.new(view_context.output_buffer))
9
- end
10
-
11
- @output_buffer = view_context.output_buffer
12
- @global_buffer_in_use = true
13
-
14
- super(view_context, &block)
15
- end
16
-
17
- def perform_render
18
- # HAML unhelpfully assigns to @output_buffer directly, so we hold onto a reference to
19
- # it and restore @output_buffer when the HAML engine is finished. In non-HAML cases,
20
- # @output_buffer and orig_buf will point to the same object, making the reassignment
21
- # statements no-ops.
22
- orig_buf = @output_buffer
23
- @output_buffer.push
24
- result = render_template_for(@__vc_variant).to_s + _output_postamble
25
- @output_buffer = orig_buf
26
- @output_buffer.pop
27
- result
28
- end
29
-
30
- def output_buffer=(other_buffer)
31
- @output_buffer.replace(other_buffer)
32
- end
33
-
34
- def with_output_buffer(buf = nil)
35
- unless buf
36
- buf = ActionView::OutputBuffer.new
37
- # rubocop:disable Style/SafeNavigation
38
- if output_buffer && output_buffer.respond_to?(:encoding)
39
- buf.force_encoding(output_buffer.encoding)
40
- end
41
- # rubocop:enable Style/SafeNavigation
42
- end
43
-
44
- output_buffer.push(buf)
45
-
46
- begin
47
- yield
48
- ensure
49
- # assign result here to avoid a return statement, which will
50
- # immediately return to the caller and swallow any errors
51
- result = output_buffer.pop
52
- end
53
-
54
- result
55
- end
56
-
57
- module ActionViewMods
58
- def output_buffer=(other_buffer)
59
- if @output_buffer.is_a?(OutputBufferStack)
60
- @output_buffer.replace(other_buffer)
61
- else
62
- super
63
- end
64
- end
65
-
66
- def with_output_buffer(buf = nil)
67
- unless buf
68
- buf = ActionView::OutputBuffer.new
69
- # rubocop:disable Style/SafeNavigation
70
- if @output_buffer && @output_buffer.respond_to?(:encoding)
71
- buf.force_encoding(@output_buffer.encoding)
72
- end
73
- # rubocop:enable Style/SafeNavigation
74
- end
75
-
76
- if @output_buffer.is_a?(OutputBufferStack)
77
- @output_buffer.push(buf)
78
-
79
- begin
80
- yield
81
- ensure
82
- result = @output_buffer.pop
83
- end
84
-
85
- result
86
- else
87
- @output_buffer, old_buffer = buf, output_buffer
88
-
89
- begin
90
- yield
91
- ensure
92
- @output_buffer = old_buffer
93
- end
94
-
95
- buf
96
- end
97
- end
98
- end
99
- end
100
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- class OutputBufferStack
5
- delegate_missing_to :@current_buffer
6
- delegate :presence, :present?, :html_safe?, to: :@current_buffer
7
-
8
- attr_reader :buffer_stack
9
-
10
- def self.make_frame(*args)
11
- ActionView::OutputBuffer.new(*args)
12
- end
13
-
14
- def initialize(initial_buffer = nil)
15
- if initial_buffer.is_a?(self.class)
16
- @current_buffer = self.class.make_frame(initial_buffer.current)
17
- @buffer_stack = [*initial_buffer.buffer_stack[0..-2], @current_buffer]
18
- else
19
- @current_buffer = initial_buffer || self.class.make_frame
20
- @buffer_stack = [@current_buffer]
21
- end
22
- end
23
-
24
- def replace(buffer)
25
- return if self == buffer
26
-
27
- @current_buffer = buffer.current
28
- @buffer_stack = buffer.buffer_stack
29
- end
30
-
31
- def append=(arg)
32
- @current_buffer.append = arg
33
- end
34
-
35
- def safe_append=(arg)
36
- @current_buffer.safe_append = arg
37
- end
38
-
39
- def safe_concat(arg)
40
- @current_buffer.safe_concat(arg)
41
- end
42
-
43
- def length
44
- @current_buffer.length
45
- end
46
-
47
- def push(buffer = nil)
48
- buffer ||= self.class.make_frame
49
- @buffer_stack.push(buffer)
50
- @current_buffer = buffer
51
- end
52
-
53
- def pop
54
- @buffer_stack.pop.tap do
55
- @current_buffer = @buffer_stack.last
56
- end
57
- end
58
-
59
- def to_s
60
- @current_buffer
61
- end
62
-
63
- alias_method :current, :to_s
64
- end
65
- end