How to find the file path where a class was (first) declared through an included module?

Here’s my use case:

When the user of my library (a GTK4 binding) inherits a Gtk::Widget to use GTK XML template widgets I need to add some methods to it with some more information.

I solved this using a annotation plus a module with the included macro, so the extra information go into the annotation and the included macro add the methods in the class. However I think a solution with just the annotation or just the include file would be more elegant.

The information I need is basically a file path to load (the .ui file), my idea is to let it load a file with the same name but the .ui extension in the same path where the class was first declared. So I would write something like {{ "#{@type.path}/#{@type.name.undesrcode}.ui" }} in the included macro instead of get the value from the annotation.

Is that possible? If not, would a patch adding such feature be appreciated?

My current solution using an annotation plus module:

Using the module + annotation:

The module:

An ASTNode in macros has a few properties for this: filename, line_number, etc. But it seems a TypeNode, which represents a type in macros, doesn’t have this information. I would open a feature request here or in GitHub about this. Given that a type might appear in multiple locations, it might be better to have a locations method that returns an Array of… something. Maybe it can be an array of hashes that each have :filename, :line_number properties, etc. Or maybe introduce a Location type in macros, not sure!

1 Like

At a first look I think Location with filename, line and column attributes seems more readable than the Hash approach.

An Array(Location) sorted by when the compiler found it, i.e. first element is the first declaration, etc…

I’ll create the issue, if I find time I can try to create a patch, but the most difficult part will be find the time to do it.

issue created Add TypeNode#locations or implement TypeNode#filename · Issue #12062 · crystal-lang/crystal · GitHub

I think that maybe the easier fix would be to implement filename for TypeNode, since it’s already a ASTNode field, even if this isn’t a complete solution and ignore types re-openings.

2 Likes