sstephenson / eco

Embedded CoffeeScript templates
MIT License
1.71k stars 70 forks source link

Can't iterate via Array.forEach() #16

Open aseemk opened 13 years ago

aseemk commented 13 years ago

I would expect this to work:

https://gist.github.com/966214#file_foreach.html

But it doesn't (no names are printed). The generated intermediate CoffeeScript is this:

https://gist.github.com/966214#file_generated.coffee

I'm not sure what the _capture function does exactly -- I'm guessing it's related to Eco's block support -- but it seems to be setting the HTML content aside instead of printing it right away, which is my intent with the forEach iteration.

In other words, if I'm defining a function, yeah it's meant to be captured, but if I'm executing (invoking) a function, shouldn't my HTML be used right away?

sstephenson commented 13 years ago

This is unsolvable without adding new syntax. There's currently no way for Eco to know whether you want to capture a block's output or print it as soon as it's called -- right now you can only capture. (See the Eco manual for examples of how to use capturing and where it's useful.)

In your case, what happens is that the string return value of the callback passed to forEach is never used. The idiomatic way to do what you want is by avoiding capturing and just using for:

<% for name in names: %>
  <li><%= name %></li>
<% end %>

Of course, for isn't always appropriate, like when iterating over a Backbone collection with Underscore's _.each. If you really need to use a capture right now, there's this unholy combination of parentheses, map and join:

<%- ( names.map (name) -> %>
  <li><%= name %></li>
<% end %><% ).join("") %>

But that's just awful. We need to introduce non-capturing blocks to Eco. I see two ways to do it.

New syntax for non-capturing blocks

The first option would be to add some sort of sigil indicating a block is non-capturing. A few ideas:

<% names.forEach (name) =-> %>

<% names.forEach (name) -> =%>

<% names.forEach (name) ->: %>

<% names.forEach (name) ->| %>

I'm currently leaning towards the first or second lines because they reuse the "print this" meaning of =. The colon looks nice, but feels inappropriate here, as trailing colons elsewhere indicate an indent. Another symbol, like |, might help disambiguate.

Blocks are non-capturing by default; new syntax for capturing blocks

The other option is to make blocks non-capturing by default and use one of the new syntaxes above to denote capturing blocks. I'm hesitant to take this approach because it's not backwards-compatible, but it may be that non-capturing blocks are a better default.

Before proceeding further, I'd like to hear feedback from anyone currently using capturing blocks, and anyone else who's been bitten by this issue.