Re-defining named functions at runtime - actionscript-3

What I am trying to do is kind of odd, but I am wondering if anyone can come up with a clever way to do what I want to do. Basically, I want to re-define a named function at runtime. I can do this with anonymous functions, but I can't figure out a way to do it for named functions. I want to do this so that I can implement a "spy" functionality on an object for a testing framework (a port of Jasmine to Flex).
Take, for instance, this class:
public class TestClass
{
public var anonymous:Function = function():void {
trace("original anonymous");
};
public function named():void {
trace("original named");
}
}
I can easily re-define the anonymous function because it is just a variable. Javascript uses this idiom a lot.
var testClass:TestClass = new TestClass();
testClass.anonymous = function():void { trace("overridden anonymous"); }
BUT, when I do the same thing for named functions, you get a compile-time error:
// Does not compile
testClass.named = function():void { trace("overridden named"); }
I tried to make it a bit more "squishy" but this leads to a runtime failure "Cannot assign to a method named on TestClass".
// Compiles with runtime failure
testClass["named"] = function():void { trace("overridden named"); }
Can anyone more clever than I come up with a way to hack this? Can the bytecode be hijacked? Something?

I want to modify an object, not a
class
But object doesn't contain functions, only non-static variables. I tried to use prototype property and replace method there, but original method still gets called instead of injected one.
About "hack" bytecode, do you mean "hack" already loaded SWF in runtime? I think it's not possible. I'm sure, though, you can parse SWF with something like as3swf, find method in bytecode, replace it and save result in new SWF.

I had an idea bout making a function "cache" . This might work with what you need.
Let's say you have a class "Car" with a method you need to redefine at runtime:
public class Car extends Sprite
{
private var functionCache:Function;
public function Car()
{
super();
}
public function flexibleFunction(functionBody:*=null):void{
if(functionBody is Function){
functionBody.call();
functionCache=functionBody;
} else {
functionCache(functionBody);
}
}
}
Usage:
public class Main extends Sprite
{
private var car:Car;
public function Main()
{
car = new Car();
car.flexibleFunction(function(){trace("redefine test #1")});
car.flexibleFunction();
car.flexibleFunction(function(doParametersWork:String="let's see"){trace("redefine test #2: " + doParametersWork);});
car.flexibleFunction("yes they do");
car.flexibleFunction();
}
}

an easy way to accomplish what you want is to simply pass a new function to the original function and execute it from there:
package
{
//Imports
import flash.display.Sprite;
//Class
public class RedefineFunction extends Sprite
{
//Constructor
public function RedefineFunction()
{
originalFunction();
originalFunction(redefinedFunction);
}
//Original Function
public function originalFunction(redefinition:Function = null):void
{
if (redefinition != null)
redefinition();
else
trace("Original Function Definition");
}
//Redefined Function
private function redefinedFunction():void
{
trace("Redefined Function Definition")
}
}
}
traces:
Original Function Definition
Redefined Function Definition

Related

public function access fail

