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

Fix inline nesting #122

Merged
merged 2 commits into from
May 5, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 5 additions & 5 deletions lib/slime/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,25 @@ defmodule Slime.Parser do
end
end

@inline_tag_regex ~r/\A(?<short_tag>(?:[\.#]?[\w-]+)++):\W*(?<inline_tag>.*)/
@inline_tag_regex ~r/\A(?<short_tag>(?:[\.#]?[\w-]+)++):[^\w\.#]*(?<rest>.*)/

def parse_line(line) do
case strip_line(line) do
{_indentation, ""} ->
if Application.get_env(:slime, :keep_lines), do: {:prev, ""}, else: nil
{indentation, line} ->
[tag, inline_tag] =
[tag, rest] =
case Regex.run(@inline_tag_regex, line, capture: :all_but_first) do
nil -> [line, nil]
match -> match
end

parse_tag = fn (tag) -> tag |> String.first |> parse_line(tag) end
tag = parse_tag.(tag)
tag = if inline_tag do
inline_tag = parse_tag.(inline_tag)
tag = if rest do
{0, rest} = parse_line(rest)
{tag_name, attrs} = tag
{tag_name, [{:children, [inline_tag]} | attrs]}
{tag_name, Keyword.put(attrs, :children, [rest])}
else
tag
end
Expand Down
19 changes: 15 additions & 4 deletions lib/slime/tree.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ defmodule Slime.Tree do
|> Enum.map(&to_branch/1)
filter = make_child_filter(indentation)
{children, rem} = Enum.split_while(t, filter)
split_children? = existing == [] && children != [] &&
Application.get_env(:slime, :keep_lines)
sep = if split_children?, do: [%TextNode{content: ""}], else: []
children_tree = existing ++ sep ++ build_tree(children)
children_tree = children |> build_tree |> append_to(existing)
attrs = Keyword.put(attrs, :children, children_tree)
branch = to_branch({tag, attrs})
tree = build_tree(rem)
Expand All @@ -45,6 +42,20 @@ defmodule Slime.Tree do
end
end

defp append_to([], existing), do: existing
defp append_to(children, []), do: sep() ++ children
defp append_to(children, existing = [%TextNode{}]), do: existing ++ children
defp append_to(children, [html_node = %HTMLNode{children: node_children}]) do
case node_children do
[%TextNode{}] -> [html_node] ++ children
_ -> [%{html_node|children: append_to(children, node_children)}]
end
end

defp sep() do
Application.get_env(:slime, :keep_lines) && [%TextNode{content: ""}] || []
end

defp to_branch(%{} = branch), do: branch
defp to_branch(text) when is_binary(text) do
%TextNode{content: text}
Expand Down
24 changes: 24 additions & 0 deletions test/parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@ defmodule ParserTest do
]
end

test "parses inline nesting" do
parsed = [".row: .col-lg-12: p Hello World"] |> Parser.parse_lines
assert parsed == [
{0, {"div",
children: [
{"div",
children: [
{"p",
attributes: [],
children: ["Hello World"],
spaces: %{},
close: false}
],
attributes: [class: "col-lg-12"],
spaces: %{},
close: false}
],
attributes: [class: "row"],
spaces: %{},
close: false}
}
]
end

test "parses css classes with dashes" do
{_, {"div", opts}} = ".my-css-class test"
|> Parser.parse_line
Expand Down
39 changes: 39 additions & 0 deletions test/renderer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,45 @@ defmodule RendererTest do
""" |> String.replace("\n", "")
end

test "render nested inline html" do
slime = ~s"""
.row: .col-lg-12: p Hello World
"""

assert render(slime) == """
<div class="row">
<div class="col-lg-12">
<p>Hello World</p>
</div>
</div>
""" |> String.replace("\n", "")
end

test "render mixed nesting" do
slime = ~s"""
.wrap: .row: .col-lg-12
.box: p One
.box: p Two
p Three
"""

assert render(slime) == """
<div class="wrap">
<div class="row">
<div class="col-lg-12">
<div class="box">
<p>One</p>
</div>
<div class="box">
<p>Two</p>
</div>
</div>
</div>
</div>
<p>Three</p>
""" |> String.replace("\n", "")
end

test "render closed tag (ending with /)" do
assert render(~s(img src="image.png"/)) == ~s(<img src="image.png"/>)
end
Expand Down
52 changes: 52 additions & 0 deletions test/tree_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,56 @@ defmodule TreeTest do

assert parsed == expected
end

test "creates tree with mixed nesting" do
expected = [
%HTMLNode{
tag: :div,
attributes: [class: ~w(wrap)],
children: [
%HTMLNode{
tag: :div,
attributes: [class: ~w(row)],
children: [
%HTMLNode{
tag: :div,
attributes: [class: ~w(col-lg-12)],
children: [
%HTMLNode{
tag: :div,
attributes: [class: ~w(box)],
children: [
%HTMLNode{
tag: :p,
attributes: [],
children: [%TextNode{content: "One"}]}]},
%HTMLNode{
tag: :p,
attributes: [],
children: [%TextNode{content: "Two"}]}]}]}]},
%HTMLNode{
tag: :p,
attributes: [],
children: [%TextNode{content: "Three"}]}]

parsed = [
{0, {:div,
attributes: [class: ~w(wrap)],
children: [
{:div,
attributes: [class: ~w(row)],
children: [
{:div,
attributes: [class: ~w(col-lg-12)],
children: []}]}]}},
{2, {:div,
attributes: [class: ~w(box)],
children: [
{:p, attributes: [], children: ~w(One)}]}},
{2, {:p, attributes: [], children: ~w(Two)}},
{0, {:p, attributes: [], children: ~w(Three)}}
] |> Tree.build_tree

assert parsed == expected
end
end