From e5c86558205a99845b337278e5dcb977440893fb Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Sun, 27 Mar 2011 20:49:00 -0400 Subject: [PATCH 1/7] Don't need the overhead of a try/catch to get the stack trace. --- src/utils/error/getStackTrace.as | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/utils/error/getStackTrace.as b/src/utils/error/getStackTrace.as index ed417ca..da7537a 100644 --- a/src/utils/error/getStackTrace.as +++ b/src/utils/error/getStackTrace.as @@ -7,15 +7,6 @@ package utils.error */ public function getStackTrace():String { - try - { - throw new Error(); - } - catch (err:Error) - { - return err.getStackTrace(); - } - // It's impossible to reach this - return null; + return new Error().getStackTrace(); } } \ No newline at end of file From ab972e95b5fc27eece65780d97535e8cc3e03a4e Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Sun, 27 Mar 2011 20:59:10 -0400 Subject: [PATCH 2/7] While we're in the business of rewriting the addEventListener function signature, why not promote the importance of the useWeakListener argument? Also, drops the dependency on DisplayObject in favor of IEventDispatcher. --- src/utils/event/addTargetEventListener.as | 16 ++++++++++------ src/utils/event/removeTargetEventListener.as | 13 ++++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/utils/event/addTargetEventListener.as b/src/utils/event/addTargetEventListener.as index 9258b62..3020136 100644 --- a/src/utils/event/addTargetEventListener.as +++ b/src/utils/event/addTargetEventListener.as @@ -1,12 +1,16 @@ package utils.event { - import flash.display.DisplayObject; + import flash.events.IEventDispatcher; - public function addTargetEventListener(_target:DisplayObject, _type:String, _listener:Function, _useCapture:Boolean = false, _priority:int = 0, _useWeakReference:Boolean = true):void + public function addTargetEventListener(target:IEventDispatcher, + type:String, + listener:Function, + useWeakReference:Boolean = true, + useCapture:Boolean = false, + priority:int = 0):void { - if (_target != null) - { - _target.addEventListener(_type, _listener, _useCapture, _priority, _useWeakReference); - } + if(!target) return; + + target.addEventListener(type, listener, useCapture, priority, useWeakReference); } } \ No newline at end of file diff --git a/src/utils/event/removeTargetEventListener.as b/src/utils/event/removeTargetEventListener.as index 0dc0662..51c0adf 100644 --- a/src/utils/event/removeTargetEventListener.as +++ b/src/utils/event/removeTargetEventListener.as @@ -1,12 +1,15 @@ package utils.event { import flash.display.DisplayObject; + import flash.events.IEventDispatcher; - public function removeTargetEventListener(_target:DisplayObject, _type:String, _listener:Function, _useCapture:Boolean = false):void + public function removeTargetEventListener(target:IEventDispatcher, + type:String, + listener:Function, + useCapture:Boolean = false):void { - if (_target != null) - { - _target.removeEventListener(_type, _listener, _useCapture); - } + if(!target) return; + + target.removeEventListener(type, listener, useCapture); } } \ No newline at end of file From f289ab731d8f78698524c6bc5d50e0f11552592d Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Sun, 27 Mar 2011 21:01:03 -0400 Subject: [PATCH 3/7] Creates/stores/removes "safe" event listeners for you, so you can write event callbacks that optionally accept the event argument. --- src/utils/event/getSafeEventHandler.as | 13 +++++++++++++ src/utils/event/safeEventHandlers.as | 5 +++++ src/utils/event/trashSafeEventHandler.as | 12 ++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 src/utils/event/getSafeEventHandler.as create mode 100644 src/utils/event/safeEventHandlers.as create mode 100644 src/utils/event/trashSafeEventHandler.as diff --git a/src/utils/event/getSafeEventHandler.as b/src/utils/event/getSafeEventHandler.as new file mode 100644 index 0000000..1be3983 --- /dev/null +++ b/src/utils/event/getSafeEventHandler.as @@ -0,0 +1,13 @@ +package utils.event +{ + import flash.events.Event; + + public function getSafeEventHandler(func:Function):Function + { + safeEventHandlers[func] ||= function(event:Event):void { + func.length ? func(event) : func(); + } + + return safeEventHandlers[func]; + } +} diff --git a/src/utils/event/safeEventHandlers.as b/src/utils/event/safeEventHandlers.as new file mode 100644 index 0000000..1bd60f1 --- /dev/null +++ b/src/utils/event/safeEventHandlers.as @@ -0,0 +1,5 @@ +package utils.event +{ + import flash.utils.Dictionary; + internal const safeEventHandlers:Dictionary = new Dictionary(false); +} \ No newline at end of file diff --git a/src/utils/event/trashSafeEventHandler.as b/src/utils/event/trashSafeEventHandler.as new file mode 100644 index 0000000..b554894 --- /dev/null +++ b/src/utils/event/trashSafeEventHandler.as @@ -0,0 +1,12 @@ +package utils.event +{ + public function trashSafeEventHandler(func:Function):Function + { + if(!(func in safeEventHandlers)) + return null; + + const handler:Function = safeEventHandlers[func]; + delete safeEventHandlers[func]; + return handler; + } +} \ No newline at end of file From 41a2eb1085162fabb743eb66e1f1ebd0795c14f9 Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Sun, 27 Mar 2011 21:11:43 -0400 Subject: [PATCH 4/7] Reflects on an instance and autowires functions annotated with [Event("eventName")] metadata. Autowires using safe listeners, so it's ok to annotate functions that don't take arguments. --- src/utils/metadata/unwireEvents.as | 30 ++++++++++++++++++++++++++++++ src/utils/metadata/wireEvents.as | 19 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/utils/metadata/unwireEvents.as create mode 100644 src/utils/metadata/wireEvents.as diff --git a/src/utils/metadata/unwireEvents.as b/src/utils/metadata/unwireEvents.as new file mode 100644 index 0000000..da14cf2 --- /dev/null +++ b/src/utils/metadata/unwireEvents.as @@ -0,0 +1,30 @@ +package utils.metadata +{ + import flash.events.IEventDispatcher; + import flash.utils.Dictionary; + + import utils.event.getSafeEventHandler; + import utils.event.removeTargetEventListener; + import utils.event.trashSafeEventHandler; + import utils.type.describeMethods; + + public function unwireEvents(target:IEventDispatcher):void + { + var methods:XMLList = describeMethods(target, 'Event'); + var type:String; + var func:Function; + var dict:Dictionary = new Dictionary(false); + + for each(var m:XML in methods) + { + type = m.arg.@value.toString(); + dict[func = target[m.name()]] = true; + removeTargetEventListener(target, type, getSafeEventHandler(func)); + } + + for(var myFunc:* in dict) + trashSafeEventHandler(myFunc); + + dict = null; + } +} \ No newline at end of file diff --git a/src/utils/metadata/wireEvents.as b/src/utils/metadata/wireEvents.as new file mode 100644 index 0000000..411bb8b --- /dev/null +++ b/src/utils/metadata/wireEvents.as @@ -0,0 +1,19 @@ +package utils.metadata +{ + import flash.events.IEventDispatcher; + + import utils.event.addTargetEventListener; + import utils.event.getSafeEventHandler; + import utils.type.describeMethods; + + public function wireEvents(target:IEventDispatcher):void + { + var methods:XMLList = describeMethods(target, 'Event'); + var type:String; + for each(var m:XML in methods) + { + type = m.arg.@value.toString(); + addTargetEventListener(target, type, getSafeEventHandler(target[m.name()]), false); + } + } +} \ No newline at end of file From ff2807e5c9f2c6154b6cd5d39bf24dd89b0667fa Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Sun, 27 Mar 2011 21:42:46 -0400 Subject: [PATCH 5/7] Adding a basic phase validation implementation. Use addphase to define phases and their order, then use invalidate to add instances to a phase at a certain depth. A phase expects each object to be validated to have a public method with the same name as the phase's name. For example: addPhase("render", 1, true); invalidate({render: function(){ trace("render was called"); }}, 0, "render"); Will trace out "render was called" on the next frame. --- src/utils/syncro/Phase.as | 46 ++++++++++++++++++++++++++++++++++ src/utils/syncro/addphase.as | 11 ++++++++ src/utils/syncro/invalidate.as | 25 ++++++++++++++++++ src/utils/syncro/render.as | 14 +++++++++++ src/utils/syncro/syncro.as | 9 +++++++ 5 files changed, 105 insertions(+) create mode 100644 src/utils/syncro/Phase.as create mode 100644 src/utils/syncro/addphase.as create mode 100644 src/utils/syncro/invalidate.as create mode 100644 src/utils/syncro/render.as create mode 100644 src/utils/syncro/syncro.as diff --git a/src/utils/syncro/Phase.as b/src/utils/syncro/Phase.as new file mode 100644 index 0000000..789ccd4 --- /dev/null +++ b/src/utils/syncro/Phase.as @@ -0,0 +1,46 @@ +package utils.syncro +{ + internal dynamic class Phase extends Array + { + public function Phase(name:String, priority:int, ascending:Boolean) + { + _name = name; + _priority = priority; + _ascending = ascending; + + super(); + } + + private var _ascending:Boolean = true; + + private var _name:String = ''; + public function get name():String + { + return _name; + } + + private var _priority:int = 0; + public function get priority():int + { + return _priority; + } + + public function render():void + { + if(_ascending) + reverse(); + + var obj:Object; + var protect:Array = concat(); + var n:int = protect.length; + + while(--n >= 0) + { + obj = protect.pop(); + + if(name in obj) + obj[name](); + } + } + } +} \ No newline at end of file diff --git a/src/utils/syncro/addphase.as b/src/utils/syncro/addphase.as new file mode 100644 index 0000000..f2c72e1 --- /dev/null +++ b/src/utils/syncro/addphase.as @@ -0,0 +1,11 @@ +package utils.syncro +{ + public function addphase(name:String, priority:int = 0, ascending:Boolean = true):void + { + if(name in syncro.names) + return; + + var phase:Phase = syncro.names[name] = new Phase(name, priority, ascending); + syncro.phases.push(phase); + } +} \ No newline at end of file diff --git a/src/utils/syncro/invalidate.as b/src/utils/syncro/invalidate.as new file mode 100644 index 0000000..a58aa17 --- /dev/null +++ b/src/utils/syncro/invalidate.as @@ -0,0 +1,25 @@ +package utils.syncro +{ + import utils.display.wait; + + public function invalidate(target:Object, depth:int, name:String):void + { + if(!(name in syncro.names)) + return; + + var phase:Array = syncro.phases.filter(function(e:Phase, ...args):Boolean{ + return e.name == name; + })[0]; + + if(!phase || phase.indexOf(target) != -1) + return; + + phase.splice(depth, 0, target); + + if(syncro.invalidated) + return; + + syncro.invalidated = true; + wait(1, render); + } +} diff --git a/src/utils/syncro/render.as b/src/utils/syncro/render.as new file mode 100644 index 0000000..ea9d76a --- /dev/null +++ b/src/utils/syncro/render.as @@ -0,0 +1,14 @@ +package utils.syncro +{ + public function render():void + { + var p:Array = syncro.phases; + p.sortOn('priority'); + + //Set this before validating. + syncro.invalidated = false; + + for(var i:int = 0, n:int = p.length; i < n; i += 1) + Phase(p[i]).render(); + } +} \ No newline at end of file diff --git a/src/utils/syncro/syncro.as b/src/utils/syncro/syncro.as new file mode 100644 index 0000000..e08df9d --- /dev/null +++ b/src/utils/syncro/syncro.as @@ -0,0 +1,9 @@ +package utils.syncro +{ + internal class syncro + { + internal static var invalidated:Boolean = false; + internal static const phases:Array = []; + internal static const names:Array = []; + } +} \ No newline at end of file From a876cc8a7a1b32cecdf3363f875cc3d59ecd5980 Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Tue, 29 Mar 2011 23:34:47 -0400 Subject: [PATCH 6/7] Added option to validate phase by dispatching an event if the target object doesn't have a public function implemented for the phase name. Fixed a bug where phases wouldn't validate a second time. oops. --- src/utils/syncro/Phase.as | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/utils/syncro/Phase.as b/src/utils/syncro/Phase.as index 789ccd4..569bf97 100644 --- a/src/utils/syncro/Phase.as +++ b/src/utils/syncro/Phase.as @@ -1,5 +1,8 @@ package utils.syncro { + import flash.events.Event; + import flash.events.IEventDispatcher; + internal dynamic class Phase extends Array { public function Phase(name:String, priority:int, ascending:Boolean) @@ -31,7 +34,13 @@ package utils.syncro reverse(); var obj:Object; + + // Protective clone so items added during + // validation don't cause an infinite loop. var protect:Array = concat(); + + // Clear the list so items can be added during validation. + length = 0; var n:int = protect.length; while(--n >= 0) @@ -40,6 +49,8 @@ package utils.syncro if(name in obj) obj[name](); + else if(obj is IEventDispatcher) + IEventDispatcher(obj).dispatchEvent(new Event(name)); } } } From e3d07cf926bb99fdd198b04cbcd753b7d5d4be52 Mon Sep 17 00:00:00 2001 From: guyinthechair Date: Tue, 29 Mar 2011 23:35:33 -0400 Subject: [PATCH 7/7] Added multiple event-wiring for a single method. --- src/utils/metadata/unwireEvents.as | 17 +++++++++-------- src/utils/metadata/wireEvents.as | 7 +++++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/utils/metadata/unwireEvents.as b/src/utils/metadata/unwireEvents.as index da14cf2..a97f211 100644 --- a/src/utils/metadata/unwireEvents.as +++ b/src/utils/metadata/unwireEvents.as @@ -12,19 +12,20 @@ package utils.metadata { var methods:XMLList = describeMethods(target, 'Event'); var type:String; - var func:Function; + var func:*; var dict:Dictionary = new Dictionary(false); for each(var m:XML in methods) { - type = m.arg.@value.toString(); - dict[func = target[m.name()]] = true; - removeTargetEventListener(target, type, getSafeEventHandler(func)); + for each(var meta:XML in m.metadata.(@name=="Event")) + { + type = meta.arg.@value.toString(); + dict[func = target[m.name()]] = true; + removeTargetEventListener(target, type, getSafeEventHandler(func)); + } } - for(var myFunc:* in dict) - trashSafeEventHandler(myFunc); - - dict = null; + for(func in dict) + trashSafeEventHandler(func); } } \ No newline at end of file diff --git a/src/utils/metadata/wireEvents.as b/src/utils/metadata/wireEvents.as index 411bb8b..78801a9 100644 --- a/src/utils/metadata/wireEvents.as +++ b/src/utils/metadata/wireEvents.as @@ -12,8 +12,11 @@ package utils.metadata var type:String; for each(var m:XML in methods) { - type = m.arg.@value.toString(); - addTargetEventListener(target, type, getSafeEventHandler(target[m.name()]), false); + for each(var meta:XML in m.metadata.(@name=="Event")) + { + type = meta.arg.@value.toString(); + addTargetEventListener(target, type, getSafeEventHandler(target[m.@name]), false); + } } } } \ No newline at end of file