I have this situation where I declare inside my main class a function that looks like this:
public class Main extends MovieClip
{
public static var instance:Main;
public function Main()
{
// constructor code
welcomeScreen();
instance = this;
}
public final function welcomeScreen():void
{
//some code in here
}
public final function startLevelOne():void
{
//some other code here
}
}
In some other class I use this statement to fire a reset:
restart.addEventListener('click', function() {
Main.instance.welcomeScreen();
});
Somehow in another class I try to use the same statement for 'startLevelOne' but it seems it is not working and gives the fallowing error:
1195: Attempted access of inaccessible method startLevelOne through a reference with static type Main.
Any ideas?
UPDATE #1
The class where I try to access the function is in full this one:
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}
}
UPDATE #2
I have pasted the full code of the main definition here http://pastebin.com/s6hGv7sT
Also the other class could be found here http://pastebin.com/s6h3Pwbp
UPDATE #3
Even though the problem was solved with a workaround, I still cannot understand where was the problem.
I would recommend to leave the static instance (singleton), and work event-based. Now you make all functions public, which is not desirable. It's not that hard to use custom events. See this is how your Main class could look:
public class Main extends MovieClip
{
public function Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
}
public function handleAddedToStage(event:Event)
{
this.removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
this.showWelcomeScreen();
stage.addEventListener(ScreenEvent.SHOW_WELCOME_SCREEN, handleScreenEvent);
stage.addEventListener(ScreenEvent.SHOW_LEVEL, handleScreenEvent);
}
private function handleScreenEvent(event:ScreenEvent):void
{
switch (event.type)
{
case ScreenEvent.SHOW_WELCOME_SCREEN:
{
this.showWelcomeScreen()
break;
}
case ScreenEvent.SHOW_LEVEL:
{
// event.data contains level number
this.startLevel(event.data);
break;
}
default:
{
trace("Main.handleScreenEvent :: Cannot find event.type '" + event.type + "'.");
break;
}
}
}
private function showWelcomeScreen():void
{
trace("show WelcomeScreen")
//some private code in here
}
private function startLevel(level:int):void
{
trace("start level: " + level)
//some other private code here
}
}
This is how the custom event class should look (ScreenEvent.as). Note it has an optional parameter called data. You can pass any value (objects, numbers, strings etc) into this. To the example as clear as possible, I used one event-class for both actions, you can also choose to make more specific custom events for other actions with more detailed parameters, you would have names like ScreenEvent, LevelEvent, PlayerEvent, GameEvent etc etc..
At the top of the class the (static constant) types are defined. An event should only have getters.
package
{
import flash.events.Event;
public class ScreenEvent extends Event
{
public static const SHOW_WELCOME_SCREEN:String = "ScreenEvent.showWelcomeScreen";
// event.data contains level number
public static const SHOW_LEVEL:String = "ScreenEvent.showLevel";
private var _data:String;
public function ScreenEvent(type:String, data:String):void
{
super(type);
this._data = data;
}
public function get data():String
{
return this._data;
}
override public function clone():Event
{
return new ScreenEvent(this.type, this._data);
}
}
}
.. Anywhere in your code you can dispatch the event to the stage.
// dispatch event to Main (stage). Should show welcome screen in our case
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_WELCOME_SCREEN));
// show level 2
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_LEVEL, 2));
I know, its a bit more code, it looks more difficult at first but if the project grows, it will help a lot. The difference with events is 'this could happen, and when it happens, do this' instead of 'do this here, do that over there'
The advantage is that if you remove the event listener in the Main class, nothing will break (loosely coupled). This makes it easier to maintain, it saves a singleton, and you have the ability to extend the Main class if you want to.
I think you wrote
Main.startLevelOne();
instead of
Main.instance.startLevelOne();
Hmm. Given your code, there is only one serious question - what is PerwollGame? You have there public static var instance:PerwollGame; and you assign it an object of type Main. Perhaps that PerwollGame has a startLevelOne() function with a different signature, that obscures your function in the Main class. Also, the other people who answered you are right as well, you should never use nested functions in your code, really put that listener of yours out from inline declaration.
Judging from your coding style and the error reported, I would assume you did this.
public static function startLevelOne():void
There is a fine line between static methods and instantiated objects.
Also never use nested functions
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', onMyClick )
}
public functiononMyClick (e:Event) {
Main.instance.startLevelOne();
});
}
}
I assume that when you register the listener Main.instance is not already assigned.
Did you try to trace Main instance here?
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
trace(Main.instance); // I assume Main.instance is null
}
what about if you add the listener in another method in LevelBrief like :
public function registerListeners():void{
trace("Main.instance == null? -> " + (Main.instance == null)); //not null here if called later.
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}

action script 3 - simplifying the code by implementing the OOP (probably abstract hack)

