-
-
Notifications
You must be signed in to change notification settings - Fork 124
Add ruby_render Liquid tag
#1055
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
base: main
Are you sure you want to change the base?
Conversation
| site:, | ||
| page: payload["page"], | ||
| cached_partials: self.class.cached_partials, | ||
| resource: document, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this becausepage is a Bridgetown::Drops::ResourceDrop, not the full resource that is needed to create a RubyTemplateView in the new tag below.
There's also context["resource"], but it too is a Bridgetown::Drops::ResourceDrop.
| require "helper" | ||
|
|
||
| class TestTags < BridgetownUnitTest | ||
| using HashWithDotAccess::Refinements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried nested Structs too, instead of .as_dots below, but that didn't make the tests in this file run noticeably faster.
| def create_post(content, override = {}, converter_class = Bridgetown::Converters::Markdown) # rubocop:disable Metrics/AbcSize | ||
| def create_post(content:, override: {}, converter_class: Bridgetown::Converters::Markdown, page_title: nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made these into keyword arguments in a separate commit to avoid one gross call to this method. If it's preferable to keep the positional args, I'm fine omitting that commit.
I added the :page_title arg because one of the new tests uses it in the component that it renders (see the expectation below). I'm passing in the page title rather than parsing the YAML header because that seems like overkill for just one test case that needs the page title to be available.
| resource: { | ||
| site:, | ||
| data: { | ||
| title: page_title, | ||
| layout: "default", | ||
| }, | ||
| }.as_dots, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:resource is needed for testing ruby_render (below).
8defa34 to
af3dd81
Compare
af3dd81 to
3b92fbe
Compare
| fill_post("test") | ||
| fill_post(code: "test") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rest of the changes in this file are the switch to keyword arguments.
| # @return [String] | ||
| def render(context) | ||
| view_context = Bridgetown::RubyTemplateView.new(context.registers[:resource]) | ||
| result = eval(@ruby_expression) # rubocop:disable Security/Eval |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to avoid eval, it might be better to use a non-Ruby syntax for the Liquid tag contents (such as the one we previously discussed in the GH Issue), because the other way to parse the contents (apart from eval) is via regex, and trying to emulate Ruby parsing via regex seems difficult to do well, even if we allow nothing other than component instantiation.
If the regex route is preferable, I assume it's because eval is insecure, but I would be curious to know how specifically, for this use case.
|
|
||
| ## Rendering Ruby Components from Liquid Templates | ||
|
|
||
| You can use the `ruby_render` helper from Liquid templates to render Ruby components. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ruby components are the primary use case, so I'm not sure if it's worth mentioning that it's possible to render any Ruby expression—if it's not a component (i.e. doesn't have #render_in) then it's rendered with #to_s (see above).
|
Some cool stuff in here @fpsvogel. I'll want to think on this a bit…one of the promises of Liquid is that you're working within a "sandboxed" environment and all the values/tags/etc. live with the Liquid environment. If we punch a hole right into Ruby land with |
This is a 🙋 feature or enhancement.
Summary
Adds a Liquid tag
ruby_renderthat renders a Ruby expression or a simple Ruby component. "Simple" meaning without content in a block:Context
Resolves #976
Manual test
I created a new site with
bridgetown new test_site -t liquid, then created two Ruby components:Then I rendered these two components plus a Ruby expression (to show that's possible too) at the top of the blog post:
Added section on website "Ruby Components" page
Adapted from the section on liquid_render