Skip to content

Commit

Permalink
Idea for allowing less arguments than the dispatching Signal
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Richardson committed Apr 11, 2011
1 parent bd94583 commit 76a48c9
Show file tree
Hide file tree
Showing 6 changed files with 363 additions and 3 deletions.
53 changes: 53 additions & 0 deletions src/org/osflash/signals/ISignalBindingSlot.as
@@ -0,0 +1,53 @@
package org.osflash.signals
{
/**
* @author Simon Richardson - simon@ustwo.co.uk
*/
public interface ISignalBindingSlot
{

/**
* Executes a listener of arity <code>0</code>.
*/
function execute0():void;

/**
* Executes a listener of arity <code>1</code>.
*
* @param value1 The argument for the listener.
*/
function execute1(value:Object):void;

/**
* Executes a listener of arity <code>2</code>.
*
* @param value1 The argument for the listener.
* @param value2 The argument for the listener.
*/
function execute2(value1:Object, value2:Object):void;

/**
* Executes a listener of arity <code>3</code>.
*
* @param value1 The argument for the listener.
* @param value2 The argument for the listener.
* @param value3 The argument for the listener.
*/
function execute3(value1:Object, value2:Object, value3:Object):void;

/**
* Executes a listener of arity <code>n</code>.
*
* @param args The argument for the listener.
*/
function execute(...args) : void;

/**
* The listener associated with this slot binding.
*/
function get listener() : Function;
function set listener(value : Function) : void;

function get numArguments() : int;
}
}
4 changes: 3 additions & 1 deletion src/org/osflash/signals/SignalBinding.as
Expand Up @@ -70,7 +70,9 @@ package org.osflash.signals

// Work out what the strict mode is from the signal and set it here. You can change
// the value of strict mode on the binding itself at a later date.
strict = signal.strict;
_strict = signal.strict;

verifyListener(listener);
}

