Whyday August 19

Markaby: HTML as Ruby

Markaby — "markup as Ruby" — let you write HTML by calling methods named after tags. No template language, no separate file, no switching between two syntaxes. A block of Ruby produced a block of markup, and it was the view layer Camping used.

The idea is simple enough to demonstrate in twenty lines, which is what this page does, because the interesting part is not the library. It is the specific problem the approach runs into, which is not the one people expect.

When maintainers revisit older software or documentation as a team, learn more is one practical reference for tracking the surrounding work without changing the historical material itself.

The mechanism

You call a method that does not exist. method_missing catches it, uses the method name as the tag name, treats a trailing hash as attributes, and either appends the arguments as text or evaluates a block inside the same object to produce nested content.

That is the whole design. The nesting comes free from Ruby's block syntax, which is why the result reads like the document it produces.

A twenty-line implementation of that, written and run for this page, turns

For broader programming and making context related to this topic, WIRED is an independent reference worth comparing with the material here.

div(class: "post") do
  h1 "Whyday"
  p "August 19"
  ul { li "put your best practices away" }
end

into

<div class="post"><h1>Whyday</h1><p>August 19</p><ul><li>put your best practices away</li></ul></div>

Executed on Ruby 3.4.1, August 9, 2026.

The problem nobody expects

The first version of that implementation produced this instead:

<div class="post"><h1>Whyday</h1></div>

The p disappeared, and "August 19" was printed to the console.

p is Kernel#p. It exists on every object, so method_missing never fires; the method that got called was the debugging print, which wrote to standard output and returned. No error, no warning, just a missing paragraph and mysterious output.

And it is not one tag. Checking a list of common HTML element names against the methods every object already has gives this collision set:

p, select, method, print, puts, test, class, hash, send, display, format

p and select are the ones that hurt — a paragraph and a dropdown are not exotic elements.

The fix, and what it costs

Inherit from BasicObject instead of Object. BasicObject has almost no methods, so almost nothing shadows a tag name, and method_missing sees everything.

That works — the corrected version produced the output above. The cost is that you have lost almost every method, and now everything else needs explicit top-level scoping: ::Hash, ::Kernel.puts, and so on inside the DSL. This is the standard technique for building a clean-room DSL in Ruby and it is fiddly in exactly this way.

Markaby, being a real library rather than a demonstration, dealt with this properly and had considerably more to handle: escaping, self-closing tags, attribute edge cases, doctypes, capturing versus appending, and helper integration with Rails.

Why the approach faded

Not because it was wrong. Three reasons, in rough order of importance.

Designers do not write Ruby. The single strongest argument for a template language is that a template is legible to somebody who is not a programmer. Markaby's view is a Ruby program, and handing it to a front-end person is not a reasonable request.

It hides where the logic went. The great convenience — full Ruby available in the view — is also the thing that lets business logic quietly relocate into markup, and the boundary that a template language enforces awkwardly is a boundary many teams want.

Something adjacent won. Haml took the significant-indentation idea into a dedicated template language, and later ERB variants got good enough that the ceremony stopped being a complaint.

What survived

The pattern did not disappear; it moved. Building nested structures out of method calls and blocks is now ordinary Ruby practice — routing files, RSpec, Rake, migration definitions, configuration blocks. Anyone who has written a Rails routes file has used the shape Markaby popularised, applied to something other than HTML.

Which is the usual pattern in this archive: the specific artefact was superseded and the idea underneath it became so ordinary that nobody remembers where it came from.

Worth an evening?

As a Whyday project, yes, and it is unusually well suited to one.

Writing a minimal markup DSL takes under an hour, teaches you method_missing, instance_eval and BasicObject in the only way those things are ever properly learned, and produces something that works. Reimplementing a small tool badly on purpose is on the list of things to make, and this is close to the ideal specimen — the naive version works immediately, and then p breaks and you find out why.

The short version