
class Maker {
  constructor() {
    this.ctx = {
      before: [],
      after: [],
      scoped: {},
      local: {},
    }
  }

  build() {
    const scoped = {}
    Object.keys(this.ctx.scoped).forEach(name => {
      scoped[name] = this.ctx.scoped[name].build()
    })
    return Object.assign({}, this.ctx, { scoped })
  }

  before(...list) {
    this.ctx.before = this.ctx.before.concat(list)
  }

  after(...list) {
    this.ctx.after = this.ctx.after.concat(list)
  }

  scope(name, creator) {
    if (name.indexOf('/') !== -1) {
      throw new Error('Name of the scope should be simple string!')
    }

    const scopedCtx = new Maker()
    creator(scopedCtx)
    this.ctx.scoped[name] = scopedCtx
  }

  /**
   * Add HTTP method listeners to local
   * @param {string} method
   * @param {function[]} listeners
   */
  local(method, listeners) {
    // if listeners for that methods exists, simple merge
    if (this.ctx.local[method]) {
      this.ctx.local[method] = this.ctx.local[method].concat(listeners)
    }
    else {
      this.ctx.local[method] = listeners
    }
  }

  /**
   * Handle method creator
   * @param {string} name
   * @param {string} method
   * @param {function[]} listeners
   */
  method(name, method, listeners) {
    if (typeof name !== 'string') {
      throw new Error('Path should be string')
    }
    if (name.indexOf('/') !== 0) {
      throw new Error('Path should start from /')
    }
    if (name.match(/\//g).length > 1) {
      throw new Error('Path should not be deep')
    }
    if (listeners.length === 0) {
      throw new Error('Maybe you forget to add listener?')
    }

    if (name === '/') {
      return this.local(method, listeners)
    }

    const absName = name.replace('/', '')
    let scoped = this.ctx.scoped[absName]
    if (!scoped) {
      scoped = new Maker()
      this.ctx.scoped[absName] = scoped
    }
    scoped.local(method, listeners)
  }

  post(name, ...listeners) {
    this.method(name, 'POST', listeners)
  }
  get(name, ...listeners) {
    this.method(name, 'GET', listeners)
  }
  put(name, ...listeners) {
    this.method(name, 'PUT', listeners)
  }
  delete(name, ...listeners) {
    this.method(name, 'DELETE', listeners)
  }
  patch(name, ...listeners) {
    this.method(name, 'PATCH', listeners)
  }
}

/**
 *
 * @param {function} creator
 */
export function createRest(creator) {
  const ctx = new Maker('')
  creator(ctx)
  return ctx.build()
}

export { flattenRoutes } from './flatten'
export { printRoutes } from './printer'


@@ -1222,22 +1222,16 @@
  method(
-name, 
 method, 
@@ -1251,191 +1251,156 @@
     
-if (typeof name !== 'string') %7B%0A      throw new Error('Path should be string')%0A    %7D%0A    if (name.indexOf('/') !== 0) %7B%0A      throw new Error('Path should start from /')%0A    %7D
+let name = ''%0A    if (typeof listeners%5B0%5D === 'string') %7B%0A      name = listeners.splice(0, 1)%5B0%5D%0A    %7D%0A    name = name.replace(/%5E%5C//gm, '')%0A
 %0A    if 
 (nam
@@ -1391,24 +1391,25 @@
 '')%0A%0A    if 
+(
 (name.match(
@@ -1414,16 +1414,23 @@
 h(/%5C//g)
+ %7C%7C %5B%5D)
 .length 
@@ -1608,111 +1608,20 @@
 ame 
-=
+!
 == '
-/
 ') %7B%0A  
-    return this.local(method, listeners)%0A    %7D%0A%0A    const absName = name.replace('/', '')%0A
     
@@ -1653,17 +1653,16 @@
 ped%5B
-absN
+n
 ame%5D%0A
+  
     
@@ -1672,24 +1672,26 @@
 (!scoped) %7B%0A
+  
       scoped
@@ -1707,24 +1707,26 @@
 ker()%0A      
+  
 this.ctx.sco
@@ -1733,12 +1733,9 @@
 ped%5B
-absN
+n
 ame%5D
@@ -1744,26 +1744,31 @@
  scoped%0A    
-%7D%0A
+  %7D%0A%0A  
     scoped.l
@@ -1795,26 +1795,61 @@
 rs)%0A
+  
   %7D%0A%0A  
-post(name, 
+  this.local(method, listeners)%0A  %7D%0A%0A  post(
 ...l
@@ -1876,22 +1876,16 @@
 .method(
-name, 
 'POST', 
@@ -1905,22 +1905,16 @@
 %7D%0A  get(
-name, 
 ...liste
@@ -1937,22 +1937,16 @@
 .method(
-name, 
 'GET', l
@@ -1965,22 +1965,16 @@
 %7D%0A  put(
-name, 
 ...liste
@@ -1997,22 +1997,16 @@
 .method(
-name, 
 'PUT', l
@@ -2028,22 +2028,16 @@
  delete(
-name, 
 ...liste
@@ -2060,22 +2060,16 @@
 .method(
-name, 
 'DELETE'
@@ -2093,22 +2093,16 @@
   patch(
-name, 
 ...liste
@@ -2125,22 +2125,16 @@
 .method(
-name, 
 'PATCH',

Refactor methods, name for methods no required