#!/usr/bin/env ruby #-- # Copyright (c) 2006 Jeff Barczewski # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ # # Setup hook to intercept template_exist? calls and read_template_file # so that rails can find masterview templates. MasterView cannot use the # provided hooks because rails always assumes everything is file based # and that there will be a file for each thing to render. If the # template dispatching code is enriched in the future we may be able # to rewrite this code to use the provided hooks # # MasterView::Log.info { 'Adding hooks to enable Rails to read erb directly from MasterView' } module ActionView #:nodoc: class Base #:nodoc: # checks for template existence, uses standard rails file based check first and if not found # check MasterView paths because might not exist on file system alias :template_exists_pre_mv? :template_exists? #:nodoc: def template_exists?(template_path, extension) #:nodoc: short_path = template_path+'.'+extension.to_s template_exists_pre_mv?(template_path, extension) || MasterView::IOMgr.erb.path(short_path).exist? end # checks for the existence of the template in MasterView first before using the # rails file system based read_template_file alias :read_template_file_pre_mv :read_template_file #:nodoc: def read_template_file(template_path, extension) #:nodoc: short_path_mio = MasterView::IOMgr.erb.path(short_relative_path_mv(template_path)) if short_path_mio.exist? short_path_mio.read else # use original rails read_template_file read_template_file_pre_mv(template_path, extension) end end # Check whether compilation is necessary. # Since rails compile_templat? is file based there was no easy way to hook into # this, so much of this method had to be duplicated. # If file_name exists in MasterView then check mtime from it otherwise defer to # original code. alias :compile_template_pre_mv? :compile_template? #:nodoc: def compile_template?(template, file_name, local_assigns) #:nodoc: short_path_mio = (file_name && !file_name.empty?) ? MasterView::IOMgr.erb.path(short_relative_path_mv(file_name)) : nil if short_path_mio && short_path_mio.exist? # mio template method_key = file_name || template render_symbol = @@method_names[method_key] if @@compile_time[render_symbol] && supports_local_assigns?(render_symbol, local_assigns) if file_name && !@@cache_template_loading need_to_compile = (@@compile_time[render_symbol] < short_path_mio.mtime) # use mio.mtime instead of File.mtime MasterView::Log.debug{ 'compile_template? template_short_path = '+short_path_mio.pathname.to_s+' compile?='+need_to_compile.to_s } need_to_compile end else true end else # use original file based mtime checking compile_template_pre_mv?(template, file_name, local_assigns) end end private # returns the short path relative to view_base since MasterView uses relative paths exclusively def short_relative_path_mv(template_path) #:nodoc: (template_path.starts_with?(self.base_path)) ? template_path[self.base_path.length+1..-1] : template_path end end # The TemplateError exception is raised when the compilation of the template fails. This exception then gathers a # bunch of intimate details and uses it to report a very precise exception message. # Extend source_extract to be able to pull from MasterView if exists and fallback to file system class TemplateError < ActionViewError #:nodoc: def source_extract(indention = 0) #:nodoc: #added/modified the following three lines to support reading from MasterView with fallback to file system relative_path = (@file_name.starts_with?(@base_path)) ? @file_name[@base_path.length+1..-1] : @file_name short_path_mio = (relative_path && !relative_path.empty?) ? MasterView::IOMgr.erb.path(relative_path) : nil source_code = (short_path_mio && short_path_mio.exist?) ? StringIO.new(short_path_mio.read).readlines : IO.readlines(@file_name) start_on_line = [ line_number - SOURCE_CODE_RADIUS - 1, 0 ].max end_on_line = [ line_number + SOURCE_CODE_RADIUS - 1, source_code.length].min line_counter = start_on_line extract = source_code[start_on_line..end_on_line].collect do |line| line_counter += 1 "#{' ' * indention}#{line_counter}: " + line end extract.join end end end module ActionController #:nodoc: module Layout #:nodoc: module ClassMethods # get list of layout template paths, original rails implementation assumes everything is file based # so this method is enhanced to pull layouts out of MasterView and concatenate them to the list # from rails alias :layout_list_pre_mv :layout_list def layout_list mv_layouts = [] MasterView::IOMgr.erb.find do |mio| mv_layouts << "#{template_root}/"+mio.pathname.to_s if mio.pathname.to_s.starts_with?('layouts/') end layout_list_pre_mv.concat( mv_layouts ) end end end end MasterView::LoadedFeatures[:rails_erb_mv_direct] = true