├── .gitignore ├── CHANGELOG.textile ├── MIT-LICENSE.txt ├── README.textile ├── TODO.textile ├── as3-signals.as3proj ├── build.properties ├── build.xml ├── libs ├── asunit4-alpha.swc ├── flexUnitTasks.jar └── hamcrest-as3.swc ├── performance-test └── org │ └── osflash │ └── signals │ ├── AddOncePerformance.as │ ├── DispatchPerformance.as │ ├── MassDispatchPerformance.as │ └── RemovePerformance.as ├── src └── org │ └── osflash │ └── signals │ ├── DeluxeSignal.as │ ├── IOnceSignal.as │ ├── IPrioritySignal.as │ ├── ISignal.as │ ├── ISlot.as │ ├── MonoSignal.as │ ├── OnceSignal.as │ ├── PrioritySignal.as │ ├── Promise.as │ ├── Signal.as │ ├── Slot.as │ ├── SlotList.as │ ├── events │ ├── GenericEvent.as │ ├── IBubbleEventHandler.as │ └── IEvent.as │ └── natives │ ├── INativeDispatcher.as │ ├── NativeMappedSignal.as │ ├── NativeRelaySignal.as │ ├── NativeSignal.as │ ├── base │ ├── SignalBitmap.as │ ├── SignalMovieClip.as │ ├── SignalShape.as │ ├── SignalSocket.as │ ├── SignalSprite.as │ ├── SignalTextField.as │ ├── SignalTimer.as │ ├── SignalURLLoader.as │ └── SignalXMLSocket.as │ └── sets │ ├── DisplayObjectSignalSet.as │ ├── EventDispatcherSignalSet.as │ ├── FileReferenceListSignalSet.as │ ├── FileReferenceSignalSet.as │ ├── InteractiveObjectSignalSet.as │ ├── LoaderInfoSignalSet.as │ ├── MicrophoneSignalSet.as │ ├── NativeSignalSet.as │ ├── NetConnectionSignalSet.as │ ├── NetStreamSignalSet.as │ ├── SharedObjectSignalSet.as │ ├── SocketSignalSet.as │ ├── SoundChannelSignalSet.as │ ├── SoundSignalSet.as │ ├── StageSignalSet.as │ ├── TextFieldSignalSet.as │ ├── TimerSignalSet.as │ ├── URLLoaderSignalSet.as │ ├── URLStreamSignalSet.as │ └── XMLSocketSignalSet.as └── tests └── org └── osflash └── signals ├── AllTests.as ├── AllTestsCIRunner.as ├── AllTestsRunner.as ├── AmbiguousRelationshipTest.as ├── DeluxeSignalWithBubblingEventTest.as ├── DeluxeSignalWithGenericEventTest.as ├── GenericEventTest.as ├── ISignalTestBase.as ├── ISlotTestBase.as ├── MXMLDeluxeSignalTest.as ├── MXMLSignalTest.as ├── MonoSignalDispatchArgsTest.as ├── MonoSignalDispatchExtraArgsTest.as ├── MonoSignalDispatchNoArgsTest.as ├── MonoSignalDispatchNonEventTest.as ├── MonoSignalDispatchVarArgsTest.as ├── MonoSignalSlotTest.as ├── MonoSignalTest.as ├── PriorityListenersTest.as ├── PrioritySignalTest.as ├── PrioritySignalTestSuite.as ├── PrioritySignalTestsRunner.as ├── PromiseTest.as ├── RedispatchedEventTest.as ├── SignalDispatchArgsTest.as ├── SignalDispatchExtraArgsTest.as ├── SignalDispatchNoArgsTest.as ├── SignalDispatchNonEventTest.as ├── SignalDispatchVarArgsTest.as ├── SignalTest.as ├── SignalWithCustomEventTest.as ├── SlotListTest.as ├── SlotTest.as ├── natives ├── AmbiguousRelationshipInNativeSignalTest.as ├── INativeDispatcherTestBase.as ├── MXMLNativeSignalTest.as ├── NativeMappedSignalBoundaryUseTest.as ├── NativeMappedSignalDefaultsTest.as ├── NativeMappedSignalFunctionArgTest.as ├── NativeMappedSignalFunctionNoArgsTest.as ├── NativeMappedSignalObjectArgTest.as ├── NativeRelaySignalTest.as ├── NativeSignalSlotTest.as ├── NativeSignalTest.as ├── base │ └── SignalSpriteTest.as └── sets │ ├── DisplayObjectSignalSetTest.as │ ├── EventDispatcherSignalSetTest.as │ └── NativeSignalSetTest.as └── support ├── SpriteWithDeluxeSignals.mxml ├── SpriteWithNativeSignals.mxml └── SpriteWithSignals.mxml /.gitignore: -------------------------------------------------------------------------------- 1 | html-template/* 2 | bin-debug/* 3 | bin-release/* 4 | bin/* 5 | doc/* 6 | docs/* 7 | obj/* 8 | dist/* 9 | report/* 10 | out/* 11 | target/* 12 | 13 | .idea/dictionaries/* 14 | .idea/uiDesigner.xml 15 | .idea/workspace.xml 16 | 17 | .settings/* 18 | .actionScriptProperties 19 | .flexProperties 20 | .flexLibProperties 21 | .FlexUnitSettings 22 | .project 23 | 24 | Icon 25 | Thumbs.db 26 | .DS_Store 27 | -------------------------------------------------------------------------------- /CHANGELOG.textile: -------------------------------------------------------------------------------- 1 | h2. AS3 Signals Changelog: 2 | 3 | h3. v0.9 - NeufGun 4 | 5 | h4. API Additions 6 | * ISlot: listener registration object with many features. 7 | ** A slot stores values of *once* and *priority*, replacing the untyped "listener box" objects. 8 | ** A slot can *remove()* its listener from the signal. 9 | ** Has *enabled* toggle to temporarily disconnect the listener without removing it. 10 | ** The slot's *listener* can be changed on the fly. 11 | ** Has optional array of *params* which are appended to the signal's dispatched values before reaching the listener. Similar to delegates that store extra args. 12 | * IOnceSignal: has *addOnce()* but not *add()*. Useful for completion signals that discard all listeners on dispatch. Idea by @alecmce. 13 | * MonoSignal: can have only one listener. Useful for callbacks and SignalCommandMap request signals. Originally implemented as SingleSignal by @stickupkid. 14 | * PrioritySignal: like DeluxeSignal without bubbling (thanks @neilmanuell). 15 | * Native Signal Sets: 16 | ** @jonopus developed an easy way to snap on NativeSignals to Sprite, Timer, etc. See *org.osflash.signals.natives.sets* package. 17 | ** Created SignalSprite, SignalTimer, etc. as example base classes. See *org.osflash.signals.natives.base* package. 18 | 19 | h4. API Changes 20 | * Removed ISignalOwner, INativeSignalOwner and IDispatcher. They became annoying, e.g. casting ISignal to Signal just to dispatch. Moved their methods into ISignal. 21 | * *add()*, *addOnce()* and *remove()* now return ISlot. 22 | 23 | h4. Implementation Changes 24 | * add() no longer checks listener.length because ...varargs listeners cannot be detected. 25 | * Dispatching 26 | ** @joa created a new, faster dispatching engine (SlotList) using an immutable recursive linked list (inspired by Scala). The list is like a snake which gets eaten by a snake, which gets eaten by a larger snake, and so on. 27 | ** NOTE: Listeners are now called in reverse order, for best performance. If precise order is needed, use an IPrioritySignal. 28 | * Enhanced MXML friendliness (ArrayElementType, better examples). 29 | * More inheritance between signals to reduce code duplication. 30 | 31 | h4. Fixes 32 | * DeluxeSignal: now handles subclass super() calls properly (thanks @stickupkid). 33 | * NativeRelaySignal: better checks for null (thanks @stickupkid). 34 | 35 | h4. Tests 36 | * Increased test coverage significantly. Many tests from @stickupkid. 37 | * Refactored duplicated test code into base classes, e.g. ISignalTestBase. This greatly increased coverage across various implementations. 38 | 39 | h4. Build 40 | * Build now has a "package" target to zip SWC and source together. 41 | * Build now has a "clean" target to remove generated folders. 42 | * Flash Player executes on Linux (thanks @joa). 43 | 44 | h3. v0.8 - Maximilian - 2010-11-14 45 | 46 | h4. API Changes 47 | * Signals are now MXML-friendly! Example: 48 | 49 | {[String, uint]} 50 | 51 | ** Constructors are now nullable. 52 | ** valueClasses and eventClass are now writable. 53 | ** Exceptions: NativeMappedSignal and NativeRelaySignal are not yet MXML-friendly. 54 | * Renamed IDeluxeSignal to IPrioritySignal, a more functional name. 55 | * New interfaces to grant access to methods that affect all listeners: 56 | ** ISignalOwner: extends ISignal, IDispatcher, adds removeAll(). 57 | ** INativeSignalOwner: extends IPrioritySignal, INativeDispatcher, adds removeAll(). 58 | ** These 2 interfaces cannot be merged because dispatch(event:Event) conflicts with dispatch(...valueObjects). 59 | ** Thanks to "Brian Heylin":http://github.com/brianheylin for getting the ball rolling. 60 | 61 | h4. Fixes 62 | * "#24 - Changing NativeSignal.target wasn't removing listeners from target.":http://github.com/robertpenner/as3-signals/issues/closed#issue/24 63 | * "#32 - FIX: Setting NativeSignal.eventClass to null and dispatching causes null exception.":http://github.com/robertpenner/as3-signals/issues/closed#issue/32 64 | 65 | h4. Build 66 | * Added continuous integration and unit test execution Ant targets: "ci" and "test". 67 | * Updated AsUnit 4 SWC: test failure call stack is more concise and readable. 68 | * Removed build-asunit.xml as its functionality has been merged into build.xml. 69 | 70 | 71 | h3. v0.7 - Bubblap - 2010-05-27 72 | 73 | h4. API Changes 74 | * Added NativeMappedSignal class from "Brian Heylin":http://github.com/brianheylin, with great "test coverage":http://github.com/brianheylin/as3-signals/tree/master/tests/org/osflash/signals/natives/. 75 | ** Addresses "#16 - Add ability to map native events to signals":http://github.com/robertpenner/as3-signals/issues/closed#issue/16 76 | * DeluxeSignal has a simpler way to continue bubbling without re-dispatching the event. 77 | ** IBubbleEventHandler.onEventBubbled() now returns true/false to continue/cancel bubbling. 78 | ** Thanks to "secoif":http://github.com/secoif for the original code and "dehash":http://www.dehash.com/?p=241h for helping with the merge. 79 | * ISignal and IDeluxeSignal: add(), addOnce() and remove() now return the listener. 80 | ** Thanks to "sammyt":http://github.com/sammyt for the contribution with unit tests. 81 | 82 | h4. Fixes 83 | * Improved error message for Signal.dispatch() with too few arguments. 84 | 85 | h4. Test Changes 86 | * The test suite is migrated to a newer version of AsUnit 4. 87 | ** Tests now receive an IAsync using [Inject]. No more Asyncleton! 88 | ** The migration pattern can be seen in "commit f6878.":http://github.com/robertpenner/as3-signals/commit/f6878dbbff95e0bd7832cc2d1cc2e7d55fb18098 89 | ** AllTestsRunner uses a "new composition pattern":http://github.com/robertpenner/as3-signals/commit/866a99570152b7399aa34839fd5c30789db67f3c instead of inheritance. 90 | ** Many thanks to "Luke Bayes":http://github.com/lukebayes and the "Bay Area Computer Club":http://github.com/bayareacomputerclub. 91 | * Added more tests for argument dispatching and consolidated in SignalDispatchArgsTest. 92 | 93 | h3. v0.6 - GreenDay - 2010-03-17 94 | 95 | h4. API Changes 96 | * "#15 - IDeluxeSignal and NativeSignal now have valueClasses property":http://github.com/robertpenner/as3-signals/issues/closed#issue/15 97 | 98 | h4. Fixes 99 | * "#14 - NativeSignal.addOnce() can't be reused after native event dispatched":http://github.com/robertpenner/as3-signals/issues/closed#issue/14 100 | 101 | h4. Implementation Changes 102 | * Optimized listeners array cloning to use slice(), which is faster than concat(). 103 | * Optimized dispatch() by moving the cloning of listeners to add(), addOnce(), and remove(). 104 | * Signal.removeAll() now uses remove() on every listener, instead of fast array clearing. This is intended to avoid possible issues with subclass overrides (as happened before with NativeRelaySignal.remove()). 105 | * Renamed createListenerRelationship() to registerListener(). 106 | * Consolidated add() and addOnce() logic in registerListener(). 107 | * Removed onceListeners Dictionary from DeluxeSignal and NativeSignal. 108 | * DeluxeSignal and NativeSignal are now more unified in their "once listeners" internal implementations. 109 | * Removed an extra semicolon which made FDT cry (thanks "vitch":http://github.com/vitch). 110 | 111 | h4. Test Changes 112 | * Removed async [Test] metadata because AsUnit 4 no longer uses it. 113 | * Updated the AsUnit 4 SWC to newer version which avoids slowdown of Timers in Flash Player 10.1. 114 | * Added tests for ambiguous relationships in Signal. 115 | * Added tests for adding a listener during a dispatch(). 116 | 117 | h3. v0.5 - GlassHalfFull - 2010-02-08 118 | 119 | * Added versioning to the Ant build, starting at 0.5. 120 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Robert Penner 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. Signals: Think Outside the Event. 2 | 3 | *Signals* are light-weight, strongly-typed AS3 messaging tools. 4 | Wire your application with better APIs and less boilerplate than AS3 Events. 5 | 6 | h2. Concept 7 | 8 | * A *Signal* is essentially a mini-dispatcher specific to one event, with its own array of listeners. 9 | * A Signal gives an event a concrete membership in a class. 10 | * Listeners subscribe to real objects, not to string-based channels. 11 | * Event string constants are no longer needed. 12 | * Signals are inspired by "C# events":http://en.wikipedia.org/wiki/C_Sharp_syntax#Events and "signals/slots":http://en.wikipedia.org/wiki/Signals_and_slots in Qt. 13 | 14 | h2. Syntax 15 | 16 |
// with EventDispatcher
17 | button.addEventListener(MouseEvent.CLICK, onClick);
18 | 
19 | // Signal equivalent; past tense is recommended
20 | button.clicked.add(onClicked);
21 | 
22 | 23 | I am still looking for impressions, critiques and suggestions. 24 | My email is robert _at_ robertpenner.com. 25 | I'm "@robpenner on Twitter":http://twitter.com/robpenner. 26 | 27 | h2. Background on AS3 Events 28 | 29 | * "My Critique of AS3 Events - Part 1":http://flashblog.robertpenner.com/2009/08/my-critique-of-as3-events-part-1.html 30 | * "AS3 Events - 7 things I've learned from community":http://flashblog.robertpenner.com/2009/09/as3-events-7-things-ive-learned-from.html 31 | * "My Critique of AS3 Events - Part 2":http://flashblog.robertpenner.com/2009/09/my-critique-of-as3-events-part-2.html 32 | -------------------------------------------------------------------------------- /TODO.textile: -------------------------------------------------------------------------------- 1 | h1. AS3 Signals TODO 2 | 3 | h2. v0.9 4 | 5 | h3. High Priority 6 | 7 | * finish base classes using signal sets, e.g. SignalSprite 8 | * ask community about impact of reversing order of listeners 9 | 10 | h3. Medium Priority 11 | 12 | * fill in asdocs 13 | 14 | h3. Low Priority 15 | 16 | * add MXML support for NativeMappedSignal, NativeRelaySignal 17 | -------------------------------------------------------------------------------- /as3-signals.as3proj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | # Properties file for build.xml 2 | project.name=as3-signals 3 | project.title=AS3 Signals 4 | 5 | # Version number for current releases 6 | ver.num=v0.9-BETA 7 | project.name.versioned=${project.name}-${ver.num} 8 | 9 | # Build locations 10 | src.dir=${basedir}/src 11 | package.dir=org/osflash/signals 12 | tests.dir=${basedir}/tests 13 | libs.dir=${basedir}/libs 14 | output.dir=${basedir}/bin 15 | docs.dir=${basedir}/docs 16 | report.dir=${basedir}/report 17 | output.swc=${output.dir}/${project.name.versioned}.swc 18 | tests.swf=${output.dir}/AS3SignalsTestRunner.swf 19 | dist.dir=${basedir}/dist 20 | 21 | # Project links 22 | as3signals.project.link=http://github.com/robertpenner/as3-signals 23 | 24 | -------------------------------------------------------------------------------- /libs/asunit4-alpha.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertpenner/as3-signals/975eefc416bdc36513a39cae0339dc205d937922/libs/asunit4-alpha.swc -------------------------------------------------------------------------------- /libs/flexUnitTasks.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertpenner/as3-signals/975eefc416bdc36513a39cae0339dc205d937922/libs/flexUnitTasks.jar -------------------------------------------------------------------------------- /libs/hamcrest-as3.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertpenner/as3-signals/975eefc416bdc36513a39cae0339dc205d937922/libs/hamcrest-as3.swc -------------------------------------------------------------------------------- /performance-test/org/osflash/signals/AddOncePerformance.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: joa 4 | * Date: 11/22/10 5 | * Time: 4:34 PM 6 | * To change this template use File | Settings | File Templates. 7 | */ 8 | package org.osflash.signals 9 | { 10 | import flash.display.Sprite; 11 | import flash.events.Event; 12 | import flash.system.System; 13 | import flash.text.TextField; 14 | import flash.text.TextFieldAutoSize; 15 | import flash.text.TextFormat; 16 | import flash.utils.getTimer; 17 | 18 | [SWF(width=800, height=600, frameRate=64, backgroundColor=0x333333)] 19 | public class AddOncePerformance extends Sprite 20 | { 21 | private var _out0: TextField; 22 | private var _out1: TextField; 23 | private var _s: Signal; 24 | private var _t0: int; 25 | 26 | private var _f: int; 27 | private var _min:int; 28 | private var _max:int; 29 | 30 | public function AddOncePerformance() 31 | { 32 | _out0 = new TextField(); 33 | _out0.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 34 | _out0.autoSize = TextFieldAutoSize.LEFT; 35 | _out0.x = 0x20; 36 | _out0.y = 0x20; 37 | 38 | _out1 = new TextField(); 39 | _out1.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 40 | _out1.autoSize = TextFieldAutoSize.LEFT; 41 | _out1.x = 0x200; 42 | _out1.y = 0x20; 43 | 44 | _s = new Signal(); 45 | 46 | addChild(_out0); 47 | addChild(_out1); 48 | 49 | addEventListener(Event.ENTER_FRAME, onEnterFrame); 50 | } 51 | 52 | private function onEnterFrame(event: Event): void 53 | { 54 | var t1: int = getTimer(); 55 | if((t1 - _t0) >= 1000) { 56 | _out0.text = _f+'fps\n'+(System.totalMemory >> 20)+'mb\n'+_min+'ms\n'+_max+'ms'; 57 | _f = 0; 58 | _t0 = t1; 59 | } 60 | 61 | _f++; 62 | var n: int = 5000/4; 63 | var m0: int = getTimer(); 64 | while(--n != 0) { 65 | _s.dispatch(); 66 | _s.addOnce(l0);//2**(4-1)=8 67 | _s.addOnce(l1); 68 | _s.addOnce(l2); 69 | _s.addOnce(l3); 70 | _s.addOnce(l4); 71 | _s.addOnce(l5); 72 | _s.addOnce(l6); 73 | _s.addOnce(l7); 74 | } 75 | var dt: int = (getTimer() - m0); 76 | if(dt < _min) _min = dt; 77 | if(dt > _max) _max = dt; 78 | _out1.text = dt+'ms'; 79 | } 80 | 81 | private function l0(): void { 82 | } 83 | 84 | private function l1(): void { 85 | } 86 | 87 | private function l2(): void { 88 | } 89 | 90 | private function l3(): void { 91 | } 92 | 93 | private function l4(): void { 94 | } 95 | 96 | private function l5(): void { 97 | } 98 | 99 | private function l6(): void { 100 | } 101 | 102 | private function l7(): void { 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /performance-test/org/osflash/signals/DispatchPerformance.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.Event; 5 | import flash.system.System; 6 | import flash.text.TextField; 7 | import flash.text.TextFieldAutoSize; 8 | import flash.text.TextFormat; 9 | import flash.utils.getTimer; 10 | 11 | [SWF(width=800, height=600, frameRate=64, backgroundColor=0x333333)] 12 | public class DispatchPerformance extends Sprite 13 | { 14 | private const FPS: int = 64; 15 | private const N: int = 4; 16 | private const NUM_LISTENERS: int = 1 << (N - 1); 17 | private const NUM_ITERATIONS: int = 80000/N; 18 | private const MAX_SCORE: int = NUM_LISTENERS * NUM_ITERATIONS * FPS; 19 | 20 | private var _out0: TextField; 21 | private var _out1: TextField; 22 | private var _t0: int; 23 | 24 | private var _s: ISignal; 25 | private var _d: int; 26 | private var _f: int; 27 | private var _min:int; 28 | private var _max:int; 29 | public function DispatchPerformance() 30 | { 31 | stage.frameRate = FPS; 32 | 33 | _out0 = new TextField(); 34 | _out0.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 35 | _out0.autoSize = TextFieldAutoSize.LEFT; 36 | _out0.x = 0x20; 37 | _out0.y = 0x20; 38 | 39 | _out1 = new TextField(); 40 | _out1.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 41 | _out1.autoSize = TextFieldAutoSize.LEFT; 42 | _out1.x = 0x200; 43 | _out1.y = 0x20; 44 | 45 | _s = new Signal(); 46 | for(var i: int = 0; i < NUM_LISTENERS; ++i) _s.add(function(): void { _d++; }); 47 | 48 | addChild(_out0); 49 | addChild(_out1); 50 | 51 | addEventListener(Event.ENTER_FRAME, onEnterFrame); 52 | } 53 | 54 | private function onEnterFrame(event: Event): void 55 | { 56 | var t1: int = getTimer(); 57 | if((t1 - _t0) >= 1000) { 58 | _out0.text = _d+'/'+MAX_SCORE+' = '+Math.round(_d/MAX_SCORE*100.0)+'%\n'+_f+ 59 | 'fps\n'+(System.totalMemory >> 20)+'mb\n'+_min+'ms\n'+_max+'ms'; 60 | _d = 0; 61 | _f = 0; 62 | _t0 = t1; 63 | } 64 | 65 | _f++; 66 | var n: int = NUM_ITERATIONS + 1; 67 | var m0: int = getTimer(); 68 | while(--n != 0) _s.dispatch(); 69 | var dt: int = (getTimer() - m0); 70 | if(dt < _min) _min = dt; 71 | if(dt > _max) _max = dt; 72 | _out1.text = dt+'ms'; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /performance-test/org/osflash/signals/MassDispatchPerformance.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.Event; 5 | import flash.system.System; 6 | import flash.text.TextField; 7 | import flash.text.TextFieldAutoSize; 8 | import flash.text.TextFormat; 9 | import flash.utils.getTimer; 10 | import flash.utils.setTimeout; 11 | 12 | [SWF(width=800, height=600, frameRate=64, backgroundColor=0x333333)] 13 | public class MassDispatchPerformance extends Sprite 14 | { 15 | private const FPS: int = 64; 16 | private const NUM_LISTENERS: int = 250000; 17 | private const MAX_SCORE: int = NUM_LISTENERS * FPS; 18 | 19 | private var _out0: TextField; 20 | private var _out1: TextField; 21 | private var _t0: int; 22 | 23 | private var _s: IPrioritySignal; 24 | public var _d: int; 25 | private var _f: int; 26 | private var _min:int; 27 | private var _max:int; 28 | private var _c: int; 29 | 30 | public function MassDispatchPerformance() 31 | { 32 | setTimeout(init, 1); 33 | } 34 | 35 | private function init(): void { 36 | stage.frameRate = FPS; 37 | 38 | _out0 = new TextField(); 39 | _out0.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 40 | _out0.autoSize = TextFieldAutoSize.LEFT; 41 | _out0.x = 0x20; 42 | _out0.y = 0x20; 43 | 44 | _out1 = new TextField(); 45 | _out1.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 46 | _out1.autoSize = TextFieldAutoSize.LEFT; 47 | _out1.x = 0x200; 48 | _out1.y = 0x20; 49 | 50 | _s = new DeluxeSignal(); 51 | var t1: int = getTimer(); 52 | for(var i: int = 0; i < NUM_LISTENERS; ++i) _s.addWithPriority(new Target(this).l, i); 53 | _c = (getTimer() - t1); 54 | 55 | addChild(_out0); 56 | addChild(_out1); 57 | 58 | addEventListener(Event.ENTER_FRAME, onEnterFrame); 59 | } 60 | 61 | private function onEnterFrame(event: Event): void 62 | { 63 | var t1: int = getTimer(); 64 | if((t1 - _t0) >= 1000) { 65 | _out0.text = _d+'/'+MAX_SCORE+' = '+Math.round(_d/MAX_SCORE*100.0)+'%\n'+_f+ 66 | 'fps\n'+(System.totalMemory >> 20)+'mb\n'+_min+'ms\n'+_max+'ms\n-> '+_c; 67 | _d = 0; 68 | _f = 0; 69 | _t0 = t1; 70 | } 71 | 72 | _f++; 73 | var m0: int = getTimer(); 74 | _s.dispatch(); 75 | var dt: int = (getTimer() - m0); 76 | if(dt < _min) _min = dt; 77 | if(dt > _max) _max = dt; 78 | _out1.text = dt+'ms'; 79 | } 80 | } 81 | } 82 | 83 | import org.osflash.signals.MassDispatchPerformance; 84 | 85 | class Target { 86 | public var mdp: MassDispatchPerformance; 87 | 88 | public function Target(mdp: MassDispatchPerformance) { 89 | this.mdp = mdp; 90 | } 91 | 92 | public function l(): void { 93 | mdp._d++; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /performance-test/org/osflash/signals/RemovePerformance.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: joa 4 | * Date: 11/22/10 5 | * Time: 4:34 PM 6 | * To change this template use File | Settings | File Templates. 7 | */ 8 | package org.osflash.signals 9 | { 10 | import flash.display.Sprite; 11 | import flash.events.Event; 12 | import flash.system.System; 13 | import flash.text.TextField; 14 | import flash.text.TextFieldAutoSize; 15 | import flash.text.TextFormat; 16 | import flash.utils.getTimer; 17 | 18 | [SWF(width=800, height=600, frameRate=64, backgroundColor=0x333333)] 19 | public class RemovePerformance extends Sprite 20 | { 21 | private var _out0: TextField; 22 | private var _out1: TextField; 23 | private var _s: ISignal; 24 | private var _t0: int; 25 | 26 | private var _f: int; 27 | private var _min:int; 28 | private var _max:int; 29 | 30 | public function RemovePerformance() 31 | { 32 | _out0 = new TextField(); 33 | _out0.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 34 | _out0.autoSize = TextFieldAutoSize.LEFT; 35 | _out0.x = 0x20; 36 | _out0.y = 0x20; 37 | 38 | _out1 = new TextField(); 39 | _out1.defaultTextFormat = new TextFormat('arial', 24, 0xff00ff); 40 | _out1.autoSize = TextFieldAutoSize.LEFT; 41 | _out1.x = 0x200; 42 | _out1.y = 0x20; 43 | 44 | _s = new Signal(); 45 | 46 | addChild(_out0); 47 | addChild(_out1); 48 | 49 | addEventListener(Event.ENTER_FRAME, onEnterFrame); 50 | } 51 | 52 | private function onEnterFrame(event: Event): void 53 | { 54 | var t1: int = getTimer(); 55 | if((t1 - _t0) >= 1000) { 56 | _out0.text = _f+'fps\n'+(System.totalMemory >> 20)+'mb\n'+_min+'ms\n'+_max+'ms'; 57 | _f = 0; 58 | _t0 = t1; 59 | } 60 | 61 | _f++; 62 | var n: int = 5000/4; 63 | var m0: int = getTimer(); 64 | while(--n != 0) { 65 | _s.dispatch(); 66 | _s.add(l0);//2**(4-1)=8 67 | _s.add(l1); 68 | _s.add(l2); 69 | _s.add(l3); 70 | _s.add(l4); 71 | _s.add(l5); 72 | _s.add(l6); 73 | _s.add(l7); 74 | } 75 | var dt: int = (getTimer() - m0); 76 | if(dt < _min) _min = dt; 77 | if(dt > _max) _max = dt; 78 | _out1.text = dt+'ms'; 79 | } 80 | 81 | private function l0(): void { 82 | _s.remove(l0); 83 | } 84 | 85 | private function l1(): void { 86 | _s.remove(l1); 87 | } 88 | 89 | private function l2(): void { 90 | _s.remove(l2); 91 | } 92 | 93 | private function l3(): void { 94 | _s.remove(l3); 95 | } 96 | 97 | private function l4(): void { 98 | _s.remove(l4); 99 | } 100 | 101 | private function l5(): void { 102 | _s.remove(l5); 103 | } 104 | 105 | private function l6(): void { 106 | _s.remove(l6); 107 | } 108 | 109 | private function l7(): void { 110 | _s.remove(l7); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/org/osflash/signals/DeluxeSignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import org.osflash.signals.events.IBubbleEventHandler; 4 | import org.osflash.signals.events.IEvent; 5 | 6 | /** 7 | * Allows the valueClasses to be set in MXML, e.g. 8 | * {[String, uint]} 9 | */ 10 | [DefaultProperty("valueClasses")] 11 | /** 12 | * Signal dispatches events to multiple listeners. 13 | * It is inspired by C# events and delegates, and by 14 | * signals and slots 15 | * in Qt. 16 | * A Signal adds event dispatching functionality through composition and interfaces, 17 | * rather than inheriting from a dispatcher. 18 | *

19 | * Project home: http://github.com/robertpenner/as3-signals/ 20 | */ 21 | public class DeluxeSignal extends PrioritySignal 22 | { 23 | protected var _target:Object; 24 | 25 | /** 26 | * Creates a DeluxeSignal instance to dispatch events on behalf of a target object. 27 | * @param target The object the signal is dispatching events on behalf of. 28 | * @param valueClasses Any number of class references that enable type checks in dispatch(). 29 | * For example, new DeluxeSignal(this, String, uint) 30 | * would allow: signal.dispatch("the Answer", 42) 31 | * but not: signal.dispatch(true, 42.5) 32 | * nor: signal.dispatch() 33 | * 34 | * NOTE: Subclasses cannot call super.apply(null, valueClasses), 35 | * but this constructor has logic to support super(valueClasses). 36 | */ 37 | public function DeluxeSignal(target:Object = null, ...valueClasses) 38 | { 39 | _target = target; 40 | // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). 41 | valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0]:valueClasses; 42 | 43 | super(valueClasses); 44 | } 45 | 46 | /** @inheritDoc */ 47 | public function get target():Object { return _target; } 48 | 49 | public function set target(value:Object):void 50 | { 51 | if (value == _target) return; 52 | removeAll(); 53 | _target = value; 54 | } 55 | 56 | /** 57 | * @inheritDoc 58 | * @throws ArgumentError ArgumentError: Incorrect number of arguments. 59 | * @throws ArgumentError ArgumentError: Value object is not an instance of the appropriate valueClasses Class. 60 | */ 61 | override public function dispatch(...valueObjects):void 62 | { 63 | // Validate value objects against pre-defined value classes. 64 | const numValueClasses:int = _valueClasses.length; 65 | const numValueObjects:int = valueObjects.length; 66 | 67 | if (numValueObjects < numValueClasses) 68 | { 69 | throw new ArgumentError('Incorrect number of arguments. '+ 70 | 'Expected at least '+numValueClasses+' but received '+ 71 | numValueObjects+'.'); 72 | } 73 | 74 | // Cannot dispatch differently typed objects than declared classes. 75 | for (var i:int = 0; i < numValueClasses; i++) 76 | { 77 | // Optimized for the optimistic case that values are correct. 78 | if (valueObjects[i] is _valueClasses[i] || valueObjects[i] === null) 79 | continue; 80 | 81 | throw new ArgumentError('Value object <'+valueObjects[i] 82 | +'> is not an instance of <'+_valueClasses[i]+'>.'); 83 | } 84 | 85 | // Extract and clone event object if necessary. 86 | var event:IEvent = valueObjects[0] as IEvent; 87 | if (event) 88 | { 89 | if (event.target) 90 | { 91 | event = event.clone(); 92 | valueObjects[0] = event; 93 | } 94 | 95 | event.target = target; 96 | event.currentTarget = target; 97 | event.signal = this; 98 | } 99 | 100 | // Broadcast to listeners. 101 | var slotsToProcess:SlotList = slots; 102 | while (slotsToProcess.nonEmpty) 103 | { 104 | slotsToProcess.head.execute(valueObjects); 105 | slotsToProcess = slotsToProcess.tail; 106 | } 107 | 108 | // Bubble the event as far as possible. 109 | if (!event || !event.bubbles) return; 110 | 111 | var currentTarget:Object = target; 112 | 113 | while (currentTarget && currentTarget.hasOwnProperty("parent")) 114 | { 115 | currentTarget = currentTarget["parent"]; 116 | if (!currentTarget) break; 117 | 118 | if (currentTarget is IBubbleEventHandler) 119 | { 120 | // onEventBubbled() can stop the bubbling by returning false. 121 | if (!IBubbleEventHandler(event.currentTarget = currentTarget).onEventBubbled(event)) 122 | break; 123 | } 124 | } 125 | } 126 | 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/org/osflash/signals/IOnceSignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | /** 4 | * 5 | */ 6 | public interface IOnceSignal 7 | { 8 | /** 9 | * An optional array of classes defining the types of parameters sent to listeners. 10 | */ 11 | function get valueClasses():Array; 12 | function set valueClasses(value:Array):void; 13 | 14 | /** The current number of listeners for the signal. */ 15 | function get numListeners():uint; 16 | 17 | /** 18 | * Subscribes a one-time listener for this signal. 19 | * The signal will remove the listener automatically the first time it is called, 20 | * after the dispatch to all listeners is complete. 21 | * @param listener A function with arguments 22 | * that matches the value classes dispatched by the signal. 23 | * If value classes are not specified (e.g. via Signal constructor), dispatch() can be called without arguments. 24 | * @return a ISlot, which contains the Function passed as the parameter 25 | */ 26 | function addOnce(listener:Function):ISlot; 27 | 28 | /** 29 | * Dispatches an object to listeners. 30 | * @param valueObjects Any number of parameters to send to listeners. Will be type-checked against valueClasses. 31 | * @throws ArgumentError ArgumentError: valueObjects are not compatible with valueClasses. 32 | */ 33 | function dispatch(...valueObjects):void; 34 | 35 | /** 36 | * Unsubscribes a listener from the signal. 37 | * @param listener 38 | * @return a ISlot, which contains the Function passed as the parameter 39 | */ 40 | function remove(listener:Function):ISlot; 41 | 42 | /** 43 | * Unsubscribes all listeners from the signal. 44 | */ 45 | function removeAll():void 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/org/osflash/signals/IPrioritySignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | /** 4 | * 5 | */ 6 | public interface IPrioritySignal extends ISignal 7 | { 8 | /** 9 | * Subscribes a listener for the signal. 10 | * After you successfully register an event listener, 11 | * you cannot change its priority through additional calls to add(). 12 | * To change a listener's priority, you must first call remove(). 13 | * Then you can register the listener again with the new priority level. 14 | * @param listener A function with an argument 15 | * that matches the type of event dispatched by the signal. 16 | * If eventClass is not specified, the listener and dispatch() can be called without an argument. 17 | * @return a ISlot, which contains the Function passed as the parameter 18 | * @see ISlot 19 | */ 20 | function addWithPriority(listener:Function, priority:int = 0):ISlot 21 | 22 | /** 23 | * Subscribes a one-time listener for this signal. 24 | * The signal will remove the listener automatically the first time it is called, 25 | * after the dispatch to all listeners is complete. 26 | * @param listener A function with an argument 27 | * that matches the type of event dispatched by the signal. 28 | * If eventClass is not specified, the listener and dispatch() can be called without an argument. 29 | * @param priority The priority level of the event listener. 30 | * The priority is designated by a signed 32-bit integer. 31 | * The higher the number, the higher the priority. 32 | * All listeners with priority n are processed before listeners of priority n-1. 33 | * @return a ISlot, which contains the Function passed as the parameter 34 | * @see ISlot 35 | */ 36 | function addOnceWithPriority(listener:Function, priority:int = 0):ISlot 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/org/osflash/signals/ISignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | /** 4 | * 5 | */ 6 | public interface ISignal extends IOnceSignal 7 | { 8 | /** 9 | * Subscribes a listener for the signal. 10 | * @param listener A function with arguments 11 | * that matches the value classes dispatched by the signal. 12 | * If value classes are not specified (e.g. via Signal constructor), dispatch() can be called without arguments. 13 | * @return a ISlot, which contains the Function passed as the parameter 14 | */ 15 | function add(listener:Function):ISlot; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/osflash/signals/ISlot.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | /** 4 | * The ISlot interface defines the basic properties of a 5 | * listener associated with a Signal. 6 | * 7 | * @author Joa Ebert 8 | * @author Robert Penner 9 | */ 10 | public interface ISlot 11 | { 12 | /** 13 | * The listener associated with this slot. 14 | */ 15 | function get listener():Function; 16 | function set listener(value:Function):void; 17 | 18 | /** 19 | * Allows the ISlot to inject parameters when dispatching. The params will be at 20 | * the tail of the arguments and the ISignal arguments will be at the head. 21 | * 22 | * var signal:ISignal = new Signal(String); 23 | * signal.add(handler).params = [42]; 24 | * signal.dispatch('The Answer'); 25 | * function handler(name:String, num:int):void{} 26 | */ 27 | function get params():Array; 28 | function set params(value:Array):void; 29 | 30 | /** 31 | * Whether this slot is automatically removed after it has been used once. 32 | */ 33 | function get once():Boolean; 34 | 35 | /** 36 | * The priority of this slot should be given in the execution order. 37 | * An IPrioritySignal will call higher numbers before lower ones. 38 | * Defaults to 0. 39 | */ 40 | function get priority():int; 41 | 42 | /** 43 | * Whether the listener is called on execution. Defaults to true. 44 | */ 45 | function get enabled():Boolean; 46 | function set enabled(value:Boolean):void; 47 | 48 | /** 49 | * Executes a listener without arguments. 50 | * Existing params are appended before the listener is called. 51 | */ 52 | function execute0():void; 53 | 54 | /** 55 | * Dispatches one argument to a listener. 56 | * Existing params are appended before the listener is called. 57 | * @param value The argument for the listener. 58 | */ 59 | function execute1(value:Object):void; 60 | 61 | /** 62 | * Executes a listener of arity n where n is 63 | * valueObjects.length. 64 | * Existing params are appended before the listener is called. 65 | * @param valueObjects The array of arguments to be applied to the listener. 66 | */ 67 | function execute(valueObjects:Array):void; 68 | 69 | /** 70 | * Removes the slot from its signal. 71 | */ 72 | function remove():void; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/org/osflash/signals/MonoSignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import flash.errors.IllegalOperationError; 4 | import flash.utils.getQualifiedClassName; 5 | 6 | /** 7 | * Allows the valueClasses to be set in MXML, e.g. 8 | * {[String, uint]} 9 | */ 10 | [DefaultProperty("valueClasses")] 11 | 12 | /** 13 | * A MonoSignal can have only one listener. 14 | */ 15 | public class MonoSignal implements ISignal 16 | { 17 | protected var _valueClasses:Array; // of Class 18 | 19 | protected var slot:Slot; 20 | 21 | /** 22 | * Creates a MonoSignal instance to dispatch value objects. 23 | * @param valueClasses Any number of class references that enable type checks in dispatch(). 24 | * For example, new Signal(String, uint) 25 | * would allow: signal.dispatch("the Answer", 42) 26 | * but not: signal.dispatch(true, 42.5) 27 | * nor: signal.dispatch() 28 | * 29 | * NOTE: Subclasses cannot call super.apply(null, valueClasses), 30 | * but this constructor has logic to support super(valueClasses). 31 | */ 32 | public function MonoSignal(...valueClasses) 33 | { 34 | // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). 35 | this.valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0] : valueClasses; 36 | } 37 | 38 | /** 39 | * @inheritDoc 40 | * @throws ArgumentError ArgumentError: Invalid valueClasses argument: item at index should be a Class but was not. 41 | */ 42 | [ArrayElementType("Class")] 43 | public function get valueClasses():Array { return _valueClasses; } 44 | 45 | public function set valueClasses(value:Array):void 46 | { 47 | // Clone so the Array cannot be affected from outside. 48 | _valueClasses = value ? value.slice() : []; 49 | for (var i:int = _valueClasses.length; i--; ) 50 | { 51 | if (!(_valueClasses[i] is Class)) 52 | { 53 | throw new ArgumentError('Invalid valueClasses argument: ' + 54 | 'item at index ' + i + ' should be a Class but was:<' + 55 | _valueClasses[i] + '>.' + getQualifiedClassName(_valueClasses[i])); 56 | } 57 | } 58 | } 59 | 60 | /** @inheritDoc */ 61 | public function get numListeners():uint { return slot ? 1 : 0; } 62 | 63 | /** 64 | * @inheritDoc 65 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot add or addOnce with a listener already added, remove the current listener first. 66 | * @throws ArgumentError ArgumentError: Given listener is null. 67 | */ 68 | public function add(listener:Function):ISlot 69 | { 70 | return registerListener(listener); 71 | } 72 | 73 | /** 74 | * @inheritDoc 75 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot add or addOnce with a listener already added, remove the current listener first. 76 | * @throws ArgumentError ArgumentError: Given listener is null. 77 | */ 78 | public function addOnce(listener:Function):ISlot 79 | { 80 | return registerListener(listener, true); 81 | } 82 | 83 | /** @inheritDoc */ 84 | public function remove(listener:Function):ISlot 85 | { 86 | if (slot && slot.listener == listener) 87 | { 88 | const theSlot:ISlot = slot; 89 | slot = null; 90 | return theSlot; 91 | } 92 | 93 | return null; 94 | } 95 | 96 | /** @inheritDoc */ 97 | public function removeAll():void 98 | { 99 | if (slot) slot.remove(); 100 | } 101 | 102 | /** 103 | * @inheritDoc 104 | * @throws ArgumentError ArgumentError: Incorrect number of arguments. 105 | * @throws ArgumentError ArgumentError: Value object is not an instance of the appropriate valueClasses Class. 106 | */ 107 | public function dispatch(...valueObjects):void 108 | { 109 | // If valueClasses is empty, value objects are not type-checked. 110 | const numValueClasses:int = _valueClasses.length; 111 | const numValueObjects:int = valueObjects.length; 112 | 113 | // Cannot dispatch fewer objects than declared classes. 114 | if (numValueObjects < numValueClasses) 115 | { 116 | throw new ArgumentError('Incorrect number of arguments. '+ 117 | 'Expected at least '+numValueClasses+' but received '+ 118 | numValueObjects+'.'); 119 | } 120 | 121 | // Cannot dispatch differently typed objects than declared classes. 122 | for (var i:int = 0; i < numValueClasses; i++) 123 | { 124 | // Optimized for the optimistic case that values are correct. 125 | if (valueObjects[i] is _valueClasses[i] || valueObjects[i] === null) 126 | continue; 127 | 128 | throw new ArgumentError('Value object <'+valueObjects[i] 129 | +'> is not an instance of <'+_valueClasses[i]+'>.'); 130 | } 131 | 132 | // Broadcast to the one listener. 133 | if (slot) 134 | { 135 | slot.execute(valueObjects); 136 | } 137 | } 138 | 139 | protected function registerListener(listener:Function, once:Boolean = false):ISlot 140 | { 141 | if (slot) 142 | { 143 | // If the listener exits previously added, definitely don't add it. 144 | throw new IllegalOperationError('You cannot add or addOnce with a listener already added, remove the current listener first.'); 145 | } 146 | 147 | return (slot = new Slot(listener, this, once)); 148 | } 149 | 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/org/osflash/signals/OnceSignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import flash.errors.IllegalOperationError; 4 | import flash.utils.getQualifiedClassName; 5 | 6 | /** 7 | * Allows the valueClasses to be set in MXML, e.g. 8 | * {[String, uint]} 9 | */ 10 | [DefaultProperty("valueClasses")] 11 | 12 | /** 13 | * Signal dispatches events to multiple listeners. 14 | * It is inspired by C# events and delegates, and by 15 | * signals and slots 16 | * in Qt. 17 | * A Signal adds event dispatching functionality through composition and interfaces, 18 | * rather than inheriting from a dispatcher. 19 | *

20 | * Project home: http://github.com/robertpenner/as3-signals/ 21 | */ 22 | public class OnceSignal implements IOnceSignal 23 | { 24 | protected var _valueClasses:Array; // of Class 25 | protected var slots:SlotList = SlotList.NIL; 26 | 27 | /** 28 | * Creates a Signal instance to dispatch value objects. 29 | * @param valueClasses Any number of class references that enable type checks in dispatch(). 30 | * For example, new Signal(String, uint) 31 | * would allow: signal.dispatch("the Answer", 42) 32 | * but not: signal.dispatch(true, 42.5) 33 | * nor: signal.dispatch() 34 | * 35 | * NOTE: In AS3, subclasses cannot call super.apply(null, valueClasses), 36 | * but this constructor has logic to support super(valueClasses). 37 | */ 38 | public function OnceSignal(...valueClasses) 39 | { 40 | // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). 41 | this.valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0] : valueClasses; 42 | } 43 | 44 | /** 45 | * @inheritDoc 46 | * @throws ArgumentError ArgumentError: Invalid valueClasses argument: item at index should be a Class but was not. 47 | */ 48 | [ArrayElementType("Class")] 49 | public function get valueClasses():Array { return _valueClasses; } 50 | 51 | public function set valueClasses(value:Array):void 52 | { 53 | // Clone so the Array cannot be affected from outside. 54 | _valueClasses = value ? value.slice() : []; 55 | for (var i:int = _valueClasses.length; i--; ) 56 | { 57 | if (!(_valueClasses[i] is Class)) 58 | { 59 | throw new ArgumentError('Invalid valueClasses argument: ' + 60 | 'item at index ' + i + ' should be a Class but was:<' + 61 | _valueClasses[i] + '>.' + getQualifiedClassName(_valueClasses[i])); 62 | } 63 | } 64 | } 65 | 66 | /** @inheritDoc */ 67 | public function get numListeners():uint { return slots.length; } 68 | 69 | /** 70 | * @inheritDoc 71 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot addOnce() then add() the same listener without removing the relationship first. 72 | * @throws ArgumentError ArgumentError: Given listener is null. 73 | */ 74 | public function addOnce(listener:Function):ISlot 75 | { 76 | return registerListener(listener, true); 77 | } 78 | 79 | /** @inheritDoc */ 80 | public function remove(listener:Function):ISlot 81 | { 82 | const slot:ISlot = slots.find(listener); 83 | if (!slot) return null; 84 | 85 | slots = slots.filterNot(listener); 86 | return slot; 87 | } 88 | 89 | /** @inheritDoc */ 90 | public function removeAll():void 91 | { 92 | slots = SlotList.NIL; 93 | } 94 | 95 | /** 96 | * @inheritDoc 97 | * @throws ArgumentError ArgumentError: Incorrect number of arguments. 98 | * @throws ArgumentError ArgumentError: Value object is not an instance of the appropriate valueClasses Class. 99 | */ 100 | public function dispatch(...valueObjects):void 101 | { 102 | 103 | // If valueClasses is empty, value objects are not type-checked. 104 | const numValueClasses:int = _valueClasses.length; 105 | const numValueObjects:int = valueObjects.length; 106 | 107 | // Cannot dispatch fewer objects than declared classes. 108 | if (numValueObjects < numValueClasses) 109 | { 110 | throw new ArgumentError('Incorrect number of arguments. '+ 111 | 'Expected at least '+numValueClasses+' but received '+ 112 | numValueObjects+'.'); 113 | } 114 | 115 | // Cannot dispatch differently typed objects than declared classes. 116 | for (var i:int = 0; i < numValueClasses; i++) 117 | { 118 | // Optimized for the optimistic case that values are correct. 119 | if (valueObjects[i] is _valueClasses[i] || valueObjects[i] === null) 120 | continue; 121 | 122 | throw new ArgumentError('Value object <'+valueObjects[i] 123 | +'> is not an instance of <'+_valueClasses[i]+'>.'); 124 | } 125 | 126 | // Broadcast to listeners. 127 | var slotsToProcess:SlotList = slots; 128 | if(slotsToProcess.nonEmpty) 129 | { 130 | while (slotsToProcess.nonEmpty) 131 | { 132 | slotsToProcess.head.execute(valueObjects); 133 | slotsToProcess = slotsToProcess.tail; 134 | } 135 | } 136 | } 137 | 138 | protected function registerListener(listener:Function, once:Boolean = false):ISlot 139 | { 140 | if (registrationPossible(listener, once)) 141 | { 142 | const newSlot:ISlot = new Slot(listener, this, once); 143 | slots = slots.prepend(newSlot); 144 | return newSlot; 145 | } 146 | 147 | return slots.find(listener); 148 | } 149 | 150 | protected function registrationPossible(listener:Function, once:Boolean):Boolean 151 | { 152 | if (!slots.nonEmpty) return true; 153 | 154 | const existingSlot:ISlot = slots.find(listener); 155 | if (!existingSlot) return true; 156 | 157 | if (existingSlot.once != once) 158 | { 159 | // If the listener was previously added, definitely don't add it again. 160 | // But throw an exception if their once values differ. 161 | throw new IllegalOperationError('You cannot addOnce() then add() the same listener without removing the relationship first.'); 162 | } 163 | 164 | return false; // Listener was already registered. 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/org/osflash/signals/PrioritySignal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | public class PrioritySignal extends Signal implements IPrioritySignal 4 | { 5 | 6 | public function PrioritySignal(...valueClasses) 7 | { 8 | // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). 9 | valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0] : valueClasses; 10 | 11 | super(valueClasses); 12 | } 13 | 14 | /** 15 | * @inheritDoc 16 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot addOnce() then add() the same listener without removing the relationship first. 17 | * @throws ArgumentError ArgumentError: Given listener is null. 18 | */ 19 | public function addWithPriority(listener:Function, priority:int = 0):ISlot 20 | { 21 | return registerListenerWithPriority(listener, false, priority); 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot addOnce() then add() the same listener without removing the relationship first. 27 | * @throws ArgumentError ArgumentError: Given listener is null. 28 | */ 29 | public function addOnceWithPriority(listener:Function, priority:int = 0):ISlot 30 | { 31 | return registerListenerWithPriority(listener, true, priority); 32 | } 33 | 34 | override protected function registerListener(listener:Function, once:Boolean = false):ISlot 35 | { 36 | return registerListenerWithPriority(listener, once); 37 | } 38 | 39 | protected function registerListenerWithPriority(listener:Function, once:Boolean = false, priority:int = 0):ISlot 40 | { 41 | if (registrationPossible(listener, once)) 42 | { 43 | const slot:ISlot = new Slot(listener, this, once, priority); 44 | slots = slots.insertWithPriority(slot); 45 | return slot; 46 | } 47 | 48 | return slots.find(listener); 49 | } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/org/osflash/signals/Promise.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import flash.errors.IllegalOperationError; 4 | 5 | import org.osflash.signals.ISlot; 6 | import org.osflash.signals.OnceSignal; 7 | 8 | public class Promise extends OnceSignal 9 | { 10 | private var isDispatched:Boolean; 11 | private var valueObjects:Array; 12 | 13 | /** @inheritDoc */ 14 | override public function addOnce(listener:Function):ISlot 15 | { 16 | var slot:ISlot = super.addOnce(listener); 17 | if (isDispatched) 18 | { 19 | slot.execute(valueObjects); 20 | slot.remove(); 21 | } 22 | 23 | return slot; 24 | } 25 | 26 | /** 27 | * @inheritDoc 28 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot dispatch() a Promise more than once 29 | */ 30 | override public function dispatch(...valueObjects):void 31 | { 32 | if (isDispatched) 33 | { 34 | throw new IllegalOperationError("You cannot dispatch() a Promise more than once"); 35 | } 36 | else 37 | { 38 | isDispatched = true; 39 | this.valueObjects = valueObjects; 40 | super.dispatch.apply(this, valueObjects); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/osflash/signals/Signal.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | 4 | /** 5 | * Allows the valueClasses to be set in MXML, e.g. 6 | * {[String, uint]} 7 | */ 8 | [DefaultProperty("valueClasses")] 9 | 10 | /** 11 | * Signal dispatches events to multiple listeners. 12 | * It is inspired by C# events and delegates, and by 13 | * signals and slots 14 | * in Qt. 15 | * A Signal adds event dispatching functionality through composition and interfaces, 16 | * rather than inheriting from a dispatcher. 17 | *

18 | * Project home: http://github.com/robertpenner/as3-signals/ 19 | */ 20 | public class Signal extends OnceSignal implements ISignal 21 | { 22 | /** 23 | * Creates a Signal instance to dispatch value objects. 24 | * @param valueClasses Any number of class references that enable type checks in dispatch(). 25 | * For example, new Signal(String, uint) 26 | * would allow: signal.dispatch("the Answer", 42) 27 | * but not: signal.dispatch(true, 42.5) 28 | * nor: signal.dispatch() 29 | * 30 | * NOTE: In AS3, subclasses cannot call super.apply(null, valueClasses), 31 | * but this constructor has logic to support super(valueClasses). 32 | */ 33 | public function Signal(...valueClasses) 34 | { 35 | // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). 36 | valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0]:valueClasses; 37 | 38 | super(valueClasses); 39 | } 40 | 41 | /** 42 | * @inheritDoc 43 | * @throws flash.errors.IllegalOperationError IllegalOperationError: You cannot addOnce() then add() the same listener without removing the relationship first. 44 | * @throws ArgumentError ArgumentError: Given listener is null. 45 | */ 46 | public function add(listener:Function):ISlot 47 | { 48 | return registerListener(listener); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/org/osflash/signals/Slot.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | /** 4 | * The Slot class represents a signal slot. 5 | * 6 | * @author Robert Penner 7 | * @author Joa Ebert 8 | */ 9 | public class Slot implements ISlot 10 | { 11 | protected var _signal:IOnceSignal; 12 | protected var _enabled:Boolean = true; 13 | protected var _listener:Function; 14 | protected var _once:Boolean = false; 15 | protected var _priority:int = 0; 16 | protected var _params:Array; 17 | 18 | /** 19 | * Creates and returns a new Slot object. 20 | * 21 | * @param listener The listener associated with the slot. 22 | * @param signal The signal associated with the slot. 23 | * @param once Whether or not the listener should be executed only once. 24 | * @param priority The priority of the slot. 25 | * 26 | * @throws ArgumentError ArgumentError: Given listener is null. 27 | * @throws Error Error: Internal signal reference has not been set yet. 28 | */ 29 | public function Slot(listener:Function, signal:IOnceSignal, once:Boolean = false, priority:int = 0) 30 | { 31 | _listener = listener; 32 | _once = once; 33 | _signal = signal; 34 | _priority = priority; 35 | 36 | verifyListener(listener); 37 | } 38 | 39 | /** 40 | * @inheritDoc 41 | */ 42 | public function execute0():void 43 | { 44 | if (!_enabled) return; 45 | if (_once) remove(); 46 | if (_params && _params.length) 47 | { 48 | _listener.apply(null, _params); 49 | return; 50 | } 51 | _listener(); 52 | } 53 | 54 | /** 55 | * @inheritDoc 56 | */ 57 | public function execute1(value:Object):void 58 | { 59 | if (!_enabled) return; 60 | if (_once) remove(); 61 | if (_params && _params.length) 62 | { 63 | _listener.apply(null, [value].concat(_params)); 64 | return; 65 | } 66 | _listener(value); 67 | } 68 | 69 | /** 70 | * @inheritDoc 71 | */ 72 | public function execute(valueObjects:Array):void 73 | { 74 | if (!_enabled) return; 75 | if (_once) remove(); 76 | 77 | // If we have parameters, add them to the valueObject 78 | // Note: This could be expensive if we're after the fastest dispatch possible. 79 | if (_params && _params.length) 80 | { 81 | valueObjects = valueObjects.concat(_params); 82 | } 83 | 84 | // NOTE: simple ifs are faster than switch: http://jacksondunstan.com/articles/1007 85 | const numValueObjects:int = valueObjects.length; 86 | if (numValueObjects == 0) 87 | { 88 | _listener(); 89 | } 90 | else if (numValueObjects == 1) 91 | { 92 | _listener(valueObjects[0]); 93 | } 94 | else if (numValueObjects == 2) 95 | { 96 | _listener(valueObjects[0], valueObjects[1]); 97 | } 98 | else if (numValueObjects == 3) 99 | { 100 | _listener(valueObjects[0], valueObjects[1], valueObjects[2]); 101 | } 102 | else 103 | { 104 | _listener.apply(null, valueObjects); 105 | } 106 | } 107 | 108 | /** 109 | * @inheritDoc 110 | * @throws ArgumentError ArgumentError: Given listener is null. Did you want to set enabled to false instead? 111 | * @throws Error Error: Internal signal reference has not been set yet. 112 | */ 113 | public function get listener():Function 114 | { 115 | return _listener; 116 | } 117 | 118 | public function set listener(value:Function):void 119 | { 120 | if (null == value) throw new ArgumentError( 121 | 'Given listener is null.\nDid you want to set enabled to false instead?'); 122 | 123 | verifyListener(value); 124 | _listener = value; 125 | } 126 | 127 | /** 128 | * @inheritDoc 129 | */ 130 | public function get once():Boolean { return _once; } 131 | 132 | /** 133 | * @inheritDoc 134 | */ 135 | public function get priority():int { return _priority; } 136 | 137 | /** 138 | * Creates and returns the string representation of the current object. 139 | * 140 | * @return The string representation of the current object. 141 | */ 142 | public function toString():String 143 | { 144 | return "[Slot listener: "+_listener+", once: "+_once 145 | +", priority: "+_priority+", enabled: "+_enabled+"]"; 146 | } 147 | 148 | /** 149 | * @inheritDoc 150 | */ 151 | public function get enabled():Boolean { return _enabled; } 152 | 153 | public function set enabled(value:Boolean):void { _enabled = value; } 154 | 155 | /** 156 | * @inheritDoc 157 | */ 158 | public function get params():Array { return _params; } 159 | 160 | public function set params(value:Array):void { _params = value; } 161 | 162 | /** 163 | * @inheritDoc 164 | */ 165 | public function remove():void 166 | { 167 | _signal.remove(_listener); 168 | } 169 | 170 | protected function verifyListener(listener:Function): void 171 | { 172 | if (null == listener) 173 | { 174 | throw new ArgumentError('Given listener is null.'); 175 | } 176 | 177 | if (null == _signal) 178 | { 179 | throw new Error('Internal signal reference has not been set yet.'); 180 | } 181 | 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/SlotList.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | /** 4 | * The SlotList class represents an immutable list of Slot objects. 5 | * 6 | * @author Joa Ebert 7 | * @author Robert Penner 8 | */ 9 | public final class SlotList 10 | { 11 | /** 12 | * Represents an empty list. Used as the list terminator. 13 | */ 14 | public static const NIL:SlotList = new SlotList(null, null); 15 | 16 | /** 17 | * Creates and returns a new SlotList object. 18 | * 19 | *

A user never has to create a SlotList manually. 20 | * Use the NIL element to represent an empty list. 21 | * NIL.prepend(value) would create a list containing value

. 22 | * 23 | * @param head The first slot in the list. 24 | * @param tail A list containing all slots except head. 25 | * 26 | * @throws ArgumentError ArgumentError: Parameters head and tail are null. Use the NIL element instead. 27 | * @throws ArgumentError ArgumentError: Parameter head cannot be null. 28 | */ 29 | public function SlotList(head:ISlot, tail:SlotList = null) 30 | { 31 | if (!head && !tail) 32 | { 33 | if (NIL) 34 | throw new ArgumentError('Parameters head and tail are null. Use the NIL element instead.'); 35 | 36 | //this is the NIL element as per definition 37 | nonEmpty = false; 38 | } 39 | else if (!head) 40 | { 41 | throw new ArgumentError('Parameter head cannot be null.'); 42 | } 43 | else 44 | { 45 | this.head = head; 46 | this.tail = tail || NIL; 47 | nonEmpty = true; 48 | } 49 | } 50 | 51 | // Although those variables are not const, they would be if AS3 would handle it correctly. 52 | public var head:ISlot; 53 | public var tail:SlotList; 54 | public var nonEmpty:Boolean = false; 55 | 56 | /** 57 | * The number of slots in the list. 58 | */ 59 | public function get length():uint 60 | { 61 | if (!nonEmpty) return 0; 62 | if (tail == NIL) return 1; 63 | 64 | // We could cache the length, but it would make methods like filterNot unnecessarily complicated. 65 | // Instead we assume that O(n) is okay since the length property is used in rare cases. 66 | // We could also cache the length lazy, but that is a waste of another 8b per list node (at least). 67 | 68 | var result:uint = 0; 69 | var p:SlotList = this; 70 | 71 | while (p.nonEmpty) 72 | { 73 | ++result; 74 | p = p.tail; 75 | } 76 | 77 | return result; 78 | } 79 | 80 | /** 81 | * Prepends a slot to this list. 82 | * @param slot The item to be prepended. 83 | * @return A list consisting of slot followed by all elements of this list. 84 | * 85 | * @throws ArgumentError ArgumentError: Parameter head cannot be null. 86 | */ 87 | public function prepend(slot:ISlot):SlotList 88 | { 89 | return new SlotList(slot, this); 90 | } 91 | 92 | /** 93 | * Appends a slot to this list. 94 | * Note: appending is O(n). Where possible, prepend which is O(1). 95 | * In some cases, many list items must be cloned to 96 | * avoid changing existing lists. 97 | * @param slot The item to be appended. 98 | * @return A list consisting of all elements of this list followed by slot. 99 | */ 100 | public function append(slot:ISlot):SlotList 101 | { 102 | if (!slot) return this; 103 | if (!nonEmpty) return new SlotList(slot); 104 | // Special case: just one slot currently in the list. 105 | if (tail == NIL) 106 | return new SlotList(slot).prepend(head); 107 | 108 | // The list already has two or more slots. 109 | // We have to build a new list with cloned items because they are immutable. 110 | const wholeClone:SlotList = new SlotList(head); 111 | var subClone:SlotList = wholeClone; 112 | var current:SlotList = tail; 113 | 114 | while (current.nonEmpty) 115 | { 116 | subClone = subClone.tail = new SlotList(current.head); 117 | current = current.tail; 118 | } 119 | // Append the new slot last. 120 | subClone.tail = new SlotList(slot); 121 | return wholeClone; 122 | } 123 | 124 | /** 125 | * Insert a slot into the list in a position according to its priority. 126 | * The higher the priority, the closer the item will be inserted to the list head. 127 | * @params slot The item to be inserted. 128 | * 129 | * @throws ArgumentError ArgumentError: Parameters head and tail are null. Use the NIL element instead. 130 | * @throws ArgumentError ArgumentError: Parameter head cannot be null. 131 | */ 132 | public function insertWithPriority(slot:ISlot):SlotList 133 | { 134 | if (!nonEmpty) return new SlotList(slot); 135 | 136 | const priority:int = slot.priority; 137 | // Special case: new slot has the highest priority. 138 | if (priority > this.head.priority) return prepend(slot); 139 | 140 | const wholeClone:SlotList = new SlotList(head); 141 | var subClone:SlotList = wholeClone; 142 | var current:SlotList = tail; 143 | 144 | // Find a slot with lower priority and go in front of it. 145 | while (current.nonEmpty) 146 | { 147 | if (priority > current.head.priority) 148 | { 149 | subClone.tail = current.prepend(slot); 150 | return wholeClone; 151 | } 152 | subClone = subClone.tail = new SlotList(current.head); 153 | current = current.tail; 154 | } 155 | 156 | // Slot has lowest priority. 157 | subClone.tail = new SlotList(slot); 158 | return wholeClone; 159 | } 160 | 161 | /** 162 | * Returns the slots in this list that do not contain the supplied listener. 163 | * Note: assumes the listener is not repeated within the list. 164 | * @param listener The function to remove. 165 | * @return A list consisting of all elements of this list that do not have listener. 166 | */ 167 | public function filterNot(listener:Function):SlotList 168 | { 169 | if (!nonEmpty || listener == null) return this; 170 | 171 | if (listener == head.listener) return tail; 172 | 173 | // The first item wasn't a match so the filtered list will contain it. 174 | const wholeClone:SlotList = new SlotList(head); 175 | var subClone:SlotList = wholeClone; 176 | var current:SlotList = tail; 177 | 178 | while (current.nonEmpty) 179 | { 180 | if (current.head.listener == listener) 181 | { 182 | // Splice out the current head. 183 | subClone.tail = current.tail; 184 | return wholeClone; 185 | } 186 | 187 | subClone = subClone.tail = new SlotList(current.head); 188 | current = current.tail; 189 | } 190 | 191 | // The listener was not found so this list is unchanged. 192 | return this; 193 | } 194 | 195 | /** 196 | * Determines whether the supplied listener Function is contained within this list 197 | */ 198 | public function contains(listener:Function):Boolean 199 | { 200 | if (!nonEmpty) return false; 201 | 202 | var p:SlotList = this; 203 | while (p.nonEmpty) 204 | { 205 | if (p.head.listener == listener) return true; 206 | p = p.tail; 207 | } 208 | 209 | return false; 210 | } 211 | 212 | /** 213 | * Retrieves the ISlot associated with a supplied listener within the SlotList. 214 | * @param listener The Function being searched for 215 | * @return The ISlot in this list associated with the listener parameter through the ISlot.listener property. 216 | * Returns null if no such ISlot instance exists or the list is empty. 217 | */ 218 | public function find(listener:Function):ISlot 219 | { 220 | if (!nonEmpty) return null; 221 | 222 | var p:SlotList = this; 223 | while (p.nonEmpty) 224 | { 225 | if (p.head.listener == listener) return p.head; 226 | p = p.tail; 227 | } 228 | 229 | return null; 230 | } 231 | 232 | public function toString():String 233 | { 234 | var buffer:String = ''; 235 | var p:SlotList = this; 236 | 237 | while (p.nonEmpty) 238 | { 239 | buffer += p.head + " -> "; 240 | p = p.tail; 241 | } 242 | 243 | buffer += "NIL"; 244 | 245 | return "[List "+buffer+"]"; 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/org/osflash/signals/events/GenericEvent.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.events 2 | { 3 | import org.osflash.signals.IPrioritySignal; 4 | 5 | /** 6 | * 7 | * @see org.osflash.signals.events.IEvent 8 | * Documentation for the event interface being maintained in IEvent to avoid duplication for now. 9 | */ 10 | public class GenericEvent implements IEvent 11 | { 12 | protected var _bubbles:Boolean; 13 | protected var _target:Object; 14 | protected var _currentTarget:Object; 15 | protected var _signal:IPrioritySignal; 16 | 17 | public function GenericEvent(bubbles:Boolean = false) 18 | { 19 | _bubbles = bubbles; 20 | } 21 | 22 | /** @inheritDoc */ 23 | public function get signal():IPrioritySignal { return _signal; } 24 | public function set signal(value:IPrioritySignal):void { _signal = value; } 25 | 26 | /** @inheritDoc */ 27 | public function get target():Object { return _target; } 28 | public function set target(value:Object):void { _target = value; } 29 | 30 | /** @inheritDoc */ 31 | public function get currentTarget():Object { return _currentTarget; } 32 | public function set currentTarget(value:Object):void { _currentTarget = value; } 33 | 34 | /** @inheritDoc */ 35 | public function get bubbles():Boolean { return _bubbles; } 36 | public function set bubbles(value:Boolean):void { _bubbles = value; } 37 | 38 | /** @inheritDoc */ 39 | public function clone():IEvent 40 | { 41 | return new GenericEvent(_bubbles); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/osflash/signals/events/IBubbleEventHandler.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.events 2 | { 3 | 4 | public interface IBubbleEventHandler 5 | { 6 | /** 7 | * Handler for event bubbling. 8 | * It's left to the IBubbleEventHandler to decide what to do with the event. 9 | * @param event The event that bubbled up. 10 | * @return whether to continue bubbling this event 11 | */ 12 | function onEventBubbled(event:IEvent):Boolean; 13 | } 14 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/events/IEvent.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.events 2 | { 3 | import org.osflash.signals.IPrioritySignal; 4 | 5 | public interface IEvent 6 | { 7 | /** The object that originally dispatched the event. 8 | * When dispatched from an signal, the target is the object containing the signal. */ 9 | function get target():Object; 10 | function set target(value:Object):void; 11 | 12 | /** The object that added the listener for the event. */ 13 | function get currentTarget():Object; 14 | function set currentTarget(value:Object):void; 15 | 16 | /** The signal that dispatched the event. */ 17 | function get signal():IPrioritySignal; 18 | function set signal(value:IPrioritySignal):void; 19 | 20 | /** Indicates whether the event is a bubbling event. */ 21 | function get bubbles():Boolean; 22 | function set bubbles(value:Boolean):void; 23 | 24 | /** Returns a new copy of the instance. */ 25 | function clone():IEvent; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/INativeDispatcher.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import org.osflash.signals.IPrioritySignal; 4 | 5 | import flash.events.Event; 6 | import flash.events.IEventDispatcher; 7 | 8 | /** 9 | * Similar to IDispatcher but using strong types specific to Flash's native event system. 10 | */ 11 | public interface INativeDispatcher extends IPrioritySignal 12 | { 13 | /** 14 | * The type of event permitted to be dispatched. Corresponds to flash.events.Event.type. 15 | */ 16 | function get eventType():String; 17 | 18 | /** 19 | * The class of event permitted to be dispatched. Will be flash.events.Event or a subclass. 20 | */ 21 | function get eventClass():Class; 22 | 23 | /** 24 | * The object considered the source of the dispatched events. 25 | */ 26 | function get target():IEventDispatcher; 27 | 28 | function set target(value:IEventDispatcher):void; 29 | 30 | /** 31 | * Dispatches an event to listeners. 32 | * @param event An instance of a class that is or extends flash.events.Event. 33 | * @throws ArgumentError ArgumentError: Event object is null. 34 | * @throws ArgumentError ArgumentError: Event object [event] is not an instance of [eventClass]. 35 | * @throws ArgumentError ArgumentError: Event object has incorrect type. Expected [eventType] but was [event.type]. 36 | * @throws ArgumentError ArgumentError: Target object cannot be null. 37 | */ 38 | function dispatchEvent(event:Event):Boolean; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalBitmap.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import org.osflash.signals.natives.sets.DisplayObjectSignalSet; 4 | import flash.display.Bitmap; 5 | 6 | /** 7 | * @author Simon Richardson - me@simonrichardson.info 8 | */ 9 | public class SignalBitmap extends Bitmap 10 | { 11 | private var _signals:DisplayObjectSignalSet; 12 | 13 | public function get signals():DisplayObjectSignalSet 14 | { 15 | return _signals ||= new DisplayObjectSignalSet(this); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalMovieClip.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import org.osflash.signals.natives.sets.InteractiveObjectSignalSet; 4 | import flash.display.MovieClip; 5 | 6 | public class SignalMovieClip extends MovieClip 7 | { 8 | private var _signals:InteractiveObjectSignalSet; 9 | 10 | public function get signals():InteractiveObjectSignalSet 11 | { 12 | return _signals ||= new InteractiveObjectSignalSet(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalShape.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import org.osflash.signals.natives.sets.DisplayObjectSignalSet; 4 | 5 | import flash.display.Shape; 6 | 7 | /** 8 | * @author Simon Richardson - me@simonrichardson.info 9 | */ 10 | public class SignalShape extends Shape 11 | { 12 | 13 | private var _signals:DisplayObjectSignalSet; 14 | 15 | public function get signals():DisplayObjectSignalSet 16 | { 17 | return _signals ||= new DisplayObjectSignalSet(this); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalSocket.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import flash.net.Socket; 4 | import org.osflash.signals.natives.sets.SocketSignalSet; 5 | 6 | public class SignalSocket extends Socket 7 | { 8 | private var _signals:SocketSignalSet; 9 | 10 | public function get signals():SocketSignalSet 11 | { 12 | return _signals ||= new SocketSignalSet(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalSprite.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import org.osflash.signals.natives.sets.InteractiveObjectSignalSet; 4 | import flash.display.Sprite; 5 | 6 | public class SignalSprite extends Sprite 7 | { 8 | private var _signals:InteractiveObjectSignalSet; 9 | 10 | public function get signals():InteractiveObjectSignalSet 11 | { 12 | return _signals ||= new InteractiveObjectSignalSet(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalTextField.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import flash.text.TextField; 4 | import org.osflash.signals.natives.sets.TextFieldSignalSet; 5 | 6 | public class SignalTextField extends TextField 7 | { 8 | private var _signals:TextFieldSignalSet; 9 | 10 | public function get signals():TextFieldSignalSet 11 | { 12 | return _signals ||= new TextFieldSignalSet(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalTimer.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import flash.utils.Timer; 4 | import org.osflash.signals.natives.sets.TimerSignalSet; 5 | 6 | public class SignalTimer extends Timer 7 | { 8 | private var _signals:TimerSignalSet; 9 | 10 | public function get signals():TimerSignalSet 11 | { 12 | return _signals ||= new TimerSignalSet(this); 13 | } 14 | 15 | public function SignalTimer(delay:Number, repeatCount:int = 0) 16 | { 17 | super(delay, repeatCount); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalURLLoader.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import flash.net.URLLoader; 4 | import org.osflash.signals.natives.sets.URLLoaderSignalSet; 5 | 6 | public class SignalURLLoader extends URLLoader 7 | { 8 | private var _signals:URLLoaderSignalSet; 9 | 10 | public function get signals():URLLoaderSignalSet 11 | { 12 | return _signals ||= new URLLoaderSignalSet(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/base/SignalXMLSocket.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import flash.net.XMLSocket; 4 | import org.osflash.signals.natives.sets.XMLSocketSignalSet; 5 | 6 | public class SignalXMLSocket extends XMLSocket 7 | { 8 | private var _signals:XMLSocketSignalSet; 9 | 10 | public function get signals():XMLSocketSignalSet 11 | { 12 | return _signals ||= new XMLSocketSignalSet(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/DisplayObjectSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import org.osflash.signals.natives.NativeSignal; 4 | 5 | import flash.display.DisplayObject; 6 | import flash.events.Event; 7 | 8 | /** 9 | * @author Jon Adams 10 | */ 11 | public class DisplayObjectSignalSet extends EventDispatcherSignalSet 12 | { 13 | 14 | public function DisplayObjectSignalSet(target:DisplayObject) 15 | { 16 | super(target); 17 | } 18 | 19 | public function get added():NativeSignal 20 | { 21 | return getNativeSignal(Event.ADDED); 22 | } 23 | public function get addedToStage():NativeSignal 24 | { 25 | return getNativeSignal(Event.ADDED_TO_STAGE); 26 | } 27 | public function get enterFrame():NativeSignal 28 | { 29 | return getNativeSignal(Event.ENTER_FRAME); 30 | } 31 | public function get exitFrame():NativeSignal 32 | { 33 | // Using a string here because we need to target FP9 34 | return getNativeSignal("exitFrame"); 35 | } 36 | 37 | public function get frameConstructed():NativeSignal 38 | { 39 | // Using a string here because we need to target FP9 40 | return getNativeSignal("frameConstructed"); 41 | } 42 | 43 | public function get removed():NativeSignal 44 | { 45 | return getNativeSignal(Event.REMOVED); 46 | } 47 | public function get removedFromStage():NativeSignal 48 | { 49 | return getNativeSignal(Event.REMOVED_FROM_STAGE); 50 | } 51 | public function get render():NativeSignal 52 | { 53 | return getNativeSignal(Event.RENDER); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/EventDispatcherSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import org.osflash.signals.natives.NativeSignal; 4 | 5 | import flash.events.Event; 6 | import flash.events.EventDispatcher; 7 | 8 | /** 9 | * @author Jon Adams 10 | */ 11 | public class EventDispatcherSignalSet extends NativeSignalSet 12 | { 13 | public function EventDispatcherSignalSet(target:EventDispatcher) 14 | { 15 | super(target); 16 | } 17 | 18 | public function get activate():NativeSignal 19 | { 20 | return getNativeSignal(Event.ACTIVATE); 21 | } 22 | 23 | public function get deactivate():NativeSignal 24 | { 25 | return getNativeSignal(Event.DEACTIVATE); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/FileReferenceListSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.net.FileReference; 6 | 7 | /** 8 | * @author Jon Adams 9 | */ 10 | public class FileReferenceListSignalSet extends EventDispatcherSignalSet { 11 | 12 | public function FileReferenceListSignalSet(target:FileReference) { 13 | super(target); 14 | } 15 | 16 | public function get cancel():NativeSignal { 17 | return getNativeSignal(Event.CANCEL); 18 | } 19 | 20 | public function get select():NativeSignal { 21 | return getNativeSignal(Event.SELECT); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/FileReferenceSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.DataEvent; 5 | import flash.events.Event; 6 | import flash.events.HTTPStatusEvent; 7 | import flash.events.IOErrorEvent; 8 | import flash.events.ProgressEvent; 9 | import flash.events.SecurityErrorEvent; 10 | import flash.net.FileReference; 11 | 12 | /** 13 | * @author Jon Adams 14 | */ 15 | public class FileReferenceSignalSet extends EventDispatcherSignalSet { 16 | 17 | public function FileReferenceSignalSet(target:FileReference) { 18 | super(target); 19 | } 20 | 21 | public function get cancel():NativeSignal { 22 | return getNativeSignal(Event.CANCEL); 23 | } 24 | public function get complete():NativeSignal { 25 | return getNativeSignal(Event.COMPLETE); 26 | } 27 | 28 | public function get httpStatus():NativeSignal { 29 | return getNativeSignal(HTTPStatusEvent.HTTP_STATUS, HTTPStatusEvent); 30 | } 31 | 32 | public function get ioError():NativeSignal { 33 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 34 | } 35 | 36 | public function get open():NativeSignal { 37 | return getNativeSignal(Event.OPEN); 38 | } 39 | 40 | public function get progress():NativeSignal { 41 | return getNativeSignal(ProgressEvent.PROGRESS, ProgressEvent); 42 | } 43 | 44 | public function get securityError():NativeSignal { 45 | return getNativeSignal(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorEvent); 46 | } 47 | public function get select():NativeSignal { 48 | return getNativeSignal(Event.SELECT); 49 | } 50 | public function get uploadCompleteData():NativeSignal { 51 | return getNativeSignal(DataEvent.UPLOAD_COMPLETE_DATA, DataEvent); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/InteractiveObjectSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import org.osflash.signals.natives.NativeSignal; 4 | 5 | import flash.display.InteractiveObject; 6 | import flash.events.Event; 7 | import flash.events.FocusEvent; 8 | import flash.events.KeyboardEvent; 9 | import flash.events.MouseEvent; 10 | import flash.events.TextEvent; 11 | 12 | /** 13 | * @author Jon Adams 14 | */ 15 | public class InteractiveObjectSignalSet extends DisplayObjectSignalSet 16 | { 17 | 18 | public function InteractiveObjectSignalSet(target:InteractiveObject) 19 | { 20 | super(target); 21 | } 22 | 23 | public function get click():NativeSignal 24 | { 25 | return getNativeSignal(MouseEvent.CLICK, MouseEvent); 26 | } 27 | 28 | public function get doubleClick():NativeSignal 29 | { 30 | return getNativeSignal(MouseEvent.DOUBLE_CLICK, MouseEvent); 31 | } 32 | 33 | public function get focusIn():NativeSignal 34 | { 35 | return getNativeSignal(FocusEvent.FOCUS_IN, FocusEvent); 36 | } 37 | 38 | public function get focusOut():NativeSignal 39 | { 40 | return getNativeSignal(FocusEvent.FOCUS_OUT, FocusEvent); 41 | } 42 | 43 | public function get keyDown():NativeSignal 44 | { 45 | return getNativeSignal(KeyboardEvent.KEY_DOWN, KeyboardEvent); 46 | } 47 | 48 | public function get keyFocusChange():NativeSignal 49 | { 50 | return getNativeSignal(FocusEvent.KEY_FOCUS_CHANGE, FocusEvent); 51 | } 52 | 53 | public function get keyUp():NativeSignal 54 | { 55 | return getNativeSignal(KeyboardEvent.KEY_UP, KeyboardEvent); 56 | } 57 | 58 | public function get mouseDown():NativeSignal 59 | { 60 | return getNativeSignal(MouseEvent.MOUSE_DOWN, MouseEvent); 61 | } 62 | 63 | public function get mouseFocusChange():NativeSignal 64 | { 65 | return getNativeSignal(FocusEvent.MOUSE_FOCUS_CHANGE, FocusEvent); 66 | } 67 | 68 | public function get mouseMove():NativeSignal 69 | { 70 | return getNativeSignal(MouseEvent.MOUSE_MOVE, MouseEvent); 71 | } 72 | 73 | public function get mouseOut():NativeSignal 74 | { 75 | return getNativeSignal(MouseEvent.MOUSE_OUT, MouseEvent); 76 | } 77 | 78 | public function get mouseOver():NativeSignal 79 | { 80 | return getNativeSignal(MouseEvent.MOUSE_OVER, MouseEvent); 81 | } 82 | 83 | public function get mouseUp():NativeSignal 84 | { 85 | return getNativeSignal(MouseEvent.MOUSE_UP, MouseEvent); 86 | } 87 | 88 | public function get mouseWheel():NativeSignal 89 | { 90 | return getNativeSignal(MouseEvent.MOUSE_WHEEL, MouseEvent); 91 | } 92 | 93 | public function get rollOut():NativeSignal 94 | { 95 | return getNativeSignal(MouseEvent.ROLL_OUT, MouseEvent); 96 | } 97 | 98 | public function get rollOver():NativeSignal 99 | { 100 | return getNativeSignal(MouseEvent.ROLL_OVER, MouseEvent); 101 | } 102 | 103 | public function get tabChildrenChange():NativeSignal 104 | { 105 | return getNativeSignal(Event.TAB_CHILDREN_CHANGE); 106 | } 107 | 108 | public function get tabEnabledChange():NativeSignal 109 | { 110 | return getNativeSignal(Event.TAB_ENABLED_CHANGE); 111 | } 112 | 113 | public function get tabIndexChange():NativeSignal 114 | { 115 | return getNativeSignal(Event.TAB_INDEX_CHANGE); 116 | } 117 | 118 | public function get textInput():NativeSignal 119 | { 120 | return getNativeSignal(TextEvent.TEXT_INPUT, TextEvent); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/LoaderInfoSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.display.LoaderInfo; 5 | import flash.events.Event; 6 | import flash.events.HTTPStatusEvent; 7 | import flash.events.IOErrorEvent; 8 | import flash.events.ProgressEvent; 9 | 10 | /** 11 | * @author Jon Adams 12 | */ 13 | public class LoaderInfoSignalSet extends EventDispatcherSignalSet { 14 | 15 | public function LoaderInfoSignalSet(target:LoaderInfo) { 16 | super(target); 17 | } 18 | 19 | public function get complete():NativeSignal { 20 | return getNativeSignal(Event.COMPLETE); 21 | } 22 | 23 | public function get httpStatus():NativeSignal { 24 | return getNativeSignal(HTTPStatusEvent.HTTP_STATUS, HTTPStatusEvent); 25 | } 26 | 27 | public function get init():NativeSignal { 28 | return getNativeSignal(Event.INIT); 29 | } 30 | public function get ioError():NativeSignal { 31 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 32 | } 33 | 34 | public function get open():NativeSignal { 35 | return getNativeSignal(Event.OPEN); 36 | } 37 | 38 | public function get progress():NativeSignal { 39 | return getNativeSignal(ProgressEvent.PROGRESS, ProgressEvent); 40 | } 41 | 42 | public function get unload():NativeSignal { 43 | return getNativeSignal(Event.UNLOAD); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/MicrophoneSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.ActivityEvent; 5 | import flash.events.StatusEvent; 6 | import flash.media.Microphone; 7 | 8 | /** 9 | * @author Jon Adams 10 | */ 11 | public class MicrophoneSignalSet extends EventDispatcherSignalSet { 12 | 13 | public function MicrophoneSignalSet(target:Microphone) { 14 | super(target); 15 | } 16 | 17 | public function get activity():NativeSignal { 18 | return getNativeSignal(ActivityEvent.ACTIVITY, ActivityEvent); 19 | } 20 | public function get status():NativeSignal { 21 | return getNativeSignal(StatusEvent.STATUS, StatusEvent); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/NativeSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import org.osflash.signals.natives.INativeDispatcher; 4 | import org.osflash.signals.natives.NativeSignal; 5 | 6 | import flash.events.Event; 7 | import flash.events.IEventDispatcher; 8 | import flash.utils.Dictionary; 9 | 10 | /** 11 | * A convenient way to access a logical set of signals. 12 | * 13 | * @author Jon Adams 14 | * 15 | * @example SignalSets allow you to get predefined signals for many built in events 16 | * 17 | package { 18 | import org.osflash.signals.natives.sets.InteractiveObjectSignalSet; 19 | 20 | import flash.display.Sprite; 21 | import flash.events.Event; 22 | 23 | public class Example extends Sprite { 24 | 25 | private var button:Sprite; 26 | private var buttonSignals:InteractiveObjectSignalSet; 27 | 28 | public function Main() { 29 | button = new Sprite(); 30 | button.graphics.beginFill(0xff0000); 31 | button.graphics.drawRect(0, 0, 100, 100); 32 | button.graphics.endFill(); 33 | 34 | buttonSignals = new InteractiveObjectSignalSet(button); 35 | buttonSignals.click.add(handler); 36 | buttonSignals.addedToStage.add(handler); 37 | buttonSignals.enterFrame.addOnce(handler); 38 | 39 | addChild(button); 40 | } 41 | 42 | private function handler(event:Event):void { 43 | trace(event.target, "fired", event.type); 44 | } 45 | } 46 | } 47 | * 48 | */ 49 | public class NativeSignalSet 50 | { 51 | protected var target:IEventDispatcher; 52 | 53 | protected const _signals:Dictionary = new Dictionary(); 54 | 55 | public function NativeSignalSet(target:IEventDispatcher) 56 | { 57 | this.target = target; 58 | } 59 | 60 | /** 61 | * Lazily instantiates a NativeSignal 62 | * @throws ArgumentError ArgumentError: eventType must not be null. 63 | */ 64 | public function getNativeSignal(eventType:String, eventClass:Class = null):NativeSignal 65 | { 66 | if(null == eventType) throw new ArgumentError('eventType must not be null.'); 67 | 68 | return _signals[eventType] ||= new NativeSignal(target, eventType, eventClass || Event); 69 | } 70 | 71 | /** 72 | * The current number of listeners for the signal. 73 | */ 74 | public function get numListeners():int 75 | { 76 | // TODO : This is horrid, it's very expensive to call this if there is a lot of signals. 77 | var count:int = 0; 78 | for each (var signal:INativeDispatcher in _signals) 79 | { 80 | count += signal.numListeners; 81 | } 82 | return count; 83 | } 84 | 85 | /** 86 | * The signals in the SignalSet as an Array. 87 | */ 88 | public function get signals():Array 89 | { 90 | // TODO : This is horrid, it's very expensive to call this if there is a lot of signals. 91 | var result:Array = []; 92 | for each (var signal:INativeDispatcher in _signals) 93 | { 94 | result[result.length] = signal; 95 | } 96 | return result; 97 | } 98 | 99 | /** 100 | * Unsubscribes all listeners from all signals in the set. 101 | */ 102 | public function removeAll():void 103 | { 104 | for each (var signal:INativeDispatcher in _signals) 105 | { 106 | signal.removeAll(); 107 | delete _signals[signal.eventType]; 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/NetConnectionSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.AsyncErrorEvent; 5 | import flash.events.IOErrorEvent; 6 | import flash.events.NetStatusEvent; 7 | import flash.events.SecurityErrorEvent; 8 | import flash.net.NetConnection; 9 | 10 | /** 11 | * @author Jon Adams 12 | */ 13 | public class NetConnectionSignalSet extends EventDispatcherSignalSet { 14 | 15 | public function NetConnectionSignalSet(target:NetConnection) { 16 | super(target); 17 | } 18 | 19 | public function get asyncError():NativeSignal { 20 | return getNativeSignal(AsyncErrorEvent.ASYNC_ERROR, AsyncErrorEvent); 21 | } 22 | 23 | public function get ioError():NativeSignal { 24 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 25 | } 26 | 27 | public function get netStatus():NativeSignal { 28 | return getNativeSignal(NetStatusEvent.NET_STATUS, NetStatusEvent); 29 | } 30 | 31 | public function get securityError():NativeSignal { 32 | return getNativeSignal(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorEvent); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/NetStreamSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.AsyncErrorEvent; 5 | import flash.events.IOErrorEvent; 6 | import flash.events.NetStatusEvent; 7 | import flash.net.NetStream; 8 | 9 | /** 10 | * @author Jon Adams 11 | */ 12 | public class NetStreamSignalSet extends EventDispatcherSignalSet { 13 | 14 | public function NetStreamSignalSet(target:NetStream) { 15 | super(target); 16 | } 17 | 18 | public function get asyncError():NativeSignal { 19 | return getNativeSignal(AsyncErrorEvent.ASYNC_ERROR, AsyncErrorEvent); 20 | } 21 | public function get ioError():NativeSignal { 22 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 23 | } 24 | public function get netStatus():NativeSignal { 25 | return getNativeSignal(NetStatusEvent.NET_STATUS, NetStatusEvent); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/SharedObjectSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.AsyncErrorEvent; 5 | import flash.events.NetStatusEvent; 6 | import flash.events.SyncEvent; 7 | import flash.net.SharedObject; 8 | 9 | /** 10 | * @author Jon Adams 11 | */ 12 | public class SharedObjectSignalSet extends EventDispatcherSignalSet { 13 | 14 | public function SharedObjectSignalSet(target:SharedObject) { 15 | super(target); 16 | } 17 | 18 | public function get asyncError():NativeSignal { 19 | return getNativeSignal(AsyncErrorEvent.ASYNC_ERROR, AsyncErrorEvent); 20 | } 21 | public function get netStatus():NativeSignal { 22 | return getNativeSignal(NetStatusEvent.NET_STATUS, NetStatusEvent); 23 | } 24 | public function get sync():NativeSignal { 25 | return getNativeSignal(SyncEvent.SYNC, SyncEvent); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/SocketSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.events.IOErrorEvent; 6 | import flash.events.ProgressEvent; 7 | import flash.events.SecurityErrorEvent; 8 | import flash.net.Socket; 9 | 10 | /** 11 | * @author Jon Adams 12 | */ 13 | public class SocketSignalSet extends EventDispatcherSignalSet { 14 | 15 | public function SocketSignalSet(target:Socket) { 16 | super(target); 17 | } 18 | 19 | public function get close():NativeSignal { 20 | return getNativeSignal(Event.CLOSE); 21 | } 22 | 23 | public function get connect():NativeSignal { 24 | return getNativeSignal(Event.CONNECT); 25 | } 26 | 27 | public function get ioError():NativeSignal { 28 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 29 | } 30 | 31 | public function get securityError():NativeSignal { 32 | return getNativeSignal(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorEvent); 33 | } 34 | 35 | public function get socketData():NativeSignal { 36 | return getNativeSignal(ProgressEvent.SOCKET_DATA, ProgressEvent); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/SoundChannelSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.media.SoundChannel; 6 | 7 | /** 8 | * @author Jon Adams 9 | */ 10 | public class SoundChannelSignalSet extends EventDispatcherSignalSet { 11 | 12 | public function SoundChannelSignalSet(target:SoundChannel) { 13 | super(target); 14 | } 15 | 16 | public function get soundComplete():NativeSignal { 17 | return getNativeSignal(Event.SOUND_COMPLETE); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/SoundSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.events.IOErrorEvent; 6 | import flash.events.ProgressEvent; 7 | import flash.media.Sound; 8 | 9 | /** 10 | * @author Jon Adams 11 | */ 12 | public class SoundSignalSet extends EventDispatcherSignalSet { 13 | 14 | public function SoundSignalSet(target:Sound) { 15 | super(target); 16 | } 17 | 18 | public function get complete():NativeSignal { 19 | return getNativeSignal(Event.COMPLETE); 20 | } 21 | 22 | public function get id3():NativeSignal { 23 | return getNativeSignal(Event.ID3); 24 | } 25 | 26 | public function get ioError():NativeSignal { 27 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 28 | } 29 | 30 | public function get open():NativeSignal { 31 | return getNativeSignal(Event.OPEN); 32 | } 33 | 34 | public function get progress():NativeSignal { 35 | return getNativeSignal(ProgressEvent.PROGRESS, ProgressEvent); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/StageSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import org.osflash.signals.natives.NativeSignal; 4 | 5 | import flash.display.Stage; 6 | import flash.events.Event; 7 | 8 | /** 9 | * @author Jon Adams 10 | */ 11 | public class StageSignalSet extends InteractiveObjectSignalSet 12 | { 13 | 14 | public function StageSignalSet(target:Stage) 15 | { 16 | super(target); 17 | } 18 | 19 | public function get fullScreen():NativeSignal 20 | { 21 | return getNativeSignal(Event.FULLSCREEN); 22 | } 23 | 24 | public function get mouseLeave():NativeSignal 25 | { 26 | return getNativeSignal(Event.MOUSE_LEAVE); 27 | } 28 | 29 | public function get resize():NativeSignal 30 | { 31 | return getNativeSignal(Event.RESIZE); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/TextFieldSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.events.TextEvent; 6 | import flash.text.TextField; 7 | 8 | /** 9 | * @author Jon Adams 10 | */ 11 | public class TextFieldSignalSet extends InteractiveObjectSignalSet { 12 | 13 | public function TextFieldSignalSet(target:TextField) { 14 | super(target); 15 | } 16 | 17 | public function get change():NativeSignal { 18 | return getNativeSignal(Event.CHANGE); 19 | } 20 | public function get link():NativeSignal { 21 | return getNativeSignal(TextEvent.LINK, TextEvent); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/TimerSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.TimerEvent; 5 | import flash.utils.Timer; 6 | 7 | /** 8 | * @author Jon Adams 9 | */ 10 | public class TimerSignalSet extends EventDispatcherSignalSet { 11 | 12 | public function TimerSignalSet(target:Timer) { 13 | super(target); 14 | } 15 | 16 | public function get timer():NativeSignal { 17 | return getNativeSignal(TimerEvent.TIMER, TimerEvent); 18 | } 19 | public function get timerComplete():NativeSignal { 20 | return getNativeSignal(TimerEvent.TIMER_COMPLETE, TimerEvent); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/URLLoaderSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.events.HTTPStatusEvent; 6 | import flash.events.IOErrorEvent; 7 | import flash.events.ProgressEvent; 8 | import flash.events.SecurityErrorEvent; 9 | import flash.net.URLLoader; 10 | 11 | /** 12 | * @author Jon Adams 13 | */ 14 | public class URLLoaderSignalSet extends EventDispatcherSignalSet { 15 | 16 | public function URLLoaderSignalSet(target:URLLoader) { 17 | super(target); 18 | } 19 | 20 | public function get complete():NativeSignal { 21 | return getNativeSignal(Event.COMPLETE); 22 | } 23 | 24 | public function get httpStatus():NativeSignal { 25 | return getNativeSignal(HTTPStatusEvent.HTTP_STATUS, HTTPStatusEvent); 26 | } 27 | 28 | public function get ioError():NativeSignal { 29 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 30 | } 31 | 32 | public function get open():NativeSignal { 33 | return getNativeSignal(Event.OPEN); 34 | } 35 | 36 | public function get progress():NativeSignal { 37 | return getNativeSignal(ProgressEvent.PROGRESS, ProgressEvent); 38 | } 39 | 40 | public function get securityError():NativeSignal { 41 | return getNativeSignal(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorEvent); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/URLStreamSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.Event; 5 | import flash.events.HTTPStatusEvent; 6 | import flash.events.IOErrorEvent; 7 | import flash.events.ProgressEvent; 8 | import flash.events.SecurityErrorEvent; 9 | import flash.net.URLStream; 10 | 11 | /** 12 | * @author Jon Adams 13 | */ 14 | public class URLStreamSignalSet extends EventDispatcherSignalSet { 15 | 16 | public function URLStreamSignalSet(target:URLStream) { 17 | super(target); 18 | } 19 | 20 | public function get complete():NativeSignal { 21 | return getNativeSignal(Event.COMPLETE); 22 | } 23 | public function get httpStatus():NativeSignal { 24 | return getNativeSignal(HTTPStatusEvent.HTTP_STATUS, HTTPStatusEvent); 25 | } 26 | public function get ioError():NativeSignal { 27 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 28 | } 29 | public function get open():NativeSignal { 30 | return getNativeSignal(Event.OPEN); 31 | } 32 | public function get progress():NativeSignal { 33 | return getNativeSignal(ProgressEvent.PROGRESS, ProgressEvent); 34 | } 35 | public function get securityError():NativeSignal { 36 | return getNativeSignal(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorEvent); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/osflash/signals/natives/sets/XMLSocketSignalSet.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets { 2 | import org.osflash.signals.natives.NativeSignal; 3 | 4 | import flash.events.DataEvent; 5 | import flash.events.Event; 6 | import flash.events.IOErrorEvent; 7 | import flash.events.SecurityErrorEvent; 8 | import flash.net.XMLSocket; 9 | 10 | /** 11 | * @author Jon Adams 12 | */ 13 | public class XMLSocketSignalSet extends EventDispatcherSignalSet { 14 | 15 | public function XMLSocketSignalSet(target:XMLSocket) { 16 | super(target); 17 | } 18 | 19 | public function get close():NativeSignal { 20 | return getNativeSignal(Event.CLOSE); 21 | } 22 | public function get connect():NativeSignal { 23 | return getNativeSignal(Event.CONNECT); 24 | } 25 | public function get data():NativeSignal { 26 | return getNativeSignal(DataEvent.DATA, DataEvent); 27 | } 28 | public function get ioError():NativeSignal { 29 | return getNativeSignal(IOErrorEvent.IO_ERROR, IOErrorEvent); 30 | } 31 | public function get securityError():NativeSignal { 32 | return getNativeSignal(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorEvent); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/AllTests.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import org.osflash.signals.natives.AmbiguousRelationshipInNativeSignalTest; 4 | import org.osflash.signals.natives.MXMLNativeSignalTest; 5 | import org.osflash.signals.natives.NativeMappedSignalBoundaryUseTest; 6 | import org.osflash.signals.natives.NativeMappedSignalDefaultsTest; 7 | import org.osflash.signals.natives.NativeMappedSignalFunctionArgTest; 8 | import org.osflash.signals.natives.NativeMappedSignalFunctionNoArgsTest; 9 | import org.osflash.signals.natives.NativeMappedSignalObjectArgTest; 10 | import org.osflash.signals.natives.NativeRelaySignalTest; 11 | import org.osflash.signals.natives.NativeSignalSlotTest; 12 | import org.osflash.signals.natives.NativeSignalTest; 13 | import org.osflash.signals.natives.sets.DisplayObjectSignalSetTest; 14 | import org.osflash.signals.natives.sets.EventDispatcherSignalSetTest; 15 | import org.osflash.signals.natives.sets.NativeSignalSetTest; 16 | 17 | [Suite] 18 | public class AllTests 19 | { 20 | public var _AmbiguousRelationshipTest:AmbiguousRelationshipTest; 21 | public var _AmbiguousRelationshipInNativeSignalTest:AmbiguousRelationshipInNativeSignalTest; 22 | public var _GenericEventTest:GenericEventTest; 23 | 24 | public var _NativeRelaySignalTest:NativeRelaySignalTest; 25 | public var _NativeSignalTest:NativeSignalTest; 26 | public var _NativeMappedSignalDefaultsTest:NativeMappedSignalDefaultsTest; 27 | public var _NativeMappedSignalObjectArgTest:NativeMappedSignalObjectArgTest; 28 | public var _NativeMappedSignalFunctionNoArgsTest:NativeMappedSignalFunctionNoArgsTest; 29 | public var _NativeMappedSignalFunctionArgTest:NativeMappedSignalFunctionArgTest; 30 | public var _NativeMappedSignalBoundaryUseTest:NativeMappedSignalBoundaryUseTest; 31 | public var _NativeSlotTest:NativeSignalSlotTest; 32 | 33 | public var _PriorityListenersTest:PriorityListenersTest; 34 | public var _PrioritySignalTest:PrioritySignalTest; 35 | public var _RedispatchedEventTest:RedispatchedEventTest; 36 | 37 | public var _DeluxeSignalWithBubblingEventTest:DeluxeSignalWithBubblingEventTest; 38 | public var _DeluxeSignalWithGenericEventTest:DeluxeSignalWithGenericEventTest; 39 | 40 | public var _MXMLDeluxeSignalTest:MXMLDeluxeSignalTest; 41 | public var _MXMLSignalTest:MXMLSignalTest; 42 | public var _MXMLNativeSignalTest:MXMLNativeSignalTest; 43 | 44 | public var _SignalDispatchArgsTest:SignalDispatchArgsTest; 45 | public var _SignalDispatchExtraArgsTest:SignalDispatchExtraArgsTest; 46 | public var _SignalDispatchNoArgsTest:SignalDispatchNoArgsTest; 47 | public var _SignalDispatchNonEventTest:SignalDispatchNonEventTest; 48 | public var _SignalTest:SignalTest; 49 | public var _SignalWithCustomEventTest:SignalWithCustomEventTest; 50 | public var _SlotTest:SlotTest; 51 | public var _SlotListTest:SlotListTest; 52 | public var _SignalDispatchVarArgsTest:SignalDispatchVarArgsTest; 53 | 54 | public var _MonoSignalTest:MonoSignalTest; 55 | public var _MonoSignalDispatchArgsTest:MonoSignalDispatchArgsTest; 56 | public var _MonoSignalDispatchExtraArgsTest:MonoSignalDispatchExtraArgsTest; 57 | public var _MonoSignalDispatchNoArgsTest:MonoSignalDispatchNoArgsTest; 58 | public var _MonoSignalDispatchNonEventTest:MonoSignalDispatchNonEventTest; 59 | public var _MonoSignalSlotTest:MonoSignalSlotTest; 60 | public var _MonoSignalDispatchVarArgsTest:MonoSignalDispatchVarArgsTest; 61 | 62 | public var _PromiseTest:PromiseTest; 63 | public var _NativeSignalSetTest:NativeSignalSetTest; 64 | public var _EventDispatcherSignalSetTest:EventDispatcherSignalSetTest; 65 | public var _DisplayObjectSignalSetTest:DisplayObjectSignalSetTest; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/AllTestsCIRunner.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.core.FlexUnitCICore; 4 | import asunit.core.TextCore; 5 | 6 | import flash.display.MovieClip; 7 | 8 | [SWF(width='1000', height='800', backgroundColor='#333333', frameRate='31')] 9 | public class AllTestsCIRunner extends MovieClip 10 | { 11 | private var core:TextCore; 12 | 13 | public function AllTestsCIRunner() 14 | { 15 | core = new FlexUnitCICore(); 16 | core.start(AllTests, null, this); 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/AllTestsRunner.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.core.TextCore; 4 | 5 | import flash.display.MovieClip; 6 | 7 | [SWF(width='1000', height='800', backgroundColor='#333333', frameRate='31')] 8 | public class AllTestsRunner extends MovieClip 9 | { 10 | private var core:TextCore; 11 | 12 | public function AllTestsRunner() 13 | { 14 | core = new TextCore(); 15 | core.textPrinter.hideLocalPaths = true; 16 | core.start(AllTests, null, this); 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/AmbiguousRelationshipTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | 5 | public class AmbiguousRelationshipTest 6 | { 7 | private var target:Object; 8 | 9 | private var instance:Signal; 10 | 11 | [Before] 12 | public function setUp():void 13 | { 14 | target = {}; 15 | instance = new Signal(); 16 | } 17 | 18 | [After] 19 | public function tearDown():void 20 | { 21 | instance = null; 22 | } 23 | 24 | [Test(expects="flash.errors.IllegalOperationError")] 25 | public function add_then_addOnce_throws_error():void 26 | { 27 | instance.add(failIfCalled); 28 | instance.addOnce(failIfCalled); 29 | } 30 | 31 | [Test(expects="flash.errors.IllegalOperationError")] 32 | public function addOnce_then_add_should_throw_error():void 33 | { 34 | instance.addOnce(failIfCalled); 35 | instance.add(failIfCalled); 36 | } 37 | 38 | [Test] 39 | public function add_then_add_should_not_throw_error():void 40 | { 41 | instance.add(failIfCalled); 42 | instance.add(failIfCalled); 43 | assertEquals(1, instance.numListeners); 44 | } 45 | 46 | [Test] 47 | public function addOnce_then_addOnce_should_not_throw_error():void 48 | { 49 | instance.addOnce(failIfCalled); 50 | instance.addOnce(failIfCalled); 51 | assertEquals(1, instance.numListeners); 52 | } 53 | 54 | private function failIfCalled():void 55 | { 56 | fail("if this listener is called, something horrible is going on"); 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/DeluxeSignalWithBubblingEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.events.GenericEvent; 7 | import org.osflash.signals.events.IBubbleEventHandler; 8 | import org.osflash.signals.events.IEvent; 9 | 10 | public class DeluxeSignalWithBubblingEventTest implements IBubbleEventHandler 11 | { 12 | [Inject] 13 | public var async:IAsync; 14 | 15 | protected var theParent:IBubbleEventHandler; 16 | protected var theChild:Child; 17 | protected var theGrandChild:Child; 18 | protected var cancelTimeout:Function; 19 | 20 | [Before] 21 | public function setUp():void 22 | { 23 | theParent = this; 24 | theChild = new Child(this, 'theChild'); 25 | theGrandChild = new Child(theChild, 'theGrandChild'); 26 | } 27 | 28 | [After] 29 | public function tearDown():void 30 | { 31 | theChild = null; 32 | theGrandChild = null; 33 | cancelTimeout = null; 34 | } 35 | 36 | [Test] 37 | public function parent_child_relationships():void 38 | { 39 | assertSame("theChild's parent is this", this, theChild.parent); 40 | assertTrue("this can handle bubbling events", this is IBubbleEventHandler); 41 | } 42 | 43 | [Test] 44 | public function dispatch_bubbling_event_from_theGrandChild_should_bubble_to_parent_IBubbleHandler():void 45 | { 46 | // If cancelTimeout() isn't called, this test will fail. 47 | cancelTimeout = async.add(null, 10); 48 | var event:IEvent = new GenericEvent(); 49 | event.bubbles = true; 50 | 51 | theGrandChild.completed.dispatch(event); 52 | } 53 | 54 | public function onEventBubbled(e:IEvent):Boolean 55 | { 56 | cancelTimeout(); 57 | assertSame('e.target should be the object that originally dispatched event', theGrandChild, e.target); 58 | assertSame('e.currentTarget should be the object receiving the bubbled event', this, e.currentTarget); 59 | return false; 60 | } 61 | 62 | [Test] 63 | public function returning_false_from_onEventBubbled_should_stop_bubbling():void 64 | { 65 | var bubbleHater:BubbleHater = new BubbleHater(); 66 | theChild = new Child(bubbleHater, 'bubblePopper'); 67 | theChild.popsBubbles = true; 68 | theGrandChild = new Child(theChild, 'bubbleBlower'); 69 | 70 | var bubblingEvent:IEvent = new GenericEvent(true); 71 | // Will only complete without error if theChild pops the bubble. 72 | theGrandChild.completed.dispatch(bubblingEvent); 73 | } 74 | 75 | [Test(expects="flash.errors.IllegalOperationError")] 76 | public function returning_true_from_onEventBubbled_should_continue_bubbling():void 77 | { 78 | var bubbleHater:BubbleHater = new BubbleHater(); 79 | theChild = new Child(bubbleHater, 'bubblePopper'); 80 | // Changing popsBubbles to false will fail the test nicely. 81 | theChild.popsBubbles = false; 82 | theGrandChild = new Child(theChild, 'bubbleBlower'); 83 | 84 | var bubblingEvent:IEvent = new GenericEvent(true); 85 | // Because theChild didn't pop the bubble, this causes bubbleHater to throw an error. 86 | theGrandChild.completed.dispatch(bubblingEvent); 87 | } 88 | } 89 | } 90 | 91 | import org.osflash.signals.DeluxeSignal; 92 | import org.osflash.signals.events.IBubbleEventHandler; 93 | import org.osflash.signals.events.IEvent; 94 | 95 | import flash.errors.IllegalOperationError; 96 | 97 | class Child implements IBubbleEventHandler 98 | { 99 | public var parent:Object; 100 | public var completed:DeluxeSignal; 101 | public var name:String; 102 | public var popsBubbles:Boolean = false; 103 | 104 | public function Child(parent:Object = null, name:String = '') 105 | { 106 | this.parent = parent; 107 | this.name = name; 108 | completed = new DeluxeSignal(this); 109 | } 110 | 111 | public function toString():String 112 | { 113 | return '[Child '+name+']'; 114 | } 115 | 116 | public function onEventBubbled(event:IEvent):Boolean 117 | { 118 | return !popsBubbles; 119 | } 120 | } 121 | 122 | class BubbleHater implements IBubbleEventHandler 123 | { 124 | public function onEventBubbled(event:IEvent):Boolean 125 | { 126 | throw new IllegalOperationError('I SAID NO BUBBLES!!!'); 127 | return false; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/DeluxeSignalWithGenericEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.events.GenericEvent; 7 | import org.osflash.signals.events.IEvent; 8 | 9 | import flash.display.Sprite; 10 | 11 | public class DeluxeSignalWithGenericEventTest 12 | { 13 | [Inject] 14 | public var async:IAsync; 15 | 16 | protected var completed:DeluxeSignal; 17 | protected var delegate:Function; 18 | 19 | [Before] 20 | public function setUp():void 21 | { 22 | completed = new DeluxeSignal(this); 23 | } 24 | 25 | [After] 26 | public function tearDown():void 27 | { 28 | completed.removeAll(); 29 | completed = null; 30 | delegate = null; 31 | } 32 | 33 | [Test] 34 | public function signal_length_is_0_after_creation():void 35 | { 36 | assertEquals(0, completed.numListeners); 37 | } 38 | 39 | ////// 40 | 41 | [Test] 42 | public function add_listener_and_dispatch_event_should_pass_event_to_listener():void 43 | { 44 | completed.add(async.add(checkGenericEvent, 10)); 45 | completed.dispatch(new GenericEvent()); 46 | } 47 | 48 | protected function checkGenericEvent(e:IEvent):void 49 | { 50 | assertTrue('instance of IEvent', e is IEvent); 51 | assertTrue('instance of GenericEvent', e is GenericEvent); 52 | assertEquals('event.signal points to the originating Signal', this.completed, e.signal); 53 | assertEquals('event.target points to object containing the Signal', this, e.target); 54 | assertEquals('event.target is e.currentTarget because event does not bubble', e.target, e.currentTarget); 55 | } 56 | 57 | ////// 58 | 59 | 60 | [Test] 61 | public function add_two_listeners_and_dispatch_should_call_both():void 62 | { 63 | completed.add(async.add(checkGenericEvent, 10)); 64 | completed.add(async.add(checkGenericEvent, 10)); 65 | completed.dispatch(new GenericEvent()); 66 | } 67 | 68 | ////// 69 | 70 | [Test] 71 | public function addOnce_and_dispatch_should_remove_listener_automatically():void 72 | { 73 | completed.addOnce(newEmptyHandler()); 74 | completed.dispatch(new GenericEvent()); 75 | assertEquals('there should be no listeners', 0, completed.numListeners); 76 | } 77 | 78 | ////// 79 | 80 | [Test] 81 | public function add_one_listener_and_dispatch_then_listener_remove_itself_using_event_signal():void 82 | { 83 | delegate = async.add(remove_myself_from_signal, 10); 84 | completed.add(delegate); 85 | completed.dispatch(new GenericEvent()); 86 | } 87 | 88 | private function remove_myself_from_signal(e:IEvent):void 89 | { 90 | assertEquals('listener still in signal', 1, e.signal.numListeners); 91 | 92 | // Can't remove(arguments.callee) because it's wrapped with delegate created by async.add(). 93 | e.signal.remove(delegate); 94 | 95 | assertEquals('listener removed from signal', 0, e.signal.numListeners); 96 | } 97 | 98 | ////// 99 | 100 | [Test] 101 | public function add_listener_then_remove_then_dispatch_should_not_call_listener():void 102 | { 103 | var delegate:Function = failIfCalled; 104 | completed.add(delegate); 105 | completed.remove(delegate); 106 | completed.dispatch(new GenericEvent()); 107 | } 108 | 109 | private function failIfCalled(e:IEvent):void 110 | { 111 | fail('This event handler should not have been called.'); 112 | } 113 | 114 | ////// 115 | 116 | [Test] 117 | public function add_2_listeners_remove_2nd_then_dispatch_should_call_1st_not_2nd_listener():void 118 | { 119 | completed.add(async.add(checkGenericEvent, 10)); 120 | var delegate:Function = failIfCalled; 121 | completed.add(delegate); 122 | completed.remove(delegate); 123 | completed.dispatch(new GenericEvent()); 124 | } 125 | ////// 126 | [Test] 127 | public function add_2_listeners_should_yield_length_of_2():void 128 | { 129 | completed.add(newEmptyHandler()); 130 | completed.add(newEmptyHandler()); 131 | assertEquals(2, completed.numListeners); 132 | } 133 | 134 | private function newEmptyHandler():Function 135 | { 136 | return function(e:*):void {}; 137 | } 138 | 139 | 140 | ////// 141 | [Test] 142 | public function add_2_listeners_then_remove_1_should_yield_length_of_1():void 143 | { 144 | var firstFunc:Function = newEmptyHandler(); 145 | completed.add(firstFunc); 146 | completed.add(newEmptyHandler()); 147 | 148 | completed.remove(firstFunc); 149 | 150 | assertEquals(1, completed.numListeners); 151 | } 152 | 153 | [Test] 154 | public function add_2_listeners_then_removeAll_should_yield_length_of_0():void 155 | { 156 | completed.add(newEmptyHandler()); 157 | completed.add(newEmptyHandler()); 158 | 159 | completed.removeAll(); 160 | 161 | assertEquals(0, completed.numListeners); 162 | } 163 | 164 | [Test] 165 | public function add_same_listener_twice_should_only_add_it_once():void 166 | { 167 | var func:Function = newEmptyHandler(); 168 | completed.add(func); 169 | completed.add(func); 170 | assertEquals(1, completed.numListeners); 171 | } 172 | ////// 173 | [Test] 174 | public function dispatch_object_that_isnt_an_IEvent_should_dispatch_without_error():void 175 | { 176 | completed.addOnce(checkSprite); 177 | // Sprite doesn't have a target property, 178 | // so if the signal tried to set .target, 179 | // an error would be thrown and this test would fail. 180 | completed.dispatch(new Sprite()); 181 | } 182 | 183 | private function checkSprite(sprite:Sprite):void 184 | { 185 | assertTrue(sprite is Sprite); 186 | } 187 | ////// 188 | 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/GenericEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | 5 | import org.osflash.signals.events.GenericEvent; 6 | import org.osflash.signals.events.IEvent; 7 | 8 | public class GenericEventTest 9 | { 10 | private var instance:GenericEvent; 11 | 12 | [Before] 13 | public function setUp():void 14 | { 15 | instance = new GenericEvent(); 16 | } 17 | 18 | [After] 19 | public function tearDown():void 20 | { 21 | instance = null; 22 | } 23 | 24 | public function testInstantiated():void 25 | { 26 | assertTrue("GenericEvent instantiated", instance is GenericEvent); 27 | assertNull('target is null by default', instance.target); 28 | assertFalse('bubbles is false by default', instance.bubbles); 29 | } 30 | 31 | [Test] 32 | public function bubbles_roundtrips_through_constructor():void 33 | { 34 | var bubblingEvent:GenericEvent = new GenericEvent(true); 35 | assertTrue(bubblingEvent.bubbles); 36 | } 37 | 38 | [Test] 39 | public function clone_should_be_instance_of_original_event_class():void 40 | { 41 | var theClone:IEvent = instance.clone(); 42 | assertTrue(theClone is GenericEvent); 43 | } 44 | 45 | [Test] 46 | public function clone_non_bubbling_event_should_have_bubbles_false():void 47 | { 48 | var theClone:GenericEvent = GenericEvent(instance.clone()); 49 | assertFalse(theClone.bubbles); 50 | } 51 | 52 | [Test] 53 | public function clone_bubbling_event_should_have_bubbles_true():void 54 | { 55 | var bubblingEvent:GenericEvent = new GenericEvent(true); 56 | var theClone:IEvent = bubblingEvent.clone(); 57 | assertTrue(theClone.bubbles); 58 | } 59 | 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/ISignalTestBase.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import flash.events.Event; 7 | 8 | public class ISignalTestBase 9 | { 10 | [Inject] 11 | public var async:IAsync; 12 | 13 | protected var signal:ISignal; 14 | 15 | [After] 16 | public function destroySignal():void 17 | { 18 | signal.removeAll(); 19 | signal = null; 20 | } 21 | 22 | [Test] 23 | public function numListeners_is_0_after_creation():void 24 | { 25 | assertEquals(0, signal.numListeners); 26 | } 27 | 28 | [Test] 29 | public function addOnce_and_dispatch_should_remove_listener_automatically():void 30 | { 31 | signal.addOnce(newEmptyHandler()); 32 | dispatchSignal(); 33 | assertEquals('there should be no listeners', 0, signal.numListeners); 34 | } 35 | 36 | [Test] 37 | public function add_listener_then_remove_then_dispatch_should_not_call_listener():void 38 | { 39 | signal.add(failIfCalled); 40 | signal.remove(failIfCalled); 41 | dispatchSignal(); 42 | } 43 | 44 | [Test] 45 | public function add_listener_then_remove_function_not_in_listeners_should_do_nothing():void 46 | { 47 | signal.add(newEmptyHandler()); 48 | signal.remove(newEmptyHandler()); 49 | assertEquals(1, signal.numListeners); 50 | } 51 | 52 | [Test] 53 | public function add_2_listeners_remove_2nd_then_dispatch_should_call_1st_not_2nd_listener():void 54 | { 55 | var called:Boolean = false; 56 | signal.add(function(e:* = null):void { called = true; }); 57 | signal.add(failIfCalled); 58 | signal.remove(failIfCalled); 59 | dispatchSignal(); 60 | assertTrue(called); 61 | } 62 | 63 | [Test] 64 | public function add_2_listeners_should_yield_numListeners_of_2():void 65 | { 66 | signal.add(newEmptyHandler()); 67 | signal.add(newEmptyHandler()); 68 | assertEquals(2, signal.numListeners); 69 | } 70 | 71 | [Test] 72 | public function add_2_listeners_then_remove_1_should_yield_numListeners_of_1():void 73 | { 74 | var firstFunc:Function = newEmptyHandler(); 75 | signal.add(firstFunc); 76 | signal.add(newEmptyHandler()); 77 | signal.remove(firstFunc); 78 | 79 | assertEquals(1, signal.numListeners); 80 | } 81 | 82 | [Test] 83 | public function add_2_listeners_then_removeAll_should_yield_numListeners_of_0():void 84 | { 85 | signal.add(newEmptyHandler()); 86 | signal.add(newEmptyHandler()); 87 | signal.removeAll(); 88 | assertEquals(0, signal.numListeners); 89 | } 90 | 91 | [Test] 92 | public function add_same_listener_twice_should_only_add_it_once():void 93 | { 94 | var func:Function = newEmptyHandler(); 95 | signal.add(func); 96 | signal.add(func); 97 | assertEquals(1, signal.numListeners); 98 | } 99 | 100 | [Test] 101 | public function addOnce_same_listener_twice_should_only_add_it_once():void 102 | { 103 | var func:Function = newEmptyHandler(); 104 | signal.addOnce(func); 105 | signal.addOnce(func); 106 | assertEquals(1, signal.numListeners); 107 | } 108 | 109 | [Test] 110 | public function add_two_listeners_and_dispatch_should_call_both():void 111 | { 112 | var calledA:Boolean = false; 113 | var calledB:Boolean = false; 114 | signal.add(function(e:* = null):void { calledA = true; }); 115 | signal.add(function(e:* = null):void { calledB = true; }); 116 | dispatchSignal(); 117 | assertTrue(calledA); 118 | assertTrue(calledB); 119 | } 120 | 121 | 122 | [Test] 123 | public function add_the_same_listener_twice_should_not_throw_error():void 124 | { 125 | var listener:Function = newEmptyHandler(); 126 | signal.add(listener); 127 | signal.add(listener); 128 | } 129 | 130 | [Test] 131 | public function dispatch_2_listeners_1st_listener_removes_itself_then_2nd_listener_is_still_called():void 132 | { 133 | signal.add(selfRemover); 134 | // async.add verifies the second listener is called 135 | signal.add(async.add(newEmptyHandler(), 10)); 136 | dispatchSignal(); 137 | } 138 | 139 | private function selfRemover(e:* = null):void 140 | { 141 | signal.remove(selfRemover); 142 | } 143 | 144 | [Test] 145 | public function dispatch_2_listeners_1st_listener_removes_all_then_2nd_listener_is_still_called():void 146 | { 147 | signal.add(async.add(allRemover, 10)); 148 | signal.add(async.add(newEmptyHandler(), 10)); 149 | dispatchSignal(); 150 | } 151 | 152 | private function allRemover(e:* = null):void 153 | { 154 | signal.removeAll(); 155 | } 156 | 157 | [Test] 158 | public function adding_a_listener_during_dispatch_should_not_call_it():void 159 | { 160 | signal.add(async.add(addListenerDuringDispatch, 10)); 161 | dispatchSignal(); 162 | } 163 | 164 | private function addListenerDuringDispatch(e:* = null):void 165 | { 166 | signal.add(failIfCalled); 167 | } 168 | 169 | //TODO: clarify test purpose through naming and/or implementation 170 | [Test] 171 | public function can_use_anonymous_listeners():void 172 | { 173 | var slots:Array = []; 174 | 175 | for ( var i:int = 0; i < 10; i++ ) 176 | { 177 | slots.push(signal.add(newEmptyHandler())); 178 | } 179 | assertEquals("there should be 10 listeners", 10, signal.numListeners); 180 | 181 | for each( var slot:ISlot in slots ) 182 | { 183 | signal.remove(slot.listener); 184 | } 185 | assertEquals("all anonymous listeners removed", 0, signal.numListeners); 186 | } 187 | 188 | //TODO: clarify test purpose through naming and/or implementation 189 | [Test] 190 | public function can_use_anonymous_listeners_in_addOnce():void 191 | { 192 | var slots:Array = []; 193 | 194 | for ( var i:int = 0; i < 10; i++ ) 195 | { 196 | slots.push(signal.addOnce(newEmptyHandler())); 197 | } 198 | assertEquals("there should be 10 listeners", 10, signal.numListeners); 199 | 200 | for each( var slot:ISlot in slots ) 201 | { 202 | signal.remove(slot.listener); 203 | } 204 | assertEquals("all anonymous listeners removed", 0, signal.numListeners); 205 | } 206 | 207 | [Test] 208 | public function add_listener_returns_slot_with_same_listener():void 209 | { 210 | var listener:Function = newEmptyHandler(); 211 | var slot:ISlot = signal.add(listener); 212 | assertSame(listener, slot.listener); 213 | } 214 | 215 | [Test] 216 | public function remove_listener_returns_same_slot_as_when_it_was_added():void 217 | { 218 | var listener:Function = newEmptyHandler(); 219 | var slot:ISlot = signal.add(listener); 220 | assertSame(slot, signal.remove(listener)); 221 | } 222 | 223 | protected function dispatchSignal():void 224 | { 225 | signal.dispatch(new Event('test')); 226 | } 227 | 228 | ////// UTILITY METHODS ////// 229 | 230 | protected static function newEmptyHandler():Function 231 | { 232 | return function(e:* = null, ...args):void {}; 233 | } 234 | 235 | protected static function failIfCalled(e:* = null):void 236 | { 237 | fail('This function should not have been called.'); 238 | } 239 | 240 | 241 | } 242 | } -------------------------------------------------------------------------------- /tests/org/osflash/signals/MXMLDeluxeSignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | 5 | import org.osflash.signals.events.IEvent; 6 | import org.osflash.signals.support.SpriteWithDeluxeSignals; 7 | 8 | public class MXMLDeluxeSignalTest 9 | { 10 | private var mxmlSprite:SpriteWithDeluxeSignals; 11 | 12 | [Before] 13 | public function setUp():void 14 | { 15 | mxmlSprite = new SpriteWithDeluxeSignals(); 16 | } 17 | 18 | [After] 19 | public function tearDown():void 20 | { 21 | mxmlSprite = null; 22 | } 23 | 24 | [Test] 25 | public function mxml_object_has_DeluxeSignals_after_creation():void 26 | { 27 | assertTrue(mxmlSprite.numChildrenChanged is DeluxeSignal); 28 | assertTrue(mxmlSprite.nameChanged is DeluxeSignal); 29 | assertTrue(mxmlSprite.tabEnabledChanged is DeluxeSignal); 30 | assertTrue(mxmlSprite.tabIndexChanged is DeluxeSignal); 31 | } 32 | 33 | [Test] 34 | public function has_single_value_class_from_mxml_default_property():void 35 | { 36 | var valueClasses:Array = mxmlSprite.numChildrenChanged.valueClasses; 37 | assertEquals(1, valueClasses.length); 38 | assertEquals(IEvent, valueClasses[0]); 39 | } 40 | 41 | [Test] 42 | public function has_multiple_value_classes_from_mxml_default_property():void 43 | { 44 | var valueClasses:Array = mxmlSprite.nameChanged.valueClasses; 45 | assertEquals(2, valueClasses.length); 46 | assertEquals(String, valueClasses[0]); 47 | assertEquals(uint, valueClasses[1]); 48 | } 49 | 50 | [Test] 51 | public function has_target_from_mxml_attribute():void 52 | { 53 | assertSame(mxmlSprite, mxmlSprite.numChildrenChanged.target); 54 | } 55 | 56 | [Test] 57 | public function has_single_value_class_from_mxml_attribute():void 58 | { 59 | var valueClasses:Array = mxmlSprite.tabEnabledChanged.valueClasses; 60 | assertEquals(1, valueClasses.length); 61 | assertEquals(Boolean, valueClasses[0]); 62 | } 63 | 64 | [Test] 65 | public function has_multiple_value_classes_from_mxml_attribute():void 66 | { 67 | var valueClasses:Array = mxmlSprite.tabIndexChanged.valueClasses; 68 | assertEquals(2, valueClasses.length); 69 | assertEquals(int, valueClasses[0]); 70 | assertEquals(Boolean, valueClasses[1]); 71 | } 72 | 73 | [Test] 74 | public function add_listener_then_dispatch_calls_listener():void 75 | { 76 | var called:Boolean = false; 77 | var handler:Function = function(newValue:Boolean):void { called = true; }; 78 | mxmlSprite.tabEnabledChanged.addOnce(handler); 79 | // when 80 | mxmlSprite.tabEnabledChanged.dispatch(true); 81 | // then 82 | assertTrue(called); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/MXMLSignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | 5 | import org.osflash.signals.support.SpriteWithSignals; 6 | 7 | public class MXMLSignalTest 8 | { 9 | private var mxmlSprite:SpriteWithSignals; 10 | 11 | [Before] 12 | public function setUp():void 13 | { 14 | mxmlSprite = new SpriteWithSignals(); 15 | } 16 | 17 | [After] 18 | public function tearDown():void 19 | { 20 | mxmlSprite = null; 21 | } 22 | 23 | [Test] 24 | public function mxml_object_has_Signals_after_creation():void 25 | { 26 | assertTrue(mxmlSprite.numChildrenChanged is Signal); 27 | assertTrue(mxmlSprite.nameChanged is Signal); 28 | assertTrue(mxmlSprite.tabEnabledChanged is Signal); 29 | } 30 | 31 | [Test] 32 | public function has_single_value_class_from_mxml_default_property():void 33 | { 34 | var valueClasses:Array = mxmlSprite.numChildrenChanged.valueClasses; 35 | assertEquals(1, valueClasses.length); 36 | assertEquals(uint, valueClasses[0]); 37 | } 38 | 39 | [Test] 40 | public function has_multiple_value_classes_from_mxml_default_property():void 41 | { 42 | var valueClasses:Array = mxmlSprite.nameChanged.valueClasses; 43 | assertEquals(2, valueClasses.length); 44 | assertEquals(String, valueClasses[0]); 45 | assertEquals(uint, valueClasses[1]); 46 | } 47 | 48 | [Test] 49 | public function has_single_value_class_from_mxml_attribute():void 50 | { 51 | var valueClasses:Array = mxmlSprite.tabEnabledChanged.valueClasses; 52 | assertEquals(1, valueClasses.length); 53 | assertEquals(Boolean, valueClasses[0]); 54 | } 55 | 56 | [Test] 57 | public function has_multiple_value_classes_from_mxml_attribute():void 58 | { 59 | var valueClasses:Array = mxmlSprite.tabIndexChanged.valueClasses; 60 | assertEquals(2, valueClasses.length); 61 | assertEquals(int, valueClasses[0]); 62 | assertEquals(Boolean, valueClasses[1]); 63 | } 64 | 65 | [Test] 66 | public function add_listener_then_dispatch_calls_listener():void 67 | { 68 | var called:Boolean = false; 69 | var handler:Function = function(newValue:Boolean):void { called = true; }; 70 | mxmlSprite.tabEnabledChanged.addOnce(handler); 71 | // when 72 | mxmlSprite.tabEnabledChanged.dispatch(true); 73 | // then 74 | assertTrue(called); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/MonoSignalDispatchArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.assertEquals; 4 | import asunit.asserts.assertTrue; 5 | import asunit.framework.IAsync; 6 | /** 7 | * @author Simon Richardson - simon@ustwo.co.uk 8 | */ 9 | public class MonoSignalDispatchArgsTest 10 | { 11 | 12 | [Inject] 13 | public var async:IAsync; 14 | 15 | public var completed:MonoSignal; 16 | 17 | [Before] 18 | public function setUp():void 19 | { 20 | completed = new MonoSignal(); 21 | } 22 | 23 | [After] 24 | public function tearDown():void 25 | { 26 | completed.removeAll(); 27 | completed = null; 28 | } 29 | 30 | [Test] 31 | public function dispatch_two_correct_value_objects_should_succeed():void 32 | { 33 | var signal:Signal = new Signal(String, uint); 34 | signal.dispatch("the Answer", 42); 35 | } 36 | 37 | [Test(expects="ArgumentError")] 38 | public function dispatch_fewer_value_objects_than_value_classes_should_should_throw_ArgumentError():void 39 | { 40 | var signal:Signal = new Signal(Date, Array); 41 | signal.dispatch(new Date()); 42 | } 43 | 44 | [Test] 45 | public function dispatch_more_value_objects_than_value_classes_should_succeed():void 46 | { 47 | var signal:Signal = new Signal(Date, Array); 48 | signal.dispatch(new Date(), new Array(), "extra value object"); 49 | } 50 | 51 | [Test] 52 | public function dispatch_values_with_no_value_classes_defined_should_pass_to_listener():void 53 | { 54 | var signalNoValueClasses:Signal = new Signal(); 55 | signalNoValueClasses.add(async.add(checkDispatchedValues, 10)); 56 | signalNoValueClasses.dispatch(22, 'done', new Date()); 57 | } 58 | 59 | private function checkDispatchedValues(a:uint, b:String, c:Date):void 60 | { 61 | assertEquals('correct number of arguments were dispatched', 3, arguments.length); 62 | assertEquals('the uint was dispatched', 22, a); 63 | assertEquals('the String was dispatched', 'done', b); 64 | assertTrue('a Date was dispatched', c is Date); 65 | } 66 | 67 | [Test(expects="ArgumentError")] 68 | public function dispatch_one_correct_and_one_incorrect_value_object_should_throw_ArgumentError():void 69 | { 70 | var signal:Signal = new Signal(Date, Array); 71 | signal.dispatch(new Date(), "wrong value type"); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/MonoSignalDispatchExtraArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.assertEquals; 4 | import asunit.asserts.assertTrue; 5 | import asunit.framework.IAsync; 6 | /** 7 | * @author Simon Richardson - simon@ustwo.co.uk 8 | */ 9 | public class MonoSignalDispatchExtraArgsTest 10 | { 11 | [Inject] 12 | public var async:IAsync; 13 | 14 | public var completed:MonoSignal; 15 | 16 | [Before] 17 | public function setUp():void 18 | { 19 | completed = new MonoSignal(); 20 | } 21 | 22 | [After] 23 | public function tearDown():void 24 | { 25 | completed.removeAll(); 26 | completed = null; 27 | } 28 | ////// 29 | [Test] 30 | public function dispatch_extra_args_should_call_listener_with_extra_args():void 31 | { 32 | completed.add( async.add(onCompleted, 10) ); 33 | completed.dispatch(22, 'done', new Date()); 34 | } 35 | 36 | private function onCompleted(a:uint, b:String, c:Date):void 37 | { 38 | assertEquals(3, arguments.length); 39 | assertEquals(22, a); 40 | assertEquals('done', b); 41 | assertTrue(c is Date); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/MonoSignalDispatchNoArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.assertEquals; 4 | import asunit.framework.IAsync; 5 | /** 6 | * @author Simon Richardson - simon@ustwo.co.uk 7 | */ 8 | public class MonoSignalDispatchNoArgsTest 9 | { 10 | [Inject] 11 | public var async:IAsync; 12 | 13 | public var completed:MonoSignal; 14 | 15 | [Before] 16 | public function setUp():void 17 | { 18 | completed = new MonoSignal(); 19 | } 20 | 21 | [After] 22 | public function tearDown():void 23 | { 24 | completed.removeAll(); 25 | completed = null; 26 | } 27 | ////// 28 | [Test] 29 | public function dispatch_no_args_should_call_listener_with_no_args():void 30 | { 31 | completed.add( async.add(onCompleted, 10) ); 32 | completed.dispatch(); 33 | } 34 | 35 | private function onCompleted():void 36 | { 37 | assertEquals(0, arguments.length); 38 | } 39 | ////// 40 | [Test] 41 | public function addOnce_in_handler_and_dispatch_should_call_new_listener():void 42 | { 43 | completed.addOnce( async.add(addOnceInHandler, 10) ); 44 | completed.dispatch(); 45 | } 46 | 47 | protected function addOnceInHandler():void 48 | { 49 | completed.addOnce( async.add(secondAddOnceListener, 10) ); 50 | completed.dispatch(); 51 | } 52 | 53 | protected function secondAddOnceListener():void 54 | { 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/MonoSignalDispatchNonEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.assertEquals; 4 | import asunit.asserts.assertNull; 5 | import asunit.framework.IAsync; 6 | /** 7 | * @author Simon Richardson - simon@ustwo.co.uk 8 | */ 9 | public class MonoSignalDispatchNonEventTest 10 | { 11 | [Inject] 12 | public var async:IAsync; 13 | 14 | public var completed:MonoSignal; 15 | 16 | [Before] 17 | public function setUp():void 18 | { 19 | completed = new MonoSignal(Date); 20 | } 21 | 22 | [After] 23 | public function tearDown():void 24 | { 25 | completed.removeAll(); 26 | completed = null; 27 | } 28 | 29 | /** 30 | * Captures bug where dispatching 0 was considered null. 31 | */ 32 | [Test] 33 | public function dispatch_zero_should_call_listener_with_zero():void 34 | { 35 | completed = new MonoSignal(Number); 36 | completed.add( async.add(onZero, 10) ); 37 | completed.dispatch(0); 38 | } 39 | 40 | private function onZero(num:Number):void 41 | { 42 | assertEquals(0, num); 43 | } 44 | ////// 45 | [Test] 46 | public function dispatch_2_zeroes_should_call_listener_with_2_zeroes():void 47 | { 48 | completed = new MonoSignal(Number, Number); 49 | completed.add( async.add(onZeroZero, 10) ); 50 | completed.dispatch(0, 0); 51 | } 52 | 53 | private function onZeroZero(a:Object, b:Object):void 54 | { 55 | assertEquals(0, a); 56 | assertEquals(0, b); 57 | } 58 | ////// 59 | [Test] 60 | public function dispatch_null_should_call_listener_with_null():void 61 | { 62 | completed.addOnce( async.add(checkNullDate, 10) ); 63 | completed.dispatch(null); 64 | } 65 | 66 | private function checkNullDate(date:Date):void 67 | { 68 | assertNull(date); 69 | } 70 | ////// 71 | [Test] 72 | public function dispatch_null_through_int_Signal_should_be_autoconverted_to_zero():void 73 | { 74 | completed = new MonoSignal(int); 75 | completed.addOnce( async.add(checkNullConvertedToZero, 10) ); 76 | completed.dispatch(null); 77 | } 78 | 79 | private function checkNullConvertedToZero(intValue:int):void 80 | { 81 | assertEquals('null was converted to 0', 0, intValue); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/MonoSignalDispatchVarArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.assertEquals; 4 | import asunit.asserts.assertEqualsArrays; 5 | import asunit.framework.IAsync; 6 | /** 7 | * @author Simon Richardson - simon@ustwo.co.uk 8 | */ 9 | public class MonoSignalDispatchVarArgsTest 10 | { 11 | 12 | [Inject] 13 | public var async:IAsync; 14 | 15 | public var completed:MonoSignal; 16 | 17 | [Before] 18 | public function setUp():void 19 | { 20 | completed = new MonoSignal(int, int, int, int); 21 | } 22 | 23 | [After] 24 | public function tearDown():void 25 | { 26 | completed.removeAll(); 27 | completed = null; 28 | } 29 | 30 | ////// 31 | 32 | [Test] 33 | public function adding_vararg_at_0_should_not_throw_error():void 34 | { 35 | completed.add(handlerArgsAt0()); 36 | } 37 | 38 | ////// 39 | 40 | [Test] 41 | public function adding_vararg_at_1_should_not_throw_error():void 42 | { 43 | completed.add(handlerArgsAt1()); 44 | } 45 | 46 | ////// 47 | 48 | [Test] 49 | public function adding_vararg_at_2_should_not_throw_error():void 50 | { 51 | completed.add(handlerArgsAt2()); 52 | } 53 | 54 | ////// 55 | 56 | [Test] 57 | public function adding_vararg_at_0_then_dispatch_should_not_throw_error():void 58 | { 59 | completed.add(handlerArgsAt0()); 60 | completed.dispatch(0, 1, 2, 3); 61 | } 62 | 63 | ////// 64 | 65 | [Test] 66 | public function adding_vararg_at_1_then_dispatch_should_not_throw_error():void 67 | { 68 | completed.add(handlerArgsAt1()); 69 | completed.dispatch(0, 1, 2, 3); 70 | } 71 | 72 | ////// 73 | 74 | [Test] 75 | public function adding_vararg_at_2_then_dispatch_should_not_throw_error():void 76 | { 77 | completed.add(handlerArgsAt2()); 78 | completed.dispatch(0, 1, 2, 3); 79 | } 80 | 81 | ////// 82 | 83 | [Test] 84 | public function verify_num_args_after_dispatch():void 85 | { 86 | completed.add(verifyNumArgs); 87 | completed.dispatch(0, 1, 2, 3); 88 | } 89 | 90 | private function handlerArgsAt0():Function 91 | { 92 | return function(...args):void 93 | { 94 | assertEqualsArrays('Arguments should be [0,1,2,3]', [0,1,2,3], args); 95 | assertEquals('Number of var arguments should be 4', 4, args.length); 96 | }; 97 | } 98 | 99 | private function handlerArgsAt1():Function 100 | { 101 | return function(a:int, ...args):void 102 | { 103 | assertEqualsArrays('Arguments should be [1,2,3]', [1,2,3], args); 104 | assertEquals('Number of var arguments should be 3', 3, args.length); 105 | }; 106 | } 107 | 108 | private function handlerArgsAt2():Function 109 | { 110 | return function(a:int, b:int, ...args):void 111 | { 112 | assertEqualsArrays('Arguments should be [2,3]', [2,3], args); 113 | assertEquals('Number of var arguments should be 2', 2, args.length); 114 | }; 115 | } 116 | 117 | private function verifyNumArgs(...args):void 118 | { 119 | assertEquals('Number of arguments should be 4', 4, args.length); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/PriorityListenersTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | public class PriorityListenersTest 7 | { 8 | [Inject] 9 | public var async:IAsync; 10 | 11 | public var completed:DeluxeSignal; 12 | private var listenersCalled:Array; 13 | 14 | [Before] 15 | public function setUp():void 16 | { 17 | completed = new DeluxeSignal(this); 18 | listenersCalled = []; 19 | } 20 | 21 | [After] 22 | public function tearDown():void 23 | { 24 | completed.removeAll(); 25 | completed = null; 26 | listenersCalled = null; 27 | } 28 | ////// 29 | [Test] 30 | public function listener_added_second_with_higher_priority_should_be_called_first():void 31 | { 32 | completed.addWithPriority( async.add(listener1, 5) ); 33 | completed.addWithPriority( async.add(listener0, 5), 10 ); 34 | 35 | completed.dispatch(); 36 | } 37 | 38 | private function listener0():void 39 | { 40 | listenersCalled.push(arguments.callee); 41 | assertSame('this should be the first listener called', arguments.callee, listenersCalled[0]); 42 | } 43 | 44 | private function listener1():void 45 | { 46 | listenersCalled.push(arguments.callee); 47 | assertSame('this should be the second listener called', arguments.callee, listenersCalled[1]); 48 | } 49 | 50 | private function listener2():void 51 | { 52 | listenersCalled.push(arguments.callee); 53 | assertSame('this should be the third listener called', arguments.callee, listenersCalled[2]); 54 | } 55 | ////// 56 | [Test] 57 | public function listeners_added_with_same_priority_should_be_called_in_order_added():void 58 | { 59 | completed.addWithPriority( async.add(listener0, 5), 10 ); 60 | completed.addWithPriority( async.add(listener1, 5), 10 ); 61 | completed.addWithPriority( async.add(listener2, 5), 10 ); 62 | 63 | completed.dispatch(); 64 | } 65 | 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/PrioritySignalTestSuite.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | [Suite] 4 | public class PrioritySignalTestSuite 5 | { 6 | 7 | public var _PriorityListenersTest:PriorityListenersTest; 8 | public var _SignalTest:SignalTest; 9 | public var _PrioritySignalTest:PrioritySignalTest; 10 | 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/PrioritySignalTestsRunner.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.core.TextCore; 4 | 5 | import flash.display.MovieClip; 6 | 7 | [SWF(width='1000', height='800', backgroundColor='#333333', frameRate='31')] 8 | public class PrioritySignalTestsRunner extends MovieClip 9 | { 10 | private var core:TextCore; 11 | 12 | public function PrioritySignalTestsRunner() 13 | { 14 | core = new TextCore(); 15 | core.textPrinter.hideLocalPaths = true; 16 | core.start(PrioritySignalTestSuite, null, this); 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/PromiseTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import org.hamcrest.assertThat; 4 | import org.hamcrest.object.isTrue; 5 | import org.hamcrest.object.sameInstance; 6 | 7 | public class PromiseTest 8 | { 9 | private var promise:Promise; 10 | 11 | [Before] 12 | public function before():void 13 | { 14 | promise = new Promise(); 15 | } 16 | 17 | [Test] 18 | public function addOncedListenerWillExecuteWhenPromiseIsDispatched():void 19 | { 20 | var isCalled:Boolean = false; 21 | function listener():void 22 | { 23 | isCalled = true; 24 | } 25 | 26 | promise.addOnce(listener); 27 | promise.dispatch(); 28 | 29 | assertThat(isCalled, isTrue()); 30 | } 31 | 32 | [Test] 33 | public function addOncedListenerWillReceiveDataWhenPromiseIsDispatched():void 34 | { 35 | var received:Object; 36 | function listener(data:Object):void 37 | { 38 | received = data; 39 | } 40 | 41 | var object:Object = {hello:"world"}; 42 | promise.addOnce(listener); 43 | promise.dispatch(object); 44 | 45 | assertThat(received, sameInstance(object)); 46 | } 47 | 48 | [Test] 49 | public function listenerWillExecuteWhenBoundAfterPromiseIsDispatched():void 50 | { 51 | var isCalled:Boolean = false; 52 | function listener():void 53 | { 54 | isCalled = true; 55 | } 56 | 57 | promise.dispatch(); 58 | promise.addOnce(listener); 59 | 60 | assertThat(isCalled, isTrue()); 61 | } 62 | 63 | [Test] 64 | public function listenerWillReceiveDataWhenBoundAfterPromiseIsDispatched():void 65 | { 66 | var received:Object; 67 | function listener(data:Object):void 68 | { 69 | received = data; 70 | } 71 | 72 | var object:Object = {hello:"world"}; 73 | promise.dispatch(object); 74 | promise.addOnce(listener); 75 | 76 | assertThat(received, sameInstance(object)); 77 | } 78 | 79 | [Test(expects="flash.errors.IllegalOperationError")] 80 | public function promiseWillThrowErrorIfDispatchedTwice():void 81 | { 82 | promise.dispatch(); 83 | promise.dispatch(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/RedispatchedEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.events.GenericEvent; 7 | 8 | public class RedispatchedEventTest 9 | { 10 | [Inject] 11 | public var async:IAsync; 12 | 13 | public var completed:DeluxeSignal; 14 | protected var originalEvent:GenericEvent; 15 | 16 | [Before] 17 | public function setUp():void 18 | { 19 | completed = new DeluxeSignal(this); 20 | } 21 | 22 | [After] 23 | public function tearDown():void 24 | { 25 | completed.removeAll(); 26 | completed = null; 27 | } 28 | ////// 29 | [Test] 30 | public function dispatch_event_already_dispatched_should_clone_it():void 31 | { 32 | completed.add(async.add(redispatchEvent, 10)); 33 | originalEvent = new GenericEvent(); 34 | completed.dispatch(originalEvent); 35 | } 36 | 37 | private function redispatchEvent(e:GenericEvent):void 38 | { 39 | DeluxeSignal(e.signal).removeAll(); 40 | assertSame(originalEvent, e); 41 | completed.add(async.add(check_redispatched_event_is_not_original, 10)); 42 | 43 | completed.dispatch(originalEvent); 44 | } 45 | 46 | private function check_redispatched_event_is_not_original(e:GenericEvent):void 47 | { 48 | assertNotSame(originalEvent, e); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalDispatchArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | public class SignalDispatchArgsTest 7 | { 8 | [Inject] 9 | public var async:IAsync; 10 | 11 | public var completed:Signal; 12 | 13 | [Before] 14 | public function setUp():void 15 | { 16 | completed = new Signal(); 17 | } 18 | 19 | [After] 20 | public function tearDown():void 21 | { 22 | completed.removeAll(); 23 | completed = null; 24 | } 25 | 26 | [Test] 27 | public function dispatch_two_correct_value_objects_should_succeed():void 28 | { 29 | var signal:Signal = new Signal(String, uint); 30 | signal.dispatch("the Answer", 42); 31 | } 32 | 33 | [Test(expects="ArgumentError")] 34 | public function dispatch_fewer_value_objects_than_value_classes_should_should_throw_ArgumentError():void 35 | { 36 | var signal:Signal = new Signal(Date, Array); 37 | signal.dispatch(new Date()); 38 | } 39 | 40 | [Test] 41 | public function dispatch_more_value_objects_than_value_classes_should_succeed():void 42 | { 43 | var signal:Signal = new Signal(Date, Array); 44 | signal.dispatch(new Date(), new Array(), "extra value object"); 45 | } 46 | 47 | [Test] 48 | public function dispatch_values_with_no_value_classes_defined_should_pass_to_listener():void 49 | { 50 | var signalNoValueClasses:Signal = new Signal(); 51 | signalNoValueClasses.add( async.add(checkDispatchedValues, 10) ); 52 | signalNoValueClasses.dispatch(22, 'done', new Date()); 53 | } 54 | 55 | private function checkDispatchedValues(a:uint, b:String, c:Date):void 56 | { 57 | assertEquals('correct number of arguments were dispatched', 3, arguments.length); 58 | assertEquals('the uint was dispatched', 22, a); 59 | assertEquals('the String was dispatched', 'done', b); 60 | assertTrue('a Date was dispatched', c is Date); 61 | } 62 | 63 | [Test(expects="ArgumentError")] 64 | public function dispatch_one_correct_and_one_incorrect_value_object_should_throw_ArgumentError():void 65 | { 66 | var signal:Signal = new Signal(Date, Array); 67 | signal.dispatch(new Date(), "wrong value type"); 68 | } 69 | 70 | 71 | 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalDispatchExtraArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | public class SignalDispatchExtraArgsTest 7 | { 8 | [Inject] 9 | public var async:IAsync; 10 | 11 | public var completed:Signal; 12 | 13 | [Before] 14 | public function setUp():void 15 | { 16 | completed = new Signal(); 17 | } 18 | 19 | [After] 20 | public function tearDown():void 21 | { 22 | completed.removeAll(); 23 | completed = null; 24 | } 25 | ////// 26 | [Test] 27 | public function dispatch_extra_args_should_call_listener_with_extra_args():void 28 | { 29 | completed.add( async.add(onCompleted, 10) ); 30 | completed.dispatch(22, 'done', new Date()); 31 | } 32 | 33 | private function onCompleted(a:uint, b:String, c:Date):void 34 | { 35 | assertEquals(3, arguments.length); 36 | assertEquals(22, a); 37 | assertEquals('done', b); 38 | assertTrue(c is Date); 39 | } 40 | ////// 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalDispatchNoArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | public class SignalDispatchNoArgsTest 7 | { 8 | [Inject] 9 | public var async:IAsync; 10 | 11 | public var signal:ISignal; 12 | 13 | [Before] 14 | public function setUp():void 15 | { 16 | signal = new Signal(); 17 | } 18 | 19 | [After] 20 | public function tearDown():void 21 | { 22 | signal.removeAll(); 23 | signal = null; 24 | } 25 | ////// 26 | [Test] 27 | public function dispatch_no_args_should_call_listener_with_no_args():void 28 | { 29 | signal.add( async.add(onCompleted, 10) ); 30 | signal.dispatch(); 31 | } 32 | 33 | private function onCompleted():void 34 | { 35 | assertEquals(0, arguments.length); 36 | } 37 | ////// 38 | [Test] 39 | public function addOnce_in_handler_and_dispatch_should_call_new_listener():void 40 | { 41 | signal.addOnce( async.add(addOnceInHandler, 10) ); 42 | signal.dispatch(); 43 | } 44 | 45 | protected function addOnceInHandler():void 46 | { 47 | signal.addOnce( async.add(secondAddOnceListener, 10) ); 48 | signal.dispatch(); 49 | } 50 | 51 | protected function secondAddOnceListener():void 52 | { 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalDispatchNonEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | public class SignalDispatchNonEventTest 7 | { 8 | [Inject] 9 | public var async:IAsync; 10 | 11 | public var completed:Signal; 12 | 13 | [Before] 14 | public function setUp():void 15 | { 16 | completed = new Signal(Date); 17 | } 18 | 19 | [After] 20 | public function tearDown():void 21 | { 22 | completed.removeAll(); 23 | completed = null; 24 | } 25 | 26 | /** 27 | * Captures bug where dispatching 0 was considered null. 28 | */ 29 | [Test] 30 | public function dispatch_zero_should_call_listener_with_zero():void 31 | { 32 | completed = new Signal(Number); 33 | completed.add( async.add(onZero, 10) ); 34 | completed.dispatch(0); 35 | } 36 | 37 | private function onZero(num:Number):void 38 | { 39 | assertEquals(0, num); 40 | } 41 | ////// 42 | [Test] 43 | public function dispatch_2_zeroes_should_call_listener_with_2_zeroes():void 44 | { 45 | completed = new Signal(Number, Number); 46 | completed.add( async.add(onZeroZero, 10) ); 47 | completed.dispatch(0, 0); 48 | } 49 | 50 | private function onZeroZero(a:Object, b:Object):void 51 | { 52 | assertEquals(0, a); 53 | assertEquals(0, b); 54 | } 55 | ////// 56 | [Test] 57 | public function dispatch_null_should_call_listener_with_null():void 58 | { 59 | completed.addOnce( async.add(checkNullDate, 10) ); 60 | completed.dispatch(null); 61 | } 62 | 63 | private function checkNullDate(date:Date):void 64 | { 65 | assertNull(date); 66 | } 67 | ////// 68 | [Test] 69 | public function dispatch_null_through_int_Signal_should_be_autoconverted_to_zero():void 70 | { 71 | completed = new Signal(int); 72 | completed.addOnce( async.add(checkNullConvertedToZero, 10) ); 73 | completed.dispatch(null); 74 | } 75 | 76 | private function checkNullConvertedToZero(intValue:int):void 77 | { 78 | assertEquals('null was converted to 0', 0, intValue); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalDispatchVarArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.assertEqualsArrays; 4 | import asunit.asserts.assertEquals; 5 | 6 | /** 7 | * @author Simon Richardson - simon@ustwo.co.uk 8 | */ 9 | public class SignalDispatchVarArgsTest 10 | { 11 | public var signal:ISignal; 12 | 13 | [Before] 14 | public function setUp():void 15 | { 16 | signal = new Signal(int, int, int, int); 17 | } 18 | 19 | [After] 20 | public function tearDown():void 21 | { 22 | signal.removeAll(); 23 | signal = null; 24 | } 25 | 26 | ////// 27 | 28 | [Test] 29 | public function adding_vararg_at_0_should_not_throw_error():void 30 | { 31 | signal.add(handlerArgsAt0()); 32 | } 33 | 34 | ////// 35 | 36 | [Test] 37 | public function adding_vararg_at_1_should_not_throw_error():void 38 | { 39 | signal.add(handlerArgsAt1()); 40 | } 41 | 42 | ////// 43 | 44 | [Test] 45 | public function adding_vararg_at_2_should_not_throw_error():void 46 | { 47 | signal.add(handlerArgsAt2()); 48 | } 49 | 50 | ////// 51 | 52 | [Test] 53 | public function adding_vararg_at_0_then_dispatch_should_not_throw_error():void 54 | { 55 | signal.add(handlerArgsAt0()); 56 | signal.dispatch(0, 1, 2, 3); 57 | } 58 | 59 | ////// 60 | 61 | [Test] 62 | public function adding_vararg_at_1_then_dispatch_should_not_throw_error():void 63 | { 64 | signal.add(handlerArgsAt1()); 65 | signal.dispatch(0, 1, 2, 3); 66 | } 67 | 68 | ////// 69 | 70 | [Test] 71 | public function adding_vararg_at_2_then_dispatch_should_not_throw_error():void 72 | { 73 | signal.add(handlerArgsAt2()); 74 | signal.dispatch(0, 1, 2, 3); 75 | } 76 | 77 | ////// 78 | 79 | [Test] 80 | public function verify_num_args_after_dispatch():void 81 | { 82 | signal.add(verifyNumArgs); 83 | signal.dispatch(0, 1, 2, 3); 84 | } 85 | 86 | ///// 87 | 88 | [Test] 89 | public function verify_redispatch_of_signal():void 90 | { 91 | const redispatch:Signal = new Signal(); 92 | redispatch.add(handlerArgsAt0()); 93 | 94 | signal.add(redispatch.dispatch); 95 | signal.dispatch(0, 1, 2, 3); 96 | } 97 | 98 | private function handlerArgsAt0():Function 99 | { 100 | return function(...args):void 101 | { 102 | assertEqualsArrays('Arguments should be [0,1,2,3]', [0,1,2,3], args); 103 | assertEquals('Number of var arguments should be 4', 4, args.length); 104 | }; 105 | } 106 | 107 | private function handlerArgsAt1():Function 108 | { 109 | return function(a:int, ...args):void 110 | { 111 | assertEqualsArrays('Arguments should be [1,2,3]', [1,2,3], args); 112 | assertEquals('Number of var arguments should be 3', 3, args.length); 113 | }; 114 | } 115 | 116 | private function handlerArgsAt2():Function 117 | { 118 | return function(a:int, b:int, ...args):void 119 | { 120 | assertEqualsArrays('Arguments should be [2,3]', [2,3], args); 121 | assertEquals('Number of var arguments should be 2', 2, args.length); 122 | }; 123 | } 124 | 125 | private function verifyNumArgs(...args):void 126 | { 127 | assertEquals('Number of arguments should be 4', 4, args.length); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | 5 | import org.osflash.signals.events.GenericEvent; 6 | 7 | import flash.display.Sprite; 8 | 9 | public class SignalTest extends ISignalTestBase 10 | { 11 | [Before] 12 | public function setUp():void 13 | { 14 | signal = new Signal(); 15 | } 16 | 17 | [Test] 18 | public function dispatch_should_pass_event_to_listener_but_not_set_signal_or_target_properties():void 19 | { 20 | signal.add(async.add(checkGenericEvent, 10)); 21 | signal.dispatch(new GenericEvent()); 22 | } 23 | 24 | protected function checkGenericEvent(e:GenericEvent):void 25 | { 26 | assertNull('event.signal is not set by Signal', e.signal); 27 | assertNull('event.target is not set by Signal', e.target); 28 | } 29 | 30 | [Test] 31 | public function dispatch_non_IEvent_without_error():void 32 | { 33 | signal.addOnce(checkSprite); 34 | // Sprite doesn't have a target property, 35 | // so if the signal tried to set .target, 36 | // an error would be thrown and this test would fail. 37 | signal.dispatch(new Sprite()); 38 | } 39 | 40 | private function checkSprite(sprite:Sprite):void 41 | { 42 | assertTrue(sprite is Sprite); 43 | } 44 | 45 | [Test] 46 | public function adding_dispatch_method_as_listener_does_not_throw_error():void 47 | { 48 | const redispatchSignal:Signal = new Signal(GenericEvent); 49 | signal = new Signal(GenericEvent); 50 | signal.add(redispatchSignal.dispatch); 51 | } 52 | 53 | [Test] 54 | public function slot_params_should_be_sent_through_to_listener():void 55 | { 56 | var listener:Function = function(number:int, string:String, sprite:Sprite):void 57 | { 58 | assertEquals(number, 12345); 59 | assertEquals(string, 'text'); 60 | assertEquals(sprite, slot.params[2]); 61 | }; 62 | 63 | var slot:ISlot = signal.add(async.add(listener)); 64 | slot.params = [12345, 'text', new Sprite()]; 65 | 66 | signal.dispatch(); 67 | } 68 | 69 | [Test] 70 | public function slot_params_with_with_10_params_should_be_sent_through_to_listener():void 71 | { 72 | // Test the function.apply - maying sure we get everything we ask for. 73 | var listener:Function = function( 74 | number:int, 75 | string:String, 76 | sprite:Sprite, 77 | alpha0:String, 78 | alpha1:String, 79 | alpha2:String, 80 | alpha3:String, 81 | alpha4:String, 82 | alpha5:String, 83 | alpha6:String 84 | ):void 85 | { 86 | assertEquals(number, 12345); 87 | assertEquals(string, 'text'); 88 | assertEquals(sprite, slot.params[2]); 89 | assertEquals(alpha0, 'a'); 90 | assertEquals(alpha1, 'b'); 91 | assertEquals(alpha2, 'c'); 92 | assertEquals(alpha3, 'd'); 93 | assertEquals(alpha4, 'e'); 94 | assertEquals(alpha5, 'f'); 95 | assertEquals(alpha6, 'g'); 96 | }; 97 | 98 | var slot:ISlot = signal.add(async.add(listener)); 99 | slot.params = [12345, 'text', new Sprite(), "a", "b", "c", "d", "e", "f", "g"]; 100 | 101 | signal.dispatch(); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SignalWithCustomEventTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.events.GenericEvent; 7 | 8 | public class SignalWithCustomEventTest 9 | { 10 | [Inject] 11 | public var async:IAsync; 12 | 13 | public var messaged:Signal; 14 | 15 | [Before] 16 | public function setUp():void 17 | { 18 | messaged = new Signal(MessageEvent); 19 | } 20 | 21 | [After] 22 | public function tearDown():void 23 | { 24 | messaged.removeAll(); 25 | messaged = null; 26 | } 27 | ////// 28 | [Test] 29 | public function valueClasses_roundtrip_through_constructor():void 30 | { 31 | assertSame(MessageEvent, messaged.valueClasses[0]); 32 | assertEquals(1, messaged.valueClasses.length); 33 | } 34 | 35 | [Test] 36 | public function valueClasses_roundtrip_through_setter():void 37 | { 38 | messaged.valueClasses = [GenericEvent]; 39 | assertSame(GenericEvent, messaged.valueClasses[0]); 40 | assertEquals(1, messaged.valueClasses.length); 41 | } 42 | 43 | [Test] 44 | public function valueClasses_setter_clones_the_array():void 45 | { 46 | var newValueClasses:Array = [GenericEvent]; 47 | messaged.valueClasses = newValueClasses; 48 | assertNotSame(newValueClasses, messaged.valueClasses); 49 | } 50 | 51 | [Test] 52 | public function add_one_listener_and_dispatch():void 53 | { 54 | messaged.add(async.add(onMessage, 50)); 55 | messaged.dispatch(new MessageEvent('ok')); 56 | } 57 | 58 | protected function onMessage(e:MessageEvent):void 59 | { 60 | assertEquals('message value in the event', 'ok', e.message); 61 | } 62 | 63 | [Test(expects="ArgumentError")] 64 | public function dispatch_wrong_event_type_should_throw_ArgumentError():void 65 | { 66 | messaged.dispatch(new GenericEvent()); 67 | } 68 | 69 | [Test(expects="ArgumentError")] 70 | public function constructing_signal_with_non_class_should_throw_ArgumentError():void 71 | { 72 | new Signal(new Date()); 73 | } 74 | 75 | [Test(expects="ArgumentError")] 76 | public function constructing_signal_with_two_nulls_should_throw_ArgumentError():void 77 | { 78 | new Signal(null, null); 79 | } 80 | 81 | [Test(expects="ArgumentError")] 82 | public function constructing_signal_with_class_and_non_class_should_throw_ArgumentError():void 83 | { 84 | new Signal(Date, 42); 85 | } 86 | 87 | } 88 | } 89 | 90 | import org.osflash.signals.events.GenericEvent; 91 | import org.osflash.signals.events.IEvent; 92 | 93 | ////// PRIVATE CLASSES ////// 94 | 95 | 96 | class MessageEvent extends GenericEvent implements IEvent 97 | { 98 | public var message:String; 99 | 100 | public function MessageEvent(message:String) 101 | { 102 | super(); 103 | this.message = message; 104 | } 105 | 106 | override public function clone():IEvent 107 | { 108 | return new MessageEvent(message); 109 | } 110 | 111 | } 112 | 113 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/SlotListTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import asunit.asserts.*; 4 | import org.osflash.signals.Signal; 5 | import org.osflash.signals.ISlot; 6 | import org.osflash.signals.SlotList; 7 | 8 | public class SlotListTest 9 | { 10 | private var signal:Signal; 11 | private var listenerA:Function; 12 | private var listenerB:Function; 13 | private var listenerC:Function; 14 | private var slotA:ISlot; 15 | private var slotB:ISlot; 16 | private var slotC:ISlot; 17 | private var listOfA:SlotList; 18 | private var listOfAB:SlotList; 19 | private var listOfABC:SlotList; 20 | 21 | [Before] 22 | public function setUp():void 23 | { 24 | signal = new Signal(); 25 | listenerA = function(e:* = null):void {}; 26 | listenerB = function(e:* = null):void {}; 27 | listenerC = function(e:* = null):void {}; 28 | slotA = new Slot(listenerA, signal); 29 | slotB = new Slot(listenerB, signal); 30 | slotC = new Slot(listenerC, signal); 31 | listOfA = new SlotList(slotA); 32 | listOfAB = listOfA.append(slotB); 33 | listOfABC = listOfAB.append(slotC); 34 | } 35 | 36 | [Test] 37 | public function NIL_has_length_zero():void 38 | { 39 | assertEquals(0, SlotList.NIL.length); 40 | } 41 | 42 | [Test] 43 | public function tail_defaults_to_NIL_if_omitted_in_constructor():void 44 | { 45 | const noTail:SlotList = new SlotList(slotA); 46 | assertSame(SlotList.NIL, noTail.tail); 47 | } 48 | 49 | [Test] 50 | public function tail_defaults_to_NIL_if_passed_null_in_constructor():void 51 | { 52 | const nullTail:SlotList = new SlotList(slotA, null); 53 | assertSame(SlotList.NIL, nullTail.tail); 54 | } 55 | 56 | [Test(expects="ArgumentError")] 57 | public function constructing_with_null_head_throws_error():void 58 | { 59 | new SlotList(null, listOfA); 60 | } 61 | 62 | [Test] 63 | public function list_with_one_listener_contains_it():void 64 | { 65 | assertTrue(listOfA.contains(listenerA)); 66 | } 67 | 68 | [Test] 69 | public function find_the_only_listener_yields_its_slot():void 70 | { 71 | assertSame(slotA, listOfA.find(listenerA)); 72 | } 73 | 74 | [Test] 75 | public function list_with_one_listener_has_it_in_its_head():void 76 | { 77 | assertSame(listenerA, listOfA.head.listener); 78 | } 79 | 80 | [Test] 81 | public function NIL_does_not_contain_anonymous_listener():void 82 | { 83 | assertFalse(SlotList.NIL.contains(function():void {})); 84 | } 85 | 86 | [Test] 87 | public function find_in_empty_list_yields_null():void 88 | { 89 | assertNull(SlotList.NIL.find(listenerA)); 90 | } 91 | 92 | [Test] 93 | public function NIL_does_not_contain_null_listener():void 94 | { 95 | assertFalse(SlotList.NIL.contains(null)); 96 | } 97 | 98 | [Test] 99 | public function find_the_1st_of_2_listeners_yields_its_slot():void 100 | { 101 | assertSame(slotA, listOfAB.find(listenerA)); 102 | } 103 | 104 | [Test] 105 | public function find_the_2nd_of_2_listeners_yields_its_slot():void 106 | { 107 | assertSame(slotB, listOfAB.find(listenerB)); 108 | } 109 | 110 | [Test] 111 | public function find_the_1st_of_3_listeners_yields_its_slot():void 112 | { 113 | assertSame(slotA, listOfABC.find(listenerA)); 114 | } 115 | 116 | [Test] 117 | public function find_the_2nd_of_3_listeners_yields_its_slot():void 118 | { 119 | assertSame(slotB, listOfABC.find(listenerB)); 120 | } 121 | 122 | [Test] 123 | public function find_the_3rd_of_3_listeners_yields_its_slot():void 124 | { 125 | assertSame(slotC, listOfABC.find(listenerC)); 126 | } 127 | 128 | [Test] 129 | public function prepend_a_slot_makes_it_head_of_new_list():void 130 | { 131 | const newList:SlotList = listOfA.prepend(slotB); 132 | assertSame(slotB, newList.head); 133 | } 134 | 135 | [Test] 136 | public function prepend_a_slot_makes_the_old_list_the_tail():void 137 | { 138 | const newList:SlotList = listOfA.prepend(slotB); 139 | assertSame(listOfA, newList.tail); 140 | } 141 | 142 | [Test] 143 | public function after_prepend_slot_new_list_contains_its_listener():void 144 | { 145 | const newList:SlotList = listOfA.prepend(slotB); 146 | assertTrue(newList.contains(slotB.listener)); 147 | } 148 | 149 | [Test] 150 | public function append_a_slot_yields_new_list_with_same_head():void 151 | { 152 | const oldHead:ISlot = listOfA.head; 153 | const newList:SlotList = listOfA.append(slotB); 154 | assertSame(oldHead, newList.head); 155 | } 156 | 157 | [Test] 158 | public function append_to_list_of_one_yields_list_of_length_two():void 159 | { 160 | const newList:SlotList = listOfA.append(slotB); 161 | assertEquals(2, newList.length); 162 | } 163 | 164 | [Test] 165 | public function after_append_slot_new_list_contains_its_listener():void 166 | { 167 | const newList:SlotList = listOfA.append(slotB); 168 | assertTrue(newList.contains(slotB.listener)); 169 | } 170 | 171 | [Test] 172 | public function append_slot_yields_a_different_list():void 173 | { 174 | const newList:SlotList = listOfA.append(slotB); 175 | assertNotSame(listOfA, newList); 176 | } 177 | 178 | [Test] 179 | public function append_null_yields_same_list():void 180 | { 181 | const newList:SlotList = listOfA.append(null); 182 | assertSame(listOfA, newList); 183 | } 184 | 185 | [Test] 186 | public function filterNot_on_empty_list_yields_same_list():void 187 | { 188 | const newList:SlotList = SlotList.NIL.filterNot(listenerA); 189 | assertSame(SlotList.NIL, newList); 190 | } 191 | 192 | [Test] 193 | public function filterNot_null_yields_same_list():void 194 | { 195 | const newList:SlotList = listOfA.filterNot(null); 196 | assertSame(listOfA, newList); 197 | } 198 | 199 | [Test] 200 | public function filterNot_head_from_list_of_1_yields_empty_list():void 201 | { 202 | const newList:SlotList = listOfA.filterNot(listOfA.head.listener); 203 | assertSame(SlotList.NIL, newList); 204 | } 205 | 206 | [Test] 207 | public function filterNot_1st_listener_from_list_of_2_yields_list_of_2nd_listener():void 208 | { 209 | const newList:SlotList = listOfAB.filterNot(listenerA); 210 | assertSame(listenerB, newList.head.listener); 211 | assertEquals(1, newList.length); 212 | } 213 | 214 | [Test] 215 | public function filterNot_2nd_listener_from_list_of_2_yields_list_of_head():void 216 | { 217 | const newList:SlotList = listOfAB.filterNot(listenerB); 218 | assertSame(listenerA, newList.head.listener); 219 | assertEquals(1, newList.length); 220 | } 221 | 222 | [Test] 223 | public function filterNot_2nd_listener_from_list_of_3_yields_list_of_1st_and_3rd():void 224 | { 225 | const newList:SlotList = listOfABC.filterNot(listenerB); 226 | assertSame(listenerA, newList.head.listener); 227 | assertSame(listenerC, newList.tail.head.listener); 228 | assertEquals(2, newList.length); 229 | } 230 | 231 | // Issue #56 232 | [Test] 233 | public function insertWithPriority_adds_4_slots_without_losing_any():void 234 | { 235 | var s:PrioritySignal = new PrioritySignal(); 236 | var l1:Function = function():void{}; 237 | var l2:Function = function():void{}; 238 | var l3:Function = function():void{}; 239 | var l4:Function = function():void{}; 240 | var slot1:ISlot = new Slot(l1, s); 241 | var slot2:ISlot = new Slot(l2, s, false, -1); 242 | var slot3:ISlot = new Slot(l3, s); 243 | var slot4:ISlot = new Slot(l4, s); 244 | var list:SlotList = new SlotList(slot1); 245 | list = list.insertWithPriority(slot2); 246 | list = list.insertWithPriority(slot3); 247 | list = list.insertWithPriority(slot4); 248 | // This was failing because one slot was being lost. 249 | assertEquals("number of slots in list", 4, list.length); 250 | assertEquals(slot1, list.head); 251 | assertEquals(slot3, list.tail.head); 252 | assertEquals(slot4, list.tail.tail.head); 253 | assertEquals(slot2, list.tail.tail.tail.head); 254 | } 255 | } 256 | } -------------------------------------------------------------------------------- /tests/org/osflash/signals/SlotTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals 2 | { 3 | import org.osflash.signals.events.GenericEvent; 4 | /** 5 | * @author Simon Richardson - simon@ustwo.co.uk 6 | */ 7 | public class SlotTest extends ISlotTestBase 8 | { 9 | 10 | [Before] 11 | public function setUp():void 12 | { 13 | signal = new Signal(); 14 | } 15 | 16 | [Test] 17 | public function add_listener_pause_then_resume_on_slot_should_dispatch():void 18 | { 19 | var slot:ISlot = signal.add(async.add(checkGenericEvent, 10)); 20 | slot.enabled = false; 21 | slot.enabled = true; 22 | 23 | signal.dispatch(new GenericEvent()); 24 | } 25 | 26 | [Test] 27 | public function addOnce_listener_pause_then_resume_on_slot_should_dispatch():void 28 | { 29 | var slot:ISlot = signal.addOnce(async.add(checkGenericEvent, 10)); 30 | slot.enabled = false; 31 | slot.enabled = true; 32 | 33 | signal.dispatch(new GenericEvent()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/AmbiguousRelationshipInNativeSignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | 8 | public class AmbiguousRelationshipInNativeSignalTest 9 | { 10 | private var target:Sprite; 11 | 12 | private var instance:NativeSignal; 13 | 14 | [Before] 15 | public function setUp():void 16 | { 17 | target = new Sprite(); 18 | instance = new NativeSignal(target, Event.CHANGE); 19 | } 20 | 21 | [After] 22 | public function tearDown():void 23 | { 24 | instance = null; 25 | } 26 | 27 | [Test(expects="flash.errors.IllegalOperationError")] 28 | public function add_then_addOnce_throws_error():void 29 | { 30 | instance.add(failIfCalled); 31 | instance.addOnce(failIfCalled); 32 | } 33 | 34 | [Test(expects="flash.errors.IllegalOperationError")] 35 | public function addOnce_then_add_should_throw_error():void 36 | { 37 | instance.addOnce(failIfCalled); 38 | instance.add(failIfCalled); 39 | } 40 | 41 | [Test] 42 | public function add_then_add_should_not_throw_error():void 43 | { 44 | instance.add(failIfCalled); 45 | instance.add(failIfCalled); 46 | assertEquals(1, instance.numListeners); 47 | } 48 | 49 | [Test] 50 | public function addOnce_then_addOnce_should_not_throw_error():void 51 | { 52 | instance.addOnce(failIfCalled); 53 | instance.addOnce(failIfCalled); 54 | assertEquals(1, instance.numListeners); 55 | } 56 | 57 | private function failIfCalled(event:Event):void 58 | { 59 | fail("if this listener is called, something horrible is going on"); 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/MXMLNativeSignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | import flash.events.Event; 5 | import flash.events.MouseEvent; 6 | import org.osflash.signals.support.SpriteWithNativeSignals; 7 | 8 | import flash.display.Sprite; 9 | 10 | public class MXMLNativeSignalTest 11 | { 12 | [Inject] public var context:Sprite; 13 | 14 | private var mxmlSprite:SpriteWithNativeSignals; 15 | 16 | [Before] 17 | public function setUp():void 18 | { 19 | mxmlSprite = new SpriteWithNativeSignals(); 20 | } 21 | 22 | [After] 23 | public function tearDown():void 24 | { 25 | mxmlSprite = null; 26 | } 27 | 28 | [Test] 29 | public function mxml_object_has_NativeSignals_after_creation():void 30 | { 31 | assertTrue(mxmlSprite.clicked is NativeSignal); 32 | assertTrue(mxmlSprite.doubleClicked is NativeSignal); 33 | assertTrue(mxmlSprite.addedToStage is NativeSignal); 34 | } 35 | 36 | [Test] 37 | public function has_eventClass_from_mxml_default_property():void 38 | { 39 | assertEquals(MouseEvent, mxmlSprite.clicked.eventClass); 40 | } 41 | 42 | [Test] 43 | public function has_eventType_from_mxml_attribute():void 44 | { 45 | assertEquals(MouseEvent.CLICK, mxmlSprite.clicked.eventType); 46 | } 47 | 48 | [Test] 49 | public function has_target_from_mxml_attribute():void 50 | { 51 | assertEquals(mxmlSprite, mxmlSprite.clicked.target); 52 | } 53 | 54 | [Test] 55 | public function has_eventClass_from_mxml_attribute():void 56 | { 57 | assertEquals(MouseEvent, mxmlSprite.doubleClicked.eventClass); 58 | } 59 | 60 | [Test] 61 | public function omitted_eventClass_defaults_to_Event():void 62 | { 63 | assertEquals(Event, mxmlSprite.addedToStage.eventClass); 64 | } 65 | 66 | [Test] 67 | public function add_listener_then_dispatch_calls_listener():void 68 | { 69 | var called:Boolean = false; 70 | var handler:Function = function(event:Event):void { called = true; }; 71 | mxmlSprite.addedToStage.addOnce(handler); 72 | // when 73 | context.addChild(mxmlSprite); 74 | // then 75 | assertTrue(called); 76 | context.removeChild(mxmlSprite); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeMappedSignalBoundaryUseTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.IPrioritySignal; 7 | 8 | import flash.display.Sprite; 9 | import flash.events.MouseEvent; 10 | 11 | public class NativeMappedSignalBoundaryUseTest 12 | { 13 | [Inject] 14 | public var async:IAsync; 15 | 16 | private var signalArrayOfFunctions:NativeMappedSignal; 17 | private var signalPassArray:NativeMappedSignal; 18 | private var signalPassArrayThroughFunction:NativeMappedSignal; 19 | private var sprite:Sprite; 20 | private const EventType:String = MouseEvent.CLICK; 21 | private const func1:Function = function ():String { return 'mapped arg 1'; }; 22 | private const func2:Function = function ():String { return 'mapped arg 2'; }; 23 | private const MappedArray:Array = [0, 1]; 24 | 25 | [Before] 26 | public function setUp():void 27 | { 28 | sprite = new Sprite(); 29 | signalArrayOfFunctions = new NativeMappedSignal(sprite, EventType).mapTo(func1, func2); 30 | signalPassArray = new NativeMappedSignal(sprite, EventType).mapTo(MappedArray); 31 | signalPassArrayThroughFunction = new NativeMappedSignal(sprite, EventType, MouseEvent, Array).mapTo( 32 | function ():Array { 33 | return MappedArray; 34 | } 35 | ); 36 | } 37 | 38 | [After] 39 | public function tearDown():void 40 | { 41 | signalArrayOfFunctions.removeAll(); 42 | signalArrayOfFunctions = null; 43 | signalPassArray.removeAll(); 44 | signalPassArray = null; 45 | signalPassArrayThroughFunction.removeAll(); 46 | signalPassArrayThroughFunction = null; 47 | } 48 | 49 | [Test] 50 | public function testInstantiated():void 51 | { 52 | assertFalse('sprite has no click event listener to start', sprite.hasEventListener(EventType)); 53 | 54 | assertTrue("NativeMappedSignal instantiated", signalArrayOfFunctions is NativeMappedSignal); 55 | assertTrue('implements ISignal', signalArrayOfFunctions is IPrioritySignal); 56 | assertSame('has no value classes', 0, signalArrayOfFunctions.valueClasses.length); 57 | 58 | assertTrue("NativeMappedSignal instantiated", signalPassArray is NativeMappedSignal); 59 | assertTrue('implements IPrioritySignal', signalPassArray is IPrioritySignal); 60 | assertSame('has no value classed', 0, signalPassArray.valueClasses.length); 61 | 62 | assertTrue("NativeMappedSignal instantiated", signalPassArrayThroughFunction is NativeMappedSignal); 63 | assertTrue('implements IPrioritySignal', signalPassArrayThroughFunction is IPrioritySignal); 64 | assertSame('has only one value class', 1, signalPassArrayThroughFunction.valueClasses.length); 65 | assertSame('single value class is of type Array', Array, signalPassArrayThroughFunction.valueClasses[0]); 66 | } 67 | ////// 68 | [Test] 69 | public function signal_array_of_functions_add_then_callback_called():void 70 | { 71 | signalArrayOfFunctions.add( async.add(callbackTwoFunctions, 10) ); 72 | sprite.dispatchEvent(new MouseEvent(EventType)); 73 | } 74 | 75 | private function callbackTwoFunctions(argFunc1:Function, argFunc2:Function):void 76 | { 77 | assertSame(func1, argFunc1); 78 | assertSame(func2, argFunc2); 79 | } 80 | 81 | [Test] 82 | public function signal_pass_array_add_then_array_callback_should_be_called():void 83 | { 84 | signalPassArray.add( async.add(callbackArrayAsArg, 10) ); 85 | sprite.dispatchEvent(new MouseEvent(EventType)); 86 | } 87 | 88 | private function callbackArrayAsArg(argArray:Array):void 89 | { 90 | assertSame(MappedArray, argArray); 91 | } 92 | 93 | [Test] 94 | public function signal_pass_array_through_function_add_then_array_callback_should_be_called():void 95 | { 96 | signalPassArrayThroughFunction.add( async.add(callbackArrayAsArg, 10) ); 97 | sprite.dispatchEvent(new MouseEvent(EventType)); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeMappedSignalDefaultsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.framework.IAsync; 4 | 5 | import flash.display.Sprite; 6 | import flash.events.MouseEvent; 7 | 8 | public class NativeMappedSignalDefaultsTest 9 | { 10 | [Inject] 11 | public var async:IAsync; 12 | 13 | private var signalDefault:NativeMappedSignal; 14 | private var signalDefaultWithMappingObject:NativeMappedSignal; 15 | private var signalDefaultWithMappingFunction:NativeMappedSignal; 16 | private var signalWithValueClassesWithoutMappingFunction:NativeMappedSignal; 17 | private var sprite:Sprite; 18 | private const EventType:String = MouseEvent.CLICK; 19 | private const MappedObject:String = "mapped " + EventType; 20 | 21 | [Before] 22 | public function setUp():void 23 | { 24 | sprite = new Sprite(); 25 | signalDefault = new NativeMappedSignal(sprite, EventType); 26 | signalDefaultWithMappingObject = new NativeMappedSignal(sprite, EventType).mapTo(MappedObject); 27 | signalDefaultWithMappingFunction = new NativeMappedSignal(sprite, EventType).mapTo( 28 | function ():String { 29 | return MappedObject; 30 | } 31 | ); 32 | signalWithValueClassesWithoutMappingFunction = new NativeMappedSignal(sprite, EventType, MouseEvent, String); 33 | } 34 | 35 | [After] 36 | public function tearDown():void 37 | { 38 | signalDefault.removeAll(); 39 | signalDefault = null; 40 | signalDefaultWithMappingObject.removeAll(); 41 | signalDefaultWithMappingObject = null; 42 | signalDefaultWithMappingFunction.removeAll(); 43 | signalDefaultWithMappingFunction = null; 44 | signalWithValueClassesWithoutMappingFunction.removeAll(); 45 | signalWithValueClassesWithoutMappingFunction = null; 46 | } 47 | 48 | ////// 49 | [Test] 50 | public function signal_default_add_then_emptyCallback_should_be_called():void 51 | { 52 | signalDefault.add( async.add(emptyCallback, 10) ); 53 | sprite.dispatchEvent(new MouseEvent(EventType)); 54 | } 55 | 56 | private function emptyCallback(e:* = null):void {} 57 | 58 | [Test] 59 | public function signal_default_with_mapped_object_add_then_emptyCallback_should_be_called():void 60 | { 61 | signalDefaultWithMappingObject.add( async.add(emptyCallback, 10) ); 62 | sprite.dispatchEvent(new MouseEvent(EventType)); 63 | } 64 | 65 | [Test] 66 | public function signal_default_with_mapped_function_add_then_emptyCallback_should_be_called():void 67 | { 68 | signalDefaultWithMappingFunction.add( async.add(emptyCallback, 10) ); 69 | sprite.dispatchEvent(new MouseEvent(EventType)); 70 | } 71 | 72 | [Test(expects="ArgumentError")] 73 | public function signal_with_value_classes_without_mapping_function():void 74 | { 75 | signalWithValueClassesWithoutMappingFunction.dispatch(new MouseEvent(EventType)); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeMappedSignalFunctionArgTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.IPrioritySignal; 7 | 8 | import flash.display.Sprite; 9 | import flash.events.Event; 10 | import flash.events.MouseEvent; 11 | 12 | public class NativeMappedSignalFunctionArgTest 13 | { 14 | [Inject] 15 | public var async:IAsync; 16 | 17 | private var signal:NativeMappedSignal; 18 | private var signalMappingToEventType:NativeMappedSignal; 19 | private var signalMappingToIncorrectEventType:NativeMappedSignal; 20 | private var signalMappingToVoid:NativeMappedSignal; 21 | private var sprite:Sprite; 22 | private const EventType:String = MouseEvent.CLICK; 23 | private const MappedObject:String = "mapped " + EventType; 24 | 25 | [Before] 26 | public function setUp():void 27 | { 28 | sprite = new Sprite(); 29 | signal = new NativeMappedSignal(sprite, EventType, MouseEvent, String).mapTo( 30 | function ():String { 31 | return MappedObject; 32 | } 33 | ); 34 | 35 | signalMappingToEventType = new NativeMappedSignal(sprite, EventType, MouseEvent, String).mapTo( 36 | function (event:MouseEvent):String { 37 | return event.type; 38 | } 39 | ); 40 | 41 | signalMappingToIncorrectEventType = new NativeMappedSignal(sprite, EventType, MouseEvent, String).mapTo( 42 | function (event:MouseEvent):int { 43 | return event.delta; 44 | } 45 | ); 46 | 47 | signalMappingToVoid = new NativeMappedSignal(sprite, EventType).mapTo(function ():void {}); 48 | } 49 | 50 | [After] 51 | public function tearDown():void 52 | { 53 | signal.removeAll(); 54 | signal = null; 55 | signalMappingToEventType.removeAll(); 56 | signalMappingToEventType = null; 57 | signalMappingToIncorrectEventType.removeAll(); 58 | signalMappingToIncorrectEventType = null; 59 | signalMappingToVoid.removeAll(); 60 | signalMappingToVoid = null; 61 | } 62 | 63 | [Test] 64 | public function testInstantiated():void 65 | { 66 | assertFalse('sprite has no click event listener to start', sprite.hasEventListener(EventType)); 67 | 68 | assertTrue("NativeMappedSignal instantiated", signal is NativeMappedSignal); 69 | assertTrue('implements IPrioritySignal', signal is IPrioritySignal); 70 | assertSame('has only one value class', 1, signal.valueClasses.length); 71 | assertSame('single value class is of type String', String, signal.valueClasses[0]); 72 | 73 | assertTrue("NativeMappedSignal instantiated", signalMappingToEventType is NativeMappedSignal); 74 | assertTrue('implements IPrioritySignal', signalMappingToEventType is IPrioritySignal); 75 | assertSame('has only one value class', 1, signalMappingToEventType.valueClasses.length); 76 | assertSame('single value class is of type String', String, signalMappingToEventType.valueClasses[0]); 77 | 78 | assertTrue("NativeMappedSignal instantiated", signalMappingToIncorrectEventType is NativeMappedSignal); 79 | assertTrue('implements IPrioritySignal', signalMappingToIncorrectEventType is IPrioritySignal); 80 | assertSame('has only one value class', 1, signalMappingToIncorrectEventType.valueClasses.length); 81 | assertSame('single value class is of type String', String, signalMappingToIncorrectEventType.valueClasses[0]); 82 | 83 | assertTrue("NativeMappedSignal instantiated", signalMappingToVoid is NativeMappedSignal); 84 | assertTrue('implements IPrioritySignal', signalMappingToVoid is IPrioritySignal); 85 | assertSame('has no value classes', 0, signalMappingToVoid.valueClasses.length); 86 | } 87 | 88 | private function dispatchTestEvent():void 89 | { 90 | sprite.dispatchEvent(buildTestEvent()); 91 | } 92 | 93 | private function buildTestEvent():Event 94 | { 95 | return new MouseEvent(EventType); 96 | } 97 | 98 | ////// 99 | [Test] 100 | public function signal_add_then_mapped_object_should_be_callback_argument():void 101 | { 102 | signal.add( async.add(checkMappedArgument, 10) ); 103 | dispatchTestEvent(); 104 | } 105 | 106 | private function checkMappedArgument(argument:String):void 107 | { 108 | assertSame(MappedObject, argument); 109 | } 110 | ////// 111 | [Test] 112 | public function mapping_function_should_receive_event_as_argument():void 113 | { 114 | signalMappingToEventType.add( async.add(checkMappedEventTypeArgument, 10) ); 115 | dispatchTestEvent(); 116 | } 117 | 118 | private function checkMappedEventTypeArgument(argument:String):void 119 | { 120 | assertSame(EventType, argument); 121 | } 122 | 123 | [Test(expects="ArgumentError")] 124 | public function mapping_function_has_to_many_arguments_should_throw_ArgumentError():void 125 | { 126 | new NativeMappedSignal(sprite, EventType, MouseEvent, String).mapTo( 127 | function (event:MouseEvent, extraArg:Object):String { 128 | return event.type; 129 | } 130 | ); 131 | } 132 | 133 | [Test(expects="Error")] 134 | public function mapping_function_returns_incorrectly_typed_argument_should_throw_Error():void 135 | { 136 | signalMappingToIncorrectEventType.dispatch(buildTestEvent()); 137 | } 138 | 139 | private function emptyHandler(argument:String):void {} 140 | 141 | [Test] 142 | public function mapping_to_void():void 143 | { 144 | signalMappingToVoid.add(async.add(emptyHandler, 10)); 145 | dispatchTestEvent(); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeMappedSignalFunctionNoArgsTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.IPrioritySignal; 7 | 8 | import flash.display.Sprite; 9 | import flash.events.MouseEvent; 10 | 11 | public class NativeMappedSignalFunctionNoArgsTest 12 | { 13 | [Inject] 14 | public var async:IAsync; 15 | 16 | private var signalSingle:NativeMappedSignal; 17 | private var signalList:NativeMappedSignal; 18 | private var sprite:Sprite; 19 | private const EventType:String = MouseEvent.CLICK; 20 | private const MappedObject:String = "mapped " + EventType; 21 | private const MappedObject2:int = 3; 22 | private const MappedObject3:Number = 3.1415; 23 | 24 | [Before] 25 | public function setUp():void 26 | { 27 | sprite = new Sprite(); 28 | signalSingle = new NativeMappedSignal(sprite, EventType, MouseEvent, String).mapTo( 29 | function ():String { 30 | return MappedObject; 31 | } 32 | ); 33 | 34 | signalList = new NativeMappedSignal(sprite, EventType, MouseEvent, String, int, Number).mapTo( 35 | function ():Array 36 | { 37 | return [MappedObject, MappedObject2, MappedObject3]; 38 | } 39 | ); 40 | } 41 | 42 | [After] 43 | public function tearDown():void 44 | { 45 | signalSingle.removeAll(); 46 | signalSingle = null; 47 | signalList.removeAll(); 48 | signalList = null; 49 | } 50 | 51 | [Test] 52 | public function testInstantiated():void 53 | { 54 | assertFalse('sprite has no click event listener to start', sprite.hasEventListener(EventType)); 55 | 56 | assertTrue("NativeMappedSignal instantiated", signalSingle is NativeMappedSignal); 57 | assertTrue('implements IPrioritySignal', signalSingle is IPrioritySignal); 58 | assertSame('has only one value class', 1, signalSingle.valueClasses.length); 59 | assertSame('single value class is of type String', String, signalSingle.valueClasses[0]); 60 | 61 | assertTrue("NativeMappedSignal instantiated", signalList is NativeMappedSignal); 62 | assertTrue('implements IPrioritySignal', signalList is IPrioritySignal); 63 | assertSame('has three value classes', 3, signalList.valueClasses.length); 64 | assertSame('first value class is of type String', String, signalList.valueClasses[0]); 65 | assertSame('second value class is of type int', int, signalList.valueClasses[1]); 66 | assertSame('third value class is of type Number', Number, signalList.valueClasses[2]); 67 | } 68 | ////// 69 | [Test] 70 | public function signal_add_then_mapped_object_should_be_callback_argument():void 71 | { 72 | signalSingle.add( async.add(checkMappedArgumentSingle, 10) ); 73 | sprite.dispatchEvent(new MouseEvent(EventType)); 74 | } 75 | 76 | private function checkMappedArgumentSingle(argument:String):void 77 | { 78 | assertSame(MappedObject, argument); 79 | } 80 | ////// 81 | [Test] 82 | public function signal_list_add_then_mapped_object_should_be_callback_argument():void 83 | { 84 | signalList.add( async.add(checkMappedArgumentList, 10) ); 85 | sprite.dispatchEvent(new MouseEvent(EventType)); 86 | } 87 | 88 | private function checkMappedArgumentList(argument1:String, argument2:int, argument3:Number):void 89 | { 90 | assertSame(MappedObject, argument1); 91 | assertSame(MappedObject2, argument2); 92 | assertSame(MappedObject3, argument3); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeMappedSignalObjectArgTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | import asunit.framework.IAsync; 5 | 6 | import org.osflash.signals.IPrioritySignal; 7 | 8 | import flash.display.Sprite; 9 | import flash.events.MouseEvent; 10 | 11 | public class NativeMappedSignalObjectArgTest 12 | { 13 | [Inject] 14 | public var async:IAsync; 15 | 16 | private var signalSingle:NativeMappedSignal; 17 | private var signalList:NativeMappedSignal; 18 | private var sprite:Sprite; 19 | private const EventType:String = MouseEvent.CLICK; 20 | private const MappedObject:String = "mapped " + EventType; 21 | private const MappedObject2:int = 3; 22 | private const MappedObject3:Number = 3.1415; 23 | 24 | [Before] 25 | public function setUp():void 26 | { 27 | sprite = new Sprite(); 28 | signalSingle = new NativeMappedSignal(sprite, EventType, MouseEvent, String).mapTo(MappedObject); 29 | signalList = new NativeMappedSignal(sprite, EventType, MouseEvent, String, int, Number).mapTo(MappedObject, MappedObject2, MappedObject3); 30 | } 31 | 32 | [After] 33 | public function tearDown():void 34 | { 35 | signalSingle.removeAll(); 36 | signalSingle = null; 37 | signalList.removeAll(); 38 | signalList = null; 39 | } 40 | 41 | [Test] 42 | public function testInstantiated():void 43 | { 44 | assertFalse('sprite has no click event listener to start', sprite.hasEventListener(EventType)); 45 | 46 | assertTrue("NativeMappedSignal instantiated", signalSingle is NativeMappedSignal); 47 | assertTrue('implements ISignal', signalSingle is IPrioritySignal); 48 | assertSame('has only one value class', 1, signalSingle.valueClasses.length); 49 | assertSame('single value class is of type String', String, signalSingle.valueClasses[0]); 50 | 51 | assertTrue("NativeMappedSignal instantiated", signalList is NativeMappedSignal); 52 | assertTrue('implements IPrioritySignal', signalList is IPrioritySignal); 53 | assertSame('has three value classes', 3, signalList.valueClasses.length); 54 | assertSame('first value class is of type String', String, signalList.valueClasses[0]); 55 | assertSame('second value class is of type int', int, signalList.valueClasses[1]); 56 | assertSame('third value class is of type Number', Number, signalList.valueClasses[2]); 57 | } 58 | ////// 59 | [Test] 60 | public function signal_single_add_then_mapped_object_should_be_callback_argument():void 61 | { 62 | signalSingle.add( async.add(checkMappedArgumentSingle, 10) ); 63 | sprite.dispatchEvent(new MouseEvent(EventType)); 64 | } 65 | 66 | private function checkMappedArgumentSingle(argument:String):void 67 | { 68 | assertSame(MappedObject, argument); 69 | } 70 | ////// 71 | [Test] 72 | public function signal_list_add_then_mapped_object_should_be_callback_argument():void 73 | { 74 | signalList.add( async.add(checkMappedArgumentList, 10) ); 75 | sprite.dispatchEvent(new MouseEvent(EventType)); 76 | } 77 | 78 | private function checkMappedArgumentList(argument1:String, argument2:int, argument3:Number):void 79 | { 80 | assertSame(MappedObject, argument1); 81 | assertSame(MappedObject2, argument2); 82 | assertSame(MappedObject3, argument3); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeRelaySignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | import flash.events.EventDispatcher; 8 | import flash.events.MouseEvent; 9 | 10 | public class NativeRelaySignalTest extends INativeDispatcherTestBase 11 | { 12 | [Before] 13 | public function setUp():void 14 | { 15 | sprite = new Sprite(); 16 | clicked = new NativeRelaySignal(sprite, 'click', MouseEvent); 17 | signal = new NativeRelaySignal(new EventDispatcher(), 'test', Event); 18 | } 19 | 20 | [After] 21 | public function tearDown():void 22 | { 23 | clicked.removeAll(); 24 | clicked = null; 25 | } 26 | 27 | [Test] 28 | public function setting_eventClass_to_null_defaults_it_to_Event():void 29 | { 30 | NativeRelaySignal(clicked).eventClass = null; 31 | clicked.dispatch(new Event('click')); 32 | assertSame(Event, clicked.eventClass); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeSignalSlotTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import org.osflash.signals.ISlotTestBase; 4 | 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | import flash.events.IEventDispatcher; 8 | /** 9 | * @author Simon Richardson - me@simonrichardson.info 10 | */ 11 | public class NativeSignalSlotTest extends ISlotTestBase 12 | { 13 | private var sprite:IEventDispatcher; 14 | 15 | [Before] 16 | public function setUp():void 17 | { 18 | sprite = new Sprite(); 19 | signal = new NativeSignal(sprite, 'click', Event); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/NativeSignalTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives 2 | { 3 | import asunit.asserts.*; 4 | 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | import flash.events.EventDispatcher; 8 | import flash.events.MouseEvent; 9 | 10 | public class NativeSignalTest extends INativeDispatcherTestBase 11 | { 12 | [Before] 13 | public function setUp():void 14 | { 15 | sprite = new Sprite(); 16 | clicked = new NativeSignal(sprite, 'click', MouseEvent); 17 | signal = new NativeSignal(new EventDispatcher(), 'test', Event); 18 | } 19 | 20 | [After] 21 | public function tearDown():void 22 | { 23 | clicked.removeAll(); 24 | clicked = null; 25 | } 26 | 27 | [Test] 28 | public function setting_eventClass_to_null_defaults_it_to_Event():void 29 | { 30 | NativeSignal(clicked).eventClass = null; 31 | // This was causing a null exception: Issue #32. 32 | clicked.dispatch(new Event('click')); 33 | assertSame(Event, clicked.eventClass); 34 | } 35 | 36 | [Test] 37 | public function adding_listener_with_no_args_does_not_throw_error():void 38 | { 39 | clicked.add(function():void {}); 40 | } 41 | 42 | [Test] 43 | public function adding_listener_with_varargs_does_not_throw_error():void 44 | { 45 | clicked.add(function(...args):void {}); 46 | } 47 | 48 | [Test] 49 | public function adding_listener_with_more_than_one_arg_does_not_throw_error():void 50 | { 51 | clicked.add(function(a:*, b:*):void { } ); 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/base/SignalSpriteTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.base 2 | { 3 | import asunit.asserts.assertEquals; 4 | import asunit.asserts.assertSame; 5 | import asunit.asserts.assertTrue; 6 | import asunit.framework.IAsync; 7 | 8 | import org.osflash.signals.natives.sets.InteractiveObjectSignalSet; 9 | 10 | import flash.events.MouseEvent; 11 | 12 | public class SignalSpriteTest 13 | { 14 | [Inject] 15 | public var async:IAsync; 16 | 17 | private var sprite:SignalSprite; 18 | 19 | [Before] 20 | public function setUp():void 21 | { 22 | sprite = new SignalSprite(); 23 | } 24 | 25 | [After] 26 | public function tearDown():void 27 | { 28 | sprite.signals.removeAll(); 29 | sprite = null; 30 | } 31 | 32 | [Test] 33 | public function has_signals_after_creation():void 34 | { 35 | assertTrue(sprite.signals is InteractiveObjectSignalSet); 36 | } 37 | 38 | [Test] 39 | public function numListeners_is_0_after_creation():void 40 | { 41 | assertEquals(sprite.signals.numListeners, 0); 42 | } 43 | 44 | [Test] 45 | public function signal_add_then_EventDispatcher_dispatch_should_call_signal_listener():void 46 | { 47 | sprite.signals.click.add( async.add(checkClickEvent) ); 48 | sprite.dispatchEvent(new MouseEvent(MouseEvent.CLICK)); 49 | } 50 | 51 | private function checkClickEvent(event:MouseEvent):void 52 | { 53 | assertSame(MouseEvent.CLICK, event.type); 54 | assertSame(sprite, event.target); 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/sets/EventDispatcherSignalSetTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import org.osflash.signals.ISlot; 4 | import asunit.asserts.fail; 5 | import asunit.asserts.assertNotNull; 6 | import asunit.asserts.assertSame; 7 | import asunit.asserts.assertTrue; 8 | import asunit.framework.IAsync; 9 | 10 | import flash.display.Sprite; 11 | import flash.events.Event; 12 | /** 13 | * @author Simon Richardson - simon@ustwo.co.uk 14 | */ 15 | public class EventDispatcherSignalSetTest 16 | { 17 | 18 | [Inject] 19 | public var async:IAsync; 20 | 21 | private var sprite:Sprite; 22 | 23 | private var signalSet:EventDispatcherSignalSet; 24 | 25 | [Before] 26 | public function setUp():void 27 | { 28 | sprite = new Sprite(); 29 | signalSet = new EventDispatcherSignalSet(sprite); 30 | } 31 | 32 | [After] 33 | public function tearDown():void 34 | { 35 | signalSet.removeAll(); 36 | signalSet = null; 37 | sprite = null; 38 | } 39 | 40 | 41 | protected function newEmptyHandler():Function 42 | { 43 | return function(e:*):void {}; 44 | } 45 | 46 | private function handleEvent(event:Event):void 47 | { 48 | assertSame(sprite, event.target); 49 | } 50 | 51 | protected function failIfCalled(e:Event):void 52 | { 53 | fail('This event handler should not have been called.'); 54 | } 55 | 56 | ////// 57 | 58 | [Test] 59 | public function numListeners_should_be_zero():void 60 | { 61 | assertTrue('Number of listeners should be 0.', signalSet.numListeners == 0); 62 | } 63 | 64 | ////// 65 | 66 | [Test] 67 | public function signals_should_be_not_null():void 68 | { 69 | assertNotNull('Signals should not be null.', signalSet.signals); 70 | } 71 | 72 | ////// 73 | 74 | [Test] 75 | public function signals_length_should_be_empty():void 76 | { 77 | assertTrue('Signals length should be 0.', signalSet.signals.length == 0); 78 | } 79 | 80 | ////// 81 | 82 | [Test] 83 | public function signals_length_should_be_zero_after_removeAll():void 84 | { 85 | signalSet.removeAll(); 86 | 87 | assertTrue('Signals length should be 0.', signalSet.signals.length == 0); 88 | } 89 | 90 | ////// 91 | 92 | [Test] 93 | public function numListeners_should_be_zero_after_removeAll():void 94 | { 95 | signalSet.removeAll(); 96 | 97 | assertTrue('Number of listeners should be 0.', signalSet.numListeners == 0); 98 | } 99 | 100 | ////// 101 | 102 | [Test] 103 | public function activate_signal_should_not_be_null():void 104 | { 105 | assertNotNull('Activate NativeSignal should not be null', signalSet.activate); 106 | } 107 | 108 | ////// 109 | 110 | [Test] 111 | public function deactivate_signal_should_not_be_null():void 112 | { 113 | assertNotNull('Deactivate NativeSignal should not be null', signalSet.deactivate); 114 | } 115 | 116 | ////// 117 | 118 | [Test] 119 | public function add_activate_then_EventDispatcher_dispatch_should_call_signal_listener():void 120 | { 121 | signalSet.activate.add(async.add(handleEvent)); 122 | sprite.dispatchEvent(new Event(Event.ACTIVATE)); 123 | } 124 | 125 | ////// 126 | 127 | [Test] 128 | public function add_deactivate_then_EventDispatcher_dispatch_should_call_signal_listener():void 129 | { 130 | signalSet.deactivate.add(async.add(handleEvent)); 131 | sprite.dispatchEvent(new Event(Event.DEACTIVATE)); 132 | } 133 | 134 | ////// 135 | 136 | [Test] 137 | public function add_activate_then_pause_and_dispatch_should_not_call_signal_listener():void 138 | { 139 | const slot:ISlot = signalSet.activate.add(failIfCalled); 140 | slot.enabled = false; 141 | 142 | sprite.dispatchEvent(new Event(Event.ACTIVATE)); 143 | } 144 | 145 | ////// 146 | 147 | [Test] 148 | public function add_deactivate_then_pause_and_dispatch_should_not_call_signal_listener():void 149 | { 150 | const slot:ISlot = signalSet.deactivate.add(failIfCalled); 151 | slot.enabled = false; 152 | 153 | sprite.dispatchEvent(new Event(Event.DEACTIVATE)); 154 | } 155 | 156 | ////// 157 | 158 | [Test] 159 | public function add_activate_then_numListeners_should_be_one():void 160 | { 161 | signalSet.activate.add(handleEvent); 162 | assertTrue('Number of listeners should be 1', signalSet.numListeners == 1); 163 | } 164 | 165 | ////// 166 | 167 | [Test] 168 | public function add_deactivate_then_numListeners_should_be_one():void 169 | { 170 | signalSet.deactivate.add(handleEvent); 171 | assertTrue('Number of listeners should be 1', signalSet.numListeners == 1); 172 | } 173 | 174 | ////// 175 | 176 | [Test] 177 | public function add_too_both_signals_then_numListeners_should_be_two():void 178 | { 179 | signalSet.activate.add(handleEvent); 180 | signalSet.deactivate.add(handleEvent); 181 | assertTrue('Number of listeners should be 2', signalSet.numListeners == 2); 182 | } 183 | 184 | [Test] 185 | public function add_too_both_signals_then_remove_activate_numListeners_should_be_one():void 186 | { 187 | signalSet.activate.add(handleEvent); 188 | signalSet.deactivate.add(handleEvent); 189 | 190 | signalSet.activate.removeAll(); 191 | 192 | assertTrue('Number of listeners should be 1', signalSet.numListeners == 1); 193 | } 194 | 195 | [Test] 196 | public function add_too_both_signals_then_remove_deactivate_numListeners_should_be_one():void 197 | { 198 | signalSet.activate.add(handleEvent); 199 | signalSet.deactivate.add(handleEvent); 200 | 201 | signalSet.deactivate.removeAll(); 202 | 203 | assertTrue('Number of listeners should be 1', signalSet.numListeners == 1); 204 | } 205 | 206 | [Test] 207 | public function add_too_both_signals_then_removeAll_numListeners_should_be_zero():void 208 | { 209 | signalSet.activate.add(handleEvent); 210 | signalSet.deactivate.add(handleEvent); 211 | 212 | signalSet.removeAll(); 213 | 214 | assertTrue('Number of listeners should be 0', signalSet.numListeners == 0); 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/natives/sets/NativeSignalSetTest.as: -------------------------------------------------------------------------------- 1 | package org.osflash.signals.natives.sets 2 | { 3 | import flash.events.Event; 4 | import org.osflash.signals.natives.NativeSignal; 5 | import asunit.asserts.assertNotNull; 6 | import asunit.asserts.assertTrue; 7 | import asunit.framework.IAsync; 8 | 9 | import flash.display.Sprite; 10 | /** 11 | * @author Simon Richardson - me@simonrichardson.info 12 | */ 13 | public class NativeSignalSetTest 14 | { 15 | 16 | [Inject] 17 | public var async:IAsync; 18 | 19 | private var sprite:Sprite; 20 | 21 | private var signalSet:NativeSignalSet; 22 | 23 | [Before] 24 | public function setUp():void 25 | { 26 | sprite = new Sprite(); 27 | signalSet = new NativeSignalSet(sprite); 28 | } 29 | 30 | [After] 31 | public function tearDown():void 32 | { 33 | signalSet.removeAll(); 34 | signalSet = null; 35 | sprite = null; 36 | } 37 | 38 | protected function newEmptyHandler():Function 39 | { 40 | return function(e:*):void {}; 41 | } 42 | 43 | ////// 44 | 45 | [Test] 46 | public function numListeners_should_be_zero():void 47 | { 48 | assertTrue('Number of listeners should be 0.', signalSet.numListeners == 0); 49 | } 50 | 51 | ////// 52 | 53 | [Test] 54 | public function signals_should_be_not_null():void 55 | { 56 | assertNotNull('Signals should not be null.', signalSet.signals); 57 | } 58 | 59 | ////// 60 | 61 | [Test] 62 | public function signals_length_should_be_empty():void 63 | { 64 | assertTrue('Signals length should be 0.', signalSet.signals.length == 0); 65 | } 66 | 67 | ////// 68 | 69 | [Test] 70 | public function signals_length_should_be_zero_after_removeAll():void 71 | { 72 | signalSet.removeAll(); 73 | 74 | assertTrue('Signals length should be 0.', signalSet.signals.length == 0); 75 | } 76 | 77 | ////// 78 | 79 | [Test] 80 | public function numListeners_should_be_zero_after_removeAll():void 81 | { 82 | signalSet.removeAll(); 83 | 84 | assertTrue('Number of listeners should be 0.', signalSet.numListeners == 0); 85 | } 86 | 87 | ////// 88 | 89 | [Test] 90 | public function getNativeSignal_should_return_NativeSignal():void 91 | { 92 | const result:NativeSignal = signalSet.getNativeSignal(Event.INIT); 93 | assertTrue('getNativeSignal should return type NativeSignal.', result is NativeSignal); 94 | } 95 | 96 | ////// 97 | 98 | [Test] 99 | public function getNativeSignal_should_not_throw_Error_when_null_is_used_as_classType():void 100 | { 101 | signalSet.getNativeSignal(Event.INIT, null); 102 | } 103 | 104 | ////// 105 | 106 | [Test(expects='ArgumentError')] 107 | public function getNativeSignal_should_throw_Error_when_used_for_event_type():void 108 | { 109 | signalSet.getNativeSignal(null); 110 | } 111 | 112 | ////// 113 | 114 | [Test] 115 | public function getNativeSignal_should_increment_num_signals_to_one():void 116 | { 117 | signalSet.getNativeSignal(Event.INIT); 118 | 119 | assertTrue('Number of Signals should be 1', signalSet.signals.length == 1); 120 | } 121 | 122 | ////// 123 | 124 | [Test] 125 | public function getNativeSignal_with_same_event_type_should_have_signal_length_of_one():void 126 | { 127 | signalSet.getNativeSignal(Event.INIT); 128 | signalSet.getNativeSignal(Event.INIT); 129 | 130 | assertTrue('Number of Signals should be 1', signalSet.signals.length == 1); 131 | } 132 | 133 | ////// 134 | 135 | [Test] 136 | public function getNativeSignal_with_different_eventType_should_increment_num_signals_to_two():void 137 | { 138 | signalSet.getNativeSignal(Event.INIT); 139 | signalSet.getNativeSignal(Event.ACTIVATE); 140 | 141 | assertTrue('Number of Signals should be 2', signalSet.signals.length == 2); 142 | } 143 | 144 | ////// 145 | 146 | [Test] 147 | public function getNativeSignal_with_lots_of_different_eventType_should_increment_num_signals_to_100():void 148 | { 149 | for(var i:int = 0; i<100; i++) 150 | { 151 | signalSet.getNativeSignal("event" + i); 152 | } 153 | 154 | assertTrue('Number of Signals should be 100', signalSet.signals.length == 100); 155 | } 156 | 157 | ////// 158 | 159 | [Test] 160 | public function get_lots_of_getNativeSignal_then_removeAll_should_have_zero_signals():void 161 | { 162 | for(var i:int = 0; i<100; i++) 163 | { 164 | signalSet.getNativeSignal("event" + i); 165 | } 166 | 167 | signalSet.removeAll(); 168 | 169 | assertTrue('Number of Signals should be 0', signalSet.signals.length == 0); 170 | } 171 | 172 | ////// 173 | 174 | [Test] 175 | public function getNativeSignal_and_add_listener():void 176 | { 177 | const nativeSignal:NativeSignal = signalSet.getNativeSignal(Event.INIT); 178 | nativeSignal.add(newEmptyHandler()); 179 | 180 | assertTrue('Number of listeners should be 1.', signalSet.numListeners == 1); 181 | } 182 | 183 | ////// 184 | 185 | [Test] 186 | public function getNativeSignal_and_add_10_listeners():void 187 | { 188 | const nativeSignal:NativeSignal = signalSet.getNativeSignal(Event.INIT); 189 | 190 | for(var i:int = 0; i<10; i++) 191 | { 192 | nativeSignal.add(newEmptyHandler()); 193 | } 194 | 195 | assertTrue('Number of listeners should be 10.', signalSet.numListeners == 10); 196 | } 197 | 198 | ////// 199 | 200 | [Test] 201 | public function getNativeSignal_and_add_10_listeners_and_removeAll():void 202 | { 203 | const nativeSignal:NativeSignal = signalSet.getNativeSignal(Event.INIT); 204 | 205 | for(var i:int = 0; i<10; i++) 206 | { 207 | nativeSignal.add(newEmptyHandler()); 208 | } 209 | 210 | signalSet.removeAll(); 211 | 212 | assertTrue('Number of listeners should be 0.', signalSet.numListeners == 0); 213 | } 214 | 215 | ////// 216 | 217 | [Test] 218 | public function getNativeSignal_and_add_10_listeners_and_removeAll_from_signal():void 219 | { 220 | const nativeSignal:NativeSignal = signalSet.getNativeSignal(Event.INIT); 221 | 222 | for(var i:int = 0; i<10; i++) 223 | { 224 | nativeSignal.add(newEmptyHandler()); 225 | } 226 | 227 | nativeSignal.removeAll(); 228 | 229 | assertTrue('Number of listeners should be 0.', signalSet.numListeners == 0); 230 | } 231 | 232 | ////// 233 | 234 | [Test] 235 | public function get_two_getNativeSignal_and_add_10_listeners_to_each():void 236 | { 237 | const nativeSignal0:NativeSignal = signalSet.getNativeSignal(Event.INIT); 238 | 239 | var i:int = 0; 240 | for(i = 0; i<10; i++) 241 | { 242 | nativeSignal0.add(newEmptyHandler()); 243 | } 244 | 245 | const nativeSignal1:NativeSignal = signalSet.getNativeSignal(Event.CHANGE); 246 | 247 | for(i = 0; i<10; i++) 248 | { 249 | nativeSignal1.add(newEmptyHandler()); 250 | } 251 | 252 | assertTrue('Number of listeners should be 20.', signalSet.numListeners == 20); 253 | } 254 | 255 | ////// 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/support/SpriteWithDeluxeSignals.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | {IEvent} 14 | 15 | 16 | [String, uint] 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/support/SpriteWithNativeSignals.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | {MouseEvent} 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/org/osflash/signals/support/SpriteWithSignals.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | {uint} 8 | 9 | 10 | [String, uint] 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | --------------------------------------------------------------------------------