Get all classes from a package
Asked Answered
H

2

6

I'd like a (platform independent) way to list all classes from a package.

A possible way would be get a list of all classes known by Haxe, then filtering through it.

Hypoglycemia answered 8/12, 2014 at 11:4 Comment(0)
E
4

This is one way to store and retrieve the information: https://gist.github.com/back2dos/c9410ed3ed476ecc1007

Beyond that you could use haxe -xml to get the type information you want, then transform it as needed (use the parser from haxe.rtti to handle the data) and embed the JSON encoded result with -resource theinfo.json (accessed through haxe.Resource).

As a side note: there are chances you'll be better off not having any automation and just add the classes to an array manually. Imagine you have somepackage.ClassA, somepackage.ClassB, ... then you can do

import somepackage.*;

//...

  static var CLASSES:Array<Class<Dynamic>> = [ClassA, ClassB, ...];

It gives you more flexibility as whatever you want to do, you can always add 3rd party classes, which may not necessarily be in the same package and you can also choose to not use a class without having to delete it.

Escargot answered 8/12, 2014 at 17:4 Comment(5)
Thanks, but the point would be to give a convenience method to an API, a shorthand instead of listing all classes of a package.Hypoglycemia
Well, then you can just go ClassList.ALL_CLASSES.filter(~/^mypackage\./.match) and you've got all that. As you've said yourself, that is one way to do it. Jason's solution works pretty much that way under the hood. If that API is convenient, use it. If not, use my example as a basis to build your own.Escargot
What exactly is exactly is ClassList in your example?Hypoglycemia
@vbence: Stupid question, but did you open the first link I gave in this post? It has code, that (among other things) defines ClassList.Escargot
I made a small change: to use fully qualified class names in the list. - gist.github.com/vbence/4b26004473191b7468edHypoglycemia
L
5

I made a macro to help with just this. It's in the compiletime haxelib.

haxelib install compiletime

And then add it to your build (hxml file):

-lib compiletime

And then use it to import your classes:

// All classes in this package, including sub packages.
var testcases = CompileTime.getAllClasses("my.package"); 

// All classes in this package, not including sub packages.
var testcases = CompileTime.getAllClasses("my.package",false); 

// All classes that extend (or implement) TestCase
var testcases = CompileTime.getAllClasses(TestCase);

// All classes in a package that extend TestCase
var testcases = CompileTime.getAllClasses("my.package",TestCase);

And then you can iterate over them:

for ( testClass in testcases ) {
    var test = Type.createInstance( testClass, [] );
}

Please note, if you never have "import some.package.SomeClass" in your code, that class will never be included, because of dead code elimination. So if you want to make sure it gets included, even if you never explicitly call it in your code, you can do something like this:

CompileTime.importPackage( "mygame.levels" );
CompileTime.getAllClasses( "mygame.levels", GameLevel );

How it works

CompileTime.getAllClasses is a macro, and what it does is:

  • Waits until compilation is finished, and we know all of the types / classes in our app.
  • Go through each one, and see if it is in the specified package
  • See also if it extends (or implements) the specified class/interface
  • If it does, add the class name to some special metadata - @classLists(...) metadata on the CompileTimeClassList file, containing the names of all the matching classes.
  • At runtime, use the metadata, together with Type.resolveClass(...) to create a list of all matching types.
Lalonde answered 9/12, 2014 at 1:37 Comment(4)
Very interesting project. I'm a bit confused, do these examples run at compile time (I can only use them in a build macro) or run time?Hypoglycemia
Also... is m.classLists (used in CompileTimeClassList.hx) documnted somewhere?Hypoglycemia
@vbence, they run at compile time. At compile time it looks at the package / class, and once all your code is ready to generate, it finds the matching classes, and adds some metadata so we can find them at runtime. So there is a small amount of runtime processing, but predominantly happens at compile time.Leelah
@Hypoglycemia The m there is the metadata on the CompileTimeClassList class. m.classLists is getting the @classLists(...) metadata that the macro created, which contains the names of all the relevant classes. I haven't got any further documentation on the exact structure of the metadata, but you could add a trace() in if you are curious :)Leelah
E
4

This is one way to store and retrieve the information: https://gist.github.com/back2dos/c9410ed3ed476ecc1007

Beyond that you could use haxe -xml to get the type information you want, then transform it as needed (use the parser from haxe.rtti to handle the data) and embed the JSON encoded result with -resource theinfo.json (accessed through haxe.Resource).

As a side note: there are chances you'll be better off not having any automation and just add the classes to an array manually. Imagine you have somepackage.ClassA, somepackage.ClassB, ... then you can do

import somepackage.*;

//...

  static var CLASSES:Array<Class<Dynamic>> = [ClassA, ClassB, ...];

It gives you more flexibility as whatever you want to do, you can always add 3rd party classes, which may not necessarily be in the same package and you can also choose to not use a class without having to delete it.

Escargot answered 8/12, 2014 at 17:4 Comment(5)
Thanks, but the point would be to give a convenience method to an API, a shorthand instead of listing all classes of a package.Hypoglycemia
Well, then you can just go ClassList.ALL_CLASSES.filter(~/^mypackage\./.match) and you've got all that. As you've said yourself, that is one way to do it. Jason's solution works pretty much that way under the hood. If that API is convenient, use it. If not, use my example as a basis to build your own.Escargot
What exactly is exactly is ClassList in your example?Hypoglycemia
@vbence: Stupid question, but did you open the first link I gave in this post? It has code, that (among other things) defines ClassList.Escargot
I made a small change: to use fully qualified class names in the list. - gist.github.com/vbence/4b26004473191b7468edHypoglycemia

© 2022 - 2024 — McMap. All rights reserved.