passing context to partials

243 views
Skip to first unread message

Paul

unread,
Nov 22, 2009, 12:02:31 PM11/22/09
to Mustache
In erubis, I do the following:

<% ['reset-min-2.6.0.css', 'jquery-ui-1.7.2.custom.css',
'main.css'].each do |css| %>
<%= partial :style, { :css => css } %>
<% end %>

partial is a helper function that renders the partial, passing in the
context. I've been attempting to conceptualize the Mustache
equivalent and this is the best I could do

# layout.rb
class Main

module ViewHelpers
def partial klass, ctx={}
markup = klass.new
ctx.each { |k,v| markup[k] = v }
markup.render
end
end

module Views
class Layout < Mustache
include ViewHelpers

def css
[ { :style => partial(Style, { :css => 'reset-
min-2.6.0.css'}) },
{ :style => partial(Style, { :css => 'jquery-
ui-1.7.2.custom.css'}) },
{ :style => partial(Style, { :css => 'main.css'}) } ]
end
end
end
end

# in layout.mustache
{{#css}}
{{{style}}}
{{/css}}

Is there a better method to accomplish what I am seeking? There is no
way to pass variables into methods from the templates correct?

Thanks,
~Paul

Chris Wanstrath

unread,
Nov 23, 2009, 12:56:52 PM11/23/09
to musta...@googlegroups.com
On Sun, Nov 22, 2009 at 9:02 AM, Paul <pjwa...@gmail.com> wrote:

> In erubis, I do the following:
>
> <% ['reset-min-2.6.0.css', 'jquery-ui-1.7.2.custom.css',
> 'main.css'].each do |css| %>
> <%= partial :style, { :css => css } %>
> <% end %>

..snip..

> Is there a better method to accomplish what I am seeking?  There is no
> way to pass variables into methods from the templates correct?

In Mustache, partials inherit the context of the caller.

Here's how I would do it:

layout.rb:
module Views
class Layout < Mustache
def css_files
['reset-min-2.6.0.css', 'jquery-ui-1.7.2.custom.css', 'main.css']
end

def css
css = {}
css_files.each do |file|
css[:style] = file
end
css
end
end
end

layout.mustache:
{{#css}}
{{>style_partial}}
{{/css}}

style_partial.mustache:
<link href="{{style}}" media="screen" rel="stylesheet" type="text/css" />

The important thing is that Mustache's partials behavior already gives
you what you want out of the box.

--
Chris Wanstrath
http://github.com/defunkt

Paul Walker

unread,
Nov 23, 2009, 10:27:44 PM11/23/09
to musta...@googlegroups.com
Beautiful, I don't know why it escaped me that partials are straight
substitutions. Now, how do I access the layout class instance for a
particular view request?

Chris Wanstrath

unread,
Nov 23, 2009, 10:36:21 PM11/23/09
to musta...@googlegroups.com
On Monday, November 23, 2009, Paul Walker <pjwa...@gmail.com> wrote:

> Beautiful, I don't know why it escaped me that partials are straight substitutions.  Now, how do I access the layout class instance for a particular view request?

Can you be more specific? I don't quite follow - what are you trying to do?

Chris
> <link href="{{style}}" media="screen" rel="stylesheet" type="text/css" />

Paul Walker

unread,
Nov 23, 2009, 11:18:02 PM11/23/09
to musta...@googlegroups.com
Building on the last example, let's say the layout css def was:

def css
@css ||=
[ { :style => 'reset-min-2.6.0.css' },
{ :style => 'jquery-ui-themes/smoothness/reset-
min-2.6.0.css' }]
end

and each view has it's own css file, so I'd like to << an entry to
css. It would be kinda neat if the layout was auto-magically mixed in
or even just accessible as a variable within the view instance class
(i.e., layout.css << 'index.css'). Or perhaps there's a better way to
go about this?

Thanks,
~Paul

Matt Murphy

unread,
Nov 24, 2009, 1:29:10 PM11/24/09
to musta...@googlegroups.com
Paul -- I've handled this by just creating modules for functionality that is needed both in the layout and the template ... 

What your'e describing sounds like the (very nice) way that django templates lets you override a block from a layout in a specific template...  

<link href="{{style}}" media="screen" rel="stylesheet" type="text/css" />


The important thing is that Mustache's partials behavior already gives
you what you want out of the box.

--
Chris Wanstrath
http://github.com/defunkt



Chris Wanstrath

unread,
Nov 24, 2009, 1:35:04 PM11/24/09
to musta...@googlegroups.com
On Tue, Nov 24, 2009 at 10:29 AM, Matt Murphy <mmm...@gmail.com> wrote:

> Paul -- I've handled this by just creating modules for functionality that is
> needed both in the layout and the template ...

That's absolutely one way to do it.

> On Mon, Nov 23, 2009 at 8:18 PM, Paul Walker <pjwa...@gmail.com> wrote:
>>
>> Building on the last example, let's say the layout css def was:
>>
>>  def css
>>   @css ||=
>>        [ { :style => 'reset-min-2.6.0.css' },
>>          { :style => 'jquery-ui-themes/smoothness/reset-min-2.6.0.css' }]
>> end

Here's how we handle this in our apps:

http://gist.github.com/242095

Basically, we have all the views inherit from Layout.

Matt Murphy

unread,
Nov 24, 2009, 2:01:43 PM11/24/09
to musta...@googlegroups.com
Chris, it's my understanding that if a tag is in the layout.mustache file, then even if you define a method in a view class (which is a subclass of the layout class) that the layout class's method will be called when rendering the tag... 


In your example I assume the tag in question is in your page template, not in the layout... is that correct?

Chris Wanstrath

unread,
Nov 24, 2009, 4:10:39 PM11/24/09
to musta...@googlegroups.com
On Tue, Nov 24, 2009 at 11:01 AM, Matt Murphy <mmm...@gmail.com> wrote:

> Chris, it's my understanding that if a tag is in the layout.mustache file,
> then even if you define a method in a view class (which is a subclass of the
> layout class) that the layout class's method will be called when rendering
> the tag...
> https://gist.github.com/a3f6c42e44b3dd30f3c2
> In your example I assume the tag in question is in your page template, not
> in the layout... is that correct?

You are right, I am wrong.

In fact after sending that message we ran into this issue: we want to
set the page title in a view but have it handled in the layout.

Is this a Sinatra-specific thing, or a Mustache-wide problem? I wonder...

Paul Walker

unread,
Nov 24, 2009, 8:42:23 PM11/24/09
to musta...@googlegroups.com
So, from this discussion, I think we have a basic use case that we
want to handle from mustache framework. The page <title> use case is
more perfect, but the general solution should be able to override/
place specific content in the layout instance.

Chris, looking at the render method in Sinatra, I'm failing to see a
way in which necessary context could be hacked in a clean way for a
client programmer...perhaps it's worth considering taking mustache out
of Sinatra's framework specifically? What is gained from it outside
of the configuration settings for the where views reside?

~Paul

Chris Wanstrath

unread,
Nov 24, 2009, 11:15:50 PM11/24/09
to musta...@googlegroups.com
On Tue, Nov 24, 2009 at 5:42 PM, Paul Walker <pjwa...@gmail.com> wrote:

> So, from this discussion, I think we have a basic use case that we want to
> handle from mustache framework.  The page <title> use case is more perfect,
> but the general solution should be able to override/place specific content
> in the layout instance.

Well for the <title> case, you can always do this:

get '/index' do
@title = "Index"
mustache :index
end

Then:

class Layout < Mustache
attr_reader :index
end

<title>{{title}}</title>

The instance variable should be available in the Layout instance.

> Chris, looking at the render method in Sinatra, I'm failing to see a way in
> which necessary context could be hacked in a clean way for a client
> programmer...perhaps it's worth considering taking mustache out of Sinatra's
> framework specifically?  What is gained from it outside of the configuration
> settings for the where views reside?

I'm not sure I understand - can you rephrase?

Chris

Chris Wanstrath

unread,
Nov 24, 2009, 11:17:57 PM11/24/09
to musta...@googlegroups.com
On Tue, Nov 24, 2009 at 10:35 AM, Chris Wanstrath <ch...@ozmm.org> wrote:

Okay, this is not the greatest but it works: http://gist.github.com/242465
Reply all
Reply to author
Forward
0 new messages