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

Separate interpolation from verbatim text #130

Merged

Conversation

little-bobby-tables
Copy link
Contributor

This is the last PR I've had in works, it fixes some long-outstanding issues like this and #119.

I've had to change the embedded engines code a bit, I've made sure that the tests are passing but they may not be covering all use cases so feedback on that is highly appreciated.

TODO:
* fix the remaining tests
* apply the changes to embedded engines as well (??? this is
a part of the public API so I'm not sure how to approach it yet)
* remove the quoting regex
Copy link
Member

@Rakoth Rakoth left a comment

Choose a reason for hiding this comment

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

😻 Awesome job, @little-bobby-tables!
There is one thing to discuss, I left a comment about interpolations in embedded engines.

@@ -91,13 +87,10 @@ text_block <- text_block_line (crlf
text_block_nested_lines <- text_block_line (crlf (
indent lines:text_block_nested_lines dedent / lines:text_block_nested_lines
))*;
text_block_line <- space? (dynamic:text_with_interpolation / simple:text);
text_block_line <- space? text_item*;
Copy link
Member

Choose a reason for hiding this comment

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

Should it be text_item+?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

text_item only matches a non-empty string, which works well for e.g. inline_html where text is mandatory, but needs the optional modifier for empty string consumers like text_block_line.


def parse(header, lines) do
case Regex.named_captures(@embedded_engine_regex, header) do
%{"engine" => engine, "indent" => indent} when engine in @registered_engines ->
Copy link
Member

Choose a reason for hiding this comment

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

Better to keep this check, it will be easier to add descriptive error in case of invalid engine name


def render_with_engine(engine, lines) when is_list(lines) do
def render_with_engine(engine, line_contents) when is_list(line_contents) do
lines = Enum.map(line_contents, &compile/1)
Copy link
Member

Choose a reason for hiding this comment

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

Since engine developer should be aware of interpolation injections into engine body, I think it will be better to pass original list of raw text and interpolations in form of {:eex, text} instead of compiled version with interpolations presented as <%= text %>. For example in elixir engine interpolations should not be converted into eex injections at all. Also with this approach there is no need in compile here, because the result of embedded engine render will any way go through a compiler later.

Copy link
Member

Choose a reason for hiding this comment

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

example for elixir engine, which now compiles into invalid eex:

elixir:
  a = "test"
  b = "b-#{a}"
= b

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I didn't think about that; it certainly makes sense to decide on how to render interpolation on a per engine basis, as your example shows. I've added it as a test case.

On a somewhat unrelated note, this should probably be mentioned in the release notes — it seems to me the Markdown example won't work anymore.

Copy link
Member

@Rakoth Rakoth left a comment

Choose a reason for hiding this comment

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

There is one more TODO left about separation of dynamic blocks and static text in grammar, we don't need it any more.
👍 LGTM

@@ -25,9 +27,6 @@ defmodule Slime.Parser.Transform do
"#" => %{attr: "id"}
})

# TODO: separate dynamic elixir blocks by parser
@quote_outside_interpolation_regex ~r/(^|\G)(?:\\.|[^#]|#(?!\{)|(?<pn>#\{(?:[^"}]++|"(?:\\.|[^"#]|#(?!\{)|(?&pn))*")*\}))*?\K"/u
Copy link
Member

Choose a reason for hiding this comment

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

RIP

@doomspork
Copy link
Member

doomspork commented Jun 9, 2017

💥 Thank you @little-bobby-tables and @Rakoth — you guys are awesome 💜

@Rakoth I'd like to release a new version, did you see my comments here: #129?

@doomspork doomspork merged commit aee527a into slime-lang:master Jun 9, 2017
@little-bobby-tables little-bobby-tables deleted the separate-interpolation branch June 10, 2017 02:19
@Rakoth Rakoth mentioned this pull request Jun 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants