Skip to content

Instantly share code, notes, and snippets.

@emorikawa
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emorikawa/9275c0de23176ae5031a to your computer and use it in GitHub Desktop.
Save emorikawa/9275c0de23176ae5031a to your computer and use it in GitHub Desktop.
Advanced Coffeescript Mixins
window.include = (obj) ->
console.log @
@::[key] = value for key, value of obj; @
Module = {}
Module.Foo = (_super) ->
overwriteMethod: -> "Foo"
extendMethod: -> "Foo"
fooMethod: -> @
boundFooMethod: => @
class Baz
class Bar extends Baz
include: (module, _super) ->
for key, value of module.call(@, _super)
@[key] = value unless @[key]?
return @
constructor: ->
@include Module.Foo, Bar.__super__
super
overwriteMethod: -> "Bar"
extendMethod: -> Module.Foo().extendMethod() + "Bar"
barMethod: -> @
boundBarMethod: => @
console.log "---"
b = new Bar
console.log "b = new Bar --->", b
console.log "b.overwriteMethod() --->", b.overwriteMethod()
console.log "b.extendMethod() --->", b.extendMethod()
console.log "---"
console.log "b.barMethod() --->", b.barMethod()
console.log "b.boundBarMethod() --->", b.boundBarMethod()
console.log "b.fooMethod() --->", b.fooMethod()
console.log "b.boundFooMethod() --->", b.boundFooMethod()
console.log "---"
console.log "b.barMethod.apply(null) --->", b.barMethod.apply(null)
console.log "b.boundBarMethod.apply(null) --->", b.boundBarMethod.apply(null)
console.log "b.fooMethod.apply(null) --->", b.fooMethod.apply(null)
console.log "b.boundFooMethod.apply(null) --->", b.boundFooMethod.apply(null)
_extends = (child, parent) ->
for key of parent
if {}.hasOwnProperty.call(parent, key) then child[key] = parent[key]
child::[key] = parent::[key] for key of parent.prototype
child.__super__ = parent.prototype
return child
class window.Foo
overwriteMethod: -> "Foo"
extendMethod: -> "Foo"
fooMethod: -> @
boundFooMethod: => @
class window.Baz
class window.Bar extends Baz
@include: (module) ->
_extends(@, module)
_extends(module, _super)
@include Foo
overwriteMethod: -> "Bar"
extendMethod: -> super + "Bar"
barMethod: -> @
boundBarMethod: => @
console.log "---"
window.b = new Bar
console.log "b = new Bar --->", b
console.log "b.overwriteMethod() --->", b.overwriteMethod()
console.log "b.extendMethod() --->", b.extendMethod()
console.log "---"
console.log "b.barMethod() --->", b.barMethod()
console.log "b.boundBarMethod() --->", b.boundBarMethod()
console.log "b.fooMethod() --->", b.fooMethod()
console.log "b.boundFooMethod() --->", b.boundFooMethod()
console.log "---"
console.log "b.barMethod.apply(null) --->", b.barMethod.apply(null)
console.log "b.boundBarMethod.apply(null) --->", b.boundBarMethod.apply(null)
console.log "b.fooMethod.apply(null) --->", b.fooMethod.apply(null)
console.log "b.boundFooMethod.apply(null) --->", b.boundFooMethod.apply(null)
_ = {}
_.isFunction = (obj) -> typeof obj is 'function'
_.extend = (obj, args...) ->
for source in args
obj[prop] = source[prop] for prop of source if source?
return obj
class window.Foo
overwriteMethod: -> "Foo"
extendMethod: -> "Foo"
fooMethod: -> @
boundFooMethod: => @
class window.Baz
bazMethod: -> "Baz"
class window.Bar extends Baz
@include: (mixin) ->
if not mixin
return throw 'Supplied mixin was not found'
if not _
return throw 'Underscore was not found'
mixin = mixin.prototype if _.isFunction(mixin)
# Make a copy of the superclass with the same constructor and use it
# instead of adding functions directly to the superclass.
if @.__super__
tmpSuper = _.extend({}, @.__super__)
tmpSuper.constructor = @.__super__.constructor
@.__super__ = tmpSuper || {}
# Copy function over to prototype and the new intermediate superclass.
for methodName, funct of mixin when methodName not in ['included']
@.__super__[methodName] = funct
if not @prototype.hasOwnProperty(methodName)
@prototype[methodName] = funct
mixin.included?.apply(this)
this
@include Foo
overwriteMethod: -> "Bar"
extendMethod: -> super + "Bar"
barMethod: -> @
boundBarMethod: => @
console.log "---"
window.b = new Bar
console.log "b = new Bar --->", b
console.log "b.overwriteMethod() --->", b.overwriteMethod()
console.log "b.extendMethod() --->", b.extendMethod()
console.log "---"
console.log "b.barMethod() --->", b.barMethod()
console.log "b.boundBarMethod() --->", b.boundBarMethod()
console.log "b.fooMethod() --->", b.fooMethod()
console.log "b.boundFooMethod() --->", b.boundFooMethod()
console.log "b.bazMethod() --->", b.bazMethod()
console.log "---"
console.log "b.barMethod.apply(null) --->", b.barMethod.apply(null)
console.log "b.boundBarMethod.apply(null) --->", b.boundBarMethod.apply(null)
console.log "b.fooMethod.apply(null) --->", b.fooMethod.apply(null)
console.log "b.boundFooMethod.apply(null) --->", b.boundFooMethod.apply(null)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment