Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 8805

Show
Ignore:
Timestamp:
02/06/08 04:26:40 (10 months ago)
Author:
nzkoz
Message:

Introduce a Template class to ActionView. Closes #11024 [lifofifo]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r8786 r8805  
    11*SVN* 
     2 
     3* Introduce a Template class to ActionView.  #11024 [lifofifo] 
    24 
    35* Introduce the :index option for form_for and fields_for to simplify multi-model forms (see http://railscasts.com/episodes/75).  #9883 [rmm5t] 
  • trunk/actionpack/lib/action_controller/base.rb

    r8683 r8805  
    66require 'action_controller/url_rewriter' 
    77require 'action_controller/status_codes' 
     8require 'action_view/template' 
    89require 'action_view/template_finder' 
    910require 'drb' 
     
    867868          elsif inline = options[:inline] 
    868869            add_variables_to_assigns 
    869             render_for_text(@template.render_template(options[:type], inline, nil, options[:locals] || {}), options[:status]) 
     870            tmpl = ActionView::Template.new(@template, options[:inline], false, options[:locals], true, options[:type]) 
     871            render_for_text(@template.render_template(tmpl), options[:status]) 
    870872 
    871873          elsif action_name = options[:action] 
  • trunk/actionpack/lib/action_view.rb

    r8689 r8805  
    2929 
    3030require 'action_view/template_finder' 
     31require 'action_view/template' 
    3132 
    3233require 'action_view/base' 
  • trunk/actionpack/lib/action_view/base.rb

    r8791 r8805  
    151151    include ERB::Util 
    152152 
    153     attr_reader   :first_render, :finder 
    154     attr_accessor :base_path, :assigns, :template_extension 
     153    attr_reader   :finder 
     154    attr_accessor :base_path, :assigns, :template_extension, :first_render 
    155155    attr_accessor :controller 
    156156 
     
    174174    @@cache_template_extensions = true 
    175175    cattr_accessor :cache_template_extensions 
    176  
    177     # Specify whether local_assigns should be able to use string keys. 
    178     # Defaults to +true+. String keys are deprecated and will be removed 
    179     # shortly. 
    180     @@local_assigns_support_string_keys = true 
    181     cattr_accessor :local_assigns_support_string_keys 
    182176     
    183177    # Specify whether RJS responses should be wrapped in a try/catch block 
     
    283277      end 
    284278       
    285       # Clear the forward slash at the beginning if exists 
    286       template_path = template_path.sub(/^\//, '') if use_full_path 
    287  
    288       @first_render ||= template_path 
    289       template_path_without_extension, template_extension = @finder.path_and_extension(template_path) 
    290       if use_full_path 
    291         if template_extension 
    292           template_file_name = @finder.pick_template(template_path_without_extension, template_extension) 
    293         else 
    294           template_extension = @finder.pick_template_extension(template_path).to_s 
    295           unless template_extension 
    296             raise ActionViewError, "No template found for #{template_path} in #{@finder.view_paths.inspect}" 
    297           end 
    298           template_file_name = @finder.pick_template(template_path, template_extension) 
    299           template_extension = template_extension.gsub(/^.+\./, '') # strip off any formats 
    300         end 
    301       else 
    302         template_file_name = template_path 
    303       end 
    304  
    305       template_source = nil # Don't read the source until we know that it is required 
    306  
    307       if template_file_name.blank? 
    308         raise ActionViewError, "Couldn't find template file for #{template_path} in #{@finder.view_paths.inspect}" 
    309       end 
     279      template = Template.new(self, template_path, use_full_path, local_assigns) 
    310280 
    311281      begin 
    312         render_template(template_extension, template_source, template_file_name, local_assigns
     282        render_template(template
    313283      rescue Exception => e 
    314284        if TemplateError === e 
    315           e.sub_template_of(template_file_name) 
     285          e.sub_template_of(template.filename) 
    316286          raise e 
    317287        else 
    318           raise TemplateError.new(@finder.find_base_path_for("#{template_path_without_extension}.#{template_extension}") || 
    319                 @finder.view_paths.first, template_file_name, @assigns, template_source, e) 
     288          raise TemplateError.new(template, @assigns, e) 
    320289        end 
    321290      end 
     
    351320          render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]) 
    352321        elsif options[:inline] 
    353           render_template(options[:type], options[:inline], nil, options[:locals]) 
     322          template = Template.new(self, options[:inline], false, options[:locals], true, options[:type]) 
     323          render_template(template) 
    354324        end 
    355325      end 
     
    358328    # Renders the +template+ which is given as a string as either erb or builder depending on <tt>template_extension</tt>. 
    359329    # The hash in <tt>local_assigns</tt> is made available as local variables. 
    360     def render_template(template_extension, template, file_path = nil, local_assigns = {}) #:nodoc: 
    361       handler = self.class.handler_class_for_extension(template_extension).new(self) 
    362       @current_render_extension = template_extension 
     330    def render_template(template) #:nodoc: 
     331      handler = template.handler 
     332      @current_render_extension = template.extension 
    363333 
    364334      if handler.compilable? 
    365         compile_and_render_template(handler, template, file_path, local_assigns
     335        compile_and_render_template(handler, template
    366336      else 
    367         template ||= handler.read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded. 
    368         handler.render(template, local_assigns) 
     337        handler.render(template.source, template.locals) 
    369338      end 
    370339    end 
     
    408377      # will only be read if it has to be compiled. 
    409378      # 
    410       def compile_and_render_template(handler, template = nil, file_path = nil, local_assigns = {}) #:nodoc: 
    411         # convert string keys to symbols if requested 
    412         local_assigns = local_assigns.symbolize_keys if @@local_assigns_support_string_keys 
    413  
     379      def compile_and_render_template(handler, template) #:nodoc: 
    414380        # compile the given template, if necessary 
    415         handler.compile_template(template, file_path, local_assigns
     381        handler.compile_template(template
    416382 
    417383        # Get the method name for this template and run it 
    418         method_name = @@method_names[file_path || template
     384        method_name = @@method_names[template.method_key
    419385        evaluate_assigns 
    420386 
    421         send(method_name, local_assigns) do |*name| 
     387        send(method_name, template.locals) do |*name| 
    422388          instance_variable_get "@content_for_#{name.first || 'layout'}" 
    423389        end 
  • trunk/actionpack/lib/action_view/template_error.rb

    r8743 r8805  
    77    attr_reader :original_exception 
    88 
    9     def initialize(base_path, file_path, assigns, source, original_exception) 
    10       @base_path, @assigns, @source, @original_exception = 
    11         base_path, assigns.dup, source, original_exception 
    12       @file_path = file_path 
     9    def initialize(template, assigns, original_exception) 
     10      @base_path = template.base_path_for_exception 
     11      @assigns, @source, @original_exception = assigns.dup, template.source, original_exception 
     12      @file_path = template.filename 
    1313      @backtrace = compute_backtrace 
    1414    end 
  • trunk/actionpack/lib/action_view/template_handler.rb

    r8756 r8805  
    3131    def cache_fragment(block, name = {}, options = nil) 
    3232    end 
    33  
    34     # This method reads a template file. 
    35     def read_template_file(template_path, extension) 
    36       File.read(template_path) 
    37     end 
    3833  end 
    3934end 
  • trunk/actionpack/lib/action_view/template_handlers/compilable.rb

    r8756 r8805  
    2727 
    2828      # Compile and evaluate the template's code 
    29       def compile_template(template, file_name, local_assigns
    30         return unless compile_template?(template, file_name, local_assigns
     29      def compile_template(template
     30        return unless compile_template?(template
    3131 
    32         template ||= read_template_file(file_name, nil) 
    33  
    34         render_symbol = assign_method_name(template, file_name) 
    35         render_source = create_template_source(template, render_symbol, local_assigns.keys) 
     32        render_symbol = assign_method_name(template) 
     33        render_source = create_template_source(template, render_symbol) 
    3634        line_offset   = self.template_args[render_symbol].size + self.line_offset 
    3735 
    3836        begin 
    39           file_name = 'compiled-template' if file_name.blank? 
     37          file_name = template.filename || 'compiled-template' 
    4038          ActionView::Base::CompiledTemplates.module_eval(render_source, file_name, -line_offset) 
    4139        rescue Exception => e  # errors from template code 
     
    4644          end 
    4745 
    48           raise ActionView::TemplateError.new(@view.finder.extract_base_path_from(file_name) || 
    49                 @view.finder.view_paths.first, file_name || template, @view.assigns, template, e) 
     46          raise ActionView::TemplateError.new(template, @view.assigns, e) 
    5047        end 
    5148 
     
    6057      # if local_assigns has a new key, which isn't supported by the compiled code yet, 
    6158      # or if the file has changed on disk and checking file mods hasn't been disabled. 
    62       def compile_template?(template, file_name, local_assigns
    63         method_key    = file_name || template 
     59      def compile_template?(template
     60        method_key    = template.method_key 
    6461        render_symbol = @view.method_names[method_key] 
    6562 
    6663        compile_time = self.compile_time[render_symbol] 
    67         if compile_time && supports_local_assigns?(render_symbol, local_assigns) 
    68           if file_name && !@view.cache_template_loading 
    69             template_changed_since?(file_name, compile_time) 
     64        if compile_time && supports_local_assigns?(render_symbol, template.locals) 
     65          if template.filename && !@view.cache_template_loading 
     66            template_changed_since?(template.filename, compile_time) 
    7067          end 
    7168        else 
     
    7471      end 
    7572 
    76       def assign_method_name(template, file_name) 
    77         method_key = file_name || template 
    78         @view.method_names[method_key] ||= compiled_method_name(template, file_name) 
     73      def assign_method_name(template) 
     74        @view.method_names[template.method_key] ||= compiled_method_name(template) 
    7975      end 
    8076 
    81       def compiled_method_name(template, file_name
    82         ['_run', self.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment(file_name)].compact.join('_').to_sym 
     77      def compiled_method_name(template
     78        ['_run', self.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment(template.filename)].compact.join('_').to_sym 
    8379      end 
    8480 
     
    9591 
    9692      # Method to create the source code for a given template. 
    97       def create_template_source(template, render_symbol, locals
    98         body = compile(template
     93      def create_template_source(template, render_symbol
     94        body = compile(template.source
    9995 
    10096        self.template_args[render_symbol] ||= {} 
    101         locals_keys = self.template_args[render_symbol].keys | local
     97        locals_keys = self.template_args[render_symbol].keys | template.locals.key
    10298        self.template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h } 
    10399 
  • trunk/actionpack/test/controller/custom_handler_test.rb

    r8624 r8805  
    2121 
    2222  def test_custom_render 
    23     result = @view.render_template( "foo", "hello <%= one %>", nil, :one => "two" ) 
     23    template = ActionView::Template.new(@view, "hello <%= one %>", false, { :one => "two" }, true, "foo") 
     24 
     25    result = @view.render_template(template) 
    2426    assert_equal( 
    2527      [ "hello <%= one %>", { :one => "two" }, @view ], 
     
    2830 
    2931  def test_custom_render2 
    30     result = @view.render_template( "foo2", "hello <%= one %>", nil, :one => "two" ) 
     32    template = ActionView::Template.new(@view, "hello <%= one %>", false, { :one => "two" }, true, "foo2") 
     33    result = @view.render_template(template) 
    3134    assert_equal( 
    3235      [ "hello <%= one %>", { :one => "two" }, @view ], 
     
    3639  def test_unhandled_extension 
    3740    # uses the ERb handler by default if the extension isn't recognized 
    38     result = @view.render_template( "bar", "hello <%= one %>", nil, :one => "two" ) 
     41    template = ActionView::Template.new(@view, "hello <%= one %>", false, { :one => "two" }, true, "bar") 
     42    result = @view.render_template(template) 
    3943    assert_equal "hello two", result 
    4044  end 
  • trunk/actionpack/test/controller/render_test.rb

    r8744 r8805  
    139139    render :inline => "<%= 'Goodbye, ' + local_name %>", 
    140140           :locals => { :local_name => name } 
    141   end 
    142  
    143   def accessing_local_assigns_in_inline_template_with_string_keys 
    144     name = params[:local_name] 
    145     ActionView::Base.local_assigns_support_string_keys = true 
    146     render :inline => "<%= 'Goodbye, ' + local_name %>", 
    147            :locals => { "local_name" => name } 
    148     ActionView::Base.local_assigns_support_string_keys = false 
    149141  end 
    150142 
     
    388380  end 
    389381 
    390   def test_accessing_local_assigns_in_inline_template_with_string_keys 
    391     get :accessing_local_assigns_in_inline_template_with_string_keys, :local_name => "Local David" 
    392     assert_equal "Goodbye, Local David", @response.body 
    393   end 
    394  
    395382  def test_render_200_should_set_etag 
    396383    get :render_hello_world_from_variable 
  • trunk/actionpack/test/template/compiled_templates_test.rb

    r8689 r8805  
    8888      v.cache_template_loading = false 
    8989 
     90      ta = ActionView::Template.new(v, @a, false, {}) 
     91      tb = ActionView::Template.new(v, @b, false, {}) 
     92      ts = ActionView::Template.new(v, @s, false, {}) 
     93 
    9094      @handler_class = ActionView::Base.handler_class_for_extension(:rhtml) 
    9195      @handler       = @handler_class.new(v) 
     
    100104      assert @handler.send(:template_changed_since?, @s, t) unless windows 
    101105 
    102       assert @handler.send(:compile_template?, nil, @a, {}
    103       assert @handler.send(:compile_template?, nil, @b, {}
    104       assert @handler.send(:compile_template?, nil, @s, {}) unless windows 
     106      assert @handler.send(:compile_template?, ta
     107      assert @handler.send(:compile_template?, tb
     108      assert @handler.send(:compile_template?, ts) unless windows 
    105109 
    106110      # All templates are rendered at t+2 
    107111      Time.expects(:now).times(windows ? 2 : 3).returns(t + 2.seconds) 
    108       v.send(:compile_and_render_template, @handler, '', @a) 
    109       v.send(:compile_and_render_template, @handler, '', @b) 
    110       v.send(:compile_and_render_template, @handler, '', @s) unless windows 
     112      v.send(:compile_and_render_template, @handler, ta) 
     113      v.send(:compile_and_render_template, @handler, tb) 
     114      v.send(:compile_and_render_template, @handler, ts) unless windows 
    111115      a_n = v.method_names[@a] 
    112116      b_n = v.method_names[@b] 
     
    123127      assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) 
    124128      assert !@handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows 
    125       assert !@handler.send(:compile_template?, nil, @a, {}
    126       assert !@handler.send(:compile_template?, nil, @b, {}
    127       assert !@handler.send(:compile_template?, nil, @s, {}) unless windows 
    128       v.send(:compile_and_render_template, @handler, '', @a) 
    129       v.send(:compile_and_render_template, @handler, '', @b) 
    130       v.send(:compile_and_render_template, @handler, '', @s)  unless windows 
     129      assert !@handler.send(:compile_template?, ta
     130      assert !@handler.send(:compile_template?, tb
     131      assert !@handler.send(:compile_template?, ts) unless windows 
     132      v.send(:compile_and_render_template, @handler, ta) 
     133      v.send(:compile_and_render_template, @handler, tb) 
     134      v.send(:compile_and_render_template, @handler, ts)  unless windows 
    131135      # none of the files have changed since last compile 
    132136      assert @handler.compile_time[a_n] < t + 3.seconds 
     
    145149      assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) 
    146150      assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows 
    147       assert !@handler.send(:compile_template?, nil, @a, {}
    148       assert !@handler.send(:compile_template?, nil, @b, {}
    149       assert @handler.send(:compile_template?, nil, @s, {}) unless windows 
     151      assert !@handler.send(:compile_template?, ta
     152      assert !@handler.send(:compile_template?, tb
     153      assert @handler.send(:compile_template?, ts) unless windows 
    150154 
    151155      # Only the symlink template gets rendered at t+3 
    152156      Time.stubs(:now).returns(t + 3.seconds) unless windows 
    153       v.send(:compile_and_render_template, @handler, '', @a) 
    154       v.send(:compile_and_render_template, @handler, '', @b) 
    155       v.send(:compile_and_render_template, @handler, '', @s) unless windows 
     157      v.send(:compile_and_render_template, @handler, ta) 
     158      v.send(:compile_and_render_template, @handler, tb) 
     159      v.send(:compile_and_render_template, @handler, ts) unless windows 
    156160      # the symlink has changed since last compile 
    157161      assert @handler.compile_time[a_n] < t + 3.seconds 
     
    171175      assert @handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) 
    172176      assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows 
    173       assert !@handler.send(:compile_template?, nil, @a, {}
    174       assert @handler.send(:compile_template?, nil, @b, {}
    175       assert @handler.send(:compile_template?, nil, @s, {}) unless windows 
     177      assert !@handler.send(:compile_template?, ta
     178      assert @handler.send(:compile_template?, tb
     179      assert @handler.send(:compile_template?, ts) unless windows 
    176180 
    177181      Time.expects(:now).times(windows ? 1 : 2).returns(t + 5.seconds) 
    178       v.send(:compile_and_render_template, @handler, '', @a) 
    179       v.send(:compile_and_render_template, @handler, '', @b) 
    180       v.send(:compile_and_render_template, @handler, '', @s) unless windows 
     182      v.send(:compile_and_render_template, @handler, ta) 
     183      v.send(:compile_and_render_template, @handler, tb) 
     184      v.send(:compile_and_render_template, @handler, ts) unless windows 
    181185      # the file at the end of the symlink has changed since last compile 
    182186      # both the symlink and the file at the end of it should be recompiled