allowedMethods(options = {}) {
    const implemented = this.methods;

    return (ctx, next) => {
      return next().then(() => {
        const allowed = {};

        if (ctx.matched && (!ctx.status || ctx.status === 404)) {
          for (let i = 0; i < ctx.matched.length; i++) {
            const route = ctx.matched[i];
            for (let j = 0; j < route.methods.length; j++) {
              const method = route.methods[j];
              allowed[method] = method;
            }
          }

          const allowedArr = Object.keys(allowed);
          if (!implemented.includes(ctx.method)) {
            if (options.throw) {
              const notImplementedThrowable =
                typeof options.notImplemented === 'function'
                  ? options.notImplemented() // set whatever the user returns from their function
                  : new HttpError.NotImplemented();

              throw notImplementedThrowable;
            } else {
              ctx.status = 501;
              ctx.set('Allow', allowedArr.join(', '));
            }
          } else if (allowedArr.length > 0) {
            if (ctx.method === 'OPTIONS') {
              ctx.status = 200;
              ctx.body = '';
              ctx.set('Allow', allowedArr.join(', '));
            } else if (!allowed[ctx.method]) {
              if (options.throw) {
                const notAllowedThrowable =
                  typeof options.methodNotAllowed === 'function'
                    ? options.methodNotAllowed() // set whatever the user returns from their function
                    : new HttpError.MethodNotAllowed();

                throw notAllowedThrowable;
              } else {
                ctx.status = 405;
                ctx.set('Allow', allowedArr.join(', '));
              }
            }
          }
        }
      });
    };
  }
Returns separate middleware for responding to `OPTIONS` requests with
an `Allow` header containing the allowed methods, as well as responding
with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.

@example

```javascript
const Koa = require('koa');
const Router = require('@koa/router');

const app = new Koa();
const router = new Router();

app.use(router.routes());
app.use(router.allowedMethods());
```

**Example with [Boom](https://github.com/hapijs/boom)**

```javascript
const Koa = require('koa');
const Router = require('@koa/router');
const Boom = require('boom');

const app = new Koa();
const router = new Router();

app.use(router.routes());
app.use(router.allowedMethods({
  throw: true,
  notImplemented: () => new Boom.notImplemented(),
  methodNotAllowed: () => new Boom.methodNotAllowed()
}));
```

@param {Object=} options
@param {Boolean=} options.throw throw error instead of setting status and header
@param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
@param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
@returns {Function}