Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for loop with reversed and limit. #456

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

joost
Copy link
Contributor

@joost joost commented Oct 10, 2014

# array being [1,2,3]
for item in array reversed limit:2

currently returns [2,1]. This fix makes it more logically: [3,2].

@joost
Copy link
Contributor Author

joost commented Oct 10, 2014

A (temporary) fix in your liquid templates would be:

{% assign array = array | reverse %}

@fw42
Copy link
Contributor

fw42 commented Oct 10, 2014

Hm. Good catch. I agree that it makes more sense like this. But this fix is not strictly backwards compatible...

@Shopify/liquid, think we can ship this without breakage?

@@ -80,6 +80,8 @@ def render(context)
context[@attributes['offset'.freeze]].to_i
end

collection.reverse! if @reversed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an in place operation on the collection itself, which seems like it could have some nasty side effects. Also, the collection may not be an array at this point, since Utils.slice_collection supports anything with the method each (see Liquid::Utils.slice_collection_using_each).

@dylanahsmith
Copy link
Contributor

I agree that it makes more sense like this. But this fix is not strictly backwards compatible...

We could log a warning when a for tag is used with reversed and a limit to see what this would break in Shopify.

@fw42
Copy link
Contributor

fw42 commented Apr 24, 2015

There is an argument to be made here that

for item in array reversed limit:2

and

for item in array limit:2 reversed

should not behave the same way (one should return [3,2], the other should return [2,1])

@joost
Copy link
Contributor Author

joost commented Apr 24, 2015

@fw42 The current syntax does not support the first (edit) second version you mention. See https://github.com/Shopify/liquid/blob/master/lib/liquid/tags/for.rb#L48

@fw42
Copy link
Contributor

fw42 commented Apr 24, 2015

Good point :-)

Can you rebase this PR?

@pushrax
Copy link
Contributor

pushrax commented Apr 24, 2015

In that case, since the syntax is for item in array limit:2 reversed, it arguably makes sense to have the current behaviour.

@joost
Copy link
Contributor Author

joost commented Apr 24, 2015

true :)

@fw42
Copy link
Contributor

fw42 commented Apr 24, 2015

Then maybe lets just implement the new syntax as well?

@pushrax
Copy link
Contributor

pushrax commented Apr 24, 2015

👍, addresses the original issue and doesn't require verifying templates don't break.

@joost
Copy link
Contributor Author

joost commented Apr 24, 2015

def test_for_reversed_with_limiting
  assigns = {'array' => [ 1, 2, 3] }
  assert_template_result('32','{%for item in array reversed limit:2 %}{{item}}{%endfor%}',assigns)
end

It is the other way around. Looking at the test I wrote for the PR (already some time ago :)) the behaviour previous to my PR was weird: [1,2,3] reversed limit:2 resulting in 21 instead of 32.

@pushrax
Copy link
Contributor

pushrax commented Apr 24, 2015

So the syntax it supports is the first version in @fw42's earlier comment, not the second.

@joost
Copy link
Contributor Author

joost commented Apr 24, 2015

Yep.

@fw42
Copy link
Contributor

fw42 commented May 16, 2015

@pushrax: What should we do here? Add some logging to Shopify first to see if we can ship this without breakage? It's not backwards compatible.

@pushrax
Copy link
Contributor

pushrax commented May 16, 2015

Could do this with static analysis – I need to get the harness set up for that again anyway (for the formatter and #569) so maybe that's the best course of action?

@fw42
Copy link
Contributor

fw42 commented Jan 6, 2016

I need to get the harness set up for that again

@pushrax: Any intentions of still doing this?

@pushrax
Copy link
Contributor

pushrax commented Jan 6, 2016

Not in the short term.

@jbrains
Copy link

jbrains commented Oct 2, 2016

I have no idea what it would mean to do this, but it seems that if you let for use filter-like behavior, then you could retain the old syntax for compatibility. Example:

for item in array reversed limit:2

Here, "reversed" and "limit:2" are effectively tags on the loop, so that keeps the current behavior. By comparison:

for item in (array | reverse | top:2)

filters the collection we iterate over, so the loop itself remains ignorant of the situation. This means adding a filter that takes the top n items of an array, which I'd like Liquid to add, anyway.

How feasible would this be, given the current design?

We could start with just adding a "top" filter, and in the worst case, we'd have

assign filtered = collection | reverse | top:2
for each in filtered ...

I'd be thrilled with that. Even a slice filter that operates on arrays and not just strings would help.

@stedman
Copy link

stedman commented Jun 7, 2020

@pushrax @dylanahsmith I'm curious about the status of this PR. I would love to see the parameters execute as expected, from left to right (reversed then limit:2), but understand the desire to maintain backward compatibility.

As a compromise, would it be possible to optionally add a value to reversed to achieve the same goal? Current implementations would then be unaffected. For example:

# array = [1,2,3]
for i in array reversed limit:2           # [2,1] (default)
for i in array reversed:"first" limit:2   # [3,2] reverses collection first, then limits
for i in array reversed:"last" limit:2    # [2,1] limits first, then reverses collection (added for syntax consistency)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants