Scry is used to turn a regular object into one with callbacks. A simple example:
Suppose that you have an object vect
.
var vect = (function() {
var x = 1;
var y = 2;
return {
setX: function(xVal) { x = xVal; },
setY: function(yVal) { y = yVal; },
move: function(xVal, yVal) { x = xVal; y = yVal; },
draw: function() { /* Drawing code here */ }
};
}());
You want to add some logging functionality to vect
, so that every time
vect.setX
is called, you see some output. You can use Scry
to
achieve this by making vect.setX
watchable.
Scry.gaze(vect, ['setX']);
Now you can watch vect.setX
with
var id = vect.scry.watch('setX', function(x) {
alert('vect.setX called with argument ' + x);
});
vect.setX(2); // alerts
You can stop watching any time with
vect.scry.unwatch(id);
vect.setX(3); // no alert
Scry is built according to the Universal Module
Definition guidelines, so it should work
with AMD loaders (e.g. require.js), with node,
or simply by including it in the browser before your other code, like a
global variable Scry
. If you happen to be using node, Scry should be
available in the npm repositories, so you can
npm install scry
See the examples folder for examples of all three.
- Watch any method on any object. Works with plain objects, as above, but also with prototyped or inherited objects.
- Preserves object constructor. If you had an instance of
Vect
before, then it will still be aVect
after youScry.gaze
it.
There are a couple of important things to know. When you use
Scry.gaze
, your object is permanently changed. This means that
-
If there was something at
object.scry
before - it's no longer useable. This isn't generally a problem, but if it is there is an optional third argument toScry.gaze
, which is the name to use instead of 'scry'. Ex:Scry.gaze(vect, ['addX', 'addY'], 'watcher'); var id = vect.watcher.watch('addX', callback);
A very spectial version is to pass in
'.'
as the name, which will simply place the scry methodswatch
,unwatch
,watchAll
, etc. on your base object.Scry.gaze(vect, ['addX', 'addY'], '.'); var id = vect.watch('addX', callback);
-
Don't use
Scry.gaze
on it again, in order to e.g. make more of the methods gazeable. I hope to fix this in a future release. -
Your object methods are now slower. There is some overhead in looking for the callbacks and parsing arguments. For most cases, the cost of the function and the callback will outweigh the overhead, so this won't matter. But I wouldn't gaze at objects or methods unless you need to.
-
There is no
Scry.ungaze
yet. I'm working on it.
-
Scry.gaze(object, methodNames [, altName]);
Adds
object.scry
toobject
, allowing for any of the functions below to be used. Note that only methods named in the second parameter can be watched or unwatched - all others will be silently ignored.The optional parameter
altName
provides an alternative name to use instead of 'scry', making the functions below available onobject[altName]
instead ofobject.scry
. However, if you pass the special case'.'
asaltName
, the methods below will all be placed directly onobject
.-
object.scry.watch(methodName, callback);
Watch the given method, so that whenver
object[methodName]
is called,callback
is called afterward. The arguments given to callback are the same as the arguments given toobject[methodName]
. Returns an id, to be used withunwatch
. -
object.scry.watchAll(callback);
Watch all the watchable methods, calling
callback
whenever one is called. The arguments given tocallback
are the name of the method called, followed by the arguments given to that method. Returns an id of a global watcher, which can be removed with -
object.scry.unwatch(id);
Stop the watcher with the given id. The id of a watcher can be obtained when
watch
orwatchAll
is first called. -
object.scry.unwatchAll([methods]);
Stop many watchers at once. Can be called with
- no arguments: stop all watchers on all methods
- one argument (a string
fname
): stop all watchers on the methodfname
- one argument (an array of
fnames
): stop all watchers on every method infnames
-
object.scry.methods();
Return a list with the names of all watchable methods.
-
object.scry.quietly(fname, without [, arg1, arg2, ...]);
Call the function given by
fname
with the arguments given, but without alerting any of the watchers whose ids are presented in the array of idswithout
. The typical use case is when an objectA
is watching the scried objectB
, and must callB.buzz
wheneverB.fizz
is called, and must callB.fizz
wheneverB.fuzz
is called. This would lead to an infinite loop of callbacks, unless it can callB.buzz
without then getting a signal thatB.fizz
was called. It should use e.g.B.scry.quietly(fname, this.fizzWatcherId, args);
Note that
without
can be either an array of ids or a single id. -
object.scry.silently(fname [, arg1, arg2, ...]);
Call the function given by
fname
with the supplied arguments, but don't alert any of the watchers. Equivalent toobject.scry.quietly(fname, object.scry.methods(), arg1, arg2, ...);
-
My goal is to use as unrestrictive a license as possible. If this license does not fit your requirements, please contact me as I would be more than happy to allow you to use this code under any conditions that you see fit.
All code in this project is placed under the following license, save:
- the copy of require.js provided in
examples/browser-requirejs/lib
, which is copyright (c) The Dojo Foundation and used under the MIT license. - the copy of qunit provided in
tests/resources
, which is copyright (c) The jQuery Foundation and other contributors and used under the MIT license.
The MIT License (MIT) Copyright (c) 2013 Brian Shourd
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.