views:

69

answers:

4

i've got a module and a class that includes the module. these are not defined in the same file, or in the same folder. i want the module to get the directory that the class is defined in.

# ./modules/foo.rb
module Foo
  def self.included(obj)
    obj_dirname = # ??? what goes here?
    puts "the class that included Foo was defined in this directory: #{obj_dirname}"
  end
end

# ./bar.rb
class Bar
  include Foo
end

i would expect the output of this to be:

the class that included Foo was defined in this directory: ../

is this possible? if so, how?

A: 

Does this do what you want?

module Foo
  def self.included(obj)
    obj_dirname = File.expand_path(File.dirname($0)) 
    puts "the class that included Foo was defined in this directory: #{obj_dirname}"
  end
end

Edit: changed according to comments.

Michael Kohl
no. that returns "./modules/foo.rb"
Derick Bailey
Yes, sorry. Replace `__FILE__` with `$0`. With bar.rb in ~/tmp and foo.rb in ~/tmp/modules, this is the output when I run bar.rb: "the class that included Foo was defined in this directory: /Users/xxx/tmp"
Michael Kohl
+1  A: 

There's no built-in way to find out where a module or class was defined (afaik). In Ruby, you can re-open a module/class at any time and any place and add or change behavior. This means, there's usually no single place where a module/class gets defined and such a method wouldn't make sense.

In your application, you can however stick to some convention so that you are able to construct the source filename. E.g. in Rails, a pages controller is by convention named PagesController and gets defined primarily in the file app/controllers/pages_controller.rb.

Andreas
+2  A: 

Classes can be defined in many files, so there is no real answer to your question. On the other hand, you can tell from which file the include Foo was made:

# ./modules/foo.rb
module Foo
  def self.included(obj)
    path, = caller[0].partition(":")
    puts "the module Foo was included from this file: #{path}"
  end
end

This will be the path you're looking for, unless there's a MyClass.send :include, Foo somewhere else then where MyClass was defined...

Note: For Ruby 1.8.6, require 'backports' or change the partition to something else.

Marc-André Lafortune
thanks! that's a good way for me to get the functionality i wanted. i was worried about the multi-file issue. knowing where the include was made is what i need. :)
Derick Bailey
A: 
module Foo

  def self.included obj
    filename = obj.instance_eval '__FILE__'
    dirname = File.expand_path(File.dirname(filename))
    puts "the class that included Foo was defined in this directory: #{dirname}"
  end

end
Justice
That doesn't work. `__FILE__` is not a method, and `instance_eval` returns `"(eval)"`
Marc-André Lafortune