Skip to content
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

Add from to use_helpers to add macro like syntax #2034

Merged
merged 23 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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 @@ -18,6 +18,10 @@ nav_order: 5

*Reegan Viljoen*

* Add `from:` option to `use_helpers` to allow for more flexible helper inclusion from modules.

*Reegan Viljoen*

## 3.12.1

* Ensure content is rendered correctly for forwarded slots.
Expand Down
12 changes: 12 additions & 0 deletions docs/guide/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@
end
```

Methods defined in helper modules that are not available in the component can be included individually using the `from:` keyword:

Check failure on line 72 in docs/guide/helpers.md

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Microsoft.Contractions] Use 'aren't' instead of 'are not'. Raw Output: {"message": "[Microsoft.Contractions] Use 'aren't' instead of 'are not'.", "location": {"path": "docs/guide/helpers.md", "range": {"start": {"line": 72, "column": 40}}}, "severity": "ERROR"}

```ruby
class UserComponent < ViewComponent::Base
use_helpers :icon, from: IconHelper
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would make sense to support the singular form use_helper as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Spone I have added this recommendation, as it seems like a great fit


def profile_icon
icon :user
end
end
```

## Nested URL helpers

Rails nested URL helpers implicitly depend on the current `request` in certain cases. Since ViewComponent is built to enable reusing components in different contexts, nested URL helpers should be passed their options explicitly:
Expand Down
22 changes: 21 additions & 1 deletion lib/view_component/use_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,35 @@ module ViewComponent::UseHelpers
extend ActiveSupport::Concern

class_methods do
def use_helpers(*args)
def use_helpers(*args, from: nil)
if from.nil?
define_helpers_without_source(*args)
else
define_helpers_with_source(*args, source: from)
end
end

private

def define_helpers_without_source(*args)
args.each do |helper_method|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
def #{helper_method}(*args, &block)
raise HelpersCalledBeforeRenderError if view_context.nil?
__vc_original_view_context.#{helper_method}(*args, &block)
end
RUBY
ruby2_keywords(helper_method) if respond_to?(:ruby2_keywords, true)
end
end

def define_helpers_with_source(*args, source:)
args.each do |helper_method|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
def #{helper_method}(*args, &block)
#{source}.instance_method(:#{helper_method}).bind(self).call(*args, &block)
end
RUBY
ruby2_keywords(helper_method) if respond_to?(:ruby2_keywords, true)
end
end
Expand Down
11 changes: 11 additions & 0 deletions test/sandbox/app/components/use_helpers_macro_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class='helper__message'>
<%= message %>
</div>

<div class='helper__args-message'>
<%= message_with_args('macro helper method') %>
</div>

<div class='helper__kwargs-message'>
<%= message_with_kwargs(name: 'macro kwargs helper method') %>
</div>
5 changes: 5 additions & 0 deletions test/sandbox/app/components/use_helpers_macro_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class UseHelpersMacroComponent < ViewComponent::Base
use_helpers :message, :message_with_args, :message_with_kwargs, from: MacroHelper
end
15 changes: 15 additions & 0 deletions test/sandbox/app/helpers/macro_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module MacroHelper
def message
"Hello helper method"
end

def message_with_args(name)
"Hello #{name}"
end

def message_with_kwargs(name:)
"Hello #{name}"
end
end
18 changes: 18 additions & 0 deletions test/sandbox/test/rendering_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1121,4 +1121,22 @@ def test_inline_component_renders_without_trailing_whitespace

refute @rendered_content =~ /\s+\z/, "Rendered component contains trailing whitespace"
end

def test_use_helper_macros
render_inline(UseHelpersMacroComponent.new)

assert_selector ".helper__message", text: "Hello helper method"
end

def test_use_helper_macros_with_args
render_inline(UseHelpersMacroComponent.new)

assert_selector ".helper__args-message", text: "Hello macro helper method"
end

def test_use_helper_macros_with_kwargs
render_inline(UseHelpersMacroComponent.new)

assert_selector ".helper__kwargs-message", text: "Hello macro kwargs helper method"
end
end
Loading