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

Allow rendering strings #596

Merged
merged 2 commits into from
Nov 24, 2023
Merged

Allow rendering strings #596

merged 2 commits into from
Nov 24, 2023

Conversation

joeldrapper
Copy link
Collaborator

No description provided.

@joeldrapper joeldrapper marked this pull request as draft October 31, 2023 20:11
@bradgessler
Copy link
Contributor

I pulled this gem into https://github.com/rubymonolith/demo/tree/render-strings

I still get these errors:

ArgumentError ('#<Method: BlogsController::Index#title() /Users/bradgessler/Projects/rubymonolith/demo/app/controllers/blogs_controller.rb:46>' is not an ActiveModel-compatible object. It must implement :to_partial_path.):

app/views/layouts/application_layout.rb:16:in `block (3 levels) in template'
app/views/layouts/application_layout.rb:16:in `block (2 levels) in template'
app/views/layouts/application_layout.rb:14:in `block in template'
app/views/layouts/application_layout.rb:13:in `template'
app/views/layouts/page_layout.rb:8:in `template'
app/views/application_view.rb:25:in `render'
app/views/application_view.rb:29:in `around_template'

Here's the code where I'm passing the block into the component as an argument: https://github.com//rubymonolith/demo/blob/07808942f21171cec51938b78c5011f34dd3c211/app/views/application_view.rb#L29-L31

These are the two places I'm trying to render it:

https://github.com//rubymonolith/demo/blob/07808942f21171cec51938b78c5011f34dd3c211/app/views/layouts/page_layout.rb#L12-L13

https://github.com//rubymonolith/demo/blob/07808942f21171cec51938b78c5011f34dd3c211/app/views/layouts/application_layout.rb#L16

Ideally if I pass a block into a class, I'd like to render it like this:

          hgroup do
            h1(&@title)
            h2(&@subtitle)
          end

Instead of like this:

          hgroup do
            h1 { render @title }
            h2 { render @subtitle }
          end

@joeldrapper
Copy link
Collaborator Author

When you render like this h1(&@title), @title must respond to to_proc, returning either a Proc accepting any number of arguments, or a Lambda that accepts exactly one argument.

I experimented with adding an arity check to the generated element methods so you could pass a Lambda that accepts no arguments, but doing this check for every element significantly slowed the overall performance.

If you use render and pass your @title without the &, after this PR, it will work if @title is:

  1. an instance of Phlex::SGML or an instance of a subclass of Phlex::SGML;
  2. a subclass of Phlex::SGML;
  3. a Proc;
  4. a Lambda accepting 0 or 1 arguments;
  5. a Method accepting 0 or 1 arguments;
  6. a String; or
  7. an Enumerable of any of the above.

If an argument is accepted by the Proc/Lambda/Method, it will be called with the component instance.

Since render is used less than elements, the arity check isn't too expensive.

What's nice about this solution is it's compatible with many different things. You can accept a title argument, and the caller can give you any of these types, including a simple String.

@bradgessler
Copy link
Contributor

I experimented with adding an arity check to the generated element methods so you could pass a Lambda that accepts no arguments, but doing this check for every element significantly slowed the overall performance.

This makes sense, thanks!

I'm wondering if there's a way to make the error messages for these types of performance trade-offs more informative. For example, if I try this:

hgroup do
  h1(&@title)
  h2(&@subtitle)
end

I'd find this a more useful exception message:

Error rendering h1(&@title). Try rendering from within the block: `h1 { render @title }`.

In theory this wouldn't impact performance, even if it takes a while to reflect on Ruby code to generate that message, because generating the exception stays out of the critical rendering path.

@joeldrapper joeldrapper marked this pull request as ready for review November 24, 2023 12:45
@joeldrapper joeldrapper merged commit ddeb5dc into main Nov 24, 2023
17 checks passed
@joeldrapper joeldrapper deleted the render-strings branch November 24, 2023 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants