Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access the current __FILE__ in a subclass from a method in the superclass in ruby

I'm hoping to set up a default path for logging, relative to the path of the file using the log, something like this:

# /path/to/lib/bar.rb
class Bar
  def settings_file_path
    File.dirname(File.expand_path(__FILE__))
  end
end

# /path/to/app/models/foo.rb
class Foo < Bar
end

Foo.new.settings_file_path

Ideal output:

# => /path/to/app/models

Actual output:

# => /path/to/lib

Because FILE references the file where it's written, not where it's being called from, it's returning the bar.rb file, but I want something like this to return the path of the foo.rb file, even though the method is defined in Bar.

Anybody have any suggestions?

like image 339
Cameron Booth Avatar asked Jan 27 '11 04:01

Cameron Booth


2 Answers

caller.first[/^[^:]+/] will not work on Windows because absolute path there looks like $DRIVE:$PATH (example C:/Windows/system32)

Instead caller.first[/^[^:]+/] use caller_locations.first.absolute_path

like image 40
CAMOBAP Avatar answered Sep 22 '22 06:09

CAMOBAP


The simplest would be something like this:

# foo.rb
class Foo
  def self.my_file
    @my_file
  end
end

# bar.rb
class Bar < Foo
  @my_file = __FILE__
end

# main.rb
require_relative 'foo'
require_relative 'bar'
p Bar.my_file
#=> "/Users/phrogz/Desktop/bar.rb"

However, you could parse the caller in a self.inherited hook like so:

# foo.rb
class Foo
  class << self
    attr_accessor :_file
  end
  def self.inherited( k )
    k._file = caller.first[/^[^:]+/]
  end
end

# bar.rb
class Bar < Foo
end

# main.rb
require_relative 'foo'
require_relative 'bar'

p Bar._file
#=> "/Users/phrogz/Desktop/bar.rb"

I'm not certain how robust or portable that parsing is; I suggest you test it.

N.B. My Bar inherits from Foo, the reverse of your question. Be not confused by the differences in our setups.

like image 61
Phrogz Avatar answered Sep 25 '22 06:09

Phrogz