From 4784864d0ab6ec6777fa41d0a6da5f0392a6b8b2 Mon Sep 17 00:00:00 2001 From: Mitchell Hanberg Date: Thu, 3 Nov 2022 08:32:32 -0700 Subject: [PATCH 1/2] Test case --- test/temple/renderer_test.exs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/temple/renderer_test.exs b/test/temple/renderer_test.exs index 74a87ff..d90a049 100644 --- a/test/temple/renderer_test.exs +++ b/test/temple/renderer_test.exs @@ -510,6 +510,21 @@ defmodule Temple.RendererTest do assert expected == result end + test "runtime boolean attributes don't emit with falsy values" do + truthy = false + result = + Renderer.compile do + input type: "text", disabled: truthy, placeholder: "Enter some text..." + end + + # html + expected = """ + + """ + + assert expected == result + end + test "multiple slots" do assigns = %{} From 412e8c33c015d8439e4a070935bf78c841d9757d Mon Sep 17 00:00:00 2001 From: Mitchell Hanberg Date: Fri, 11 Nov 2022 22:24:25 -0500 Subject: [PATCH 2/2] fix: runtime boolean attributes Closes #187 Attributes dynamically set to false are not discarded --- CHANGELOG.md | 12 ++++++++---- guides/your-first-template.md | 4 ++-- lib/temple/ast/utils.ex | 11 ++++++++++- test/parser/utils_test.exs | 23 +++++++++++------------ test/temple/renderer_test.exs | 10 ++++++---- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85827d2..3f579fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Main +### Breaking Changes + +- Rendering slots is now done by passing the assign with the slot name to the `slot` keyword instead of name as an atom. If this slot has multiple definitions, you can loop through them and render each one individually, or render them all at once. Please see the migration guide for more information. +- The `:default` slot has been renamed to `:inner_block`. This is to be easily compatible with HEEx/Surface. Please see the migration guide for more information. +- Capturing the data being passed into a slot is now defined using the `:let` attribute. Please see the migration guide for more information. + ### Enhancements - Temple components are now compatible with HEEx/Surface components! Some small tweaks to the component implementation has made this possible. Please see the guides for more information. @@ -9,11 +15,9 @@ - You can now pass arbitrary data to slots, and it does not need to be a map or a keyword list. I don't think this is a breaking change, but please submit an issue if you notice it is. - Slot attributes. You can now pass data into a slot from the definition site and use it at the call site (inside the component). -### Breaking Changes +### Fixes -- Rendering slots is now done by passing the assign with the slot name to the `slot` keyword instead of name as an atom. If this slot has multiple definitions, you can loop through them and render each one individually, or render them all at once. Please see the migration guide for more information. -- The `:default` slot has been renamed to `:inner_block`. This is to be easily compatible with HEEx/Surface. Please see the migration guide for more information. -- Capturing the data being passed into a slot is now defined using the `:let` attribute. Please see the migration guide for more information. +- Attributes with runtime values that evaluate to true or false will be rendered correctly as boolean attributes. ### 0.10.0 diff --git a/guides/your-first-template.md b/guides/your-first-template.md index e2bd592..035d035 100644 --- a/guides/your-first-template.md +++ b/guides/your-first-template.md @@ -125,8 +125,8 @@ Attributes are declared as a keyword list. - Keys with underscores are converted to the kebab syntax. - Values can be Elixir expressions. -- Values that are compile time `true` will be emitted as a boolean attribute. `disabled` and `checked` are examples of boolean attributes. -- Values that are compile time `false` will not be emitted into the document at all. +- Values that evaluate to `true` will be emitted as a boolean attribute. `disabled` and `checked` are examples of boolean attributes. +- Values that evaluate `false` will not be emitted into the document at all. - The class attribute has a special "object syntax" that allows you to specify classes as a keyword list, only emitting classes that evaluate to true into the final class. Let's look at an example. diff --git a/lib/temple/ast/utils.ex b/lib/temple/ast/utils.ex index a1513d2..fad2f14 100644 --- a/lib/temple/ast/utils.ex +++ b/lib/temple/ast/utils.ex @@ -49,7 +49,16 @@ defmodule Temple.Ast.Utils do end def build_attr(name, {_, _, _} = value) do - [{:text, ~s' #{name}="'}, {:expr, value}, {:text, ~s'"'}] + expr = + quote do + case unquote(value) do + true -> " " <> unquote(name) + false -> "" + _ -> ~s' #{unquote(name)}="#{unquote(value)}"' + end + end + + [{:expr, expr}] end def build_attr("class", classes) when is_list(classes) do diff --git a/test/parser/utils_test.exs b/test/parser/utils_test.exs index f03b374..31d6343 100644 --- a/test/parser/utils_test.exs +++ b/test/parser/utils_test.exs @@ -19,20 +19,19 @@ defmodule Temple.Ast.UtilsTest do test "returns a list of text and expr nodes for attributes with runtime values" do class_ast = quote(do: @class) - id_ast = quote(do: @id) - attrs = [class: class_ast, id: id_ast, disabled: false, checked: true] + attrs = [class: class_ast, id: "foo"] - actual = Utils.compile_attrs(attrs) + assert [{:expr, actual}, {:text, ~s' id="foo"'}] = Utils.compile_attrs(attrs) - assert [ - {:text, ~s' class="'}, - {:expr, class_ast}, - {:text, ~s'"'}, - {:text, ~s' id="'}, - {:expr, id_ast}, - {:text, ~s'"'}, - {:text, ~s' checked'} - ] == actual + assert Macro.to_string( + quote do + case @class do + true -> " " <> "class" + false -> "" + _ -> ~s' #{"class"}="#{@class}"' + end + end + ) == Macro.to_string(actual) end test "returns a list of text and expr nodes for the class object syntax" do diff --git a/test/temple/renderer_test.exs b/test/temple/renderer_test.exs index d90a049..4e9cfe6 100644 --- a/test/temple/renderer_test.exs +++ b/test/temple/renderer_test.exs @@ -510,16 +510,18 @@ defmodule Temple.RendererTest do assert expected == result end - test "runtime boolean attributes don't emit with falsy values" do - truthy = false + test "runtime boolean attributes emit the right values" do + truthy = true + falsey = false + result = Renderer.compile do - input type: "text", disabled: truthy, placeholder: "Enter some text..." + input type: "text", disabled: falsey, checked: truthy, placeholder: "Enter some text..." end # html expected = """ - + """ assert expected == result