Mixins leves em CoffeeScript

A classe Mixin:

class Mixin
@attachTo: (klass) ->
klass
::[k] = v for k,v of this.prototype when k isnt 'constructor'
@included? klass

Editar : a versão original não testou a chave de propriedade, o que resultou no construtor original não sendo mais acessível.

Um mixin simples:

class Suspendable extends Mixin

start
: ->
# lazy context binding of handleFrameRequest
unless @handleFrameRequest.bound
f
= @handleFrameRequest
@handleFrameRequest = => f.apply this, argument
@handleFrameRequest.bound = true

# animation start
unless @animated
@lastTime = new Date()
requestAnimationFrame
@handleFrameRequest
@animated = true

stop
: -> @animated = false if @animated

handleFrameRequest
: ->
if @animated
currentTime
= new Date()
delta
= currentTime - @lastTime
@animate delta
requestAnimationFrame
@handleFrameRequest
@lastTime = currentTime

animate
: -> # override to create your animations

Mixins parametrizados:

Equatable = (properties...) ->
class extends Mixin
equals
: (o) -> o? and properties.every (p) =>
if @[p].equals? then @[p].equals o[p] else o[p] is @[p]

Formattable = (classname, properties...) ->
class extends Mixin
toString
: ->
if properties.length is 0
"[#{classname}]"
else
formattedProperties
= ("#{p}=#{@[p]}" for p in properties)
"[#{classname}(#{formattedProperties.join ', '})]"

classname
: -> classname

Decorar uma aula:

class Dummy
Suspendable.attachTo Dummy
Equatable('position', 'speed').attachTo Dummy
Formattable('Dummy','position', 'speed').attachTo Dummy

constructor: (@position, @speed) ->

animate
: (delta) ->
@position = @position.add(@speed.scale(delta / 1000))
# ...

Ótima maneira de embrulhar muitas inclusões de mixin:

class Rectangle
PROPERTIES
= ['x','y','width','height','rotation']

[
Equatable.apply(null, PROPERTIES)
Formattable.apply(null, ['Rectangle'].concat PROPERTIES)
Sourcable.apply(null, ['geomjs.Rectangle'].concat PROPERTIES)
Parameterizable('rectangleFrom', {
x
: NaN
y
: NaN
width
: NaN
height
: NaN
rotation
: NaN
})
Cloneable, Geometry, Surface
Path, Triangulable, Intersections
].forEach (mixin) -> mixin.attachTo Rectangle

#....

Edit : Para responder à sugestão de @sheerun , alguma outra maneira de embrulhar inclusões de mixins:

Por meio de uma classe de módulo base:

class Module 
@include: (mixins...) ->
if Object::toString.call(mixins[0]).indexOf('Array') >= 0
mixins
= mixins[0]

mixins
.forEach (mixin) -> mixin.attachTo this

class Dummy extends Module
@include Suspendable,
Equatable('position', 'speed'),
Formattable('Dummy','position', 'speed')

Ou se você não puder ou não quiser usar herança:

 include = (mixins...) ->
if Object::toString.call(mixins[0]).indexOf('Array') >= 0
mixins
= mixins[0]

in: (klass) -> mixins.forEach (mixin) -> mixin.attachTo klass

class Dummy extends Module
include
(
Suspendable,
Equatable('position', 'speed'),
Formattable('Dummy','position', 'speed')
).in Dummy