Skip to content

Instantly share code, notes, and snippets.

@fred-o
Created January 12, 2015 10:17
Show Gist options
  • Save fred-o/61e32b86abe76b7371f6 to your computer and use it in GitHub Desktop.
Save fred-o/61e32b86abe76b7371f6 to your computer and use it in GitHub Desktop.
# mutators
get = ->
set = (newVal) -> (val) -> newVal
add = (inc) -> (val) -> val + inc
sub = (inc) -> (val) -> val - inc
# guards
increasing = (oldVal, newVal) -> throw Error "#{newVal} <= #{oldVal}" unless newVal > oldVal
decreasing = (oldVal, newVal) -> throw Error "#{newVal} >= #{oldVal}" unless newVal < oldVal
immutable = -> throw Error "immutable"
# defining classes
defineClass = (slotDefs, superClass) ->
(slotVals, self) ->
dispatcher = (slotName, mutator) ->
if def = slotDefs[slotName]
type = typeof (newVal = mutator.call self, slots[slotName])
unless newVal is undefined
def?.guard slots[slotName], newVal if slots[slotName] isnt undefined
throw Error "slot #{slotName} wants #{def.type}; got #{type}" if type isnt def.type
slots[slotName] = newVal
else
throw Error "no slot named #{slotName}" if not parent
parent slotName, mutator
return slots[slotName]
self or= dispatcher
parent = superClass slotVals, self if superClass
slots = {}
for name, def of slotDefs
do (name, def) ->
self[name] = (mutator) -> dispatcher name, mutator
self[name] set slotVals[name] or def.default
return dispatcher
# example classes
Animal = defineClass {
_name: { type: 'string' }
age: { type: 'number', guard: increasing }
}
Mammal = defineClass {
legs: { type: 'number', default: 4, guard: immutable }
parent: { type: 'function' }
}, Animal
# creating a class instance
bird = Animal { _name: 'Birdie', age: 3 }
panda = Mammal { _name: 'Mama Panda', age: 10 }
cub = Mammal { _name: 'Cubby', age: 1, parent: panda }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment