solid icon indicating copy to clipboard operation
solid copied to clipboard

Passing a variable to access a hash

Open chouzar opened this issue 1 year ago • 4 comments

When attempting to fetch values from a hash by passing a variable, I'm getting errors when trying to render:

{% assign value = hash[variable] %}

Example

For example this elixir test passes with no issues when giving the hash a literal value:

test "fetch hash with variable" do
  template = """
  {% assign greeting = greetings['greeting_b'].text %}
  <p>{{ greeting }} world</p>
  """

  data = %{
    "default" => "greeting_c",
    "greetings" => %{
      "greeting_a" => %{"text" => "Hello"},
      "greeting_b" => %{"text" => "Hey!"},
      "greeting_c" => %{"text" => "Yo!"}
    }
  }

  markup = template |> Solid.parse!() |> Solid.render!(data) |> to_string()

  assert """

         <p>Hey! world</p>
         """ == markup
end

However when changing the template to:

{% assign greeting = greetings[default].text %}
 <p>{{ greeting }} world</p>     

I get a render error:

%Solid.TemplateError{
   message: "Reason: expected end of string, line: 1, header: {% assign greeting = ",
   line: {1, 0},
   reason: "expected end of string",
   header: "{% assign greeting = "
}

Likewise if I define the variable above it with an assign (update: fixed template typo, corrected parse error):

{% assign default = "greeting_a" %}
{% assign greeting = greetings[default].text %}
<p>{{ greeting }} world</p>

The above gives a:

%Solid.TemplateError{
   message: "Reason: expected end of string, line: 2, header: {% assign default = \"",
   line: {2, 36},
   reason: "expected end of string",
   header: "{% assign default = \""
 }

Wondering if this is expected behaviour or maybe a bug?

chouzar avatar Jul 31 '24 21:07 chouzar

:thinking: I could be wrong but I don't think this is valid Liquid:

{% assign greeting = greetings[default].text %}

Have you tried doing this with the Liquid gem in ruby? Do you get the expected result or Liquid just ignores the [default] bit?

From memory the [] access is just for positional access like [1], [2]. I don't remember if there was a way to do what you want without a custom filter :thinking:

I think if there is a bug here is that we should still allow non-numbers but just ignore like Liquid does :thinking:

Examples: https://github.com/edgurgel/solid/blob/main/test/integration/objects_test.exs#L27-L34

edgurgel avatar Aug 01 '24 09:08 edgurgel

Ah I see, I think it is somewhat hinted in the official liquid page that this syntax should work however the example is scoped down to the EmptyDrop return value:

{% assign variable = "hello" %}
{% assign page_1 = pages[variable] %}

Thanks for the pointer! Will try to setup the liquid gem from ruby and get back with results.

chouzar avatar Aug 02 '24 18:08 chouzar

So I tried this in a Ruby 3.2.2 version in my machine.

  • Installed the liquid gem with gem install liquid.
  • Launched irl and ran this script.
require 'liquid'

template = "\n" +
           "{% assign greeting = greetings[default] %}\n" +
           "<p>{{ greeting }} world</p>"
           
hash = { 
  'default' => 'special', 
  'greetings' => { 
    'default' => 'Hello', 
    'special' => 'Yo!' }
  }
    
Liquid::Template.parse(template).render(hash, {})

Which renders the string:

"\n\n<p>Yo! world</p>"

chouzar avatar Aug 08 '24 00:08 chouzar

Thanks for the detailed report! Yeah definitely something we should support then!

edgurgel avatar Aug 09 '24 10:08 edgurgel

Any update on when this might be released? We’d love to add support here for dynamic hash lookups in our liquid templating

cjbell avatar Dec 18 '24 21:12 cjbell

Oh yup will get this release later today! 👍

edgurgel avatar Dec 18 '24 21:12 edgurgel

https://github.com/edgurgel/solid/releases/tag/v0.17.0

Thanks @jmks !

edgurgel avatar Dec 19 '24 04:12 edgurgel