Created
July 13, 2012 08:27
-
-
Save threepointone/3103649 to your computer and use it in GitHub Desktop.
attributes for objects (ala YUI)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
match = require 'minimatch' | |
_ = require 'underscore' | |
class Events | |
on: (evt, handler = _.i, scope = @) -> | |
@_events or= [] | |
spec = | |
evt: evt | |
handler: handler | |
scope: scope | |
enable:=> @_events = _.union @_events, spec;spec | |
disable:=> @_events = _.without @_events, spec;spec | |
@_events.push spec | |
spec | |
off: (evt, handler, scope) -> | |
if evt.indexOf('*') >= 0 then throw 'no wildcards in .off(), use .disable() instead' | |
@_events or= [] | |
for spec in @_events | |
matches = evt is spec.evt | |
if handler | |
matches = matches and handler is spec.handler | |
if scope | |
matches = matches and scope is spec.scope | |
if matches | |
spec.disable() | |
@ | |
fire: (evt, args...) -> | |
if evt.indexOf('*') >= 0 then throw "#{evt} no wildcards in .fire()" | |
@_events or= [] | |
for spec in @_events | |
if match evt, spec.evt | |
spec.handler.apply spec.scope, [{evt, _evt:spec.evt}].concat args | |
@ | |
class Attr extends Events | |
# default spec for an attribute | |
defaults = | |
lazy: false | |
setter: (value) -> value | |
getter: (value) -> value | |
value: null | |
valueFn: -> null # this overrides value | |
validate: (value) -> true | |
readOnly: false | |
# private | |
_value: null | |
_init: false | |
set: (key, value) -> | |
@describe key unless @_attrs?[key] # if key is not an attrib yet, make a blank stub | |
attr = @_attrs[key].startup() | |
if attr.readOnly | |
@fire 'attr:fail' | |
throw "attr:#{key} is read only" | |
if attr.validate.call @, value | |
attr._value = attr.setter.call @, value | |
@fire 'set', key, attr._value, value | |
else | |
@fire 'attr:fail' | |
throw "attr:#{key} did not validate for value #{value}" | |
@ | |
get: (key) -> | |
@describe key unless @_attrs?[key] | |
attr = @_attrs[key].startup() | |
value = attr.getter.call @, attr._value | |
@fire 'get', key, value | |
value | |
describe: (name, spec = {}) -> | |
@_attrs or= {} # private | |
attr = @_attrs[name] = _.defaults spec, defaults | |
attr.startup = => | |
if !attr._init | |
attr._value = if attr.valueFn then attr.valueFn.apply @ else attr.value | |
attr._init = true | |
@fire 'attr:init', name, attr._value | |
attr | |
attr.startup() unless attr.lazy | |
@fire 'attr:describe', name, spec | |
# x = new Attr | |
# x.describe 'a', | |
# lazy: true | |
# value: 2 | |
# valueFn: -> 3 | |
# validate: (value) -> value%8 is 0 | |
# setter: (value) -> value*2 | |
# getter: (value) -> value.toString() | |
# # readOnly: true | |
# # value still isn't set because lazy: true | |
# console.log x.get 'a' | |
# # value is now set | |
# # can initialize automatically | |
# x.set 'b', 5 | |
# console.log x.get 'c' | |
# console.log 'a', x.get 'a' | |
# x.set 'a', 16 | |
# console.log 'a', x.get 'a' | |
# # simple handler | |
# _h = (e) -> | |
# console.log "matched #{e._evt} for evt #{e.evt}" | |
# # x = new Events | |
# x.on 'a:*', _h | |
# alpha = x.on '*', _h | |
# x.on '*:b', _h | |
# x.on '*:b:*', _h | |
# # fire a bunch of events | |
# x.fire 'a' | |
# x.fire 'a:b' | |
# x.fire 'a:b:c' | |
# x.fire 'l:m:n' | |
# console.log 'disabling * listener' | |
# alpha.disable() | |
# x.fire 'l:m:n' | |
# alpha.enable() | |
# x.fire 'l:m:n' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
[working on removing the minimatch dependency]