From b6ca06cd62ccb4e9a466eac06957926fa466ad0a Mon Sep 17 00:00:00 2001 From: stephann Date: Fri, 26 Dec 2025 10:57:47 -0300 Subject: [PATCH 1/2] Allow Hash attributes --- .../html/attributes_handling_spec.cr | 25 ++++++++++++++++++- src/blueprint/html/attributes_renderer.cr | 10 +++++--- src/blueprint/html/element_registrar.cr | 18 ++++++++++++- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/spec/blueprint/html/attributes_handling_spec.cr b/spec/blueprint/html/attributes_handling_spec.cr index eab94d2..5655e56 100644 --- a/spec/blueprint/html/attributes_handling_spec.cr +++ b/spec/blueprint/html/attributes_handling_spec.cr @@ -29,7 +29,7 @@ describe "attributes handling" do actual_html.should eq expected_html end - it "replaces `_` by `-` on attribute names" do + it "replaces `_` by `-` on Symbol attribute names" do actual_html = Blueprint::HTML.build do section v_model: "user.name", "@click": "doSomething" do "Blueprint" @@ -43,6 +43,29 @@ describe "attributes handling" do actual_html.should eq expected_html end + it "accepts Hash attributes" do + actual_html = Blueprint::HTML.build do + input({ + "data-on:mycustomevent__window" => "$result = evt.detail.value", + "data-bind:foo" => true + }) + + div(id: "myDiv", aria: {enabled: "true"}, data: {"on:mycustomevent__window" => "$result = evt.detail.value" }) do + "Hello" + end + end + + expected_html = normalize_html <<-HTML + + +
+ Hello +
+ HTML + + actual_html.should eq expected_html + end + it "accepts boolean attributes" do actual_html = Blueprint::HTML.build do input disabled: true, checked: false, outline: "true", border: "false" diff --git a/src/blueprint/html/attributes_renderer.cr b/src/blueprint/html/attributes_renderer.cr index 68aed9c..abc6666 100644 --- a/src/blueprint/html/attributes_renderer.cr +++ b/src/blueprint/html/attributes_renderer.cr @@ -1,7 +1,7 @@ module Blueprint::HTML::AttributesRenderer extend self - def render(attributes : NamedTuple, to buffer : String::Builder) : Nil + def render(attributes : NamedTuple | Hash, to buffer : String::Builder) : Nil attributes.each { |name, value| append_attribute(buffer, name, value) } end @@ -15,7 +15,7 @@ module Blueprint::HTML::AttributesRenderer buffer << parse_name(name) end - private def append_attribute(buffer : String::Builder, name, value : NamedTuple) : Nil + private def append_attribute(buffer : String::Builder, name, value : NamedTuple | Hash) : Nil name_prefix = parse_name(name) value.each do |attr_name, attr_value| @@ -51,7 +51,11 @@ module Blueprint::HTML::AttributesRenderer append_value buffer, value.to_s end - private def parse_name(name) : String + private def parse_name(name : Symbol) : String name.to_s.gsub("_", "-") end + + private def parse_name(name : String) : String + name + end end diff --git a/src/blueprint/html/element_registrar.cr b/src/blueprint/html/element_registrar.cr index f3ce5ef..bd5339e 100644 --- a/src/blueprint/html/element_registrar.cr +++ b/src/blueprint/html/element_registrar.cr @@ -3,6 +3,14 @@ module Blueprint::HTML::ElementRegistrar {% tag ||= method_name.tr("_", "-") %} def {{method_name.id}}(**attributes, &block) : Nil + {{method_name.id}}(attributes) { yield } + end + + def {{method_name.id}}(**attributes) : Nil + {{method_name.id}}(attributes) + end + + def {{method_name.id}}(attributes : NamedTuple | Hash, &block) : Nil @buffer << "<{{tag.id}}" AttributesRenderer.render(attributes, to: @buffer) @buffer << ">" @@ -10,7 +18,7 @@ module Blueprint::HTML::ElementRegistrar @buffer << "" end - def {{method_name.id}}(**attributes) : Nil + def {{method_name.id}}(attributes : NamedTuple | Hash) : Nil @buffer << "<{{tag.id}}" AttributesRenderer.render(attributes, to: @buffer) @buffer << ">" @@ -21,6 +29,10 @@ module Blueprint::HTML::ElementRegistrar {% tag ||= method_name.tr("_", "-") %} def {{method_name.id}}(**attributes) : Nil + {{method_name.id}}(attributes) + end + + def {{method_name.id}}(attributes : NamedTuple | Hash) : Nil @buffer << "<{{tag.id}}" AttributesRenderer.render(attributes, to: @buffer) @buffer << ">" @@ -31,6 +43,10 @@ module Blueprint::HTML::ElementRegistrar {% tag ||= method_name.tr("_", "-") %} def {{method_name.id}}(**attributes) : Nil + {{method_name.id}}(attributes) + end + + def {{method_name.id}}(attributes : NamedTuple | Hash) : Nil @buffer << "<{{tag.id}}" AttributesRenderer.render(attributes, to: @buffer) @buffer << ">" From 5959a41215e1ef8fee39da78847dc139da0156bc Mon Sep 17 00:00:00 2001 From: stephann Date: Fri, 26 Dec 2025 11:03:42 -0300 Subject: [PATCH 2/2] Lint code --- spec/blueprint/html/attributes_handling_spec.cr | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/spec/blueprint/html/attributes_handling_spec.cr b/spec/blueprint/html/attributes_handling_spec.cr index 5655e56..983bd6a 100644 --- a/spec/blueprint/html/attributes_handling_spec.cr +++ b/spec/blueprint/html/attributes_handling_spec.cr @@ -45,12 +45,9 @@ describe "attributes handling" do it "accepts Hash attributes" do actual_html = Blueprint::HTML.build do - input({ - "data-on:mycustomevent__window" => "$result = evt.detail.value", - "data-bind:foo" => true - }) + input({"data-on:mycustomevent__window" => "$result = evt.detail.value", "data-bind:foo" => true}) - div(id: "myDiv", aria: {enabled: "true"}, data: {"on:mycustomevent__window" => "$result = evt.detail.value" }) do + div(id: "myDiv", aria: {enabled: "true"}, data: {"on:mycustomevent__window" => "$result = evt.detail.value"}) do "Hello" end end