Class: Philiprehberger::HtmlBuilder::Builder
- Inherits:
-
Object
- Object
- Philiprehberger::HtmlBuilder::Builder
- Defined in:
- lib/philiprehberger/html_builder/builder.rb
Overview
DSL-based HTML builder that creates a tree of nodes
Constant Summary collapse
- STANDARD_TAGS =
%i[ a abbr address article aside audio b bdi bdo blockquote body button canvas caption cite code colgroup data datalist dd del details dfn dialog div dl dt em fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup html i iframe ins kbd label legend li main map mark menu meter nav noscript object ol optgroup option output p picture pre progress q rp rt ruby s samp script section select slot small span strong style sub summary sup table tbody td template textarea tfoot th thead time title tr u ul var video ].freeze
- VOID_TAGS =
%i[area base br col embed hr img input link meta param source track wbr].freeze
- ALL_TAGS =
(STANDARD_TAGS + VOID_TAGS).freeze
Instance Method Summary collapse
-
#cache(key) { ... } ⇒ void
Cache a rendered block result by key.
-
#class_names(*args) ⇒ String
Build a space-joined CSS class string from mixed arguments.
-
#define_component(name) { ... } ⇒ void
Define a reusable named component.
-
#field(name, label_text: nil, type: 'text', **attrs) ⇒ void
Form builder helper: builds a label + input pair.
-
#form_for(action, method_type: 'post', **attrs) { ... } ⇒ Node
Form builder helper: builds a form tag with common defaults.
-
#hidden_field(name, value) ⇒ Node
Form builder helper: generate a hidden input field.
-
#initialize ⇒ Builder
constructor
A new instance of Builder.
-
#raw(html) ⇒ void
Add raw HTML content without escaping.
-
#render_if(condition) { ... } ⇒ void
Conditionally render a block if the condition is truthy.
-
#render_unless(condition) { ... } ⇒ void
Conditionally render a block if the condition is falsy.
-
#select_field(name, options_list, label_text: nil, selected: nil, **attrs) ⇒ void
Form builder helper: builds a label + select with options.
-
#submit(text = 'Submit', **attrs) ⇒ Node
Form builder helper: generate a submit button.
-
#text(content) ⇒ void
Add raw text content to the current context.
-
#textarea_field(name, content = nil, label_text: nil, **attrs) ⇒ void
Form builder helper: builds a label + textarea.
-
#to_html ⇒ String
Render all root-level nodes to HTML (minified).
-
#to_pretty_html(indent_size: 2) ⇒ String
Render all root-level nodes to pretty-printed HTML with indentation.
-
#use_component(name, **locals) ⇒ void
Render a previously defined component.
Constructor Details
#initialize ⇒ Builder
Returns a new instance of Builder.
22 23 24 25 26 27 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 22 def initialize @root_children = [] @stack = [] @components = {} @cache_store = {} end |
Instance Method Details
#cache(key) { ... } ⇒ void
This method returns an undefined value.
Cache a rendered block result by key
On the first call with a given key, the block is executed, its rendered HTML is stored, and a raw node is appended. On subsequent calls with the same key, the cached HTML is appended without re-executing the block.
247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 247 def cache(key, &block) raise Error, 'a block is required for cache' unless block if @cache_store.key?(key) raw(@cache_store[key]) else nested = Builder.new nested.instance_eval(&block) html = nested.to_html @cache_store[key] = html raw(html) end end |
#class_names(*args) ⇒ String
Build a space-joined CSS class string from mixed arguments
Strings are included as-is. Hash keys are included when their value is truthy.
225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 225 def class_names(*args) result = [] args.each do |arg| case arg when Hash arg.each { |key, val| result << key.to_s if val } else result << arg.to_s end end result.join(' ') end |
#define_component(name) { ... } ⇒ void
This method returns an undefined value.
Define a reusable named component
112 113 114 115 116 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 112 def define_component(name, &block) raise Error, 'a block is required for define_component' unless block @components[name.to_sym] = block end |
#field(name, label_text: nil, type: 'text', **attrs) ⇒ void
This method returns an undefined value.
Form builder helper: builds a label + input pair
152 153 154 155 156 157 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 152 def field(name, label_text: nil, type: 'text', **attrs) field_id = attrs.delete(:id) || name.to_s.tr('_', '-') label_str = label_text || name.to_s.gsub('_', ' ').split.map(&:capitalize).join(' ') label label_str, for: field_id input(type: type, name: name.to_s, id: field_id, **attrs) end |
#form_for(action, method_type: 'post', **attrs) { ... } ⇒ Node
Form builder helper: builds a form tag with common defaults
141 142 143 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 141 def form_for(action, method_type: 'post', **attrs, &block) form(action: action, method: method_type, **attrs, &block) end |
#hidden_field(name, value) ⇒ Node
Form builder helper: generate a hidden input field
206 207 208 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 206 def hidden_field(name, value) input(type: 'hidden', name: name.to_s, value: value.to_s) end |
#raw(html) ⇒ void
This method returns an undefined value.
Add raw HTML content without escaping
78 79 80 81 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 78 def raw(html) node = RawNode.new(html) current_children << node end |
#render_if(condition) { ... } ⇒ void
This method returns an undefined value.
Conditionally render a block if the condition is truthy
88 89 90 91 92 93 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 88 def render_if(condition, &block) return unless condition raise Error, 'a block is required for render_if' unless block instance_eval(&block) end |
#render_unless(condition) { ... } ⇒ void
This method returns an undefined value.
Conditionally render a block if the condition is falsy
100 101 102 103 104 105 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 100 def render_unless(condition, &block) return if condition raise Error, 'a block is required for render_unless' unless block instance_eval(&block) end |
#select_field(name, options_list, label_text: nil, selected: nil, **attrs) ⇒ void
This method returns an undefined value.
Form builder helper: builds a label + select with options
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 167 def select_field(name, , label_text: nil, selected: nil, **attrs) field_id = attrs.delete(:id) || name.to_s.tr('_', '-') label_str = label_text || name.to_s.gsub('_', ' ').split.map(&:capitalize).join(' ') label label_str, for: field_id select(name: name.to_s, id: field_id, **attrs) do .each do |opt| if opt.is_a?(Array) opt_text, opt_value = opt option_attrs = { value: opt_value.to_s } option_attrs[:selected] = true if opt_value.to_s == selected.to_s option opt_text, **option_attrs else option_attrs = { value: opt.to_s } option_attrs[:selected] = true if opt.to_s == selected.to_s option opt.to_s, **option_attrs end end end end |
#submit(text = 'Submit', **attrs) ⇒ Node
Form builder helper: generate a submit button
215 216 217 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 215 def submit(text = 'Submit', **attrs) (text, type: 'submit', **attrs) end |
#text(content) ⇒ void
This method returns an undefined value.
Add raw text content to the current context
70 71 72 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 70 def text(content) current_children << content.to_s end |
#textarea_field(name, content = nil, label_text: nil, **attrs) ⇒ void
This method returns an undefined value.
Form builder helper: builds a label + textarea
194 195 196 197 198 199 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 194 def textarea_field(name, content = nil, label_text: nil, **attrs) field_id = attrs.delete(:id) || name.to_s.tr('_', '-') label_str = label_text || name.to_s.gsub('_', ' ').split.map(&:capitalize).join(' ') label label_str, for: field_id textarea(content, name: name.to_s, id: field_id, **attrs) end |
#to_html ⇒ String
Render all root-level nodes to HTML (minified)
32 33 34 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 32 def to_html @root_children.map { |c| c.respond_to?(:to_html) ? c.to_html : Escape.html(c.to_s) }.join end |
#to_pretty_html(indent_size: 2) ⇒ String
Render all root-level nodes to pretty-printed HTML with indentation
40 41 42 43 44 45 46 47 48 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 40 def to_pretty_html(indent_size: 2) @root_children.map do |c| if c.respond_to?(:to_html) c.to_html(indent: 0, indent_size: indent_size) else Escape.html(c.to_s) end end.join("\n") end |
#use_component(name, **locals) ⇒ void
This method returns an undefined value.
Render a previously defined component
123 124 125 126 127 128 129 130 131 132 |
# File 'lib/philiprehberger/html_builder/builder.rb', line 123 def use_component(name, **locals) block = @components[name.to_sym] raise Error, "undefined component: #{name}" unless block if block.arity.zero? || (block.arity.negative? && locals.empty?) instance_eval(&block) else instance_exec(locals, &block) end end |