philiprehberger-html_builder 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +49 -0
- data/lib/philiprehberger/html_builder/builder.rb +44 -0
- data/lib/philiprehberger/html_builder/version.rb +1 -1
- data/lib/philiprehberger/html_builder.rb +21 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2422583ee49313a76a8eb70b50d6d8de0040b3f8ea9a9e22722013b0ab7537f5
|
|
4
|
+
data.tar.gz: b61ca71f0b42e279fdd9fa4375b7d67c7c9c8db7a85cc4c6575d5e9ba455b87e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 16b555765bd466535c05261da722bdacd670ee72bae7fc635e09de789a02eed4ad6f9020e17404fcb140e34060e1c1be2c5bfff05674e8c5d3867e4f9c8917ed
|
|
7
|
+
data.tar.gz: 75d90b85a6a865213dda114f6e3880d1f059a96ebbfbe348ad872b702fd644c5eece3e86bb56bb1237eae573b74c721dcbf004d3377a05503fce95319e200b69
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-04-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- HTML5 `<!DOCTYPE html>` helper via `Builder#doctype` and `HtmlBuilder.document`
|
|
14
|
+
|
|
15
|
+
## [0.5.0] - 2026-04-15
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `list(items, ordered: false, **attrs, &block)` helper for building `<ul>` or `<ol>` lists from an array of items with optional custom rendering via block
|
|
19
|
+
|
|
10
20
|
## [0.4.0] - 2026-04-15
|
|
11
21
|
|
|
12
22
|
### Added
|
data/README.md
CHANGED
|
@@ -142,6 +142,27 @@ Philiprehberger::HtmlBuilder.build do
|
|
|
142
142
|
end
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
### Lists
|
|
146
|
+
|
|
147
|
+
Build `<ul>` or `<ol>` lists from an array of items. Items are text-escaped by default. Pass `ordered: true` for an ordered list. Use a block for custom rendering of each item:
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
Philiprehberger::HtmlBuilder.build do
|
|
151
|
+
list(%w[Apple Banana Cherry])
|
|
152
|
+
end
|
|
153
|
+
# => '<ul><li>Apple</li><li>Banana</li><li>Cherry</li></ul>'
|
|
154
|
+
|
|
155
|
+
Philiprehberger::HtmlBuilder.build do
|
|
156
|
+
list(%w[First Second], ordered: true, class: 'steps')
|
|
157
|
+
end
|
|
158
|
+
# => '<ol class="steps"><li>First</li><li>Second</li></ol>'
|
|
159
|
+
|
|
160
|
+
Philiprehberger::HtmlBuilder.build do
|
|
161
|
+
list(%w[Alice Bob]) { |name| strong name }
|
|
162
|
+
end
|
|
163
|
+
# => '<ul><li><strong>Alice</strong></li><li><strong>Bob</strong></li></ul>'
|
|
164
|
+
```
|
|
165
|
+
|
|
145
166
|
### CSS Class Helpers
|
|
146
167
|
|
|
147
168
|
Build conditional CSS class strings from mixed arguments. Strings are included as-is, hash keys are included when their value is truthy:
|
|
@@ -206,6 +227,31 @@ end
|
|
|
206
227
|
|
|
207
228
|
Components without parameters use a simple block with no arguments. Components with parameters receive a hash of locals.
|
|
208
229
|
|
|
230
|
+
### HTML5 Documents
|
|
231
|
+
|
|
232
|
+
Emit a standards-compliant `<!DOCTYPE html>` declaration via the `doctype` DSL helper, or use `HtmlBuilder.document` for a full HTML5 document shortcut that prefixes the doctype automatically. The block decides the root element, so no hardcoded `<html>` wrapper is added:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
Philiprehberger::HtmlBuilder.build do
|
|
236
|
+
doctype
|
|
237
|
+
html { head { title 'Home' } }
|
|
238
|
+
end
|
|
239
|
+
# => '<!DOCTYPE html><html><head><title>Home</title></head></html>'
|
|
240
|
+
|
|
241
|
+
Philiprehberger::HtmlBuilder.document do
|
|
242
|
+
html do
|
|
243
|
+
head { title 'Home' }
|
|
244
|
+
body { h1 'Welcome' }
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
# => "<!DOCTYPE html>\n<html><head><title>Home</title></head><body><h1>Welcome</h1></body></html>"
|
|
248
|
+
|
|
249
|
+
Philiprehberger::HtmlBuilder.document(pretty: true) do
|
|
250
|
+
html { head { title 'Home' } }
|
|
251
|
+
end
|
|
252
|
+
# pretty-printed with the doctype on its own line
|
|
253
|
+
```
|
|
254
|
+
|
|
209
255
|
### Output Modes
|
|
210
256
|
|
|
211
257
|
Choose between minified and pretty-printed output:
|
|
@@ -258,12 +304,14 @@ Philiprehberger::HtmlBuilder.merge(header, body, footer)
|
|
|
258
304
|
| `HtmlBuilder.build { ... }` | Build minified HTML using the tag DSL, returns a string |
|
|
259
305
|
| `HtmlBuilder.build_pretty { ... }` | Build pretty-printed HTML with indentation |
|
|
260
306
|
| `HtmlBuilder.build_minified { ... }` | Alias for `build`, explicitly produces minified output |
|
|
307
|
+
| `HtmlBuilder.document(pretty:, indent_size:) { ... }` | Build an HTML5 document; prefixes `<!DOCTYPE html>` before the block output |
|
|
261
308
|
| `HtmlBuilder.merge(*fragments)` | Merge multiple HTML fragment strings into one |
|
|
262
309
|
| `HtmlBuilder.escape(value)` | Escape HTML special characters in a string using the DSL's escaper |
|
|
263
310
|
| `Builder#to_html` | Render builder contents to a minified HTML string |
|
|
264
311
|
| `Builder#to_pretty_html` | Render builder contents to a pretty-printed HTML string |
|
|
265
312
|
| `Builder#text(content)` | Add escaped text content to the current element |
|
|
266
313
|
| `Builder#raw(html)` | Add raw HTML without escaping |
|
|
314
|
+
| `Builder#doctype` | Emit an HTML5 `<!DOCTYPE html>` declaration |
|
|
267
315
|
| `Builder#render_if(condition) { ... }` | Conditionally render a block if condition is truthy |
|
|
268
316
|
| `Builder#render_unless(condition) { ... }` | Conditionally render a block if condition is falsy |
|
|
269
317
|
| `Builder#define_component(name) { ... }` | Define a reusable named block |
|
|
@@ -274,6 +322,7 @@ Philiprehberger::HtmlBuilder.merge(header, body, footer)
|
|
|
274
322
|
| `Builder#textarea_field(name, content, label_text:, **attrs)` | Build a label + textarea |
|
|
275
323
|
| `Builder#hidden_field(name, value)` | Generate a hidden input element |
|
|
276
324
|
| `Builder#submit(text, **attrs)` | Generate a submit button (default text "Submit") |
|
|
325
|
+
| `Builder#list(items, ordered:, **attrs, &block)` | Build a `<ul>` or `<ol>` from an array of items |
|
|
277
326
|
| `Builder#class_names(*args)` | Build a conditional CSS class string from strings and hashes |
|
|
278
327
|
| `Builder#cache(key) { ... }` | Cache rendered block output by key; return cached HTML on repeat calls |
|
|
279
328
|
| `Escape.html(value)` | Escape HTML special characters in a string |
|
|
@@ -80,6 +80,16 @@ module Philiprehberger
|
|
|
80
80
|
current_children << node
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# Emit an HTML5 doctype declaration (`<!DOCTYPE html>`)
|
|
84
|
+
#
|
|
85
|
+
# Has no children and no attributes. In pretty mode the declaration is
|
|
86
|
+
# rendered on its own line at the current indentation.
|
|
87
|
+
#
|
|
88
|
+
# @return [void]
|
|
89
|
+
def doctype
|
|
90
|
+
current_children << DoctypeNode.new
|
|
91
|
+
end
|
|
92
|
+
|
|
83
93
|
# Conditionally render a block if the condition is truthy
|
|
84
94
|
#
|
|
85
95
|
# @param condition [Object] the condition to evaluate
|
|
@@ -216,6 +226,26 @@ module Philiprehberger
|
|
|
216
226
|
button(text, type: 'submit', **attrs)
|
|
217
227
|
end
|
|
218
228
|
|
|
229
|
+
# Build a list (ul or ol) from an array of items
|
|
230
|
+
#
|
|
231
|
+
# @param items [Array] the list items
|
|
232
|
+
# @param ordered [Boolean] use ol instead of ul (default false)
|
|
233
|
+
# @param attrs [Hash] additional attributes for the list element
|
|
234
|
+
# @yield [item] optional block for custom rendering of each item
|
|
235
|
+
# @return [Node]
|
|
236
|
+
def list(items, ordered: false, **attrs, &block)
|
|
237
|
+
tag_name = ordered ? :ol : :ul
|
|
238
|
+
send(tag_name, **attrs) do
|
|
239
|
+
items.each do |item|
|
|
240
|
+
if block
|
|
241
|
+
li { block.call(item) }
|
|
242
|
+
else
|
|
243
|
+
li item.to_s
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
219
249
|
# Build a space-joined CSS class string from mixed arguments
|
|
220
250
|
#
|
|
221
251
|
# Strings are included as-is. Hash keys are included when their value is truthy.
|
|
@@ -286,5 +316,19 @@ module Philiprehberger
|
|
|
286
316
|
end
|
|
287
317
|
end
|
|
288
318
|
end
|
|
319
|
+
|
|
320
|
+
# A node that renders the HTML5 doctype declaration
|
|
321
|
+
class DoctypeNode
|
|
322
|
+
DECLARATION = '<!DOCTYPE html>'
|
|
323
|
+
|
|
324
|
+
# @return [String] the doctype declaration
|
|
325
|
+
def to_html(indent: nil, indent_size: 2)
|
|
326
|
+
if indent
|
|
327
|
+
"#{' ' * (indent * indent_size)}#{DECLARATION}"
|
|
328
|
+
else
|
|
329
|
+
DECLARATION
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
289
333
|
end
|
|
290
334
|
end
|
|
@@ -45,6 +45,27 @@ module Philiprehberger
|
|
|
45
45
|
build(&)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# Build a full HTML5 document: emits `<!DOCTYPE html>` followed by the
|
|
49
|
+
# rendered block, separated by a newline.
|
|
50
|
+
#
|
|
51
|
+
# The block is evaluated at the root level exactly like `.build` / `.build_pretty`,
|
|
52
|
+
# so the caller decides whether to add an `<html>` wrapper. When `pretty: true`,
|
|
53
|
+
# output is pretty-printed with the given indent size.
|
|
54
|
+
#
|
|
55
|
+
# @param pretty [Boolean] whether to pretty-print the block output (default false)
|
|
56
|
+
# @param indent_size [Integer] number of spaces per indent level when pretty (default 2)
|
|
57
|
+
# @yield [Builder] the builder instance for DSL evaluation
|
|
58
|
+
# @return [String] the rendered HTML document string
|
|
59
|
+
# @raise [Error] if no block is given
|
|
60
|
+
def self.document(pretty: false, indent_size: 2, &block)
|
|
61
|
+
raise Error, 'a block is required' unless block
|
|
62
|
+
|
|
63
|
+
builder = Builder.new
|
|
64
|
+
builder.instance_eval(&block)
|
|
65
|
+
body = pretty ? builder.to_pretty_html(indent_size: indent_size) : builder.to_html
|
|
66
|
+
"#{DoctypeNode::DECLARATION}\n#{body}"
|
|
67
|
+
end
|
|
68
|
+
|
|
48
69
|
# Merge multiple HTML fragment strings into one
|
|
49
70
|
#
|
|
50
71
|
# @param fragments [Array<String>] HTML fragments to merge
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-html_builder
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Build HTML programmatically using a clean tag DSL with nested blocks,
|
|
14
14
|
automatic content escaping, void element support, and attribute hashes.
|