Reputation: 29536
I have two files in two different directories:
module MyModule
def my_method path
p File.join (File.dirname __FILE__), path
end
end
and
require_relative '../modules/mymodule' # definition of MyModule
class MyClass
extend MyModule
my_method 'my_file.yml'
end
I am getting output like my_home_dir/modules/my_file.yml
but I want it to be my_home_dir/files/my_file.yml
where files
is the name of the directory where MyClass
is defined.
I know I can use full path when I call my_method
but is there a way for imported files to still have __FILE__
set to the name of the importing file?
Basically in my_method
I need to have the full path of the file and I want to pass just a path relative to my calling file's path.
Upvotes: 2
Views: 468
Reputation: 574
Ruby 2.7 adds Module#const_source_location
const_source_location(:MyMoudule)
Upvotes: 0
Reputation: 123
There's a simpler method available if you can pass in a block; use the block's binding:
# In example.rb:
module Example
def execute_if_main(&block)
if $PROGRAM_NAME == eval("__FILE__", block.binding)
yield
end
end
end
Then in the test file:
# in test.rb:
require_relative 'example.rb'
include Example
execute_if_main do
puts "hi, I'm being loaded"
end
This will execute the block only if test.rb is being loaded directly by the Ruby interpreter. If test.rb is loaded instead via some other file via require, the block at the end won't be executed (which is the idea)
Upvotes: 2
Reputation: 160551
__FILE__
always is the name of the file containing the __FILE__
variable, so saying my_method
will always return where my_method
is defined, not where MyClass
calls it.
You can probably get at the information you want using caller
:
module MyModule
def my_method path
p caller
end
end
include MyModule # definition of MyModule
class MyClass
extend MyModule
my_method 'my_file.yml'
end
my_class = MyClass.new
Which outputs:
["test.rb:10:in `<class:MyClass>'", "test.rb:8:in `<main>'"]
Edit:
the caller array has only file names without paths...
Well, I'd hoped you'd know how to work around that but....
This is in test.rb:
require './test2'
class MyClass
extend MyModule
my_method __FILE__, 'my_file.yml'
end
my_class = MyClass.new
This is in test2.rb:
module MyModule
def my_method path, file
dir = File.dirname(path)
p caller.map{ |c| File.join(dir, c) }
end
end
Running test.rb outputs:
["./test.rb:4:in `<class:MyClass>'", "./test.rb:2:in `<main>'"]
Upvotes: 2