'use strict'
var assert = require('assert')

class Given {
  constructor (args, matcher) {
    this.args = args
    this.matcher = matcher
  }

  match (subject) {
    this.matcher.match(() => subject.apply(null, this.args))
  }

  toString () {
    return `given ${this.args} ${this.matcher}`
  }
}

class Returns {
  constructor (result) {
    this.result = result
  }

  match (subject) {
    assert.deepStrictEqual(subject(), this.result)
  }

  toString () {
    return `returns ${this.result}`
  }
}

class Throws {
  constructor (exception) {
    this.exception = exception
  }

  match (subject) {
    assert.throws(subject, this.exception)
  }

  toString () {
    return `throws ${this.exception}`
  }
}

module.exports = {
  setup (target) {
    Object.assign(target || global,
                  this.matchers,
                  { test: this.test })
  },

  test (name, subject) {
    return () => {
      console.log(name)
      var matchers = Array.from(arguments).slice(2)
      matchers.forEach(matcher => {
        console.log(`  ${matcher}`)
        matcher.match(subject)
      })
    }
  },

  matchers: {
    given (args, matcher) {
      return new Given(args, matcher)
    },

    returns (result) {
      return new Returns(result)
    },

    throws (exception) {
      return new Throws(exception)
    }
  }
}

@@ -742,24 +742,271 @@
  (target) %7B%0A
+    var matchers = Object.keys(this.matchers).reduce((memo, key) =%3E %7B%0A      var MatcherClass = this.matchers%5Bkey%5D%0A      return Object.assign(%7B%7D, memo, %7B%0A        %5Bkey.toLowerCase()%5D: (arg1, arg2) =%3E new MatcherClass(arg1, arg2)%0A      %7D)%0A    %7D, %7B%7D)%0A
     Object.a
@@ -1043,29 +1043,24 @@
             
-this.
 matchers,%0A  
@@ -1363,214 +1363,31 @@
 s: %7B
-%0A    given (args, matcher) %7B%0A      return new Given(args, matcher)%0A    %7D,%0A%0A    returns (result) %7B%0A      return new Returns(result)%0A    %7D,%0A%0A    throws (exception) %7B%0A      return new Throws(exception)%0A    %7D%0A 
+ Given, Returns, Throws
  %7D%0A%7D

Make matcher setup DRY