I apologize in advance if my question is not clear, because I don't know how to put this.
What I am trying to do is to reduce few lines of repeated code by implementing various OOP methods/concepts.
The problem
I have few set of of classes which has initialization process. So, I am implementing an init() method in all those classes. From the calling class (main), these objects will be instantiated and init() method of each object is called in the the order and call some other process after all of them are initialized.
Something like this
public function mainClass(){
_obj1 = new Class1();
_obj1.init();
_obj2 = new Class2();
_obj2.init();
_obj3 = new Class3();
_obj3.init();
doSomething();
}
Well, its not a big deal, but some of the classes' init() methods are asynchronous and I need to add an event listener to get notified when they have finished initialization.
I tried that by extending EventDispatcher for each of those classes and dispatch event and handle it. I even implemented a logic to handle multiple asynchhnous calls by maintaining a counter.
It will be a painful job for me whenever I need to add a new class. I thought I could untilize OOP and reduce and simplify the code.
So I came up with some thing like this, which is currently not possible (abstract class).
abstract class Initializable
{
private var _callBack:Function;
//implement initializaton process in this method
function init(callback:Function=null):void;
protected function get callback():Function{
return _callBack;
}
protected function set callback(func:Function):void{
_callBack = func;
}
protected function onComplete():void{
if (_callBack){
_callBack(this);
}
}
}
This is the main problem for me, as you know abstract class is not allowed in AS3, and the "this" refers to the Initializer class but not its subclass I guess.
This is what I am asking for your help (for the hack)
I need it very much to make my system design simple and flexible, because I can extend the solution to allow mass synchronous initialization which will allow to easily queue up all objects in the order and call init() one after the other in the order in which they are added.
The mass initializer which takes care of handling the asynchronous job
public class MassInitializer
{
private var _objList:Array; //holds objects
private var _callBacks:Array;
private var _onComplete:Function;
public function MassInitializer()
{
_objList = new Array();
}
public function add(obj:Initializable,callback:Function=null):void{
_objList.push(obj);
_callBacks.push(callback);
}
public function init():void{
for (var i:int = 0;i < _objList.length;i++){
_objList.init(this);
}
}
private function onProgress(obj:Initializable):void{
//do updates here
for (var i:int;i<_objList.length;i++){
var obj:Initializable = _objList[i];
var fun:Function = _callBacks[i];
//update progress
if (fun){
fun(obj);
}
_callBacks.splice(i,1);
_objList.splice(i, 1);
}
if (_objList.length == 0){
onComplete();
}
}
private function onComplete():void{
_onComplete(this);
}
}
the main (manager/caller) class (ClassA, ClassB are subclasses of Initialzable class)
public class MainClass
{
private var _obj1:ClassA;
private var _obj2:ClassB;
public function MainClass()
{
_obj1 = new ClassA();
_obj2 = new ClassB();
}
public function init():void{
var initManager:MassInitializer = new MassInitializer();
initManager.add(obj1);
initManager.start();
}
}
probably I am trying to (or want to )implement an observer pattern, but I don't want to confuse you by saying it in advance. Oops I said it? please ignore.
You can emulate abstract classes in ActionScript by enforcing method overrides: Just throw an error if the "abstract" method is called. I like to also implement an interface, but that's not a must, of course:
public interface Initializable
{
function init (callback : Function = null) : void;
function get callback () : Function;
function set callback ( callback : Function ) : void;
}
public class AbstractInitializableImpl implements Initializable
{
private var _callBack:Function;
protected function init(callback:Function=null):void {
throw new Error ("You must implement the init() method!");
}
protected function get callback():Function {
return _callBack;
}
protected function set callback(func:Function):void {
_callBack = func;
}
protected function onComplete():void {
if (_callBack){
_callBack(this);
}
}
}
It's not a 'hack'. It's also very simple. Make each subclass implement an interface, instead of extend an abstract class.
Here is the adobe reference on AS3 interfaces.

Flex Strongly Typed Proxy Classes for Lazy Instantiation

