module Rad::Controller::Abstract::Render SPECIAL_FORMAT_HANDLERS = { json: lambda{|o| o.to_json}, xml: lambda{|o| o.to_xml}, js: lambda{|o| o}, } def _layout *args @_layout = *args unless args.empty? @_layout end def _layout= layout @_layout = layout end def render *args options = rad.template.parse_arguments *args content = render_with_parsed_arguments options, args throw :halt, content end protected def render_action options instance_variables = { action_name: (options[:action] || workspace.action).to_sym, controller_name: self.class.controller_name } instance_variable_names.each do |name| instance_variables[name[1..-1]] = instance_variable_get name unless name =~ /^@_/ end context = self.class.context_class.new(instance_variables, self) options[:template] ||= options.delete(:action) options[:template].must_be.present options[:template] = options[:template].to_s options.reverse_merge!( context: context, format: params.format, exact_format: true, prefixes: [''] ) # rendering content content, context = render_content options # rendering layout options[:content] = context render_layout options, content end def render_layout options, content layout = options.include?(:layout) ? options[:layout] : self._layout if layout # and rad.template.exist? layout, options rad.template.render layout, options do |*args| if args.empty? content else args.size.must_be == 1 variable_name = args.first.to_s options[:context].content_variables[variable_name] end end else content end end def render_content options rad.template.basic_render options.merge(relative_path_resolver: self.class, if_not_exist: '/rad_default_templates/blank_template') end def render_with_parsed_arguments options, original_args if special_format = SPECIAL_FORMAT_HANDLERS.keys.find{|f| options.include? f} handler = SPECIAL_FORMAT_HANDLERS[special_format] if special_format.to_s != params.format raise "You trying responing with '#{special_format}' to the '#{params.format}' requested format!" end handler.call options[special_format] elsif options.include? :inline options[:inline] elsif options[:template] == :nothing '' else render_action options end end module ClassMethods def layout layout, options = {} before options do |controller| controller._layout = layout end end def context_class unless @context_class parent_context_class = nil ancestors[1..-1].each do |anc| break if parent_context_class = anc.respond_to(:context_class) end parent_context_class ||= Rad::Controller::Context class_name = "#{self.name}::#{self.name.split('::').last}Context" # raise "Tempate context #{class_name} already defined!" if Object.const_defined? class_name eval "class #{class_name} < #{parent_context_class}; end", TOPLEVEL_BINDING, __FILE__, __LINE__ @context_class = class_name.constantize end @context_class end def find_relative_template *args return _find_relative_template *args unless rad.production? # use cache @relative_template ||= {} unless @relative_template.include? args @relative_template[args] = _find_relative_template *args end @relative_template[args] end def _find_relative_template tname, prefixes, format, exact_format, current_dir tname.must_be.present path = nil # own templates ["/#{controller_name.underscore}/#{tname}", "/#{controller_name.gsub('::', '/')}/#{tname}"].each do |name| path ||= rad.template.find_file(name, prefixes, format, exact_format, rad.template.paths) end # own :actions templates ["/#{controller_name.underscore}/actions", "/#{controller_name.gsub('::', '/')}/actions"].each do |name| unless path path = rad.template.find_file(name, prefixes, format, exact_format, rad.template.paths) path = nil if path and (File.read(path) !~ /^.*when.+[^_a-zA-Z0-9]#{tname}[^_a-zA-Z0-9].*$/) end end # superclasses templates unless path parent = ancestors[1..-1].find{|a| a.respond_to?(:find_relative_template)} # and a.instance_methods.include?(action) if parent and parent != Rad::Controller::Abstract path = parent.find_relative_template(tname, prefixes, format, exact_format, current_dir) end end # relative template if !path and current_dir path = rad.template.relative_path_resolver.find_relative_template(tname, prefixes, format, exact_format, current_dir) end return path end end end