__FILE__ for requiring file

Hello

I keep wondering if there is a way to have __FILE__ be delayed
in its evaluation. For example, in my tests cases, I usually do the
following so that my test cases are imune to where they are run from:

class TestMyClass < Test::Unit::TestCase

  TEST_DIR = File.dirname(__FILE__)
  DATA_DIR = File.join(TEST_DIR, "data")

  def data_file(file)
    File.join(DATA_DIR, file)
  end

  def test_xyz
    open(data_file("fred"))
    assert ...
  end
end

The problem is I have to add this to every test case since I can't put
data_file inside a module and include it without also having o define
TEST_DIR as a constant of Object inside every testcase.

In other words, I don't want to do:

TEST_DIR = File.dirname(__FILE__)
class TestMyClass < Test::Unit::TestCase
  require 'test_helper'
  include TestHelper
  TestHelper.init __FILE__
end

This just seems a bit verbose.

I guess what I need is something like: __REQUIRING_FILE__
so my TestHelper module could be written as:

module TestHelper
  TEST_DIR = File.dirname(__REQUIRING_FILE__)
  DATA_DIR = ...as above
end

Has anyone ever needed such a thing? Is there a better way of solving
this problem?

Thanks

···

--
Jim Freeze

Jim Freeze wrote:

Hello

I keep wondering if there is a way to have __FILE__ be delayed
in its evaluation. For example, in my tests cases, I usually do the
following so that my test cases are imune to where they are run from:

class TestMyClass < Test::Unit::TestCase

TEST_DIR = File.dirname(__FILE__)
DATA_DIR = File.join(TEST_DIR, "data")

def data_file(file)
   File.join(DATA_DIR, file)
end

def test_xyz
   open(data_file("fred"))
   assert ...
end
end

The problem is I have to add this to every test case since I can't put
data_file inside a module and include it without also having o define
TEST_DIR as a constant of Object inside every testcase.

In other words, I don't want to do:

TEST_DIR = File.dirname(__FILE__)
class TestMyClass < Test::Unit::TestCase
require 'test_helper'
include TestHelper
TestHelper.init __FILE__
end

This just seems a bit verbose.

I guess what I need is something like: __REQUIRING_FILE__
so my TestHelper module could be written as:

module TestHelper
TEST_DIR = File.dirname(__REQUIRING_FILE__)
DATA_DIR = ...as above
end

Has anyone ever needed such a thing? Is there a better way of solving
this problem?

Thanks

Untested - just sketching ideas:

mytest.rb:

require 'test/unit'

class TC < Test::Unit::TestCase
   def open_data(f,&b)
     File.open(File.join(get_dir, f), &b)
   end

   def get_dir
     x = caller(2).shift
     if /^(.*):\d+:in / =~ x
       File.dirname $1
     else
       raise "Whatever"
     end
   end
end

your_test.rb:

class TestFoo < TC
   def test_x
     open_data("foo") do |io|
       io.each_line ...
     end
   end
end

  robert

I think this could get there:

    def __REQUIRING_FILE__; caller[1] =~ /([^:]*):/; $1 end

But probably only if you don't call it within any other methods. I'll
have to play around some more.

···

--
Lou.

you can defer the evaluation by simply using methods:

     harp:~/d > cat test/test.rb
     require 'test/unit'
     class TestMyClass < Test::Unit::TestCase
       require 'test/helper' and include TestHelper

       def __file__() __FILE__ end
       def test_dir() File.dirname __file__ end

       def test_that_it_works()
         assert_nothing_raised{ p data_file('forty-two') }
       end
     end

     harp:~/d > cat test/helper.rb
     module TestHelper
       def data_dir() File.join test_dir, 'data' end
       def data_file(file) File.join data_dir, file end
     end

     harp:~/d > ruby test/test.rb
     Loaded suite test/test
     Started
     ."test/data/forty-two"
     .
     Finished in 0.00122 seconds.

     2 tests, 1 assertions, 0 failures, 0 errors

kind regards.

-a

···

On Tue, 31 Oct 2006, Jim Freeze wrote:

Hello

I keep wondering if there is a way to have __FILE__ be delayed in its
evaluation. For example, in my tests cases, I usually do the following so
that my test cases are imune to where they are run from:

--
my religion is very simple. my religion is kindness. -- the dalai lama

Louis J Scoras wrote:

I think this could get there:

   def __REQUIRING_FILE__; caller[1] =~ /([^:]*):/; $1 end

But probably only if you don't call it within any other methods. I'll
have to play around some more.

I played around already :slight_smile:

def find_dir
   caller.each do |cl|
     if %r{^(.*):\d+(?::in )?$} =~ cl
       f = $1
       return File.dirname(f) if f != __FILE__
     end
   end
   raise "Not found"
end

Regards

  robert

Very nice.

I realized after I posted that ':' could be a valid character in a
filename, so my above try at it won't work anyway.

···

On 10/30/06, Robert Klemme <shortcutter@googlemail.com> wrote:

I played around already :slight_smile:

def find_dir
   caller.each do |cl|
     if %r{^(.*):\d+(?::in )?$} =~ cl
       f = $1
       return File.dirname(f) if f != __FILE__
     end
   end
   raise "Not found"
end

--
Lou.

Thanks guys.
This is what I ended up with:

module TestHelper
  __REQUIRING_FILE__ = /([^:]*):/.match(caller[1])[1]

  TEST_DIR = File.dirname(__REQUIRING_FILE__)
  DATA_DIR = File.join(TEST_DIR, "data")

  def data_file(file)
    File.join(DATA_DIR, file)
  end
end#module TestHelper

···

--
Jim Freeze

Just make sure that you won't have any file names with a ':' in them =)

···

On 10/30/06, Jim Freeze <jim@freeze.org> wrote:

module TestHelper
  __REQUIRING_FILE__ = /([^:]*):/.match(caller[1])[1]

--
Lou.

Just make sure that you won't have any file names with a ':' in them =)

Sure:

  __REQUIRING_FILE__ = caller.grep(/^(.*):\d+(?::in)?$/)[0]

···

--
Jim Freeze