diff --git a/spec/blueprint/html/enveloping_spec.cr b/spec/blueprint/html/enveloping_spec.cr
deleted file mode 100644
index ad7af25..0000000
--- a/spec/blueprint/html/enveloping_spec.cr
+++ /dev/null
@@ -1,63 +0,0 @@
-require "../../spec_helper"
-
-private class MainLayout
- include Blueprint::HTML
-
- private def blueprint(&)
- html do
- body do
- yield
- end
- end
- end
-end
-
-private class BasePage
- include Blueprint::HTML
-
- private def envelope(&)
- render(MainLayout.new) do
- yield
- end
- end
-end
-
-private class Component
- include Blueprint::HTML
-
- def blueprint
- h1 "Hello World!"
- end
-
- def envelope(&)
- div class: "title" do
- yield
- end
- end
-end
-
-private class IndexPage < BasePage
- private def blueprint
- h1 "Home"
- render Component.new
- end
-end
-
-describe "enveloping" do
- it "allows defining a blueprint wrapper" do
- page = IndexPage.new
- expected_html = normalize_html <<-HTML
-
-
- Home
-
-
-
Hello World!
-
-
-
- HTML
-
- page.to_s.should eq expected_html
- end
-end
diff --git a/spec/blueprint/html/hooks_spec.cr b/spec/blueprint/html/hooks_spec.cr
new file mode 100644
index 0000000..758af2e
--- /dev/null
+++ b/spec/blueprint/html/hooks_spec.cr
@@ -0,0 +1,77 @@
+require "../../spec_helper"
+
+private class ExampleWithBlock
+ include Blueprint::HTML
+
+ private def blueprint(&)
+ h1 { yield }
+ end
+
+ private def before_render(&)
+ span { "Before render" }
+ end
+
+ private def around_render(&)
+ span { "Around start" }
+ yield
+ span { "Around end" }
+ end
+
+ private def after_render(&)
+ span { "After render" }
+ end
+end
+
+private class ExampleWithoutBlock
+ include Blueprint::HTML
+
+ private def blueprint
+ h1 "Without block"
+ end
+
+ private def before_render(&)
+ span { "Before render" }
+ end
+
+ private def around_render(&)
+ span { "Around start" }
+ yield
+ span { "Around end" }
+ end
+
+ private def after_render(&)
+ span { "After render" }
+ end
+end
+
+describe "hooks" do
+ context "with block" do
+ it "allows defining hooks before_render, around_render, after_render" do
+ actual_html = ExampleWithBlock.new.to_s { "With block" }
+ expected_html = normalize_html <<-HTML
+ Before render
+ Around start
+ With block
+ Around end
+ After render
+ HTML
+
+ actual_html.should eq expected_html
+ end
+ end
+
+ context "without block" do
+ it "allows defining hooks before_render, around_render, after_render" do
+ actual_html = ExampleWithoutBlock.new.to_s
+ expected_html = normalize_html <<-HTML
+ Before render
+ Around start
+ Without block
+ Around end
+ After render
+ HTML
+
+ actual_html.should eq expected_html
+ end
+ end
+end
diff --git a/src/blueprint/html.cr b/src/blueprint/html.cr
index 2246485..12dd753 100644
--- a/src/blueprint/html.cr
+++ b/src/blueprint/html.cr
@@ -39,7 +39,19 @@ module Blueprint::HTML
@buffer = buffer
- envelope { blueprint }
+ {% if @type.has_method?(:before_render) %}
+ before_render { }
+ {% end %}
+
+ {% if @type.has_method?(:around_render) %}
+ around_render { blueprint }
+ {% else %}
+ blueprint
+ {% end %}
+
+ {% if @type.has_method?(:after_render) %}
+ after_render { }
+ {% end %}
end
def to_s(buffer : String::Builder, &) : Nil
@@ -47,16 +59,24 @@ module Blueprint::HTML
@buffer = buffer
- envelope do
+ {% if @type.has_method?(:before_render) %}
+ before_render { yield }
+ {% end %}
+
+ {% if @type.has_method?(:around_render) %}
+ around_render do
+ blueprint { capture_content { yield } }
+ end
+ {% else %}
blueprint { capture_content { yield } }
- end
+ {% end %}
+
+ {% if @type.has_method?(:after_render) %}
+ after_render { yield }
+ {% end %}
end
private def render? : Bool
true
end
-
- private def envelope(&) : Nil
- yield
- end
end