-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
308 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
require "../../../spec_helper" | ||
|
||
describe MartenTurbo::Template::Tag::TurboStream do | ||
describe "::new" do | ||
it "raises if turbo_stream does not define an action" do | ||
parser = Marten::Template::Parser.new("") | ||
|
||
expect_raises( | ||
Marten::Template::Errors::InvalidSyntax, | ||
"Malformed turbo_stream tag: you must define an action" | ||
) do | ||
MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream") | ||
end | ||
end | ||
|
||
it "raises if turbo_stream does not define a target_id" do | ||
parser = Marten::Template::Parser.new("{% turbo_stream.append %}") | ||
|
||
expect_raises( | ||
Marten::Template::Errors::InvalidSyntax, | ||
"Malformed turbo_stream tag: you must define a target id" | ||
) do | ||
MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream.append") | ||
end | ||
end | ||
|
||
it "raises if turbo_stream block is not closed when 'do' is present at the end" do | ||
parser = Marten::Template::Parser.new( | ||
<<-TEMPLATE | ||
<p>some content</p> | ||
TEMPLATE | ||
) | ||
|
||
expect_raises( | ||
Marten::Template::Errors::InvalidSyntax, | ||
"Unclosed tags, expected: end_turbostream" | ||
) do | ||
MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream.append 'tags' do") | ||
end | ||
end | ||
end | ||
|
||
describe "#render" do | ||
it "properly renders a turbo-stream tag with the correct action and target" do | ||
parser = Marten::Template::Parser.new("") | ||
tag = MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream.remove 'my-id'") | ||
|
||
content = tag.render(Marten::Template::Context.new) | ||
content.should contain "<turbo-stream action=\"remove\" target=\"my-id\">" | ||
content.should_not contain "<template>" | ||
end | ||
|
||
it "properly renders a turbo-stream tag with the correct action and target when given a Marten::Model" do | ||
tag_model = Tag.create!(name: "Marten Turbo") | ||
|
||
parser = Marten::Template::Parser.new("") | ||
tag = MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream.remove tag") | ||
|
||
context = Marten::Template::Context{"tag" => tag_model} | ||
|
||
tag.render(context).should contain "<turbo-stream action=\"remove\" target=\"tag_#{tag_model.pk!}\">" | ||
end | ||
|
||
it "properly renders a turbo-stream tag with correct specified template" do | ||
tag_model = Tag.create!(name: "Marten Turbo") | ||
|
||
parser = Marten::Template::Parser.new("") | ||
tag = MartenTurbo::Template::Tag::TurboStream.new( | ||
parser, | ||
"turbo_stream.append \"tags\" template: \"tags/tag.html\"" | ||
) | ||
|
||
context = Marten::Template::Context{"tag" => tag_model} | ||
|
||
content = tag.render(context) | ||
content.should contain "<div class=\"tag_#{tag_model.pk}\">" | ||
content.should contain "Marten Turbo" | ||
end | ||
|
||
it "raises if the specified template could not be found" do | ||
tag_model = Tag.create!(name: "Marten Turbo") | ||
|
||
parser = Marten::Template::Parser.new("") | ||
tag = MartenTurbo::Template::Tag::TurboStream.new( | ||
parser, | ||
"turbo_stream.append \"tags\" template: \"tags/not_existing_tag.html\"" | ||
) | ||
|
||
context = Marten::Template::Context{"tag" => tag_model} | ||
|
||
expect_raises( | ||
Marten::Template::Errors::TemplateNotFound, | ||
"Template tags/not_existing_tag.html could not be found" | ||
) do | ||
tag.render(context) | ||
end | ||
end | ||
|
||
it "raises if the specified template value is not a string" do | ||
tag_model = Tag.create!(name: "Marten Turbo") | ||
|
||
parser = Marten::Template::Parser.new("") | ||
tag = MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream.append \"tags\" template: 1") | ||
|
||
context = Marten::Template::Context{"tag" => tag_model} | ||
|
||
expect_raises( | ||
Marten::Template::Errors::UnsupportedValue, | ||
"Template name must resolve to a string, git a Int32 instead." | ||
) do | ||
tag.render(context) | ||
end | ||
end | ||
|
||
it "properly renders a turbo_stream block if 'do' is present as last argument" do | ||
parser = Marten::Template::Parser.new( | ||
<<-TEMPLATE | ||
<p>some content</p> | ||
{% end_turbostream %} | ||
TEMPLATE | ||
) | ||
tag = MartenTurbo::Template::Tag::TurboStream.new(parser, "turbo_stream.append 'tags' do") | ||
|
||
tag.render(Marten::Template::Context.new).should contain "<p>some content</p>" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<div class="{% dom_id tag %}"> | ||
{{ tag.name }} | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
module MartenTurbo | ||
module Template | ||
module Tag | ||
module Identifiable | ||
def create_dom_id(value : Marten::Template::Value, prefix : Marten::Template::Value? = nil) | ||
if value.raw.is_a? Marten::Model | ||
generate_id_for_model(value.raw.as(Marten::Model), prefix) | ||
else | ||
dom_id = value.to_s | ||
prefix ? "#{prefix}_#{dom_id}" : dom_id | ||
end | ||
end | ||
|
||
private def formatted_prefix(prefix) | ||
prefix ? "#{prefix}_" : "" | ||
end | ||
|
||
private def generate_id_for_model(model, prefix) | ||
identifier = model.class.name.downcase.gsub(RE_NAMESPACE_IDENTIFIER, '_') | ||
if model.new_record? | ||
"#{formatted_prefix(prefix)}new_#{identifier}" | ||
else | ||
"#{formatted_prefix(prefix)}#{identifier}_#{model.pk}" | ||
end | ||
end | ||
|
||
RE_NAMESPACE_IDENTIFIER = /(?:\:\:|\.)/ | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
require "./concerncs/dom_identifier" | ||
|
||
module MartenTurbo | ||
module Template | ||
module Tag | ||
class TurboStream < Marten::Template::Tag::Base | ||
include Marten::Template::Tag::CanSplitSmartly | ||
include Marten::Template::Tag::CanExtractKwargs | ||
include Identifiable | ||
|
||
@turbo_stream_nodes : Marten::Template::NodeSet? | ||
@action : String | ||
@target_id : Marten::Template::Variable | ||
|
||
def initialize(parser : Marten::Template::Parser, source : String) | ||
parts = split_smartly(source) | ||
|
||
tag_name_parts = parts[0].split(".") | ||
|
||
if tag_name_parts.size != 2 | ||
raise Marten::Template::Errors::InvalidSyntax.new( | ||
"Malformed turbo_stream tag: you must define an action" | ||
) | ||
end | ||
|
||
@action = tag_name_parts[1] | ||
|
||
if parts.size < 2 | ||
raise Marten::Template::Errors::InvalidSyntax.new( | ||
"Malformed turbo_stream tag: you must define a target id" | ||
) | ||
end | ||
|
||
@target_id = Marten::Template::Variable.new(parts[1]) | ||
|
||
if parts[-1] == "do" | ||
@turbo_stream_nodes = parser.parse(up_to: {"end_turbostream"}) | ||
parser.shift_token | ||
kwargs_parts = parts[2...-2] | ||
else | ||
kwargs_parts = parts[2..] | ||
end | ||
|
||
@kwargs = {} of String => Marten::Template::FilterExpression | ||
extract_kwargs(kwargs_parts.join(' ')).each do |key, value| | ||
@kwargs[key] = Marten::Template::FilterExpression.new(value) | ||
end | ||
end | ||
|
||
private def render_template_tag(content) | ||
return "" unless content | ||
|
||
<<-TEMPLATE_TAG | ||
<template> | ||
#{content} | ||
</template> | ||
TEMPLATE_TAG | ||
end | ||
|
||
private def render_turbo_stream_tag(target_id, content) | ||
<<-TURBO_STREAM_TAG | ||
<turbo-stream action="#{@action}" target="#{target_id}"> | ||
#{render_template_tag(content)} | ||
</turbo-stream> | ||
TURBO_STREAM_TAG | ||
end | ||
|
||
def render(context : Marten::Template::Context) : String | ||
content = if turbo_stream_nodes = @turbo_stream_nodes | ||
turbo_stream_nodes.render(context) | ||
else | ||
nil | ||
end | ||
|
||
template = nil | ||
|
||
@kwargs.each do |param_name, param_expression| | ||
raw_param_value = param_expression.resolve(context).raw | ||
|
||
# Ensure that the raw param value can be used as an URL parameter. | ||
unless raw_param_value.is_a?(Marten::Routing::Parameter::Types) | ||
raise Marten::Template::Errors::UnsupportedType.new( | ||
"#{raw_param_value.class} objects cannot be used as URL parameters" | ||
) | ||
end | ||
|
||
if param_name == "template" | ||
unless raw_param_value.is_a?(String) | ||
raise Marten::Template::Errors::UnsupportedValue.new( | ||
"Template name must resolve to a string, git a #{raw_param_value.class} instead." | ||
) | ||
end | ||
template = Marten.templates.get_template(raw_param_value) | ||
end | ||
end | ||
|
||
if template | ||
content = template.render(context) | ||
end | ||
|
||
render_turbo_stream_tag(create_dom_id(@target_id.resolve(context)), content) | ||
end | ||
end | ||
end | ||
end | ||
end |