[Q]: How can I find the filename where a class is defined?

Hello everyone,

I would like to find the filename where a given class is defined.
One simple solution is the following:

class MyClass
SOURCE_FILENAME = __FILE__
....
end

then the filename is:

MyClass::SOURCE_FILENAME

This is inelegant though, is there a better solution?
Thanks in advance,
George

Hi George!

I would like to find the filename where a given class is defined.

Since a class can be spread over multiple files, you have to define which one(s) you want to get.

> class MyClass
> SOURCE_FILENAME = __FILE__
> ...
> end
>
> This is inelegant though, is there a better solution?

I cannot think of something simpler / better / more elegant...

Regards,
Pit

Since a class can be spread over multiple files, you have to define

which

one(s) you want to get.

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas?
-g.

George Moschovitis wrote:

Since a class can be spread over multiple files, you have to define

which

one(s) you want to get.

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas?

Yes, that's what I needed last night, too (and some month ago where I considered Wee+templating).

class Object
   class << self
     attr_accessor :classdef_in_file

     alias __old_inherited inherited
     def inherited(klass)
       klass.classdef_in_file = caller.last.split(":").first
       __old_inherited(klass)
     end
   end
end

# in file test.rb

class MyClass; end
p MyClass.classdef_in_file # => test.rb

Regards,

   Michael

t.rb
   class Class
      def inherited t
         puts "class #{t} created at #{caller.first}"
      end
   end
   require 'g.rb'

g.rb:
   class Blah
   end

->

class Blah created at ./g.rb:1

···

On Jan 28, 2005, at 3:40 PM, George Moschovitis wrote:

Since a class can be spread over multiple files, you have to define

which

one(s) you want to get.

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas

"George Moschovitis" <george.moschovitis@gmail.com> schrieb im Newsbeitrag
news:1106922976.553171.111240@c13g2000cwb.googlegroups.com...

> Since a class can be spread over multiple files, you have to define
which
> one(s) you want to get.

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas?
-g.

Maybe you can cook something up with set_trace_func. So you can set the
trace funtion at the beginning of your script and fill some global mapping
from class to file name.

    robert

Yes, that's what I needed last night, too (and some month ago where I
...
class MyClass; end
p MyClass.classdef_in_file # => test.rb

Thank you very much!

considered Wee+templating).

I want this for a similar reason (new version of controller/action
reloading in Nitro)

-g.

···

--

Michael Neumann schrieb:

class Object
  class << self
    attr_accessor :classdef_in_file

    alias __old_inherited inherited
    def inherited(klass)
      klass.classdef_in_file = caller.last.split(":").first
      __old_inherited(klass)
    end
  end
end

This is a nice idea!

Note that it doesn't work on Windows, though, cause there you have filenames with colons ("C:/xxx"). You could change the line

> klass.classdef_in_file = caller.last.split(":").first

to

> klass.classdef_in_file = caller.last.sub(/:\d+$/, "")

BTW: now I can finally get rid of all those ugly

   if $0 == __FILE__
   end

Code :slight_smile:

Thanks for the reminder,
Pit

Michael Neumann wrote:

George Moschovitis wrote:

Since a class can be spread over multiple files, you have to define

which

one(s) you want to get.

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas?

Yes, that's what I needed last night, too (and some month ago where I considered Wee+templating).

class Object
  class << self
    attr_accessor :classdef_in_file

    alias __old_inherited inherited
    def inherited(klass)
      klass.classdef_in_file = caller.last.split(":").first
      __old_inherited(klass)
    end
  end
end

Don't you forget

private :inherited

?

:slight_smile:

Also I would like to ask why you used "class Object" but not "class Class"?
There are some reasons I haven't seen?

···

--
   s&g

George Moschovitis wrote:

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas?

I dont' know what kind of performance you are looking for, but if you know the file:

classes = {}
File.open( "file.rb" ) do |file|
   file.each_line do |line|
     next unless line =~ /\s*class\s*(\w+)/
     classes[ $1 ] = file.lineno
   end
end

puts "I found the class MyClass in file file.rb at line #{classes['MyClass']}"

This will build a hash of your class to lineno found in the source "file.rb". the "file.rb" could also be replaced with just saying __FILE__ if you are wanting to parse the currently loaded file.

This could easily be expanded to suit any need, but granted it reparses your source files and thus is slower and less efficient,

Zach

Zach Dennis wrote:

George Moschovitis wrote:

My class is defined in one file only. I dont want a general solution. I
want a solution for classes defined in a single file. Any other ideas?

I dont' know what kind of performance you are looking for, but if you know the file:

classes = {}
File.open( "file.rb" ) do |file|
  file.each_line do |line|
    next unless line =~ /\s*class\s*(\w+)/
    classes[ $1 ] = file.lineno
  end
end

If you need it to gooo real fast, we can write a c extension =) and add more functions so we don't get charged with being wasteful... The usage could be similar to:

RubySourceParser::find_method_decl( "mymethod" )
    =>[[Class1,"file.rb", lineno=1044], [Class2, "file2.rb", lineno=56]]

RubySourceParser::find_method_decl( "Class1", "mymethod" ) => ...etc...

RubySourceParser::find_class_decl( "Class1" ) => ["file1.rb",lineno=10]

RubySourceParser::find_module_decl( "...etc..." )

Perhaps this is overkill, but I am on a ruby high right now, after I wrote a mini-library to handle NetworkDrives in Windows. It is a small very simple thing, but it makes me sooo happy. Happying Rubying!

Zach