Access hashmap elements in liquid template

Feb 17, 2014

The search plugin that I’m writing for Jekyll with bloom filters is coming along swimmingly. I still haven’t thought of a convenient way of using it with Github pages since Github runs all Jekyll-powered sites with the safe: true configuration option, but I’ll cross that bridge when I come to it. In the meantime, I’m generating one bloom filter per blog post and putting all the filters into a /search.json page that will be filled up by my plugin. I serialized each filter for use in the liquid template as follows:

# ... Create a filter for each page in the site in a loop. At the end of the loop:
filters.push({
            url: filter.url,
            length: filter.length,
            hash_count: filter.hash_count,
            filter: filter.filter.join(",") # filter.filter is an array of 32-bit unsigned integers
                                            # that represent the bitfields in my filter
            })

# outside the loop:
json = site.pages.detect {|page| page.name == "search.json"}
json.data['filters'] = filters

The object I’m push-ing into the filters array is the idiomatic way of making a HashMap in Ruby 1.9+. However, no matter how hard I tried, I couldn’t access any of the values inside my liquid template.

data = {
    filters: [
    {% for item in page.filters %}
    {
        item: {{ item }},
        url: {{ item[:url] }},    # doesn't work
        length: {{ item.length }} # doesn't work
        ...
    },
    {% endfor %}
    ]
};

Turns out that liquid doesn’t like symbols, and the actual “idiomatic” way of creating a HashMap for use with liquid templates is as follows:

filters.push({
            'url' => filter.url,
            'length' => filter.length,
            'hash_count' => filter.hash_count,
            'filter' => filter.filter.join(",")
            })

Yep, that’s right. Strings as keys instead of symbols. And then you access them in your template like so:

...
        url: {{ item['url'] }},    # works
        length: {{ item.length }}  # works
...

Rather idiotic if you ask me.