Does anyone know of a framework, preferably some way to have the Flex compiler run an extension or perhaps just a build step that we could generate strongly typed proxy classes of our application's data models.
There are 2 main things we want to do with the proxy's:
At runtime we want to lazily parse and instantiate the instance as accessed (similiar to how Java's Hibernate has Lazy proxy objects)
In an editor application we want to implement setter calls so we can track which objects have been modified
The Proxy is really necessary in this situation beyond things like programatically setting up ChangeWatcther's because we need to track Array adds/remove and possibly track "reference" objects so that when a "reference key" is changed we know to save those objects that are referencing it by key
In the first case we want the proxy to basically abstract when that object is loaded from serialized data, but still pass around references of it with the same public properties and data access pattern if it were the real object.
Basically the proxy would instantiate the object the first time a method is called on it.
I know we could use some AS3 byte-code libraries like as3-commons-bytecode.
Or possibly repurposing the GraniteDS Code Generation.
I'd prefer to generate code because it is a deterministic thing and it'd be nice if we could have a way to debug it at runtime easier.
Does anyone know if I could do something like MXMLC does when it generates AS3 code from MXML files.
Also is there anyway to control "when" in the compilation pipeline I can generate code, because we have a lot of data objects using public fields instead of getter/setters, but that are [Bindable] and so if I could generate the proxy based on the generated getter/setter methods that would work.
Here's an example application data object and proxy classes:
[Bindable]
public class PersonDTO implements Serializable {
private var _name:String;
private var _age:Number
public function get age():Number {
return _age;
}
public function set age(a:Number):void {
_age = a;
}
public function get name():String {
return _name;
}
public function set name(n:String):void {
_name = n;
}
public void readObject(data:*) {
//...
}
}
// GENERATED CLASS BASED ON PersonDTO
public class LazyProxy_PersonDTO extends PersonDTO {
private var _instance:PersonDTO = null;
private var _instanceData:*;
private function getInstance():void {
if (_instance == null) {
_instance = new PersonDTO();
_instance.readObject(_instanceData);
}
}
override public function get age():Number {
//Ensure object is instantiated
return getInstance().age;
}
override public function get name():String {
//Ensure object is instantiated
return getInstance().name;
}
}
// GENERATED CLASS BASED ON PersonDTO
public class LogChangeProxy_PersonDTO extends PersonDTO {
//This will be set in the application
public var instance:PersonDTO;
//set by application
public var dirtyWatcher:DirtyWatcherManager;
override public function set age(a:Number):void {
dirtyWatcher.markAsDirty(instance);
instance.age = a;
}
}
Digging a little deeper into AS3-Commons byte code library it looks like they support generating proxy classes and interceptors.
http://www.as3commons.org/as3-commons-bytecode/proxy.html
public class DirtyUpdateInterceptor implements IInterceptor {
public function DirtyUpdateInterceptor() {
super();
}
public function intercept(invocation:IMethodInvocation):void {
if (invocation.kind === MethodInvocationKind.SETTER) {
if (invocation.arguments[0] != invocation.instance[invocation.targetMember]) {
invocation.instance.isDirty = true;
}
}
}
}

AS3 - Can I have access to the object (or function) who call me?

I've asked this same question with Python.
Now I like to know if this can be done in AS3.
If I have something like this:
package
{
public class SomeClass
{
private function A():void { C() }
private function B():void { C() }
private function C():void
{
// who is the caller, A or B ???
}
public function SomeClass()
{
A()
B()
}
}
}
Despite the design or other issues, this is only a question of an inquiring mind.
Note: I like to have an access to an instance of the caller function so I can call that caller function (if I want to)
Note 2 : This has to be done without changing function C() signature
"Unlike previous versions of ActionScript, ActionScript 3.0 has no arguments.caller property. To get a reference to the function that called the current function, you must pass a reference to that function as an argument."
From http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/arguments.html
That's the only way you can do that, otherwise you'll need to make a global variable to tell what function is calling C
Sure it can be done. You can do something like
private function C():void
{
var e:Error = new Error();
var stack:String = e.getStackTrace();
//analyze stack and find out which function called it.
}
this is ugly but it would work.

Creating a custom trace() class in AS3

I got this idea of expanding my trace() messages.
Why
trace() is all over my code, I want to turn them on/off by a simple command and maybe add some sort of priority functionality to the trace(), i.e.
myTrace.TraceMsg("loosehere",debugme, 0);
myTrace.TraceMsg("winhere",debugme, 1);
And when I run, only the one with the higher priority, "1" in this case, shows.
There is a lot more functionality I would like to add as well, like logging messages to file and so on.
Problem
How do trace() work? -Is it possible to overload trace() somehow? -How would I implement the custom TraceMsg(what code here?) method?
Having some serious problems finding info on this subject on our favourite search engine, so any help would be appreciated.
I have come up with a rather efficient, yet tedious way of using my own trace() function in Flash only projects, but calling it simply with
trace("this", "that", "and that too");
I basically implement one trace() method in every class of my project, that calls a public function (so that i can call the real trace() function from there.
here is what I do : in every class I call this
include "trace_implementation.as";
in the .as file comes a simple method implementation (it could be a static method too).
public function trace(... arguments){
for(var i in arguments){
myTrace(arguments[i]);
}
}
and the myTrace function is defined in its own myTrace.as file
package pt.utils{
import flash.external.ExternalInterface
public function myTrace(_s:String):void{
trace(_s);// this will call the original flash trace() function
ExternalInterface.call("console.log", _s);// to get traces outside of flash IDE
/*implement what you want here*/
}
}
so now when I compile with "omit trace actions", my whole debugging is ignored as if I used trace() simply.
the really good part here is that you could implement custom actions depending on instructions you give in the trace, so :
trace(Debug.DEBUG_MESSAGE, "message to output in debug");
trace(Profile.START_PROFILING, this, 'name');
/*do heavy code*/
trace(Profile.STOP_PROFILING, this);
then dispatch it from myTrace, or a Tracer class or anything :)
Hope this helps future tracers.
trace() itself is a top-level function, not a class, so unfortunately we cannot extend it. That being said, we can utilize it in a simple class to do just what it does normally, only in this case the trace is based on conditions (i.e. Boolean - true|false, etc). First we create the Trace class, which we wouldn't instantiate ourselves because we are utilizing a Factory design pattern through the class below, Tracer. Tracer is built around the singleton design pattern, yet utilizes the Factory pattern to instantiate instances of Trace, when the trace method of Tracer is called.
//This class is handled by Tracer, which is right below it.
//You WILL NOT instantiate these, nor hold references.
package
{
public class Trace
{
private function _value:*;
private function _trace:Boolean;
public function Trace(pValue:*, pTrace:Boolean):void
{
_value = pValue;
_trace = pTrace;
}
public function get value():*
{
return _value;
}
public function get trace():Boolean
{
return _trace;
}
}
}
//This is the important class and the only one you will work with.
package
{
/**
*Utilizes Singleton and Factory design patterns.
*/
public class Tracer
{
private var _traceArray:Array;
private static var _instance:Tracer;
public function Tracer(pvt:PrivateClass = null):void
{
if(pvt == null)
{
throw(new Error("You cannot instantiate this class directly, please use the static getInstance method."));
}
_init();
}
public static function getInstance():Tracer
{
if(Tracer._instance == null)
{
Tracer._instance = new Tracer(new PrivateClass());
}
return Tracer._instance;
}
public function trace(pValue:*, pTrace:Boolean):void
{
var trace:Trace = new Trace(pValue, pTrace);
if(trace.pTrace)
{
trace(pValue);
}
}
//Since we have the option for individual traces to be disabled
//I provide this to get access to any and all later.
public function traceAll():void
{
traceStr:String = _traceArray.toString();
}
public function get traceables():Array
{
return _traceArray;
}
//Here we provide a method to trace all, even if set to false in their constructor.
private function _init():void
{
_traceArray = new Array();
}
}
}
//Here we create a class that is OUTSIDE of the package.
//It can only be accessed from within this class file. We use this
//to make sure this class isn't instantiated directly.
class PrivateClass
{
function PrivateClass():void
{
trace('can only be accessed from within this class file');
}
}
//Now for use in doc class
package
{
import flash.display.Sprite;
import flash.events.Event;
//No need to import Tracer and Trace, they are also in the
//unnamed package.
public class DocumentClass extends Sprite
{
private var _tracer:Tracer;
public function DocumentClass():void
{
if(stage) _init();
else addEventListener(Event.ADDED_TO_STAGE, _init);
}
private function _init(e:Event = null):void
{
_tracer = Tracer.getInstance();
_tracer.trace(10*20, false);
_tracer.trace(10*20, 0); //SAME AS ABOVE
_tracer.trace("I love AS3", true); //traces
_tracer.traceAll(); //Would trace: 200, 200, I love AS3
}
}
}
Keep in mind this is off the hip and very well could have a bug or two, but the idea is there; That is to say that this is not tested, it is merely to give you an idea of how you might implement this.
I hope this helps.
Look at the Flex logging API, particularly the section: Implementing a custom logger with the logging API.
Look up the TraceTarget class as well.
You can't override trace itself, but for ease of typing I like to create a global function called 'tr'. It's a little known fact that you can create global functions in AS3, but it's easy.
Create a file called tr.as inside you main source directory (not in a subdirectory or package), with the contents:
package {
public function tr(msg:String, ...):void {
// add custom trace logic here
trace("tr message: "+msg);
}
}
If you need to have a lot of logic or static storage variables etc, it might be better to make a separate static class, and have the global tr function call out to that, such as:
package {
import org.code.MyTracer;
public function tr(msg:String, ...):void {
MyTracer.tr(msg); // all the tracing logic is inside the MyTracer class
}
}
Here is a super simple custom trace function I use. debugFlag can be set to true/false
elsewhere in the package.
public static function myTrace(... vars) :void {
if (debugFlag) {
var output:Array = new Array;
for each (var arg in vars) {
output.push(arg);
}
trace(output);
}
}
In AS2, it was possible to override the global trace function by doing something like this (taken from memory, might be a bit wrong but the gist of it is there):
public static var realTrace:Function = _global["trace"];
// This is put in some init code somewhere
_global["trace"] = myTrace;
public static function myTrace(... args):void
{
// Do whatever you want with args here, build a nice formatted string or whatever
// before passing to realTrace. Using with MTASC one could add line numbers, class
// names and all sorts of nice meta data. Or just return should you want to turn
// tracing off.
realTrace.apply(args);
}
Unfortunately I haven't found a way to do the same in AS3. Yet.
Trace is a top-level function, so you can't override it, and as far as I know, it does not fire any events. Since it's a top-level function (not contained in any named package), you can use it without import statements.
Here is an example of a top-level "Tracer" class that you can use in place of trace without import statements.
Just call "Tracer.write" or "Tracer.writeError" for tracing Error objects.
"Tracer.write" accepts a variable number of arguments, just like the built-in trace function. "Tracer.writeError" is a helper method that allows you to easily trace Error objects.
Features:
Calls built-in trace.
Keeps a log of all your calls to Tracer.write as an array of strings.
The call log is accessible as a string through getText, which joins all elements in the array with a newline character and will optionally tack on line numbers!
Fires events when new lines are added to the log, so if you have some kind of display window for the log, the display window can listen for Tracer events to update the log display in real-time as the events occur. This is great for displaying trace events when running inside a web browser or stand-alone player.
-Tracer class definition
package
{
import flash.events.EventDispatcher;
public class Tracer extends EventDispatcher
{
private static var traced_text:Array = new Array( "--Start of Trace Log--" );
public static var enabled:Boolean = true;
private static var suspended:Boolean = false;
public static var instance:Tracer = new Tracer();
public static const newline:String = "\n"; //workaround for TextField.appendText bug.. use "\n" instead of "\r". See note and link to bug post in getText method
public function Tracer()
{
}
static public function write( ...args ):void
{
if (enabled && !suspended)
{
trace.apply( null, args );
var text:String = args.join( newline );
var next_index:int = traced_text.length;
traced_text.push( text );
suspended = true; //prevent recursive calls from TracerEvent handler
instance.dispatchEvent( new TracerEvent( text, next_index ) );
suspended = false;
}
}
static public function writeError( e:Error ):void
{
write( "errorID: " + e.errorID, "errorName: " + e.name, "errorMessage: " + e.message, "stackTrace: " + e.getStackTrace() );
}
static public function getText( include_line_numbers:Boolean ):String
{
var line_count:int = traced_text.length;
var lines:Array = traced_text; //store pointer to traced_text; pointer may be changed to reference an altered array that includes line numbers
if (include_line_numbers) //create temporary trace log copy with altered lines; allows quick call to join at end
{
var new_lines:Array = new Array();
for (var i:int = 0; i < line_count; i++)
new_lines.push( i.toString() + ": " + lines[i] );
lines = new_lines;
}
return lines.join( newline ); //do not include last newline character (workaround for bug in appendText method (https://bugs.adobe.com/jira/browse/FP-1982); I have to call appendText with newline character first, otherwise it has issues like not acknoledging the newline thats already there at the end).
}
static public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
{
instance.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
static public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
{
instance.removeEventListener(type, listener, useCapture);
}
static public function willTrigger(type:String):Boolean
{
return instance.willTrigger(type);
}
static public function hasEventListener(type:String):Boolean
{
return instance.hasEventListener(type);
}
}
}
-TracerEvent class definition
package
{
import flash.events.Event;
public class TracerEvent extends Event
{
public static const WRITE:String = "te_write";
public var text:String;
public var index:int; //index of newly traced text in the traced_text array (trace log)
public function TracerEvent( text:String, index:int )
{
super( WRITE, false, false );
this.text = text;
this.index = index;
}
override public function clone():Event
{
return new TracerEvent( text, index );
}
}
}
As mentioned below, there is no way to override trace (at least not if you want your traces to reach the output stream), but it's actually very easy to create your own universally accessable logging function. Plus, you can even define a universally accessable boolean to turn logging on or off:
log.as (note that the filename must reflect the name of the function)
package {
function log(... arguments):void {
trace("Custom logging FTW!");
if (logEnabled)
trace(arguments);
}
}
logEnabled.as (note that the filename must reflect the name of the variable)
package {
var logEnabled:Boolean = true;
}
Main.as
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
log("Testing");
logEnabled = false;
log("Testing2");
}
}
}
Response
Custom logging FTW!
Testing
Custom logging FTW!
you dont need to override it , just create a function in your project and call it trace then any trace call will point to this.trace ;)
function trace(... arguments){
yourfunction(arguments);
}