Files
narya/src/as/com/threerings/util/Util.as
T
Ray Greenwell 62fb546f27 Check this out. This little buddy rocks.
I sorta want to make a new FunctionUtil so that I can use it
with impunity everwhere without having to include the other crap in here.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5730 542714f4-19e9-0310-aa3c-eee0fc999fb1
2009-04-17 21:23:23 +00:00

257 lines
9.0 KiB
ActionScript

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.util {
import flash.utils.ByteArray;
import flash.utils.getQualifiedClassName;
public class Util
{
/**
* Initialize the target object with values present in the initProps object and the defaults
* object. Neither initProps nor defaults will be modified.
* @throws ReferenceError if a property cannot be set on the target object.
*
* @param target any object or class instance.
* @param initProps a plain Object hash containing names and properties to set on the target
* object.
* @param defaults a plain Object hash containing names and properties to set on the target
* object, only if the same property name does not exist in initProps.
* @param maskProps a plain Object hash containing names of properties to omit setting
* from the initProps object. This allows you to add custom properties to
* initProps without having to modify the value from your callers.
*/
public static function init (
target :Object, initProps :Object, defaults :Object = null, maskProps :Object = null) :void
{
var prop :String;
for (prop in initProps) {
if (maskProps == null || !(prop in maskProps)) {
target[prop] = initProps[prop];
}
}
if (defaults != null) {
for (prop in defaults) {
if (initProps == null || !(prop in initProps)) {
target[prop] = defaults[prop];
}
}
}
}
/**
* Return a var-args function that will attempt to pass only the arguments accepted by the
* passed-in function. Does not work if the passed-in function is varargs, and anyway
* then you don't need adapting, do you?
*/
public static function adapt (fn :Function) :Function
{
return function (... args) :* {
args.length = fn.length; // fit the args to the fn, filling in 'undefined' if growing
return fn.apply(null, args);
}
}
/**
* Returns true if the specified object is just a regular old associative hash.
*/
public static function isPlainObject (obj :Object) :Boolean
{
return getQualifiedClassName(obj) == "Object";
}
/**
* Is the specified object 'simple': one of the basic built-in flash types.
*/
public static function isSimple (obj :Object) :Boolean
{
var type :String = typeof(obj);
switch (type) {
case "number":
case "string":
case "boolean":
return true;
case "object":
return (obj is Date) || (obj is Array);
default:
return false;
}
}
/**
* Get an array containing the property keys of the specified object, in their
* natural iteration order.
*/
public static function keys (obj :Object) :Array
{
var arr :Array = [];
for (var k :* in obj) { // no "each": iterate over keys
arr.push(k);
}
return arr;
}
/**
* Get an array containing the property values of the specified object, in their
* natural iteration order.
*/
public static function values (obj :Object) :Array
{
var arr :Array = [];
for each (var v :* in obj) { // "each" iterates over values
arr.push(v);
}
return arr;
}
/**
* Parse the 'value' object into XML safely. This is equivalent to <code>new XML(value)</code>
* but offers protection from other code that may have changing the default settings
* used for parsing XML. Also, if you would like to use non-standard parsing settings
* this method will protect other code from being broken by you.
*
* @param value the value to parse into XML.
* @param settings an Object containing your desired XML settings, or null (or omitted) to
* use the default settings.
* @see XML#setSettings()
*/
public static function newXML (value :Object, settings :Object = null) :XML
{
return safeXMLOp(function () :* {
return new XML(value);
}, settings) as XML;
}
/**
* Call toString() on the specified XML object safely. This is equivalent to
* <code>xml.toString()</code> but offers protection from other code that may have changed
* the default settings used for stringing XML. Also, if you would like to use the
* non-standard printing settings this method will protect other code from being
* broken by you.
*
* @param xml the xml value to Stringify.
* @param settings an Object containing your desired XML settings, or null (or omitted) to
* use the default settings.
* @see XML#toString()
* @see XML#setSettings()
*/
public static function XMLtoString (xml :XML, settings :Object = null) :String
{
return safeXMLOp(function () :* {
return xml.toString();
}, settings) as String;
}
/**
* Call toXMLString() on the specified XML object safely. This is equivalent to
* <code>xml.toXMLString()</code> but offers protection from other code that may have changed
* the default settings used for stringing XML. Also, if you would like to use the
* non-standard printing settings this method will protect other code from being
* broken by you.
*
* @param xml the xml value to Stringify.
* @param settings an Object containing your desired XML settings, or null (or omitted) to
* use the default settings.
* @see XML#toXMLString()
* @see XML#setSettings()
*/
public static function XMLtoXMLString (xml :XML, settings :Object = null) :String
{
return safeXMLOp(function () :* {
return xml.toXMLString();
}, settings) as String;
}
/**
* Perform an operation on XML that takes place using the specified settings, and
* restores the XML settings to their previous values.
*
* @param fn a function to be called with no arguments.
* @param settings an Object containing your desired XML settings, or null (or omitted) to
* use the default settings.
*
* @return the return value of your function, if any.
* @see XML#setSettings()
* @see XML#settings()
*/
public static function safeXMLOp (fn :Function, settings :Object = null) :*
{
var oldSettings :Object = XML.settings();
try {
XML.setSettings(settings); // setting to null resets to all the defaults
return fn();
} finally {
XML.setSettings(oldSettings);
}
}
/**
* A nice utility method for testing equality in a better way.
* If the objects are Equalable, then that will be tested. Arrays
* and ByteArrays are also compared and are equal if they have
* elements that are equals (deeply).
*/
public static function equals (obj1 :Object, obj2 :Object) :Boolean
{
// catch various common cases (both primitive or null)
if (obj1 === obj2) {
return true;
} else if (obj1 is Equalable) {
// if obj1 is Equalable, then that decides it
return (obj1 as Equalable).equals(obj2);
} else if ((obj1 is Array) && (obj2 is Array)) {
return ArrayUtil.equals(obj1 as Array, obj2 as Array);
} else if ((obj1 is ByteArray) && (obj2 is ByteArray)) {
var ba1 :ByteArray = (obj1 as ByteArray);
var ba2 :ByteArray = (obj2 as ByteArray);
if (ba1.length != ba2.length) {
return false;
}
for (var ii :int = 0; ii < ba1.length; ii++) {
if (ba1[ii] != ba2[ii]) {
return false;
}
}
return true;
}
return false;
}
/**
* If you call a varargs method by passing it an array, the array
* will end up being arg 1.
*/
public static function unfuckVarargs (args :Array) :Array
{
return (args.length == 1 && (args[0] is Array)) ? (args[0] as Array)
: args;
}
}
}