4 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
12 var path = require('path')
13 , extname = path.extname
14 , dirname = path.dirname
15 , basename = path.basename
23 exports = module.exports = View;
32 * Initialize a new `View` with the given `view` path and `options`.
34 * @param {String} view
35 * @param {Object} options
39 function View(view, options) {
40 options = options || {};
42 this.root = options.root;
43 this.relative = false !== options.relative;
44 this.defaultEngine = options.defaultEngine;
45 this.parent = options.parentView;
46 this.basename = basename(view);
47 this.engine = this.resolveEngine();
48 this.extension = '.' + this.engine;
49 this.name = this.basename.replace(this.extension, '');
50 this.path = this.resolvePath();
51 this.dirname = dirname(this.path);
52 if (options.attempts) options.attempts.push(this.path);
56 * Check if the view path exists.
62 View.prototype.__defineGetter__('exists', function(){
72 * Resolve view engine.
78 View.prototype.resolveEngine = function(){
80 if (~this.basename.indexOf('.')) return extname(this.basename).substr(1);
81 // Inherit from parent
82 if (this.parent) return this.parent.engine;
84 return this.defaultEngine;
94 View.prototype.resolvePath = function(){
97 if (!~this.basename.indexOf('.')) path += this.extension;
99 if ('/' == path[0]) return path;
100 // Relative to parent
101 if (this.relative && this.parent) return this.parent.dirname + '/' + path;
104 ? this.root + '/' + path
109 * Get view contents. This is a one-time hit, so we
110 * can afford to be sync.
116 View.prototype.__defineGetter__('contents', function(){
117 return fs.readFileSync(this.path, 'utf8');
121 * Get template engine api, cache exports to reduce
128 View.prototype.__defineGetter__('templateEngine', function(){
129 var ext = this.extension;
130 return cache[ext] || (cache[ext] = require(this.engine));
134 * Return root path alternative.
140 View.prototype.__defineGetter__('rootPath', function(){
141 this.relative = false;
142 return this.resolvePath();
146 * Return index path alternative.
152 View.prototype.__defineGetter__('indexPath', function(){
154 + '/' + this.basename.replace(this.extension, '')
155 + '/index' + this.extension;
159 * Return ../<name>/index path alternative.
165 View.prototype.__defineGetter__('upIndexPath', function(){
166 return this.dirname + '/../' + this.name + '/index' + this.extension;
170 * Return _ prefix path alternative
176 View.prototype.__defineGetter__('prefixPath', function(){
177 return this.dirname + '/_' + this.basename;
181 * Register the given template engine `exports`
182 * as `ext`. For example we may wish to map ".html"
185 * app.register('.html', require('jade'));
189 * app.register('html', require('jade'));
191 * This is also useful for libraries that may not
192 * match extensions correctly. For example my haml.js
193 * library is installed from npm as "hamljs" so instead
194 * of layout.hamljs, we can register the engine as ".haml":
196 * app.register('.haml', require('haml-js'));
198 * @param {String} ext
199 * @param {Object} obj
203 exports.register = function(ext, exports) {
204 if ('.' != ext[0]) ext = '.' + ext;
205 cache[ext] = exports;