module Crystal module AbstractController module Render SPECIAL_FORMAT_HANDLERS = [ ['json', lambda{|o| o.to_json}], ['xml', lambda{|o| o.to_xml}], ['js', lambda{|o| o}], ] SPECIAL_CASES_HANDLERS = [ ['inline', lambda{|o| o}], ] def layout tname = nil if tname @_layout = tname else @_layout end end def layout= layout @_layout = layout end def render *args options = Template.parse_arguments *args render_with_parsed_arguments options end def render_action options options = options.to_openobject template = self.class.template_name_for options.action return "" unless Template.exist? template instance_variables = {} instance_variable_names.each do |name| instance_variables[name[1..-1]] = instance_variable_get name unless name =~ /^@_/ end render_options = { :template => template, :instance_variables => instance_variables, :context_class => self.class.controller_context_class, :format => params.format, :action => true # this willn't allow to render partial starting with _ }.to_openobject content, context = Template.basic_render render_options layout = options.include?(:layout) ? options.layout : self.layout if layout content = Template.render_layout layout, :content => content, :context => context end content end protected def render_with_parsed_arguments options content = if options.action? render_action options elsif special_format_handler = SPECIAL_FORMAT_HANDLERS.find{|format, handler| options.include? format} format, handler = special_format_handler if format != params.format raise "You trying responing with :#{format} to the :#{params.format} requested format!" end handler.call options[format] elsif special_format_handler = SPECIAL_CASES_HANDLERS.find{|key, handler| options.include? key} key, handler = special_format_handler handler.call options[key] else Template.basic_render(options).first end throw :special_result, content end module ClassMethods def layout layout, options = {} before options do |controller| controller.layout = layout end end def template_name_for action action = action.to_s return _template_name_for(action) if config.development? @template_name_for ||= {} unless tname = @template_name_for[action] tname = _template_name_for(action) @template_name_for[action] = tname end tname end protected def _template_name_for action instance_methods.must.include(action) own_tnames = [ "/#{controller_name.gsub('::', '/')}/#{action}", "/#{controller_name.underscore}/#{action}" ] own_actions_tnames = [ "/#{controller_name.gsub('::', '/')}/actions", "/#{controller_name.underscore}/actions" ] action_template_exist = lambda do |tname| Crystal::Template.exist?(tname) and Crystal::Template.read(tname) =~ /^.+when.+:#{action}.+$/ end if existing_template = own_tnames.find{|tname| Crystal::Template.exist? tname} existing_template elsif existing_action_template = own_actions_tnames.find(&action_template_exist) existing_action_template elsif parent = ancestors[1..-1].find{|a| a.respond_to?(:template_name_for) and a.instance_methods.include?(action)} parent.template_name_for(action) else own_tnames.first end end end end end end