Shopify / Shopify/liquid

Allow creating hashes and/or assigning hash members

Open
#1,368 0 comments 10 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Feature Request
Dominant language
Ruby
Stars
11.9k
Forks
1.5k
Avg merge
17h 55m
Merged PRs (30d)
3

Description

It would be helpful if you could create and assign to hashes (aka objects, maps or associative arrays) from inside liquid. Doing so would allow doing some pre-processing of data at the start of a template, or in an included snippet, an produce a result in a structured way, to be easily used by the rest of the template. This is particularly useful when producing an array of objects (instead of producing a single object, you can just produce multiple variables, on for each attribute, but when you do this to produce multiple arrays, it becomes a lot more cumbersome to iterate them in parallel.

As an example from a Jekyll site I'm building, I'm collecting downloadable files, and to render those I need the URL and original filename. It would be ideal if the preprocessing could just produce an array of hashes, i.e. something like:

{% for p in site.pages %}
  {% capture url %}{{ page.dir }}{{ page.download_url }}{% endcapture %}
  {% assign download.url=url %}
  {% assign download.filename=page.download_filename %}
  {% assign dowloads=downloads | push:download  %}
{% endfor %}

This should produce an array downloads, where each element is a hash with two keys: url and filename. This array can then later be iterated in the rest of the template in a clean and compact way.

Note that this also needs a way to build a (non-associative) array, for which Jekyll already has push. See also #699 and #1202 requesting similar features in Liquid core.

As for how to implement this, I can imagine three components:

  1. Having a way to assign hash keys. This should probably create a new hash if it does not exist yet.
  2. Having a way to create a new hash in one go
  3. (If not implementing 2.) having a way to create an empty hash
1. Assigning a key

This could probably just reuse the existing assign tag as shown above. This would make . in a filename special. AFAIU these are currently just put in the variable name, so assigning foo.bar just creates a variable named exactly that, but they can never be referenced, since {{ foo.bar }} always looks in foo (. Any existing code that uses dots in variable names (e.g. assigns and references both foo.bar) would, AFAICS, still stay working (except may Also, if e.g. foo already exists (as a hash?) and you assign foo.bar currently, the new foo.bar variable will be masked by the foo variable (see also #302).

2. Creating a hash

This would be useful to create empty hashes, or create a small hash in one go.

I think this could be something like {% assign-hash download url=url filename=page.download_filename %} which uses an initial variable name to assign, along with a list of key-value pairs (like include).

Alternatively, a syntax like {% assign download={url: url, filename: page.download_filename} %} could be useful, and is certainly easier to read. I'm not sure if this would produce any conflicts with existing allowed expressions, though.

The last can maybe also be extended to arrays using e.g. {% assign foo=[1, 2, 3] %}, or if the expression parser is made into a proper parser, maybe even nested: {% assign foo={bar: [1, 2]} %}. This is probably the most powerful and easy-to-read approach, but might be a bit more complicated to implement.

3. Creating an empty hash.

If 2. is not implemented, you might want to be able to create an empty hash (which 1. cannot do). Not sure how this should look, though, and I'd rather see 2. implemented anyway.

Also see #1237, which has a related proposal, of which hash creating is, I think, a part.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation files or tests are named. Start by reviewing Liquid’s existing assign tag and expression parser, then read related issues #699, #1202, and #1237; done means an agreed, tested approach for creating and assigning hashes and any required arrays.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.