Last Updated: February 25, 2016
· cameron

Phil 'er Up: Better Markup Through Content Generation

The design team at Hashrocket writes the vast majority of the HAML/SASS on our projects, and we're always looking for ways to better simulate what our designs will look like with real data in place. It's a common occurrence: those repeating blocks of "Lorem ipsum title here" don't properly reflect the random, fluid nature of real content. Enter Phil: our shiny new markup generation gem.

As you might have noticed from my UI Controller blog post series (part 1, part 2, part 3), I'm constantly working to find ways to more easily generate properly simulated data. In the above blog posts, I talked about using Ffaker and some one-off helper methods to assist in that goal. Well, now all that stuff is in a gem, and here's how it works:

gem install phil


Phil started out as a cleaner way to get at some common Faker methods (e.g. Faker::Lorem.words(3) became Phil.words(3)), but it's more than that: Phil focuses on giving you more varied content by accepting ranges for a ton of methods.

So you can say Phil.words(1..100) to get between 1 and 100 words. Convenient? You bet. Designers, you'll sigh with relief (or frustration) the first time Phil reveals that you weren't prepared for a particularly long post to screw up your column alignment. These things happen. I know.

Never miss a tag again.

Faker spits out words, but it's intended mostly for populating databases – and on the frontend, we're more interested in populating markup. So there are a bunch of methods in Phil that spit out whatever content tags you might want. Here are just a few:

    = Phil.paragraphs 1..5     # outputs between 1 and 5 <p>
    = Phil.blockquote 1..5     # outputs a <blockquote> with 1 to 5 <p>
    = Phil.ul 1..5, 10..20     # <ul> with 1 to 5 <li>, 10 to 20 words apiece

If you're styling the markup for something that will contain a ton of different tag types, like an article or blog post, don't clutter your code with tons of method calls – just use Phil.markup and pass it a string of the tags that you want. Here's a simple blog post:

    %h1= Phil.words 1..20
    .content= Phil.markup "h2 p ul p blockquote h5 p h6 p p"

Voila – less time spent copying & pasting filler content means more time to catch layout bugs.

Iterate, iterate, iterate.

Here's a situation that comes up all the time for us: maybe you're styling a news feed, or a list of followers, or something else where the content of each item might change dramatically. Outputting and debugging the layout of each possible content combination is a pain – and that's where Phil.pick, Phil.sometimes and Phil.loop can help. None of these methods are particularly fancy under the hood – they're mostly just syntax sugar – but they're easy to type and read.

So here's a pretty beefy hypothetical example I whipped up for this blog post. This is a list of 1 to 20 comments from the last 30 days. Each comment has an avatar image, some content, and some author data, some of which might or might not be available to the view, and might even have some attachments. Take it away, Phil!

- Phil.loop(1..20) do
    %h1= Phil.words 1..15 "posted on #{'%A, %B %e, %Y')}"
    .content= Phil.markup 'h1 p p ul p'
      .avatar= Phil.image '200x400'
      .author= "posted by #{}"
      - Phil.sometimes do
      - Phil.sometimes do
        .phone= '###-####'
      - Phil.sometimes do
        .location= "#{}, #{Phil.state}"
      - Phil.loop(0..5) do
        %li= link_to "#{Phil.words 1..5}", "#"

Check out the Github page for more examples and complete documentation, and may Phil help you save some keyboard wear and tear in the near future!

(originally posted on The Hashrocket Blog)

3 Responses
Add your response

Can I get this in Node.js ;)?

over 1 year ago ·

@zamber ha! Well, there is a Faker.js out there ( so a Phil layer on top of that seems quite doable; I just have no personal need for it so I doubt I'll be tackling that anytime soon. It'd be fun though.

over 1 year ago ·

@zamber Here's a Node/JavaScript/CoffeeScript version I created[1]. Go lazyweb[2], go!



over 1 year ago ·