Skip to content

Migrate strip_trailing_whitespace to use component-local config under the hood #2230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ nav_order: 6

## main

* Introduce component-local config and migrate `strip_trailing_whitespace` to use it under the hood.

*Simon Fish*

* Add documentation on how ViewComponent works.

*Joel Hawksley*
Expand Down
10 changes: 7 additions & 3 deletions docs/guide/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,18 @@ end

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.

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

```ruby
class MyComponent < ViewComponent::Base
# do strip whitespace
strip_trailing_whitespace
configure_view_component do |config|
config.strip_trailing_whitespace = true
end

# don't strip whitespace
strip_trailing_whitespace(false)
configure_view_component do |config|
config.strip_trailing_whitespace = false
end
end
```
32 changes: 26 additions & 6 deletions lib/view_component/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "view_component/collection"
require "view_component/compile_cache"
require "view_component/compiler"
require "view_component/component_local_config"
require "view_component/config"
require "view_component/errors"
require "view_component/inline_template"
Expand Down Expand Up @@ -38,6 +39,7 @@ def config
include ViewComponent::Slotable
include ViewComponent::Translatable
include ViewComponent::WithContentHelper
include ViewComponent::ComponentLocalConfig

RESERVED_PARAMETER = :content
VC_INTERNAL_DEFAULT_FORMAT = :html
Expand All @@ -48,10 +50,6 @@ def config
# For Content Security Policy nonces
delegate :content_security_policy_nonce, to: :helpers

# Config option that strips trailing whitespace in templates before compiling them.
class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false
self.__vc_strip_trailing_whitespace = false # class_attribute:default doesn't work until Rails 5.2

attr_accessor :__vc_original_view_context

# Components render in their own view context. Helpers and other functionality
Expand Down Expand Up @@ -613,16 +611,38 @@ def with_collection_parameter(parameter)
# end
# ```
#
# @deprecated Use the new component-local configuration option instead.
#
# ```ruby
# class MyComponent < ViewComponent::Base
# configure_view_component do |config|
# config.strip_trailing_whitespace = true
# end
# end
# ```
#
# @param value [Boolean] Whether to strip newlines.
def strip_trailing_whitespace(value = true)
self.__vc_strip_trailing_whitespace = value
ViewComponent::Deprecation.deprecation_warning(
"strip_trailing_whitespace",
<<~DOC
Use the new component-local configuration option instead:

class #{self.class.name} < ViewComponent::Base
configure_view_component do |config|
config.strip_trailing_whitespace = #{value}
end
end
DOC
)
view_component_config.strip_trailing_whitespace = value
end

# Whether trailing whitespace will be stripped before compilation.
#
# @return [Boolean]
def strip_trailing_whitespace?
__vc_strip_trailing_whitespace
view_component_config.strip_trailing_whitespace
end

# Ensure the component initializer accepts the
Expand Down
60 changes: 60 additions & 0 deletions lib/view_component/component_local_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

module ViewComponent
module ComponentLocalConfig
class Configuration
def self.defaults
ActiveSupport::Configurable::Configuration[
strip_trailing_whitespace: false
]
end

def initialize(config = defaults)
@config = config
end

delegate_missing_to :@config

def inheritable_copy
self.class.new(@config.inheritable_copy)
end

private

delegate :defaults, to: :class
end

extend ActiveSupport::Concern

included do
# :nocov:
def view_component_config
@__vc_config ||= self.class.view_component_config.inheritable_copy
end

private

def inherited(child)
child.instance_variable_set(:@__vc_config, nil)
super
end
# :nocov:
end

class_methods do
def view_component_config
@__vc_config ||= if respond_to?(:superclass) && superclass.respond_to?(:view_component_config)
superclass.view_component_config.inheritable_copy
else
# create a new "anonymous" class that will host the compiled reader methods
ViewComponent::ComponentLocalConfig::Configuration.new
end
end

def configure_view_component(&block)
view_component_config.instance_eval(&block)
view_component_config.compile_methods!
end
end
end
end
7 changes: 7 additions & 0 deletions test/sandbox/app/components/configurable_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class ConfigurableComponent < ViewComponent::Base
configure_view_component do |config|
config.strip_trailing_whitespace = true
end
end
8 changes: 8 additions & 0 deletions test/sandbox/test/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,12 @@ def test_uses_module_configuration
assert_equal "AnotherController", TestAlreadyConfigurableModule::SomeComponent.test_controller
assert_equal "AnotherController", TestAlreadyConfiguredModule::SomeComponent.test_controller
end

def test_component_local_config_is_inheritable
assert_equal false, ViewComponent::Base.view_component_config.strip_trailing_whitespace
# This component doesn't call configure, so it should inherit the defaults.
assert_equal false, AnotherComponent.view_component_config.strip_trailing_whitespace
# This component overrides the defaults.
assert_equal true, ConfigurableComponent.view_component_config.strip_trailing_whitespace
end
end
Loading