/**
Expand Down
79 changes: 79 additions & 0 deletions src/org/osflash/signals/SignalBindingSlot.as
@@ -0,0 +1,79 @@
package org.osflash.signals
{
/**
* @author Simon Richardson - simon@ustwo.co.uk
*/
public class SignalBindingSlot implements ISignalBindingSlot
{

/**
* Private backing variable for the <code>listener</code> property.
* @private
*/
private var _listener : Function;

/**
* Private backing variable for the <code>numArguments</code> property.
* @private
*/
private var _numArguments : int;

public function SignalBindingSlot(listener : Function)
{
_listener = listener;
// Use the listener length to generate the numArguments
_numArguments = listener.length;
}

/**
* @inheritDoc
*/
public function execute0() : void
{
_listener();
}

/**
* @inheritDoc
*/
public function execute1(valueObject1:Object) : void
{
_listener(valueObject1);
}

/**
* @inheritDoc
*/
public function execute2(valueObject1:Object, valueObject2:Object) : void
{
_listener(valueObject1, valueObject2);
}

/**
* @inheritDoc
*/
public function execute3(valueObject1:Object, valueObject2:Object, valueObject3:Object) : void
{
_listener(valueObject1, valueObject2, valueObject3);
}

/**
* @inheritDoc
*/
public function execute(...args) : void
{
_listener.apply(null, args);
}

/**
* @inheritDoc
*/
public function get listener() : Function { return _listener; }
public function set listener(value : Function) : void { _listener = value; }

/**
* @inheritDoc
*/
public function get numArguments() : int { return _numArguments; }
}
}
42 changes: 42 additions & 0 deletions src/org/osflash/signals/SlotSignal.as
@@ -0,0 +1,42 @@
package org.osflash.signals
{
/**
* @author Simon Richardson - simon@ustwo.co.uk
*/
public class SlotSignal extends Signal
{
/**
* Creates a SlotSignal instance to dispatch arguments that are less than the ammount of
* valueClasses passed in via the constructor.
* @param valueClasses Any number of class references that enable type checks in dispatch().
* For example, var signal : SlotSignal = new SlotSignal(String, uint)
* would allow: signal.add(function(s:String):void{})
*
*
* NOTE: Subclasses cannot call super.apply(null, valueClasses),
* but this constructor has logic to support super(valueClasses).
*/
public function SlotSignal(...valueClasses)
{
// Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses).
valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0]:valueClasses;

super(valueClasses);
}

/**
* @inheritDoc
*/
override protected function registerListener(listener:Function, once:Boolean = false):ISignalBinding
{
if (registrationPossible(listener, once))
{
const binding:ISignalBinding = new SlotSignalBinding(listener, once, this);
bindings = new SignalBindingList(binding, bindings);
return binding;
}

return bindings.find(listener);
}
}
}
185 changes: 185 additions & 0 deletions src/org/osflash/signals/SlotSignalBinding.as
@@ -0,0 +1,185 @@
package org.osflash.signals
{
/**
* @author Simon Richardson - simon@ustwo.co.uk
*/
public class SlotSignalBinding implements ISignalBinding
{
/**
* Private backing variable for the <code>signal</code> property.
* @private
*/
private var _signal:ISignal;

/**
* Private backing variable for the <code>enabled</code> property.
* @private
*/
private var _enabled:Boolean = true;

/**
* Private backing variable for the <code>strict</code> property.
* @private
*/
private var _strict:Boolean = true;

/**
* Private backing variable for the <code>once</code> property.
*
* Visible in the signals package for fast access.
* @private
*/
private var _once:Boolean;

/**
* Private backing variable for the <code>priority</code> property.
*
* Visible in the signals package for fast access.
* @private
*/
private var _priority:int;

/**
* @private
*/
private var _slot:ISignalBindingSlot;

/**
* Creates and returns a new SignalBinding object.
*
* @param listener The listener associated with the binding.
* @param once Whether or not the listener should be executed only once.
* @param signal The signal associated with the binding.
* @param priority The priority of the binding.
*
* @throws ArgumentError An error is thrown if the given listener closure is <code>null</code>.
*/
public function SlotSignalBinding(listener:Function, once:Boolean = false, signal:ISignal = null, priority:int = 0)
{
_once = once;
_signal = signal;
_priority = priority;

// Work out what the strict mode is from the signal and set it here. You can change
// the value of strict mode on the binding itself at a later date.
_strict = signal.strict;

verifyListener(listener);

_slot = new SignalBindingSlot(listener);
}

/**
* @inheritDoc
*/
public function execute(valueObjects:Array):void
{
if (!_enabled) return;
if (_once) remove();

// Here we're using what the listener.length is to provide the correct arguments.
const numArguments : int = _slot.numArguments;
if(numArguments == 0)
{
_slot.execute0();
}
else if(numArguments == 1)
{
_slot.execute1(valueObjects[0]);
}
else if(numArguments == 2)
{
_slot.execute2(valueObjects[0], valueObjects[1]);
}
else if(numArguments == 3)
{
_slot.execute3(valueObjects[0], valueObjects[1], valueObjects[2]);
}
else
{
_slot.execute.apply(null, valueObjects);
}
}

/**
* @inheritDoc
*/
public function get listener():Function
{
return _slot.listener;
}

public function set listener(value:Function):void
{
if (null == value) throw new ArgumentError(
'Given listener is null.\nDid you want to call pause() instead?');

verifyListener(value);

_slot.listener = value;
}

/**
* @inheritDoc
*/
public function get once():Boolean { return _once; }

/**
* @inheritDoc
*/
public function get priority():int { return _priority; }

/**
* Creates and returns the string representation of the current object.
*
* @return The string representation of the current object.
*/
public function toString():String
{
return "[SlotSignalBinding listener: "+listener+", once: "+_once
+", priority: "+_priority+", enabled: "+_enabled+"]";
}

/**
* @inheritDoc
*/
public function get enabled():Boolean { return _enabled; }

public function set enabled(value:Boolean):void { _enabled = value; }

/**
* @inheritDoc
*/
public function get strict():Boolean { return _strict; }

public function set strict(value:Boolean):void
{
_strict = value;

// Check that when we move from one strict mode to another strict mode and verify the
// listener again.
verifyListener(listener);
}

/**
* @inheritDoc
*/
public function remove():void
{
_signal.remove(_slot.listener);
}

protected function verifyListener(listener:Function): void
{
if (null == listener)
{
throw new ArgumentError('Given listener is null.');
}

if (null == _signal)
{
throw new Error('Internal signal reference has not been set yet.');
}
}
}
}
3 changes: 1 addition & 2 deletions src/org/osflash/signals/natives/NativeSignal.as
Expand Up @@ -181,8 +181,7 @@ package org.osflash.signals.natives

protected function registerListener(listener:Function, once:Boolean = false, priority:int = 0):ISignalBinding
{
//TODO: Consider removing this check to allow ...args listeners.
if (listener.length != 1)
if (_strict && listener.length != 1)
throw new ArgumentError('Listener for native event must declare exactly 1 argument.');

if (registrationPossible(listener, once))
Expand Down

0 comments on commit 76a48c9

Please sign in to comment.