Skip to content

Commit a8ae59a

Browse files
Migrate strip_trailing_whitespace to use component-local config under the hood (#2230)
* Introduce component-local config * Migrate strip_trailing_whitespace to component-local-config * Update changelog * Refine and test component-local config * Rename interface methods * Mark deprecation in docs * Rename `configure_component` to `configure_view_component` --------- Co-authored-by: Joel Hawksley <[email protected]>
1 parent 60ed479 commit a8ae59a

File tree

6 files changed

+112
-9
lines changed

6 files changed

+112
-9
lines changed

docs/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ nav_order: 6
1010

1111
## main
1212

13+
* Introduce component-local config and migrate `strip_trailing_whitespace` to use it under the hood.
14+
15+
*Simon Fish*
16+
1317
* Add docs about Slack channel in Ruby Central workspace. (Join us! #oss-view-component). Email [email protected] for an invite.
1418

1519
*Joel Hawksley

docs/guide/templates.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,18 @@ end
181181

182182
Code editors commonly add a trailing newline character to source files in keeping with the Unix standard. Including trailing whitespace in component templates can result in unwanted whitespace in the HTML, eg. if the component is rendered before the period at the end of a sentence.
183183

184-
To strip trailing whitespace from component templates, use the `strip_trailing_whitespace` class method.
184+
To strip trailing whitespace from component templates, use the `strip_trailing_whitespace` component-local config option.
185185

186186
```ruby
187187
class MyComponent < ViewComponent::Base
188188
# do strip whitespace
189-
strip_trailing_whitespace
189+
configure_view_component do |config|
190+
config.strip_trailing_whitespace = true
191+
end
190192

191193
# don't strip whitespace
192-
strip_trailing_whitespace(false)
194+
configure_view_component do |config|
195+
config.strip_trailing_whitespace = false
196+
end
193197
end
194198
```

lib/view_component/base.rb

+26-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require "view_component/collection"
66
require "view_component/compile_cache"
77
require "view_component/compiler"
8+
require "view_component/component_local_config"
89
require "view_component/config"
910
require "view_component/errors"
1011
require "view_component/inline_template"
@@ -38,6 +39,7 @@ def config
3839
include ViewComponent::Slotable
3940
include ViewComponent::Translatable
4041
include ViewComponent::WithContentHelper
42+
include ViewComponent::ComponentLocalConfig
4143

4244
RESERVED_PARAMETER = :content
4345
VC_INTERNAL_DEFAULT_FORMAT = :html
@@ -48,10 +50,6 @@ def config
4850
# For Content Security Policy nonces
4951
delegate :content_security_policy_nonce, to: :helpers
5052

51-
# Config option that strips trailing whitespace in templates before compiling them.
52-
class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false
53-
self.__vc_strip_trailing_whitespace = false # class_attribute:default doesn't work until Rails 5.2
54-
5553
attr_accessor :__vc_original_view_context
5654

5755
# Components render in their own view context. Helpers and other functionality
@@ -613,16 +611,38 @@ def with_collection_parameter(parameter)
613611
# end
614612
# ```
615613
#
614+
# @deprecated Use the new component-local configuration option instead.
615+
#
616+
# ```ruby
617+
# class MyComponent < ViewComponent::Base
618+
# configure_view_component do |config|
619+
# config.strip_trailing_whitespace = true
620+
# end
621+
# end
622+
# ```
623+
#
616624
# @param value [Boolean] Whether to strip newlines.
617625
def strip_trailing_whitespace(value = true)
618-
self.__vc_strip_trailing_whitespace = value
626+
ViewComponent::Deprecation.deprecation_warning(
627+
"strip_trailing_whitespace",
628+
<<~DOC
629+
Use the new component-local configuration option instead:
630+
631+
class #{self.class.name} < ViewComponent::Base
632+
configure_view_component do |config|
633+
config.strip_trailing_whitespace = #{value}
634+
end
635+
end
636+
DOC
637+
)
638+
view_component_config.strip_trailing_whitespace = value
619639
end
620640

621641
# Whether trailing whitespace will be stripped before compilation.
622642
#
623643
# @return [Boolean]
624644
def strip_trailing_whitespace?
625-
__vc_strip_trailing_whitespace
645+
view_component_config.strip_trailing_whitespace
626646
end
627647

628648
# Ensure the component initializer accepts the
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# frozen_string_literal: true
2+
3+
module ViewComponent
4+
module ComponentLocalConfig
5+
class Configuration
6+
def self.defaults
7+
ActiveSupport::Configurable::Configuration[
8+
strip_trailing_whitespace: false
9+
]
10+
end
11+
12+
def initialize(config = defaults)
13+
@config = config
14+
end
15+
16+
delegate_missing_to :@config
17+
18+
def inheritable_copy
19+
self.class.new(@config.inheritable_copy)
20+
end
21+
22+
private
23+
24+
delegate :defaults, to: :class
25+
end
26+
27+
extend ActiveSupport::Concern
28+
29+
included do
30+
# :nocov:
31+
def view_component_config
32+
@__vc_config ||= self.class.view_component_config.inheritable_copy
33+
end
34+
35+
private
36+
37+
def inherited(child)
38+
child.instance_variable_set(:@__vc_config, nil)
39+
super
40+
end
41+
# :nocov:
42+
end
43+
44+
class_methods do
45+
def view_component_config
46+
@__vc_config ||= if respond_to?(:superclass) && superclass.respond_to?(:view_component_config)
47+
superclass.view_component_config.inheritable_copy
48+
else
49+
# create a new "anonymous" class that will host the compiled reader methods
50+
ViewComponent::ComponentLocalConfig::Configuration.new
51+
end
52+
end
53+
54+
def configure_view_component(&block)
55+
view_component_config.instance_eval(&block)
56+
view_component_config.compile_methods!
57+
end
58+
end
59+
end
60+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
class ConfigurableComponent < ViewComponent::Base
4+
configure_view_component do |config|
5+
config.strip_trailing_whitespace = true
6+
end
7+
end

test/sandbox/test/base_test.rb

+8
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,12 @@ def test_uses_module_configuration
197197
assert_equal "AnotherController", TestAlreadyConfigurableModule::SomeComponent.test_controller
198198
assert_equal "AnotherController", TestAlreadyConfiguredModule::SomeComponent.test_controller
199199
end
200+
201+
def test_component_local_config_is_inheritable
202+
assert_equal false, ViewComponent::Base.view_component_config.strip_trailing_whitespace
203+
# This component doesn't call configure, so it should inherit the defaults.
204+
assert_equal false, AnotherComponent.view_component_config.strip_trailing_whitespace
205+
# This component overrides the defaults.
206+
assert_equal true, ConfigurableComponent.view_component_config.strip_trailing_whitespace
207+
end
200208
end

0 commit comments

Comments
 (0)