5 var debug = require('debug')('express:view');
6 var path = require('path');
7 var fs = require('fs');
8 var utils = require('./utils');
15 var dirname = path.dirname;
16 var basename = path.basename;
17 var extname = path.extname;
19 var resolve = path.resolve;
25 module.exports = View;
28 * Initialize a new `View` with the given `name`.
32 * - `defaultEngine` the default template engine name
33 * - `engines` template engine require() cache
34 * - `root` root path for view lookup
36 * @param {String} name
37 * @param {Object} options
41 function View(name, options) {
42 options = options || {};
44 this.root = options.root;
45 var engines = options.engines;
46 this.defaultEngine = options.defaultEngine;
47 var ext = this.ext = extname(name);
48 if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
49 if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
50 this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
51 this.path = this.lookup(name);
55 * Lookup view by the given `name`
57 * @param {String} name
62 View.prototype.lookup = function lookup(name) {
64 var roots = [].concat(this.root);
66 debug('lookup "%s"', name);
68 for (var i = 0; i < roots.length && !path; i++) {
72 var loc = resolve(root, name);
73 var dir = dirname(loc);
74 var file = basename(loc);
77 path = this.resolve(dir, file);
84 * Render with the given `options` and callback `fn(err, str)`.
86 * @param {Object} options
87 * @param {Function} fn
91 View.prototype.render = function render(options, fn) {
92 debug('render "%s"', this.path);
93 this.engine(this.path, options, fn);
97 * Resolve the file within the given directory.
100 * @param {string} file
104 View.prototype.resolve = function resolve(dir, file) {
110 path = join(dir, file);
111 stat = tryStat(path);
113 if (stat && stat.isFile()) {
117 // <path>/index.<ext>
118 path = join(dir, basename(file, ext), 'index' + ext);
119 stat = tryStat(path);
121 if (stat && stat.isFile()) {
127 * Return a stat, maybe.
129 * @param {string} path
134 function tryStat(path) {
135 debug('stat "%s"', path);
138 return fs.statSync(path);