I'm a new Dancer user, but I'm loving it so far. In 4 days I was able to learn dancer, create plugins for accessing our existing APIs, session management and authentication, and port a relatively complex application. Dancer is elegantly simple. Thanks for a great architecture. Now for my question: Since the app I was porting used HTML::Template, I decided to use the Dancer::Template::HtmlTemplate module contributed by David Precious. It nicely renders the tokens passed in, however I believe HTML::Template expects a Hash Ref made up of either scalars or of Array of Hash - something to the effect of: { PARAM => 'value', PARAM2 => 'value', LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ], ANOTHER_LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ] } However, Dancer::Helpers::template() passes the settings, session, request and params as a Hash of Hash - making the vars inaccessible to HTML::Template. $tokens ||= {}; $tokens->{settings} = Dancer::Config->settings; $tokens->{request} = Dancer::SharedData->request; $tokens->{params} = Dancer::SharedData->request->params; if (setting('session')) { $tokens->{session} = Dancer::Session->get; } I think there are two approaches: 1) Dancer::Template::HtmlTemplate needs to be smart enough to fix up the $tokens hash to reformat those default values into something visible to HTML::Template - *something* like: foreach my $kind ( qw( settings request params session ) ) { foreach my $key ( keys %{ $tokens->{$kind} } ) { $tokens->{$kind.'-'.$key} = delete $tokens->{$kind}->{$key}; } } 2) an alternate solution would be to make the creation of tokens a subroutine that a Template plugin can expose back to Dancer as an alternative way of serializing the tokens for the given Template engine. *something like: $tokens ||= {}; if (Dancer::Template->engine->can('create_default_tokens') ) { $tokens = Dancer::Template->engine->create_default_tokens($tokens); } else { $tokens->{settings} = Dancer::Config->settings; $tokens->{request} = Dancer::SharedData->request; $tokens->{params} = Dancer::SharedData->request->params; if (setting('session')) { $tokens->{session} = Dancer::Session->get; } } If I am missing something really obvious, my apologies in advance. Assuming this *is* a legitimate issue, which way is the preferred solution? Mike.
Hi Mike, Sorry for the slow & rushed reply. On Saturday 02 October 2010 20:32:52 Mike Schroeder wrote:
I'm a new Dancer user, but I'm loving it so far. In 4 days I was able to learn dancer, create plugins for accessing our existing APIs, session management and authentication, and port a relatively complex application. Dancer is elegantly simple. Thanks for a great architecture.
Good to hear you're enjoying Dancer! :)
Now for my question:
Since the app I was porting used HTML::Template, I decided to use the Dancer::Template::HtmlTemplate module contributed by David Precious. It nicely renders the tokens passed in, however I believe HTML::Template expects a Hash Ref made up of either scalars or of Array of Hash - something to the effect of: [...snipped example...]
However, Dancer::Helpers::template() passes the settings, session, request and params as a Hash of Hash - making the vars inaccessible to HTML::Template.
Yes, HTML::Template can be a pain to work with - you're right that it doesn't handle a hash of hashes. This is something that needs fixing - can you raise an issue on Github at http://github.com/bigpresh/Dancer-Template-HtmlTemplate/issues ? I'm rather busy this week so probably won't have time to deal with it right away.
I think there are two approaches:
1) Dancer::Template::HtmlTemplate needs to be smart enough to fix up the $tokens hash to reformat those default values into something visible to HTML::Template - *something* like:
foreach my $kind ( qw( settings request params session ) ) { foreach my $key ( keys %{ $tokens->{$kind} } ) { $tokens->{$kind.'-'.$key} = delete $tokens->{$kind}->{$key}; }
}
Rather than hardcoding the param names to look at, I think I'd be inclined to have it automatically flatten any hashrefs in the params into keys in the to level hashref of params - so, for instance, if the params that were going to be passed to HTML::Template looked like: { foo => 1, bar => { baz => 2, bletch => 3, } } it would get "flattened" into, say,: { foo => 1, bar.baz => 2, bar.bletch => 3, } Having to do that is nasty, but it's a limitation of HTML::Template which doesn't let you dig into hashrefs, unlike for instance TT, where you can quite happily use e.g. [% foo.bar %]
2) an alternate solution would be to make the creation of tokens a subroutine that a Template plugin can expose back to Dancer as an alternative way of serializing the tokens for the given Template engine. *something like:
$tokens ||= {}; if (Dancer::Template->engine->can('create_default_tokens') ) { $tokens = Dancer::Template->engine->create_default_tokens($tokens); } else { $tokens->{settings} = Dancer::Config->settings; $tokens->{request} = Dancer::SharedData->request; $tokens->{params} = Dancer::SharedData->request->params; if (setting('session')) { $tokens->{session} = Dancer::Session->get; } }
This might be a cleaner way, perhaps, but requires changes to Dancer's core just to support this single template engine; on the other hand, it means working around issues like this in future could be be easier.
Assuming this *is* a legitimate issue, which way is the preferred solution?
I think I'd be inclined to go with option 1; anyone else care to comment? Cheers Dave P -- David Precious <davidp@preshweb.co.uk> http://blog.preshweb.co.uk/ www.preshweb.co.uk/twitter www.preshweb.co.uk/linkedin www.preshweb.co.uk/facebook www.preshweb.co.uk/identica www.lyricsbadger.co.uk "Programming is like sex. One mistake and you have to support it for the rest of your life". (Michael Sinz)
On Mon, Oct 4, 2010 at 10:14 AM, David Precious <davidp@preshweb.co.uk>wrote:
Sorry for the slow & rushed reply.
No worries - thanks for responding!
Yes, HTML::Template can be a pain to work with - you're right that it doesn't handle a hash of hashes.
This is something that needs fixing - can you raise an issue on Github at http://github.com/bigpresh/Dancer-Template-HtmlTemplate/issues ?
Done: http://github.com/bigpresh/Dancer-Template-HtmlTemplate/issues/issue/1
I'm rather busy this week so probably won't have time to deal with it right away.
Sounds great - I have a workaround for the moment, but I refactor my hack out and end up with a cleaner app when your patch is done. Rather than hardcoding the param names to look at, I think I'd be inclined
to have it automatically flatten any hashrefs in the params into keys in the to level hashref of params - so, for instance, if the params that were going to be passed to HTML::Template looked like:
{ foo => 1, bar => { baz => 2, bletch => 3, } }
it would get "flattened" into, say,:
{ foo => 1, bar.baz => 2, bar.bletch => 3, }
Great idea - just pre-process the whole $tokens hash regardless of source.
Having to do that is nasty, but it's a limitation of HTML::Template which doesn't let you dig into hashrefs, unlike for instance TT, where you can quite happily use e.g. [% foo.bar %]
2) an alternate solution would be to make the creation of tokens a subroutine that a Template plugin can expose back to Dancer as an alternative way of serializing the tokens for the given Template engine. *something like:
$tokens ||= {}; if (Dancer::Template->engine->can('create_default_tokens') ) { $tokens = Dancer::Template->engine->create_default_tokens($tokens); } else { $tokens->{settings} = Dancer::Config->settings; $tokens->{request} = Dancer::SharedData->request; $tokens->{params} = Dancer::SharedData->request->params; if (setting('session')) { $tokens->{session} = Dancer::Session->get; } }
This might be a cleaner way, perhaps, but requires changes to Dancer's core just to support this single template engine; on the other hand, it means working around issues like this in future could be be easier.
Right - I was thinking someone might want to give some architectural direction, but either approach works for me. Thanks again David. Mike.
participants (2)
-
David Precious -
Mike Schroeder