UNPKG

spectacular

Version:

Advanced BDD framework for CoffeeScript and JavaScript

215 lines (170 loc) 5.95 kB
#### Mixins class spectacular.HasAncestors @included: (ctor) -> ctor.getter 'ancestors', -> ancestors = [] parent = @parent while parent ancestors.push parent parent = parent.parent ancestors ctor.ancestorsScope = (name, block) -> @getter name, -> @ancestors.filter block nthAncestor: (level) -> level = 1 if level < 1 parent = this n = 0 for n in [0..level] parent = parent.parent parent class spectacular.Globalizable @unglobalizable: ['globalize', 'unglobalize', 'keepContext', 'globalizeMember', 'unglobalizeMember', 'globalizable', 'globalized', 'alternate', 'previous'] keepContext: true globalize: -> @previous ||= {} @globalizable.forEach (k) => unless k in (@constructor.unglobalizable or Globalizable.unglobalizable) @globalizeMember k, @[k] @globalized = true unglobalize: -> @globalizable.forEach (k) => unless k in (@constructor.unglobalizable or Globalizable.unglobalizable) @unglobalizeMember k, @[k] @globalized = false globalizeMember: (key, value, alternate=true) -> _global = spectacular.global @previous[key] = _global[key] if _global[key]? self = this if typeof value is 'function' value._name = key unless value._name? if @keepContext proxy = -> value.apply self, arguments proxy._name = key _global[key] = proxy else _global[key] = value else _global[key] = value if alternate alt = @alternate key @globalizeMember alt, value, false if alt isnt key unglobalizeMember: (key, value, alternate=true) -> _global = spectacular.global if @previous[key]? _global[key] = @previous[key] else delete _global[key] if alternate alt = @alternate key @unglobalizeMember alt, value, false if alt isnt key alternate: (key) -> if key.indexOf('_') is -1 utils.underscore key else utils.camelize key class spectacular.Hookable @hook: (name) -> capitalizedName = utils.capitalize name @mergeUp "#{name}Hooks" @accessor "own#{capitalizedName}Hooks", { get: -> @["__own#{capitalizedName}Hooks"] ||= [] set: (v) -> @["__own#{capitalizedName}Hooks"] = v } registerHook: (name, block) -> capitalizedName = utils.capitalize name @["own#{capitalizedName}Hooks"].push block class spectacular.GlobalizableObject @include spectacular.Globalizable @unglobalizable = spectacular.Globalizable.unglobalizable.concat 'set' constructor: (@__globalizable...) -> Object.defineProperty this.prototype, 'globalizable', configurable: true get: -> if @__globalizable.length > 0 @__globalizable else utils.keys this set: (property, value) -> @[property] = value @globalizeMember property, value if @globalized spectacular.HasCollection = (plural, singular) -> capitalizedSingular = utils.capitalize singular capitalizedPlural = utils.capitalize plural mixin = class ConcreteHasCollection @included: (ctor) -> ctor["#{plural}Scope"] = (name, block) -> ctor.getter name, -> @[plural].filter block mixin::["add#{capitalizedSingular}"] = (items...) -> @[plural].push item for item in items when item not in @[plural] mixin::["remove#{capitalizedSingular}"] = (items...) -> newArray = [] newArray.push item for item in @[plural] when item not in items @[plural] = newArray mixin::["#{singular}At"] = (index) -> @[plural][index] mixin::["find#{capitalizedSingular}"] = mixin::["indexOf#{capitalizedSingular}"] = (item) -> @[plural].indexOf item mixin::["has#{capitalizedSingular}"] = mixin::["contains#{capitalizedSingular}"] = (item) -> @[plural].indexOf(item) isnt -1 mixin::["#{plural}Length"] = mixin::["#{plural}Size"] = mixin::["#{plural}Count"] = -> @[plural].length mixin spectacular.HasNestedCollection = (name, options={}) -> through = options.through throw new Error('missing through option') unless through? mixin = class ConcreteHasNestedCollection @included: (ctor) -> ctor["#{name}Scope"] = (scopeName, block) -> ctor.getter scopeName, -> @[name].filter block ctor.getter name, -> items = [] @[through].forEach (item) -> items.push(item) items = items.concat(item[name]) if item[name]? items mixin class spectacular.AncestorsProperties @followUp: (property) -> capitalizedProperty = utils.capitalize property privateProperty = "own#{capitalizedProperty}" @accessor property, { get: -> @[privateProperty] or @parent?[property] set: (value) -> @[privateProperty] = value } @mergeUp: (property) -> capitalizedProperty = utils.capitalize property privateProperty = "own#{capitalizedProperty}" @accessor property, { get: -> a = @[privateProperty] a = @parent[property].concat a if @parent? a set: (value) -> @[privateProperty] = value } class spectacular.Describable @included: (ctor) -> ctor.getter 'description', -> if @parent?.description? space = '' space = ' ' unless @noSpaceBeforeDescription "#{@parent.description}#{space}#{@ownDescription}" else @ownDescription class spectacular.Event constructor: (@name, @target) -> class spectacular.EventDispatcher on: (event, callback) -> @listeners ||= {} @listeners[event] ||= [] @listeners[event].push callback unless callback in @listeners[event] off: (event, callback) -> if @listeners?[event]? and callback in @listeners[event] @listeners[event].splice @listeners[event].indexOf(callback), 1 hasListener: (event) -> @listeners?[event]? and @listeners[event].length > 0 dispatch: (event) -> @listeners?[event.name]?.forEach (listener) -> listener event