Merge pull request #77 from koajs/refactor/accept-methods

replace content-negotiation accessors with 0-arity method calls
This commit is contained in:
TJ Holowaychuk 2013-11-08 15:26:42 -08:00
commit 5bbe362294
3 changed files with 175 additions and 84 deletions

View file

@ -485,21 +485,74 @@ switch (this.accepts('json', 'html', 'text')) {
} }
``` ```
### ctx.accepted ### ctx.acceptsEncodings(encodings)
Return accepted mime types ordered by quality. Check if `encodings` are acceptable, returning
the best match when true, otherwise `undefined`.
### ctx.acceptedEncodings ```js
// Accept-Encoding: gzip
this.acceptsEncodings('gzip', 'deflate');
// => "gzip"
Return accepted content encodings ordered by quality. this.acceptsEncodings(['gzip', 'deflate']);
// => "gzip"
```
### ctx.acceptedCharsets When no arguments are given all accepted encodings
are returned as an array:
Return accepted charsets ordered by quality. ```js
// Accept-Encoding: gzip, deflate
this.acceptsEncodings();
// => ["gzip", "deflate"]
```
### ctx.acceptedLanguages ### ctx.acceptsCharsets(charsets)
Return accepted languages ordered by quality. Check if `charsets` are acceptable, returning
the best match when true, otherwise `undefined`.
```js
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
this.acceptsCharsets('utf-8', 'utf-7');
// => "utf-8"
this.acceptsCharsets(['utf-7', 'utf-8']);
// => "utf-8"
```
When no arguments are given all accepted charsets
are returned as an array:
```js
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
this.acceptsCharsets();
// => ["utf-8", "utf-7", "iso-8859-1"]
```
### ctx.acceptsLanguages(langs)
Check if `langs` are acceptable, returning
the best match when true, otherwise `undefined`.
```js
// Accept-Language: en;q=0.8, es, pt
this.acceptsLanguages('es', 'en');
// => "es"
this.acceptsLanguages(['en', 'es']);
// => "es"
```
When no arguments are given all accepted languages
are returned as an array:
```js
// Accept-Language: en;q=0.8, es, pt
this.acceptsLanguages();
// => ["es", "pt", "en"]
```
### ctx.headerSent ### ctx.headerSent

View file

@ -542,87 +542,79 @@ Context.prototype = {
* // => "json" * // => "json"
* *
* @param {String|Array} type(s)... * @param {String|Array} type(s)...
* @return {String} * @return {String|Array|Boolean}
* @api public * @api public
*/ */
accepts: function(types){ accepts: function(types){
// TODO: memoize
if (!Array.isArray(types)) types = [].slice.call(arguments); if (!Array.isArray(types)) types = [].slice.call(arguments);
var normalized = types.map(extToMime);
var n = new Negotiator(this.req); var n = new Negotiator(this.req);
var accepts = n.preferredMediaTypes(normalized); if (!types.length) return n.preferredMediaTypes();
var mimes = types.map(extToMime);
var accepts = n.preferredMediaTypes(mimes);
var first = accepts[0]; var first = accepts[0];
if (!first) return false; if (!first) return false;
return types[normalized.indexOf(first)]; return types[mimes.indexOf(first)];
}, },
/** /**
* Return accepted encodings. * Return accepted encodings or best fit based on `encodings`.
* *
* Given `Accept-Encoding: gzip, deflate` * Given `Accept-Encoding: gzip, deflate`
* an array sorted by quality is returned: * an array sorted by quality is returned:
* *
* ['gzip', 'deflate'] * ['gzip', 'deflate']
* *
* @return {Array} * @param {String|Array} encoding(s)...
* @return {String|Array}
* @api public * @api public
*/ */
get acceptedEncodings() { acceptsEncodings: function(encodings) {
if (!Array.isArray(encodings)) encodings = [].slice.call(arguments);
var n = new Negotiator(this.req); var n = new Negotiator(this.req);
return n.preferredEncodings(); if (!encodings.length) return n.preferredEncodings();
return n.preferredEncodings(encodings)[0];
}, },
/** /**
* Return accepted charsets. * Return accepted charsets or best fit based on `charsets`.
* *
* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
* an array sorted by quality is returned: * an array sorted by quality is returned:
* *
* ['utf-8', 'utf-7', 'iso-8859-1'] * ['utf-8', 'utf-7', 'iso-8859-1']
* *
* @return {Array} * @param {String|Array} charset(s)...
* @return {String|Array}
* @api public * @api public
*/ */
get acceptedCharsets() { acceptsCharsets: function(charsets) {
if (!Array.isArray(charsets)) charsets = [].slice.call(arguments);
var n = new Negotiator(this.req); var n = new Negotiator(this.req);
return n.preferredCharsets(); if (!charsets.length) return n.preferredCharsets();
return n.preferredCharsets(charsets)[0];
}, },
/** /**
* Return accepted languages. * Return accepted languages or best fit based on `langs`.
* *
* Given `Accept-Language: en;q=0.8, es, pt` * Given `Accept-Language: en;q=0.8, es, pt`
* an array sorted by quality is returned: * an array sorted by quality is returned:
* *
* ['es', 'pt', 'en'] * ['es', 'pt', 'en']
* *
* @return {Array} * @param {String|Array} lang(s)...
* @return {Array|String}
* @api public * @api public
*/ */
get acceptedLanguages() { acceptsLanguages: function(langs) {
if (!Array.isArray(langs)) langs = [].slice.call(arguments);
var n = new Negotiator(this.req); var n = new Negotiator(this.req);
return n.preferredLanguages(); if (!langs.length) return n.preferredLanguages();
}, return n.preferredLanguages(langs)[0];
/**
* Return accepted media types.
*
* Given `Accept: application/*;q=0.2, image/jpeg;q=0.8, text/html`
* an array sorted by quality is returned:
*
* ['text/html', 'image/jpeg', 'application/*']
*
* @return {Array}
* @api public
*/
get accepted() {
var n = new Negotiator(this.req);
return n.preferredMediaTypes();
}, },
/** /**

View file

@ -389,23 +389,6 @@ describe('ctx.fresh', function(){
}) })
}) })
describe('ctx.accepted', function(){
describe('when Accept is populated', function(){
it('should return accepted types', function(){
var ctx = context();
ctx.req.headers.accept = 'application/*;q=0.2, image/jpeg;q=0.8, text/html, text/plain';
ctx.accepted.should.eql(['text/html', 'text/plain', 'image/jpeg', 'application/*']);
})
})
describe('when Accept is not populated', function(){
it('should return an empty array', function(){
var ctx = context();
ctx.accepted.should.eql([]);
})
})
})
describe('ctx.vary(field)', function(){ describe('ctx.vary(field)', function(){
describe('when Vary is not set', function(){ describe('when Vary is not set', function(){
it('should set it', function(){ it('should set it', function(){
@ -437,10 +420,18 @@ describe('ctx.vary(field)', function(){
}) })
describe('ctx.accepts(types)', function(){ describe('ctx.accepts(types)', function(){
describe('with no types', function(){ describe('with no arguments', function(){
it('should return all accepted types', function(){
var ctx = context();
ctx.req.headers.accept = 'application/*;q=0.2, image/jpeg;q=0.8, text/html, text/plain';
ctx.accepts().should.eql(['text/html', 'text/plain', 'image/jpeg', 'application/*']);
})
})
describe('with no valid types', function(){
it('should return false', function(){ it('should return false', function(){
var ctx = context(); var ctx = context();
ctx.accepts('').should.be.false; ctx.accepts('', 'hey').should.be.false;
}) })
}) })
@ -504,53 +495,108 @@ describe('ctx.accepts(types)', function(){
}) })
}) })
describe('ctx.acceptedLanguages', function(){ describe('ctx.acceptsLanguages(langs)', function(){
describe('when Accept-Language is populated', function(){ describe('with no arguments', function(){
it('should return accepted types', function(){ describe('when Accept-Language is populated', function(){
it('should return accepted types', function(){
var ctx = context();
ctx.req.headers['accept-language'] = 'en;q=0.8, es, pt';
ctx.acceptsLanguages().should.eql(['es', 'pt', 'en']);
})
})
describe('when Accept-Language is not populated', function(){
it('should return an empty array', function(){
var ctx = context();
ctx.acceptsLanguages().should.eql([]);
})
})
})
describe('with multiple arguments', function(){
it('should return the best fit', function(){
var ctx = context(); var ctx = context();
ctx.req.headers['accept-language'] = 'en;q=0.8, es, pt'; ctx.req.headers['accept-language'] = 'en;q=0.8, es, pt';
ctx.acceptedLanguages.should.eql(['es', 'pt', 'en']); ctx.acceptsLanguages('es', 'en').should.equal('es');
}) })
}) })
describe('when Accept-Language is not populated', function(){ describe('with an array', function(){
it('should return an empty array', function(){ it('should return the best fit', function(){
var ctx = context(); var ctx = context();
ctx.acceptedLanguages.should.eql([]); ctx.req.headers['accept-language'] = 'en;q=0.8, es, pt';
ctx.acceptsLanguages(['es', 'en']).should.equal('es');
}) })
}) })
}) })
describe('ctx.acceptedCharsets', function(){ describe('ctx.acceptsCharsts()', function(){
describe('when Accept-Charset is populated', function(){ describe('with no arguments', function(){
it('should return accepted types', function(){ describe('when Accept-Charset is populated', function(){
it('should return accepted types', function(){
var ctx = context();
ctx.req.headers['accept-charset'] = 'utf-8, iso-8859-1;q=0.2, utf-7;q=0.5';
ctx.acceptsCharsets().should.eql(['utf-8', 'utf-7', 'iso-8859-1']);
})
})
describe('when Accept-Charset is not populated', function(){
it('should return an empty array', function(){
var ctx = context();
ctx.acceptsCharsets().should.eql([]);
})
})
})
describe('with multiple arguments', function(){
it('should return the best fit', function(){
var ctx = context(); var ctx = context();
ctx.req.headers['accept-charset'] = 'utf-8, iso-8859-1;q=0.2, utf-7;q=0.5'; ctx.req.headers['accept-charset'] = 'utf-8, iso-8859-1;q=0.2, utf-7;q=0.5';
ctx.acceptedCharsets.should.eql(['utf-8', 'utf-7', 'iso-8859-1']); ctx.acceptsCharsets('utf-7', 'utf-8').should.equal('utf-8');
}) })
}) })
describe('when Accept-Charset is not populated', function(){ describe('with an array', function(){
it('should return an empty array', function(){ it('should return the best fit', function(){
var ctx = context(); var ctx = context();
ctx.acceptedCharsets.should.eql([]); ctx.req.headers['accept-charset'] = 'utf-8, iso-8859-1;q=0.2, utf-7;q=0.5';
ctx.acceptsCharsets(['utf-7', 'utf-8']).should.equal('utf-8');
}) })
}) })
}) })
describe('ctx.acceptedEncodings', function(){ describe('ctx.acceptsEncodings()', function(){
describe('when Accept-Encoding is populated', function(){ describe('with no arguments', function(){
it('should return accepted types', function(){ describe('when Accept-Encoding is populated', function(){
var ctx = context(); it('should return accepted types', function(){
ctx.req.headers['accept-encoding'] = 'gzip, compress;q=0.2'; var ctx = context();
ctx.acceptedEncodings.should.eql(['gzip', 'compress', 'identity']); ctx.req.headers['accept-encoding'] = 'gzip, compress;q=0.2';
ctx.acceptsEncodings().should.eql(['gzip', 'compress', 'identity']);
})
})
describe('when Accept-Encoding is not populated', function(){
it('should return identity', function(){
var ctx = context();
ctx.acceptsEncodings().should.eql(['identity']);
})
}) })
}) })
describe('when Accept-Encoding is not populated', function(){ describe('with multiple arguments', function(){
it('should return identity', function(){ it('should return the best fit', function(){
var ctx = context(); var ctx = context();
ctx.acceptedEncodings.should.eql(['identity']); ctx.req.headers['accept-encoding'] = 'gzip, compress;q=0.2';
ctx.acceptsEncodings('compress', 'gzip').should.eql('gzip');
ctx.acceptsEncodings('gzip', 'compress').should.eql('gzip');
})
})
describe('with an array', function(){
it('should return the best fit', function(){
var ctx = context();
ctx.req.headers['accept-encoding'] = 'gzip, compress;q=0.2';
ctx.acceptsEncodings(['compress', 'gzip']).should.eql('gzip');
}) })
}) })
}) })