module ActionView # CompiledTemplates modules hold methods that have been compiled. # Templates are compiled into these methods so that they do not need to be # read and parsed for each request. # # Each template may be compiled into one or more methods. Each method accepts a given # set of parameters which is used to implement local assigns passing. # # To use a compiled template module, create a new instance and include it into the class # in which you want the template to be rendered. class CompiledTemplates < Module attr_reader :method_names def initialize @method_names = Hash.new do |hash, key| hash[key] = "__compiled_method_#{(hash.length + 1)}" end @mtimes = {} end # Return the full key for the given identifier and argument names def full_key(identifier, arg_names) [identifier, arg_names] end # Return the selector for this method or nil if it has not been compiled def selector(identifier, arg_names) key = full_key(identifier, arg_names) method_names.key?(key) ? method_names[key] : nil end alias :compiled? :selector # Return the time at which the method for the given identifier and argument names was compiled. def mtime(identifier, arg_names) @mtimes[full_key(identifier, arg_names)] end # Compile the provided source code for the given argument names and with the given initial line number. # The identifier should be unique to this source. # # The file_name, if provided will appear in backtraces. If not provded, the file_name defaults # to the identifier. # # This method will return the selector for the compiled version of this method. def compile_source(identifier, arg_names, source, initial_line_number = 0, file_name = nil) file_name ||= identifier name = method_names[full_key(identifier, arg_names)] arg_desc = arg_names.empty? ? '' : "(#{arg_names * ', '})" fake_file_name = "#{file_name}#{arg_desc}" # Include the arguments for this version (for now) method_def = wrap_source(name, arg_names, source) begin module_eval(method_def, fake_file_name, initial_line_number) @mtimes[full_key(identifier, arg_names)] = Time.now rescue Exception => e # errors from compiled source e.blame_file! identifier raise end name end # Wrap the provided source in a def ... end block. def wrap_source(name, arg_names, source) "def #{name}(#{arg_names * ', '})\n#{source}\nend" end end end