Dennis Hackethal’s Blog

My blog about philosophy, coding, and anything else that interests me.

Programming in Strings

Published · 1-minute read

I used to be a big fan of Angular and Angular 2. Then a colleague at Apple explained to me why what he called "programming in strings" is a bad idea. For example, this nonsense:

<h1 ng-repeat="i in array">{{i}}</h1>

Angular isn't the only framework that makes this mistake. Rails makes it, too, with embedded Ruby. If you're used to writing embedded Ruby (those pesky .erb files), you may not realize how bad it is.

Consider this template:

<ul>
  <% [1, 2, 3].each do |i| %>
    <li><%= i %></li>
  <% end %>
</ul>

This is gross. Embedded Ruby makes you mix your template and your logic. Rails is big on separation of concerns, and the above example is the opposite of that. It's "programming in strings" because you're writing logic inside your template string. This problem is well known in the Clojure world. Logic should be taken care of before rendering, not during.

Hiccdown makes this happen by taking a datastructure representing your template – which you're free to build up logically in any way you like, using the full power of the Ruby programming language (map, filter, reduce etc) – and then turning that into HTML at the end. All of this still happens on the server, so you still get all the benefits of pre-processing.

This solution was first implemented in the Clojure world with the Hiccup package. Hiccdown introduces the same (?) functionality in Ruby. (There's another package doing that but, at the time of writing, it hasn't been maintained in seven years. Plus, it was more fun building this from scratch!)

Usage

# plain
Hiccdown::to_html [:h1, 'hello world']
# => '<h1>hello world</h1>'

# nested siblings
Hiccdown::to_html [:div, [:h1, 'hello world'], [:h2, 'hello again']]
# => '<div><h1>hello world</h1><h2>hello again</h2></div>'

# attributes
Hiccdown::to_html [:h1, {class: 'heading big'}, 'hello world']
# => '<h1 class="heading big">hello world</h1>'

# children as arrays
Hiccdown::to_html [:ul, [[:li, 'first'], [:li, 'second']]]
# => '<ul><li>first</li><li>second</li></ul>'
#
# This is equivalent to writing:
Hiccdown::to_html [:ul, [:li, 'first'], [:li, 'second']]
# So why use it? So you can use methods that return arrays inside your hiccdown structure without having to use the splat operator every time:
Hiccdown::to_html [:ul, ['first', 'second'].map { |i| [:li, i] }]
# => '<ul><li>first</li><li>second</li></ul>'

The last example in particular gives you an insight into how powerful Hiccdown is. In embedded Ruby or Angular or what have you, I cannot map over elements, only over data. And I need special syntax for it, and I need to extend that syntax manually. With Hiccdown, you use plain old Ruby, and you can iterate over whatever you like because everything is data.

Usage in Rails

Delete your view file. In your controller action, do:

class FooController < ApplicationController
  def bar
    render html: Hiccdown::to_html([:h1, 'hello world!']).html_safe
  end
end

(Be careful with html_safe.)

How to get it?

Hiccdown (currently version 0.1.2) is available as a gem and the source code is on GitHub.


What people are saying

What are your thoughts?

You are responding to comment #. Clear
Your real name is preferred.
Markdown supported. cmd + enter to comment. You are responsible for what you write. Terms, privacy policy
This small puzzle helps protect the blog against automated spam.

Preview