Skip to content

Instantly share code, notes, and snippets.

@elia
Created July 15, 2015 22:19
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 elia/a076c2cbe69f30229cba to your computer and use it in GitHub Desktop.
Save elia/a076c2cbe69f30229cba to your computer and use it in GitHub Desktop.
Included and prepended modules in JavaScript with __proto__
p = console?.log
# Prepend module "mod" to the class "cla"
prepend_module = (cla, mod)->
icla = dup_methods(mod.prototype)
icla.__proto__ = cla.pre.__proto__
cla.pre.__proto__ = icla
cla
# Include module "mod" into the class "cla"
include_module = (cla, mod)->
icla = dup_methods(mod.prototype)
icla.__proto__ = cla.inc.__proto__
cla.inc.__proto__ = icla
cla
# Copy all (owned) methods from source to dest
dup_methods = (source, dest = {})->
for method_name of source
if source.hasOwnProperty(method_name)
dest[method_name] = source[method_name]
dest
C = (->) # a class
C.def = new (->) # where methods are defined
C.inc = C.def # where modules are included
C.pre = C.prototype # where modules are prepended
C.prototype.__proto__ = C.def # C.prototype will stay as a link for subclasses
C.def.foo = 'c' # define a method
C.def.foo0 = 'c' # define a method
C.def.foo1 = 'c' # define a method
C.def.foo2 = 'c' # define a method
M1 = (->) # a module (included)
M1.prototype.foo = 'm1' # a module is a pure list of methods
M1.prototype.foo1 = 'm1' # a module is a pure list of methods
M1.prototype.foo4 = 'm1' # a module is a pure list of methods
M2 = (->) # a module (prepended)
M2.prototype.foo = 'm2' # a module is a pure list of methods
M2.prototype.foo2 = 'm2' # a module is a pure list of methods
M2.prototype.foo3 = 'm2' # a module is a pure list of methods
assert_eq = (actual, expected)-> p "actual: #{actual}, expected: #{expected}"
c = new C
include_module(C,M1)
prepend_module(C,M2)
assert_eq c.foo, 'm2' # => actual: m2, expected: m2
assert_eq c.foo0, 'c' # => actual: c, expected: c
assert_eq c.foo1, 'c' # => actual: c, expected: c
assert_eq c.foo2, 'm2' # => actual: m2, expected: m2
assert_eq c.foo3, 'm2' # => actual: m2, expected: m2
assert_eq c.foo4, 'm1' # => actual: m1, expected: m1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment