lib/merb/mixins/render_mixin.rb in merb-0.3.4 vs lib/merb/mixins/render_mixin.rb in merb-0.3.7
- old
+ new
@@ -1,59 +1,105 @@
module Merb
module RenderMixin
-
+
+ def self.included(base)
+ base.class_eval {
+ class_inheritable_accessor :_template_root,
+ :_layout
+
+ @@template_extensions = { }
+ self._layout = :application
+ self._template_root = File.expand_path(MERB_VIEW_ROOT)
+ # This method is called by templating-engines to register themselves with
+ # a list of extensions that will be looked up on #render of an action.
+ def self.register_engine(engine, *extensions)
+ [extensions].flatten.uniq.each do |ext|
+ @@template_extensions[ext] = engine
+ end
+ end
+
+ }
+ end
+
# universal render method. Template handlers are registered
# by template extension. So you can use the same render method
# for any kind of template that implements an adapter module.
- # out of the box Merb support Erubis, Markaby and Builder templates
+ # out of the box Merb support Erubis, Haml, Markaby and Builder templates
#
# Erubis template ext: .herb .jerb .erb
# Markaby template ext: .mab
# Builder template ext: .rxml .builder .xerb
+ # Haml template ext: .haml
#
# Examples:
#
- # render
- # looks for views/controllername/actionname.* and renders
+ # render
+ #
+ # Looks for views/controllername/actionname.* and renders
# the template with the proper engine based on its file extension.
#
- # render :layout => :none
- # renders the current template with no layout. XMl Builder templates
+ # render :layout => :none
+ #
+ # Renders the current template with no layout. XMl Builder templates
# are exempt from layout by default.
#
- # render :action => 'foo'
- # renders views/controllername/foo.*
+ # render :action => 'foo'
#
- # render :nothing => 200
- # renders nothing with a status of 200
+ # Renders views/controllername/foo.*
#
- # render :template => 'shared/message'
- # renders views/shared/message
+ # render :nothing => 200
#
- # render :js => "$('some-div').toggle();"
- # if the right hand side of :js => is a string then the proper
+ # Renders nothing with a status of 200
+ #
+ # render :template => 'shared/message'
+ #
+ # Renders views/shared/message
+ #
+ # render :js => "$('some-div').toggle();"
+ #
+ # If the right hand side of :js => is a string then the proper
# javascript headers will be set and the string will be returned
# verbatim as js.
#
- # render :js => :spinner
- # when the rhs of :js => is a Symbol, it will be used as the
+ # render :js => :spinner
+ #
+ # When the rhs of :js => is a Symbol, it will be used as the
# action/template name so: views/controllername/spinner.jerb
# will be rendered as javascript
#
- # render :js => true
- # this will just look for the current controller/action tenmplate
+ # render :js => true
+ #
+ # This will just look for the current controller/action template
# with the .jerb extension and render it as javascript
#
- # render :xml => @posts.to_xml
- # render :xml => "<foo><bar>Hi!</bar></foo>"
- # this will set the appropriate xml headers and render the rhs
+ # XML can be rendered with the same options as Javascript.
+ #
+ # render :xml => @posts.to_xml
+ # render :xml => "<foo><bar>Hi!</bar></foo>"
+ #
+ # This will set the appropriate xml headers and render the rhs
# of :xml => as a string. SO you can pass any xml string to this
# to be rendered.
#
+ # render :xml => :hello
+ #
+ # Renders the hello.xrb template for the current controller.
+ #
+ # render :xml => true
+ # render :xml => true, :action => "buffalo"
+ #
+ # Renders the buffalo.xerb template for the current controller.
+ #
def render(opts={}, &blk)
- action = opts[:action] || params[:action]
+
+ action = if kind_of?(Merb::ControllerExceptions::Base)
+ self.class.name.snake_case.split('::').last
+ else
+ opts[:action] || params[:action]
+ end
+
opts[:layout] ||= _layout
case
when status = opts[:nothing]
return render_nothing(status)
@@ -68,27 +114,36 @@
end
opts[:clean_context] = true
when js = opts[:js]
headers['Content-Type'] = "text/javascript"
opts[:layout] = :none
- if String === js
+ case js
+ when String
return js
- elsif Symbol === js
+ when Symbol
template = find_template(:action => js, :ext => 'jerb')
- else
+ else
template = find_template(:action => action, :ext => 'jerb')
end
when xml = opts[:xml]
headers['Content-Type'] = 'application/xml'
headers['Encoding'] = 'UTF-8'
- return xml
+ # TODO This is the same as the js logic above. Can it be refactored?
+ case xml
+ when String
+ return xml
+ when Symbol
+ template = find_template(:action => xml, :ext => 'rxml,xerb,builder')
+ else
+ template = find_template(:action => action, :ext => 'rxml,xerb,builder')
+ end
when template = opts[:template]
template = find_template(:template => template)
else
template = find_template(:action => action)
end
-
+
engine = engine_for(template)
options = {
:file => template,
:view_context => (opts[:clean_context] ? clean_view_context : cached_view_context),
:opts => opts
@@ -99,21 +154,12 @@
else
wrap_layout(content, opts)
end
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 cached_view_context
- @_view_context_cache ||= ViewContext.new(self)
- end
+
- def clean_view_context
- ViewContext.new(self)
- end
-
# does a render with no layout. Also sets the
# content type header to text/javascript. Use
# this when you want to render a template with
# .jerb extension.
def render_js(template=nil)
@@ -122,14 +168,18 @@
# renders nothing but sets the status, defaults
# to 200. does send one ' ' space char, this is for
# safari and flash uploaders to work.
def render_nothing(status=200)
- @status = status
+ @_status = status
return " "
end
+ def set_status(status)
+ @_status = status
+ end
+
def render_no_layout(opts={})
render opts.update({:layout => :none})
end
# This is merb's partial render method. You name your
@@ -142,18 +192,36 @@
# if you create a views/shared directory then you can call
# partials that live there like partial('shared/foo')
def partial(template, locals={})
render :partial => template, :locals => locals
end
+
+ # +catch_content+ catches the thrown content from another template
+ # So when you throw_content(:foo) {...} you can catch_content :foo
+ # in another view or the layout.
+ def catch_content(name)
+ cached_view_context.instance_variable_get("@_#{name}_content")
+ end
private
+ # 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 cached_view_context
+ @_view_context_cache ||= ViewContext.new(self)
+ end
+
+ def clean_view_context
+ ViewContext.new(self)
+ end
+
def wrap_layout(content, opts={})
if opts[:layout] != :application
layout_choice = find_template(:layout => opts[:layout])
else
- if name = find_template(:layout => self.class.name.snake_case)
+ if name = find_template(:layout => self.class.name.snake_case.split('::').join('/'))
layout_choice = name
else
layout_choice = find_template(:layout => :application)
end
end
@@ -170,32 +238,46 @@
# OPTIMIZE : combine find_template and find_partial ?
def find_template(opts={})
if template = opts[:template]
path = _template_root / template
+ elsif opts[:action] and kind_of?(Merb::ControllerExceptions::Base)
+ path = _template_root / 'exceptions' / opts[:action]
elsif action = opts[:action]
- path = _template_root / self.class.name.snake_case / action
+ segment = self.class.name.snake_case.split('::').join('/')
+ path = _template_root / segment / action
elsif _layout = opts[:layout]
- path = _layout_root / _layout
+ path = _template_root / 'layout' / _layout
else
raise "called find_template without an :action or :layout"
- end
- extensions = [_template_extensions.keys].flatten.uniq
+ end
+ extensions = [@@template_extensions.keys].flatten.uniq
glob = "#{path}.{#{opts[:ext] || extensions.join(',')}}"
Dir[glob].first
end
def find_partial(template, opts={})
if template =~ /\//
t = template.split('/')
template = t.pop
path = _template_root / t.join('/') / "_#{template}"
else
- path = _template_root / self.class.name.snake_case / "_#{template}"
+ segment = self.class.name.snake_case.split('::').join('/')
+ path = _template_root / segment / "_#{template}"
end
- extensions = [_template_extensions.keys].flatten.uniq
+ extensions = [@@template_extensions.keys].flatten.uniq
glob = "#{path}.{#{opts[:ext] || extensions.join(',')}}"
Dir[glob].first
end
+ # lookup the template_extensions for the extname of the filename
+ # you pass. Answers with the engine that matches the extension, Template::Erubis
+ # is used if none matches.
+ def engine_for(file)
+ extension = File.extname(file)[1..-1]
+ @@template_extensions[extension]
+ rescue
+ ::Merb::Template::Erubis
+ end
+
end
end
\ No newline at end of file