I am building many functions in my application and now I want to alphabetise them. Is there any function in Sublime Text 2 that will do this automatiaclly. It should change these
public function login_1()
{
........
}
public function about()
{
........
}
public function close()
{
........
}
Into these
public function about()
{
........
}
public function close()
{
........
}
public function login_1()
{
........
}
I wonder if you are using PHP, from the syntax you provided it seems you do.
Here is a plugin for that task, but it looks like it works with PHP only. It sorts your methods using the scope first and then by method name.
Related
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();
});
}
I would like to read the source of the flash.net.FileReference class. Is this possible? Where can I find the source files, do they come with the Adobe Flash or Flash Builder?
To read the flash package files, you can find the playerglobal.swc - change the name to playerglobal.zip and unzip the package. Then, decompile the library.swf file and get the script files. Here's what I found for FileReference:
//FileReference
package flash.net
{
import flash.events.*;
import flash.utils.*;
public class FileReference extends flash.events.EventDispatcher
{
public function FileReference()
{
super();
return;
}
public function upload(arg1:flash.net.URLRequest, arg2:String="Filedata", arg3:Boolean=false):void
{
}
private function _load(arg1:flash.utils.ByteArray):void
{
}
public function load():void
{
this._load(new ByteArray());
return;
}
public function get size():uint
{
}
public function get type():String
{
}
public function browse(arg1:Array=null):Boolean
{
}
public function get name():String
{
}
public function get creator():String
{
}
public function get creationDate():Date
{
}
public function download(arg1:flash.net.URLRequest, arg2:String=null):void
{
}
public function get modificationDate():Date
{
}
public function get data():flash.utils.ByteArray
{
}
public function cancel():void
{
}
private function _save(arg1:flash.utils.ByteArray, arg2:String):void
{
}
public function save(arg1:*, arg2:String=null):void
{
var defaultFileName:String=null;
var data:*;
var d:flash.utils.ByteArray;
var loc1:*;
data = arg1;
defaultFileName = arg2;
d = new ByteArray();
if (data == null)
{
throw new ArgumentError("data");
}
if (data is String)
{
d.writeUTFBytes(data as String);
}
else if (data is XML)
{
d.writeUTFBytes((data as XML).toXMLString());
}
else if (data is ByteArray)
{
d.writeBytes(data as ByteArray);
}
else
{
try
{
d.writeUTFBytes(data);
}
catch (e:Error)
{
throw new ArgumentError("data");
}
}
d.position = 0;
if (defaultFileName == null)
{
defaultFileName = "";
}
this._save(d, defaultFileName);
return;
}
}
}
I highly recommend not changing this file and rather extend it and override the functions you need to modify. Otherwise, you'll need to recompile the library.swf and create a custom playerglobal.swc.
As others mentioned you can see the sources for the Flash and Flex framework classes. The exact location will vary.
For Flash CS4 on Windows 7:
C:\Users\<your_user>\AppData\Local\Adobe\Flash CS4\en\Configuration
For Flex:
...\flex_sdk\frameworks\projects\framework\src
You CAN change any framework class you want as long as you're careful. In Flash nomenclature this is referred to as Monkey Patching. Create a class in your project with the same full package structure and class name as the framework class and the compiler will find and use your custom class instead of the framework class.
There are some complications in doing this with framework RSL's. For that see here:
How to Monkey Patch when using Flex RSLs
http://blogs.adobe.com/dloverin/2010/01/how_to_monkey_patch_when_using_flex_rsls.html
This does not apply to built-in or "intrinsic" classes. Those are built-into the player and wills till have stub code in the above source locations. You can't actually change intrinsic classes.
Any of the "stuff" that is available for you to view are located (for Win7 anyway) in C:\Users\<your_user>\AppData\Local\Adobe\Flash CS4\en\Configuration
The Flash CS4 portion might change depending on the version you have. Classes are in the Classes folder inside configuration.
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
The following code seems to create an ambiguity for the compiler (please see error commented near the bottom). Is it not possible to have getters and setters split between interfaces?
public interface GetterInterface
{
function get test():int;
}
public interface SetterInterface
{
function set test(value:int):void;
}
public interface SplitTestInterface extends GetterInterface, SetterInterface
{
}
public class SplitTest implements SplitTestInterface
{
public function SplitTest()
{
}
/* INTERFACE test.SetterInterface */
public function set test(value:int):void
{
}
/* INTERFACE test.GetterInterface */
public function get test():int
{
return 0;
}
}
//Somewhere...
var splitTest:SplitTestInterface = new SplitTest();
splitTest.test = 2; //Error: Property is read-only.
I put together the following (which is all but identical to your code) and works fine for both the get and set method.
/* IGet.as */
package {
public interface IGet
{
function get test():int;
}
}
/* ISet.as */
package {
public interface ISet
{
function set test(i:int):void;
}
}
/* ISplit.as */
package {
public interface ISplit extends IGet, ISet {
}
}
/* SplitTest.as */
package {
public class SplitTest implements ISplit {
public function SplitTest() {
}
public function set test(i:int):void {
trace("Set");
}
public function get test():int {
trace("Get");
}
}
}
The following is on the maintimeline:
var foo:SplitTest = new SplitTest();
foo.test;
foo.test = 1;
And outputs:
Get
Set
Interesting question. Based on the output, it looks like the compiler doesn't really understand what's going on. Using a custom compiler to call force the call in the player results in
Property SplitTestInterface::test not found on SplitTest and there is no default value.
So the answer is no. It's not supported by the language, and it's not supported by the runtime. That's good though, I would never want to see this in production code.
Edit: My test was messed up, actually it works fine in the runtime.
So, how do we write a class over several files in action script 3?
In C# there's the "partial" keyword.
In C++ it's natural (you just "#include ..." all files).
In Flex 3, in a component, you add this tag: <mx:Script source="myfile.as"/>.
How do I split the following class into several files;
package package_path
{
public class cSplitMeClass
{
public function cSplitMeClass()
{
}
public function doX():void
{
// ....
}
public function doY():void
{
// ....
}
}
}
For example I want to have the doX() and doY() functions implemented in another ".as" file.
Can I do this?
And please, don't tell me something like "a good practice is to have them in one file" :)
As per your request, I'm sparing you the "best practices lecture". So, I'll just say there's an include directive in AS 3.0, which could help you out here.
Basically, you can do:
package package_path
{
public class cSplitMeClass
{
public function cSplitMeClass()
{
}
include "the_file_where_doX_and_doY_live.as"
}
}
And then in "the_file_where_doX_and_doY_live.as"
public function doX():void
{
// ....
}
public function doY():void
{
// ....
}
You could do it with inheritance:
// file: cSplitMe1.as
class cSplitMe1 {
function doX() {
// ...
}
// file: cSplitMe2.as
class cSplitMe2 extends cSplitMe1 {
function doY() {
// ...
}
// file: cSplitMe.as
class cSplitMe extends cSplitMe2 {
function cSplitMe() {
doX();
doY();
}
}
It's good practice, nothing wrong with that.
There's the import keyword. Example:
import Class_A.as;
import Class_B.as;
Now of course in order to use them, you need to declare them, preferably in your constructor.
public function Class_C()
{
//Create a new instance of Class_A
var objA:Object = new Class_A("parameter one", "parameter two");
//Create a new instance of Class_B
var objA:Object = new Class_B("parameter one", "parameter two");
}
Of course it all depends on how you're going to make this work. I would also suggest you use a Main class from where you could run your code. I guess you already knew that though.
Good luck.