src/define.coffee in luca-0.9.4 vs src/define.coffee in luca-0.9.6
- old
+ new
@@ -9,21 +9,19 @@
# _.def, or Luca.define returns a chainable object which allows you to define
# your components with a readable syntax. For example:
# _.def("Luca.View").extends("Backbone.View").with the_good:"shit"
# _.def("MyView").extends("Luca.View").with the_custom:"shit"
+_.mixin
+ def: Luca.component = Luca.define = Luca.register = (componentName)-> new DefineProxy(componentName)
-Luca.define = (componentName)->
- new DefineProxy(componentName)
-
-Luca.component = Luca.define
-
# The define proxy chain sets up a call to Luca.extend, which is a wrapper around Luca and Backbone component class' extend function.
class DefineProxy
constructor:(componentName)->
@namespace = Luca.util.namespace()
@componentId = @componentName = componentName
+ @superClassName = 'Luca.View'
if componentName.match(/\./)
@namespaced = true
parts = componentName.split('.')
@componentId = parts.pop()
@@ -38,28 +36,45 @@
# allow for multiple ways of saying the same thing for readability purposes
from: (@superClassName)-> @
extends: (@superClassName)-> @
extend: (@superClassName)-> @
- # an alias for with, or a readability helper in multi-line definitions
- enhance: (properties)->
- return @with(properties) if properties?
+ triggers: (hooks...)->
+ _.defaults(@properties ||= {}, hooks: [])
+ for hook in hooks
+ @properties.hooks.push(hook)
+ @properties.hooks = _.uniq(@properties.hooks)
@
- # which properties, methods, etc will you be extending the base class with?
- with: (properties)->
+ includes: (includes...)->
+ _.defaults(@properties ||= {}, include: [])
+ for include in includes
+ @properties.include.push(include)
+ @properties.include = _.uniq(@properties.include)
+ @
+
+ mixesIn: (mixins...)->
+ _.defaults(@properties ||= {}, mixins: [])
+ for mixin in mixins
+ @properties.mixins.push(mixin)
+ @properties.mixins = _.uniq(@properties.mixins)
+ @
+
+ defaultProperties: (properties={})->
+ _.defaults((@properties||={}), properties)
+
at = if @namespaced
Luca.util.resolve(@namespace, (window || global))
else
(window||global)
# automatically create the namespace
if @namespaced and not at?
eval("(window||global).#{ @namespace } = {}")
at = Luca.util.resolve(@namespace,(window || global))
- at[@componentId] = Luca.extend(@superClassName,@componentName, properties)
+ at[@componentId] = Luca.extend(@superClassName,@componentName, @properties)
if Luca.autoRegister is true
componentType = "view" if Luca.isViewPrototype( at[@componentId] )
if Luca.isCollectionPrototype( at[@componentId] )
@@ -68,43 +83,100 @@
componentType = "collection"
componentType = "model" if Luca.isModelPrototype( at[@componentId] )
# automatically register this with the component registry
- Luca.register( _.string.underscored(@componentId), @componentName, componentType)
+ Luca.registerComponent( _.string.underscored(@componentId), @componentName, componentType)
at[@componentId]
+# Aliases for the mixin definition
+DefineProxy::behavesAs = DefineProxy::uses = DefineProxy::mixesIn
+
+# Aliases for the final call on the define proxy
+DefineProxy::defines = DefineProxy::defaults = DefineProxy::exports = DefineProxy::defaultProperties
+DefineProxy::defaultsTo = DefineProxy::enhance = DefineProxy::with = DefineProxy::defaultProperties
+
# The last method of the DefineProxy chain is always going to result in
# a call to Luca.extend. Luca.extend wraps the call to Luca.View.extend,
# or Backbone.Collection.extend, and accepts the names of the extending,
# and extended classes as strings. This allows us to maintain information
# and references to the classes and their prototypes, mainly for the purposes
# of introspection and development tools
Luca.extend = (superClassName, childName, properties={})->
superClass = Luca.util.resolve( superClassName, (window || global) )
+ superClass.__initializers ||= []
+
unless _.isFunction(superClass?.extend)
- throw "#{ superClassName } is not a valid component to extend from"
+ throw "Error defining #{ childName }. #{ superClassName } is not a valid component to extend from"
properties.displayName = childName
properties._superClass = ()->
superClass.displayName ||= superClassName
superClass
- properties._super = (method, context, args)->
+ properties._super = (method, context=@, args=[])->
+ # protect against a stack too deep error in weird cases
+ # TODO: debug this better
+
@_superClass().prototype[method]?.apply(context, args)
definition = superClass.extend(properties)
# _.def("MyView").extends("View").with
# include: ['Luca.Events']
if _.isArray( properties?.include )
- for mixin in properties.include
- mixin = Luca.util.resolve(mixin) if _.isString(mixin)
- _.extend(definition::, mixin)
+ for include in properties.include
+ include = Luca.util.resolve(include) if _.isString(include)
+ _.extend(definition::, include)
definition
-_.mixin
- def: Luca.define
+
+Luca.mixin = (mixinName)->
+ namespace = _( Luca.mixin.namespaces ).detect (space)->
+ Luca.util.resolve(space)?[ mixinName ]?
+
+ namespace ||= "Luca.modules"
+
+ resolved = Luca.util.resolve(namespace)[ mixinName ]
+
+ console.log "Could not find #{ mixinName } in ", Luca.mixin.namespaces unless resolved?
+
+ resolved
+
+Luca.mixin.namespaces = [
+ "Luca.modules"
+]
+
+Luca.mixin.namespace = (namespace)->
+ Luca.mixin.namespaces.push(namespace)
+ Luca.mixin.namespaces = _( Luca.mixin.namespaces ).uniq()
+
+# Luca.decorate('Luca.View').with('Luca.modules.MyCustomMixin')
+Luca.decorate = (componentPrototype)->
+ componentPrototype = Luca.util.resolve(componentPrototype).prototype if _.isString(componentPrototype)
+
+ return with: (mixin)->
+ mixinDefinition = Luca.mixin(mixin)
+
+ mixinPrivates = _( mixinDefinition ).chain().keys().select (key)->
+ "#{ key }".match(/^__/)
+
+ sanitized = _( mixinDefinition ).omit( mixinPrivates.value() )
+
+ _.extend(componentPrototype, sanitized)
+
+ # When a mixin is included, we may want to do things
+ mixinDefinition?.__included?.call(mixinDefinition, mixin)
+
+ superclassMixins = componentPrototype._superClass()::mixins
+
+ componentPrototype.mixins ||= []
+ componentPrototype.mixins.push( mixin )
+ componentPrototype.mixins = componentPrototype.mixins.concat( superclassMixins )
+
+ componentPrototype.mixins = _( componentPrototype.mixins ).chain().uniq().compact().value()
+
+ componentPrototype