lib/merb/mixins/render_mixin.rb in merb-0.0.7 vs lib/merb/mixins/render_mixin.rb in merb-0.0.8
- old
+ new
@@ -1,91 +1,165 @@
module Merb
module RenderMixin
-
+
# shortcut to a template path based on name.
def template_dir(loc)
- File.expand_path(Merb::Server.config[:merb_root] + "/dist/app/views/#{loc}")
+ File.expand_path(Merb::Server.config[:merb_root] / "/dist/app/views/#{loc}")
end
# returns the current method name. Used for
# auto discovery of which template to render
# based on the action name.
def current_method_name(depth=0)
caller[depth] =~ /`(.*)'$/; $1
end
+ # given html, js and xml this method returns the template
+ # extension from the :template_ext map froom your app's
+ # configuration. defaults to .herb, .jerb & .xerb
def template_extension_for(ext)
Merb::Server.config[:template_ext][ext]
end
+ # this returns a ViewContext object populated with all
+ # the instance variables in your controller. This is used
+ # as the view context object for the Erubis templates.
+ def create_view_context
+ ViewContext.new(self)
+ end
+
# does a render with no layout. Also sets the
- # content type header to text/javascript
- def render_js(template=current_method_name(1), b=binding)
+ # content type header to text/javascript. Use
+ # this when you want to render a template with
+ # .jerb extension.
+ def render_js(template=current_method_name(1))
headers['Content-Type'] = "text/javascript"
- template = Erubis::Eruby.new(IO.read( template_dir(self.class.name.snake_case) + "/#{template}.#{template_extension_for(:js)}" ))
- template.result(b)
+ template = new_eruby_obj(template_dir(self.class.name.snake_case) / "/#{template}.#{template_extension_for(:js)}")
+ template.evaluate(create_view_context)
end
- # set the @layout. Use this right before a render to
- # set the name of the layout to use minus the .rhtml
- def layout(l)
- @layout = l
- end
-
- # renders nothing but sets the status
+ # renders nothing but sets the status, defaults
+ # to 200
def render_nothing(status=200)
@status = status
return "\n"
end
# renders the action without wrapping it in a layout.
- def render_no_layout(template=current_method_name(1), b=binding)
- template = Erubis::Eruby.new( IO.read( template_dir(self.class.name.snake_case) + "/#{template}.#{template_extension_for(:html)}" ) )
- template.result(b)
+ # call it without arguments if your template matches
+ # the name of the running action. Otherwise you can
+ # explicitely set the template name excluding the file
+ # extension
+ def render_no_layout(template=current_method_name(1))
+ template = new_eruby_obj(template_dir(self.class.name.snake_case) / "/#{template}.#{template_extension_for(:html)}")
+ template.evaluate(create_view_context)
end
+ # This is merb's partial render method. You name your
+ # partials _partialname.herb, and then call it like
+ # partial(:partialname). If there is no '/' character
+ # in the argument passed in it will look for the partial
+ # in the view directory that corresponds to the current
+ # controller name. If you pass a string with a path in it
+ # you can render partials in other view directories. So
+ # if you create a views/shared directory then you can call
+ # partials that live there like partial('shared/foo')
def partial(template)
- template = Erubis::Eruby.new( IO.read( template_dir(self.class.name.snake_case) + "/_#{template}.#{template_extension_for(:html)}" ) )
- template.result(binding)
+ if template =~ /\//
+ t = template.split('/')
+ template = t.pop
+ tmpl = new_eruby_obj(template_dir(t.join('/')) / "/_#{template}.#{template_extension_for(:html)}")
+ else
+ tmpl = new_eruby_obj(template_dir(self.class.name.snake_case) / "/_#{template}.#{template_extension_for(:html)}")
+ end
+ tmpl.evaluate(create_view_context)
end
+ # This creates and returns a new Erubis object populated
+ # with the template from path. If there is no matching
+ # template then we rescue the Errno::ENOENT exception
+ # and raise a no template found message
+ def new_eruby_obj(path)
+ begin
+ Erubis::MEruby.new(IO.read(path))
+ rescue Errno::ENOENT
+ raise "No template found at path: #{path}"
+ end
+ end
+
+ # this is the xml builder render method. This method
+ # builds the Builder::XmlMarkup object for you and adds
+ # the xml headers and encoding. Then it evals your template
+ # in the context of the xml object. So your .xerb templates
+ # will look like this:
+ # xml.foo {|xml|
+ # xml.bar "baz"
+ # }
def render_xml(template=current_method_name(1))
xml = Builder::XmlMarkup.new :indent => 2
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
eval IO.read( template_dir(self.class.name.snake_case) + "/#{template}.#{template_extension_for(:xml)}" )
@headers['Content-Type'] = 'application/xml'
@headers['Encoding'] = 'UTF-8'
xml.target!
end
- # renders a template based on the current action name
- # you can pass the name of a template if you want to
- # render a template with a different name then then
- # current action name. Wraps the rendered template in
- # the layout. Uses layout/application.rhtml unless
+ # This is the main render method that handles layouts.
+ # render will use layout/application.rhtml unless
# there is a layout named after the current controller
- # or @layout has been set to another value.
- def render(template=current_method_name(1), b=binding)
+ # or if self.layout= has been set to another value in
+ # the current controller. You can over-ride this setting
+ # by passing an options hash with a :layout => 'layoutname'.
+ # if you with to not render a layout then pass :layout => :none
+ # the first argument to render is the template name. if you do
+ # not pass a template name, it will set the template to
+ # views/controller/action automatically.
+ # examples:
+ # class Test < Merb::Controller
+ # # renders views/test/foo.herb
+ # # in layout application.herb
+ # def foo
+ # # code
+ # render
+ # end
+ #
+ # # renders views/test/foo.herb
+ # # in layout application.herb
+ # def bar
+ # # code
+ # render :foo
+ # end
+ #
+ # # renders views/test/baz.herb
+ # # with no layout
+ # def baz
+ # # code
+ # render :layout => :none
+ # end
+ def render(opts={})
+ template = opts[:action] || params[:action]
tmpl_ext = template_extension_for(:html)
- MERB_LOGGER.info("Rendering template: #{template_dir(template)}..#{tmpl_ext}")
+ MERB_LOGGER.info("Rendering template: #{template}.#{tmpl_ext}")
name = self.class.name.snake_case
- template = Erubis::Eruby.new( IO.read( template_dir(name) + "/#{template}.#{tmpl_ext}" ) )
- layout_content = template.result(b)
- return layout_content if (@layout.to_s == 'none')
- if ['application', name].include?(@layout.to_s)
+ template = new_eruby_obj(template_dir(name) / "/#{template}.#{tmpl_ext}")
+ view_context = create_view_context
+ layout_content = template.evaluate(view_context)
+ self.layout = opts[:layout].to_sym if opts.has_key?(:layout)
+ return layout_content if (layout == :none)
+ if layout != :application
+ layout_choice = layout
+ else
if File.exist?(template_dir("layout/#{name}.#{tmpl_ext}"))
- layout = name
+ layout_choice = name
else
- layout = 'application'
- end
- else
- layout = @layout.to_s
- end
- MERB_LOGGER.info("With Layout: #{template_dir('layout')}/#{layout}.#{tmpl_ext}")
- @layout_content = layout_content
- layout_tmpl = Erubis::Eruby.new( IO.read( "#{template_dir('layout')}/#{layout}.#{tmpl_ext}" ) )
- layout_tmpl.result(b)
+ layout_choice = layout
+ end
+ end
+ MERB_LOGGER.info("With Layout: #{layout_choice}.#{tmpl_ext}")
+ view_context.instance_eval { throw_content(:layout) { layout_content } }
+ layout_tmpl = new_eruby_obj("#{template_dir('layout')}/#{layout_choice}.#{tmpl_ext}")
+ layout_tmpl.evaluate(view_context)
end
end
end
\ No newline at end of file