Skip to content

Commit

Permalink
Messy but specs passing
Browse files Browse the repository at this point in the history
  • Loading branch information
winton committed May 24, 2015
1 parent 7fc4798 commit d144034
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 26 deletions.
66 changes: 52 additions & 14 deletions lib/mixin.coffee
Original file line number Diff line number Diff line change
@@ -1,20 +1,58 @@
module.exports = ->
Function::extend = (from) ->
merge @, from

merge = (to, from) ->
for key, value of from
unless to[key] || key == "__super__"
to[key] = value
Function::include = (from) ->
merge @::, from::

merge = (to, from) ->
for key, value of from
unless to[key] || key == "__super__"
to[key] = value

to

module.exports = (klasses..., options={}) ->
klasses.push(options) unless typeof options == "object"
klasses.reduce (to, from, index, array) ->

to
from.__super__ ||= to::
real_to = array[index-1]::

class
@include from
@extend from

@include to
@extend to

constructor: ->
makeArray = (a) ->
if !a || a instanceof Array then a else [ a ]

wrapFunctions = =>
for name, fn of @
stop = name == "constructor"
stop ||= typeof @[name] != "function"

unless stop
do (name, fn) =>
@[name] = =>
if options.prepend && real_to[name]
args = real_to[name].apply @, arguments

args = fn.apply @, makeArray(args) || arguments

if options.append && real_to[name]
args = real_to[name].apply @, makeArray(args) || arguments

args

Function::extend = extend = (to, from) ->
merge(@, from)
wrapFunctions()

Function::include = include = (to, from) ->
merge(@::, from::)
if options.prepend
args = from.__super__.constructor.apply @, arguments

Function::mixin = mixin = (from, options={}) ->
include @, from
extend @, from
args = from.apply @, args || arguments

@.__super__ ||= from::
if options.append
from.__super__.constructor.apply @, args
66 changes: 54 additions & 12 deletions spec/lib/mixin_spec.coffee
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
require("../../lib/mixin")()
mix = require("../../lib/mixin")

describe "Module", ->

describe "three-level deep class inheritance with super", ->

beforeAll ->

Mixin1 = class
class Mixin1
constructors: []

constructor: ->
@constructors.push("Mixin1")

test: (p) -> "hello #{p}"
constructor: -> @constructors.push("Mixin1")
test: (p) -> "hello #{p}"

Mixin2 = class
@mixin Mixin1
class Mixin2

constructor: ->
super
Expand All @@ -24,17 +21,18 @@ describe "Module", ->
test2: (p) -> "hello #{p}"
test3: -> "hello world 3"

@Mixin3 = class
@mixin Mixin2
class Mixin3

constructor: ->
super
@constructors.push("Mixin3")

test: -> super("world")
test: ->
super("world")
test2: -> super("world 2")

@test = new @Mixin3()
Test = mix Mixin1, Mixin2, Mixin3
@test = new Test()

it "calls contructors", ->
expect(@test.constructors).toEqual [ "Mixin1", "Mixin2", "Mixin3" ]
Expand All @@ -47,3 +45,47 @@ describe "Module", ->

it "returns correct value without super", ->
expect(@test.test3()).toBe "hello world 3"

describe "three-level deep class inheritance with appended super", ->

beforeAll ->

class Mixin1
constructors: []

constructor: ->
@constructors.push("Mixin1")

test: (p) ->
"hello #{p}"

class Mixin2

constructor: ->
@constructors.push("Mixin2")

test2: (p) -> "hello #{p}"
test3: -> "hello world 3"

class Mixin3

constructor: ->
@constructors.push("Mixin3")

test: -> "world"
test2: -> "world 2"

Test = mix Mixin1, Mixin2, Mixin3, append: true
@test = new Test()

it "calls contructors", ->
expect(@test.constructors).toEqual [ "Mixin3", "Mixin2", "Mixin1" ]

it "calls super on first mixin", ->
expect(@test.test()).toBe "hello world"

it "calls super on second mixin", ->
expect(@test.test2()).toBe "hello world 2"

it "returns correct value without super", ->
expect(@test.test3()).toBe "hello world 3"

0 comments on commit d144034

Please sign in to comment.