liquid: strict_variables throws exception on checking if variable exists
I’m using a jekyll layout where I want to include content of pages, depending on whether it exists. Apparently, it is supposed to be done like described in https://github.com/Shopify/liquid/issues/89 In my case it would look as follows:
{% assign title = page.title %}
{% if page.name %}
{% assign title = page.name %}
{% endif %}
<title> {{ title }} | {{ site.title }} </title>
But since I have strict_variables set to true, which is really useful for development, Liquid throws an exception on building (undefined variable name included
).
In my opinion, strict_variables should not throw exceptions for cases where the undefined variable is checked for existance.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 17
- Comments: 23 (7 by maintainers)
Commits related to this issue
- Styles layout of the blog. This makes a few changes that I was too lazy to split into multiple commits: 1. Sets strict options on Liquid so that it complains when I misuse properties, rather than sil... — committed to dgp1130/blog by dgp1130 4 years ago
- jekyll: Use `contains` for explicit nested config check See: https://github.com/Shopify/liquid/issues/1034#issuecomment-590121750 — committed to EricCousineau-TRI/drake by EricCousineau-TRI 3 years ago
- jekyll: sset strict_variables to false Use `contains` for explicit nested config check for one missing var See: https://github.com/Shopify/liquid/issues/1034#issuecomment-590121750 — committed to EricCousineau-TRI/drake by EricCousineau-TRI 3 years ago
- jekyll: Do not use strict mode Use `contains` for explicit nested config check for one missing var See: https://github.com/Shopify/liquid/issues/1034#issuecomment-590121750 — committed to EricCousineau-TRI/drake by EricCousineau-TRI 3 years ago
- jekyll: Do not use strict mode (#14672) Use `contains` for explicit nested config check for one missing var See: https://github.com/Shopify/liquid/issues/1034#issuecomment-590121750 — committed to RobotLocomotion/drake by EricCousineau-TRI 3 years ago
- jekyll: Do not use strict mode (#14672) Use `contains` for explicit nested config check for one missing var See: https://github.com/Shopify/liquid/issues/1034#issuecomment-590121750 — committed to EricCousineau-TRI/drake by EricCousineau-TRI 3 years ago
- Enable strict checking of filter existance * Strict checking of variable existence is not enabled due to a long-standing bug: https://github.com/Shopify/liquid/issues/1034 — committed to faktaoklimatu/web-core by mukrop 2 years ago
- Enable strict checking of filter existance * Strict checking of variable existence is not enabled due to a long-standing bug: https://github.com/Shopify/liquid/issues/1034 — committed to faktaoklimatu/web-core by mukrop 2 years ago
I’ve found that the Liquid
contains
operator works well for existence testing variables. Shouldn’t this be the canonical way to test for fields?Example:
A brief reminder that this issue is Insanely Stupid ™ and makes
strict_variables
unexpectedly useless. It’s like building a house with no door. Or a swimming pool in the desert. Don’t mean to offend anyone, I’m sure you guys are busy and all. It’s just clearly, aesthetically, stupid.I would also like to be able to check if a top-level variable is defined, not just keys on hashes or methods on drops.
{% if defined page %}
feels like the best option to make clear that it’s a special case where strict_variable checking is not being used and it makes it clear that it’s separate from being defined but nil.Just adding my 👍 as we’d love to enable
strict_variables
on our project (in our case, a Jekyll site) but we rely heavily on checking for variable existence in our templates, so we can’t use this as currently implemented.(thanks also for a great templating library!)
Here is another 👍 as I was hoping to use strict_variables too to avoid dumb mistakes - but it doesn’t work as existence check is used in not only my templates but also many themes.
I would say to be backwards compatible it should be that
page.missing_key
is allowed, butpage.missing_key.value
should give error and then have a more explicit operator to get better checks in new code.imo:
if
should be possible regardless of whether the variable is defined.Thus the following code would be exception-free.
last_name
is not defined, but it is only used within a guardedif
block:Hello placeholder
I’m surprised this behavior is not supported.
Re: docs, Using
contains
with hashes is mentioned on the Wiki, but not on thegh_pages
branch page.https://github.com/Shopify/liquid/wiki/Liquid-for-Designers#if--else
contains
will work for container types like hashes, but I don’t think it will work for drops, which don’t respond toinclude?
. https://github.com/Shopify/liquid/blob/e83b1e415990894c9517f94a8c2020ff825da027/lib/liquid/condition.rb#L20-L27Though modifying the implementation of
contains
to callkey?
if it exists could work. Or we could aliasDrop#include?
toDrop#key?
. All are slightly breaking changes but likely safe.This article on Jekyll plugins taught me that plugins can just be dumped in a
_plugins
folder, so your filter seems to be working in my Jekyll instance now, @pascalbetz. Thanks!@pascalbetz, that custom filter looks exactly like what I’m after – until this issue is resolved, at least. I’m just wondering how you “install” such a custom filter into a Jekyll site. Do I need to create a whole repository, gem, bundle and all to host those 6 lines of code to say
plugins: "jekyll-key"
in my Jekyll site’s_config.yml
or can a Jekyll plugin reside “locally” within the Jekyll site, somehow?Has a syntax been chosen?
It seems like there are a lot of good ideas and one needs to be chosen and implemented.
Defined and present (truthy/falsey) are two different things, IMHO.
I would prefer to be able to check if:
while having
strict_variables: true
To achieve this I had to jump through some hoops:
I added a custom filter
And then used it in my template like so
while direct access to undefined keys still raises.
I think we need to decide whether we want to expose the concept of undefined as being distinct from
nil
. Currently, strict_variables has that distinction and it can help with typos or variable renames that miss some usage. However, it also requires either making sure the variable is always initialized (e.g. explicitly set tonil
) or that we add something new to explicit check for undefined or handle the undefined value (e.g. using a filter like the default filter).Alternatively, we could decide we don’t really want that concept of undefined and treat undefined as
nil
. That is basically howstrict_variables
works. This would also be more consistent with the already recommended way of checking for the existence of a variable. We could still make things more strict about wherenil
could be used in even in this case, like doing a variable lookup onnil
(e.g.page.name
when page isnil
). We could also try to do static analysis in the future to determine where a variable lookup always returnsnil
as a way of making it more strict.I think we should try to avoid mixing concepts for consistency, because it would lead to unexpected behaviour. For instance, if we treat the
{% if some_var %}
as a special case, then it would lead to the expectation that{{ some_var | default: other_var }}
would work. If we special case thedefault
filter as well, then it would seem like other filters might be able to work with an undefined value. So I think we would end up with either special cases that we would have to document or something more like javascript where undefined is an actual value which application code would have to be updated to handle in a backwards compatible way.I think this probably makes the most sense, since it will be conceptually consistent with how liquid works without strict_variables where there isn’t a distinction between undefined and
nil
.Do we have an update on this?
This is a really good point, thanks for opening the issue. Some options:
if
as a key existence operator in strict_variables mode| has: 'name'
) or operator (if defined page.name
orif page has name
) to check existence of a key