Skip to content

Instantly share code, notes, and snippets.

@pootsbook
Created March 8, 2021 21:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pootsbook/09702fb05cbac6dbc507169a3a56fed3 to your computer and use it in GitHub Desktop.
Save pootsbook/09702fb05cbac6dbc507169a3a56fed3 to your computer and use it in GitHub Desktop.
class HTMLDoc
def initialize
@node_id = 0
@parent_id = 0
@doc = []
yield self if block_given?
end
def el(type, attributes = {})
@node_id += 1
grandparent_id = @parent_id
node = {
id: @node_id,
parent_id: @parent_id,
type: type,
attrs: attributes
}
case type
when :text
@doc << node.merge(content: yield)
else
@doc << node
@parent_id = @node_id
yield
end
@parent_id = grandparent_id
end
def ast
root = @doc.find {|el| el[:parent_id] == 0 }
{ type: root[:type],
attributes: root[:attrs],
children: gather_children(root[:id])
}
end
def gather_children(node_id)
@doc.select do |el|
el[:parent_id] == node_id
end.map do |el|
if el[:type] == :text
children = [el[:content]]
else
children = gather_children(el[:id])
end
{ type: el[:type],
attributes: el[:attrs],
children: children }
end
end
def to_s
puts @doc.inspect # DEBUG
puts ast.inspect # DEBUG
node(ast[:type], ast[:attributes], ast[:children])
end
def node(type, attributes = {}, children = [])
case type
when :text
children.empty? ? "" : children.first
when :input
render_opening_tag(type, attributes)
else
[
render_opening_tag(type, attributes),
render_children(children),
"</#{type}>"
].flatten.join("\n")
end
end
def render_children(children)
children.map do |child|
node(child[:type], child[:attributes], child[:children])
end.flatten.join("\n")
end
def render_opening_tag(name, attrs)
if attrs.nil? || attrs.empty?
"<#{name}>"
else
"<#{name} #{stringify_attrs(attrs)}>"
end
end
def stringify_attrs(attrs)
attrs.map do |key, value|
%Q(#{key}="#{value}")
end.join(" ")
end
end
doc = HTMLDoc.new do |d|
d.el :html do
d.el :head do
d.el :title do
d.el :text do
"Hello,"
end
d.el :text do
" World!"
end
end
end
d.el :body do
d.el :h1 do
d.el :text do
"TITLE"
end
end
d.el :p do
d.el :text do
"Paragraph 1"
end
end
d.el :p do
d.el :text do
"Paragraph 2"
end
end
end
end
end
puts doc.to_s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment