Skip to content

Commit 4c4abaa

Browse files
authored
Omit attributes when the value is an empty list or contains only nils (#910)
Implements #909. I haven't benchmarked this but I'm hopeful about it. Because `__attributes__` implicitly discards nil via the `case value` statement, we just have to make `__nested_tokens__` resolve to nil, which is accomplished by returning early on an empty buffer. We can handle nested arrays and sets, as well as nested attributes, by checking for that nil return value in places where we call `__nested_tokens__`.
2 parents 06f624e + 561aa6e commit 4c4abaa

File tree

2 files changed

+102
-13
lines changed

2 files changed

+102
-13
lines changed

lib/phlex/sgml/attributes.rb

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,13 @@ def generate_nested_attributes(attributes, base_name, buffer = +"")
135135
when Hash
136136
generate_nested_attributes(v, "#{base_name}#{name}-", buffer)
137137
when Array
138-
buffer << " " << base_name << name << '="' << generate_nested_tokens(v) << '"'
138+
if (value = generate_nested_tokens(v))
139+
buffer << " " << base_name << name << '="' << value << '"'
140+
end
139141
when Set
140-
buffer << " " << base_name << name << '="' << generate_nested_tokens(v.to_a) << '"'
142+
if (value = generate_nested_tokens(v.to_a))
143+
buffer << " " << base_name << name << '="' << value << '"'
144+
end
141145
when Phlex::SGML::SafeObject
142146
buffer << " " << base_name << name << '="' << v.to_s.gsub('"', "&quot;") << '"'
143147
else
@@ -181,11 +185,19 @@ def generate_nested_tokens(tokens, sep = " ", gsub_from = nil, gsub_to = "")
181185
buffer << token.to_s
182186
end
183187
when Array
184-
if token.length > 0
188+
if token.length > 0 && (value = generate_nested_tokens(token, sep, gsub_from, gsub_to))
189+
if i > 0
190+
buffer << sep << value
191+
else
192+
buffer << value
193+
end
194+
end
195+
when Set
196+
if token.length > 0 && (value = generate_nested_tokens(token.to_a, sep, gsub_from, gsub_to))
185197
if i > 0
186-
buffer << sep << generate_nested_tokens(token, sep, gsub_from, gsub_to)
198+
buffer << sep << value
187199
else
188-
buffer << generate_nested_tokens(token, sep, gsub_from, gsub_to)
200+
buffer << value
189201
end
190202
end
191203
when nil
@@ -197,6 +209,8 @@ def generate_nested_tokens(tokens, sep = " ", gsub_from = nil, gsub_to = "")
197209
i += 1
198210
end
199211

212+
return if buffer.empty?
213+
200214
buffer.gsub('"', "&quot;")
201215
end
202216

quickdraw/sgml/attributes.test.rb

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,27 @@
194194

195195
test "_, Array" do
196196
output = phlex { div(attribute: []) }
197-
assert_equal_html output, %(<div attribute=""></div>)
197+
assert_equal_html output, %(<div></div>)
198+
end
199+
200+
test "_, Array(Array)" do
201+
output = phlex { div(attribute: [[], [], []]) }
202+
assert_equal_html output, %(<div></div>)
198203
end
199204

200205
test "_, Array(nil)" do
201206
output = phlex { div(attribute: [nil, nil, nil]) }
202-
assert_equal_html output, %(<div attribute=""></div>)
207+
assert_equal_html output, %(<div></div>)
208+
end
209+
210+
test "_, Array(Array(nil))" do
211+
output = phlex { div(attribute: [[nil, nil], [nil, nil]]) }
212+
assert_equal_html output, %(<div></div>)
213+
end
214+
215+
test "_, Array(Array(nil), nil)" do
216+
output = phlex { div(attribute: [[nil, nil], nil]) }
217+
assert_equal_html output, %(<div></div>)
203218
end
204219

205220
test "_, Array(String)" do
@@ -371,6 +386,11 @@
371386
assert_equal_html output, %(<div data-controller-hello="world"></div>)
372387
end
373388

389+
test "_, Hash(_, Hash(_, nil)" do
390+
output = phlex { div(data: { controller: { hello: nil } }) }
391+
assert_equal_html output, %(<div></div>)
392+
end
393+
374394
test "_, Hash(_, Phlex::SGML::SafeObject)" do
375395
output = phlex { div(data: { controller: Phlex::SGML::SafeValue.new("Hello") }) }
376396
assert_equal_html output, %(<div data-controller="Hello"></div>)
@@ -386,15 +406,70 @@
386406
assert_equal_html output, %(<div></div>)
387407
end
388408

409+
test "_, Hash(_, Array)" do
410+
output = phlex { div(data: { action: [] }) }
411+
assert_equal_html output, %(<div></div>)
412+
end
413+
414+
test "_, Hash(_, Array(nil))" do
415+
output = phlex { div(data: { action: [nil] }) }
416+
assert_equal_html output, %(<div></div>)
417+
end
418+
419+
test "_, Hash(_, Set)" do
420+
output = phlex { div(data: { action: Set[] }) }
421+
assert_equal_html output, %(<div></div>)
422+
end
423+
424+
test "_, Hash(_, Set(Set))" do
425+
output = phlex { div(data: { action: Set[Set[]] }) }
426+
assert_equal_html output, %(<div></div>)
427+
end
428+
429+
test "_, Hash(_, Set(nil))" do
430+
output = phlex { div(data: { action: Set[nil] }) }
431+
assert_equal_html output, %(<div></div>)
432+
end
433+
434+
test "_, Hash(_, Set(Set(nil)))" do
435+
output = phlex { div(data: { action: Set[Set[nil]] }) }
436+
assert_equal_html output, %(<div></div>)
437+
end
438+
389439
test "_, Hash(_, *invalid*)" do
390440
assert_raises(Phlex::ArgumentError) do
391441
phlex { div(data: { controller: Object.new }) }
392442
end
393443
end
394444

445+
test "_, Set" do
446+
output = phlex { div(attribute: Set[]) }
447+
assert_equal_html output, %(<div></div>)
448+
end
449+
395450
test "_, Set(nil)" do
396451
output = phlex { div(attribute: Set[nil, nil, nil]) }
397-
assert_equal_html output, %(<div attribute=""></div>)
452+
assert_equal_html output, %(<div></div>)
453+
end
454+
455+
test "_, Set(Set)" do
456+
output = phlex { div(attribute: Set[Set[]]) }
457+
assert_equal_html output, %(<div></div>)
458+
end
459+
460+
test "_, Set(Set(nil))" do
461+
output = phlex { div(attribute: Set[Set[nil, nil, nil]]) }
462+
assert_equal_html output, %(<div></div>)
463+
end
464+
465+
test "_, Set(Set, nil)" do
466+
output = phlex { div(attribute: Set[Set[], nil]) }
467+
assert_equal_html output, %(<div></div>)
468+
end
469+
470+
test "_, Set(Set(nil), nil)" do
471+
output = phlex { div(attribute: Set[Set[nil], nil]) }
472+
assert_equal_html output, %(<div></div>)
398473
end
399474

400475
test "_, Set(String)" do
@@ -540,7 +615,7 @@
540615

541616
test ":srcset on img with an Array" do
542617
output = phlex { img(srcset: []) }
543-
assert_equal_html output, %(<img srcset="">)
618+
assert_equal_html output, %(<img>)
544619

545620
output = phlex { img(srcset: ["/width=400/image.jpg 1x", "/width=400,dpr=2/image.jpg 2x"]) }
546621
assert_equal_html output, %(<img srcset="/width=400/image.jpg 1x, /width=400%2Cdpr=2/image.jpg 2x">)
@@ -551,7 +626,7 @@
551626

552627
test ":media on link with an Array" do
553628
output = phlex { link(media: []) }
554-
assert_equal_html output, %(<link media="">)
629+
assert_equal_html output, %(<link>)
555630

556631
output = phlex { link(media: ["screen", "print"]) }
557632
assert_equal_html output, %(<link media="screen, print">)
@@ -562,15 +637,15 @@
562637

563638
test ":sizes on link with an Array" do
564639
output = phlex { link(sizes: []) }
565-
assert_equal_html output, %(<link sizes="">)
640+
assert_equal_html output, %(<link>)
566641

567642
output = phlex { link(sizes: ["16x16", "32x32", "64x64"]) }
568643
assert_equal_html output, %(<link sizes="16x16, 32x32, 64x64">)
569644
end
570645

571646
test ":imagesrcset on link with an Array when rel is preload and as is image" do
572647
output = phlex { link(imagesrcset: [], rel: "preload", as: "image") }
573-
assert_equal_html output, %(<link imagesrcset="" rel="preload" as="image">)
648+
assert_equal_html output, %(<link rel="preload" as="image">)
574649

575650
output = phlex { link(imagesrcset: ["image.jpg 1x", "[email protected] 2x"], rel: "preload", as: "image") }
576651
assert_equal_html output, %(<link imagesrcset="image.jpg 1x, [email protected] 2x" rel="preload" as="image">)
@@ -584,7 +659,7 @@
584659

585660
test ":accept on input with array when type is file" do
586661
output = phlex { input(accept: [], type: "file") }
587-
assert_equal_html output, %(<input accept="" type="file">)
662+
assert_equal_html output, %(<input type="file">)
588663

589664
output = phlex { input(accept: ["image/jpeg", "image/png"], type: "file") }
590665
assert_equal_html output, %(<input accept="image/jpeg, image/png" type="file">)

0 commit comments

Comments
 (0)