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

Already on GitHub? Sign in to your account

Lambda functions not supported in precompiled templates #75

Closed
arendjr opened this Issue Apr 23, 2012 · 13 comments

Comments

Projects
None yet
6 participants

arendjr commented Apr 23, 2012

Hey guys,

I noticed lambda functions are not supported in precompiled templates. The core reason for this appears to be that the official Mustache specification reads:

Lambdas are a special-cased data type for use in interpolations and sections.

(...)

When used as the data value for a Section tag, the lambda MUST be treatable as an arity 1 function, and invoked as such
(passing a String containing the unprocessed section contents). The returned value MUST be rendered against the current
delimiters, then interpolated in place of the section.

Unfortunately, this behavior requires that when a lambda function is used, the original (unprocessed) source of the template is available. In order to remedy this situation, I created a fork that works on the processed section contents instead (I've not created a pull request as it deliberately diverts from the spec to create the desired result).

Anyway, I think it's good to make you aware of this fork, and I'm looking for any feedback you guys can give me. Also, if you prefer I create a pull request for this, I can do that too.

One more question, I tried running the test suite through run.js to see if my changes had any unintended side-effects, but run.js gave me no output whatsoever. Probably I'm just unaware how to properly run the suite, but I didn't see instructions either, so if someone can point me to how to properly run the test suite that would be great.

You can find my fork right here: https://github.com/arendjr/hogan.js

Regards,
Arend jr.

elsigh commented May 2, 2012

I thought I'd read that lambdas would work, but required that you include hogan.js (the compiler).
That said, I've just run hulk against a bunch of my files and none of my lambdas seem to be working.
I'm going to try the fork, but it would be good to get clarification.

arendjr commented May 2, 2012

Hi Lindsey,

Thanks for your reply! You're right that lambdas are supposed to work... using an old version of Hogan I got it to work as well (from memory I'm unsure if this still works with the current master). However, just including the compiler is not enough to make it work, you will have to send both the original template, as well as the processed template to the client.

This means that performance benefits from precompiling are largely neglected as you're now sending more than twice as much data to the client as well as invoking the compiler for every invocation of a lambda function. So these are the primary benefits of using the fork: no longer needing or invoking the compiler on the client and no need to send duplicate template data to the client.

Hope that clarifies :)

Regards,
Arend jr.

elsigh commented May 2, 2012

I'm happy to use the fork, but I'm not really sure how to use it. As a first-timer on hogan, I actually fumbled awhile with how to use hulk at all.

I looked at the fork's bin/hulk and it didn't look like it did Hogan.Template's using the minify option or whatnot, but maybe ?

Anyhow, maybe I'm dense, but if you could give a brother a little howto on that page that would help alot. =)

i.e. do I just git clone the repo and then ./bin/hulk in your fork? That didn't seem to work for me fwiw. Does your fork's version of Hulk invoke Hogan.Template in the "new" way that will work? Is it theoretically then sufficient to just include templates.js without any other file (that's what it sounds like you're saying) or do I still need one of the hogan files?

On another note, what do people who don't believe in lambdas do? ;) Having to dive into the server-handed-over objects before templating, and say find all the GMT timestamps, create another property, and then reference that new property in the template seems harder that it could be. But then you don't need lambdas..

arendjr commented May 3, 2012

Hey there,

I'm not using hulk myself (caling Hogan.compile() directly as part of some larger build script), but you should be able to use hulk in exactly the same way as with the regular Hogan build. Indeed, if you want to use the minify option you should enable it yourself in bin/hulk in the calls to hogan.compile(), but remember it's not required to use the fork.

How do you run hulk with the Hogan.js master? In theory it should work exactly the same with my fork, if not I guess I broke something... In that case I'd by happy to fix it :)

And yes, you're right about only needing to include template.js on the client.

Cheers,
Arend jr.

elsigh commented May 3, 2012

Doh, I just hadn't run npm install in the clone repo yet (dependencies were missing).

Ok! So I used the forked version of template.js, but I have another question. Here's an example of one of my lambdas - note that it calls a function which works for me with Mustache.

data['gmt_line_1'] = function() {
return function(gmtDateString, render) {
var rendered = ws.format.trim(render(gmtDateString));
return ws.format.gmtToRelativeTime(rendered,
ws.format.SecondsIn.HOUR * 1000) || ws.format.gmtToTime(rendered);
}

In my template, I'm dereferencing the property {{gmt_line_1}}, and I can tell that it is invoking this function (I set a breakpoint on the line with "var rendered = ").

I'm seeing the following error in the console:
Uncaught TypeError: undefined is not a function

The undefined function here is "render" - note that I'm porting code that works in Mustache but seems not to work here. How do you pass your lambdas in? Note, I also tried taking the render param out as indicated by the example here:
http://mustache.github.com/mustache.5.html

I think a working demo of a lambda with the fork would be sweet =)

elsigh commented May 4, 2012

Wow, ok, that was easy - I went back to my breakpoint and realize I just don't even need to call render - the value of the text is right there in the param and I can just plain use it as is. ;)

arendjr commented May 4, 2012

Good to hear you got it working!

I'll make a mention the "porting effort" of the lambda functions in my README too :)

Cheers!

@sayrer sayrer closed this Nov 24, 2012

I'm really confused! I have the same problem as @elsigh but in my case I do need the render function because my date is a date object that is there in locals and so my first param is "{{startdate}}".

function dateFormat () {
  return function (date, render) {
    return (new Date(render(date))).getMonth();
  } 
}

I get ReferenceError: render is not defined. How am I supposed to handle this?

This is all serverside, fwiw, so I'm not worried about increased cost of sending stuff to the client.

Umm... I didn't really find a solution. I ended up rendering things on the
front-end, in angular, instead.

+1 @malcolmocean

I'm struggling with the exact issue when trying to augment the data object by adding the lambda function on the client-side. My lambda function looks like taken straight out of the manual. All I get is Uncaught ReferenceError: render is not defined. Please help, as this seriously compromises my use case for Hogan.

MeTaNoV commented Mar 25, 2015

I have the same issue with a similar use-case with Date... no news?

@MeTaNoV Please see the discussion on the other thread I'd started. In particular, see the tests to figure how Hogan is now handling lambdas: I could get it to work following the tests. It's a pity it's not documented, but I'm not even sure Hogan is being actively maintained anymore.

MeTaNoV commented Mar 25, 2015

Thx @prashaantt !!! I get it to work also now... Well, like you, I was following the Mustache way, and am wondering now which one is correct, the current implementation of Hogan or Mustache...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment