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

Support inline tags #755

Merged
merged 3 commits into from
Sep 2, 2024
Merged

Conversation

Xanderwot
Copy link
Contributor

@Xanderwot Xanderwot commented Aug 30, 2024

Based on issue

Adding support of inline tag declaration
Examples:

h1 'Hello'

will render:

<h1>Hello</h1>
div do
  h1 'Hello', class: 'title'
end

will render:

<div><h1 class="title">Hello</h1></div>

Adding support of inline tag declaration
Examples:
```
h1 'Hello'
```
will render:
```
<h1>Hello</h1>
```

```
div do
  h1 'Hello', class: 'title'
end
```
will render:
```
<div><h1 class="title">Hello</h1></div>
```

Some specific cases where block passed as inline element should be properly wrapped because of ruby blocks calls sequence rules
ie:
```
def div_block
  proc do
    div attr: 'fourth' do
      'Hello'
    end
  end
end

def view_template
  div attr: 'first' do
    div attr: 'second' do
      div(div_block, attr: 'third')
    end
  end
end
```
In this particular case `div_block` content should be wrapped to a proc to keep execution sequence
Comment on lines 64 to 65
inline_block = content.is_a?(Proc) ? content : proc { content }
yield_content(&inline_block)
Copy link
Collaborator

@joeldrapper joeldrapper Aug 30, 2024

Choose a reason for hiding this comment

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

I think we should probably do something more like this:

case content
when Proc
  yield_content(&content)
when String
  plain(content)
else
  raise ArgumentError
end

In the case that we're given a string, we can completely avoid the block which should mean it’s faster.

Copy link
Contributor Author

@Xanderwot Xanderwot Aug 30, 2024

Choose a reason for hiding this comment

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

Good catch.
I moved processing method to SGML class. I hope it's ok.
Tests also improved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pls let me know if I need to update documentation somewhere. Thanks

@Xanderwot Xanderwot force-pushed the inline-tag-support branch 2 times, most recently from db28a5c to 5682854 Compare August 30, 2024 12:00
Copy link
Collaborator

@joeldrapper joeldrapper left a comment

Choose a reason for hiding this comment

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

I like this change and it’s non-breaking. We’ve never come up with anything else to use the positional argument for so I think this makes sense. I’ve pinged @willcosgrove for his thoughts though as this is a huge change and one that would be difficult to reverse.

@willcosgrove
Copy link
Contributor

@joeldrapper convinced me that this is a good change 😄

I think we should not allow nesting using this though.

h1(em("Hello")) # 💥

And I think wrapping it in a proc (while it does fix the issue of the elements not getting added to the buffer at the right time) is not something we should support.

@Xanderwot
Copy link
Contributor Author

Xanderwot commented Aug 31, 2024

@joeldrapper convinced me that this is a good change 😄

I think we should not allow nesting using this though.

h1(em("Hello")) # 💥

And I think wrapping it in a proc (while it does fix the issue of the elements not getting added to the buffer at the right time) is not something we should support.

It's actually pretty specific cases what I faced when tests inline tags in my application. I doubt what it frequently used(h1(em("Hello")) I mean). Anyway proc wrapping is not a main idea. Idea of inline tags to make page structure little bit easier in some cases and not to use it in some crazy cases like huge inline tags sequence.
I did include this specific to a tests just to show how it can be solved because of ruby specific but using it delegates to a developers(if they know what they doing)
It's yours decision anyway I'm just suggesting small improvement to you(I hope so) maybe it will be useful for someone.
Actually it comes from our migration from fortitude which supports this inline tags
Main idea not to create extra Proc objects for tables for example:

table do
  tr do
    th 'Name'
    th 'Age' 
  end
  @users.each do |user|
    tr do
      td user.name
      td user.age
    end
  end
end

@joeldrapper joeldrapper self-requested a review August 31, 2024 12:09
@joeldrapper
Copy link
Collaborator

joeldrapper commented Aug 31, 2024

Okay final feedback on this:

Let's make sure we raise if you use a positional argument and a block, e.g.

h1("Hello") { "World" }

Let’s make sure we raise if you pass nil.

h1(h2("Hi"))

h2 here returns nil so the h1 call should raise. The way we can detect this is by setting the default to a different “null object” that we can specifically check for.

We won’t be able to use nil as the default (content = nil). Instead, let’s define a Phlex::Null and use that as the default.

module Phlex
  Null = Object.new.freeze
end

Then we can check against that

  if Phlex::Null != content
    ...

Let’s also remove the Proc option as @willcosgrove mentioned at least for now. Adding support for this later is non-breaking but we can’t remove it once we add it.

Finally, while extracting methods is generally good practice, I expect we will get better performance if we just inline the stuff in process_inline_content even though there will be some duplication between standard and void elements. This will save a method call for every time we render an element with positional content, which might be thousands of times per page.

@Xanderwot
Copy link
Contributor Author

@joeldrapper Pls take a look ;)

@joeldrapper joeldrapper merged commit 29eb1e4 into phlex-ruby:main Sep 2, 2024
9 of 12 checks passed
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.

3 participants