From: Tim Pease Date: 2007-02-03T07:53:26+09:00 Subject: Re: How do Rakefiles "know" about built-in Rake methods? On 2/2/07, Jeff wrote: > I'm looking into a way to let business users write functional tests in > rails, and I wanted to have my functional test file load an external > file to supply the body of a method. It occurs to me that Rake must > have solved a similar problem, but I can't quite figure out how Jim > did it. > > What I want to write is something like this: > > class MyTests < Test::Unit::TestCase > > # typical setup and teardown here > > # a test method to "wrap" an external ruby file > > def test_acceptance > load 'acceptance.rb' # load file written by business user > end > > def foo > end > > def bar > end > > end > > I admit it didn't look right when I wrote it. I had hoped that the > code in acceptance.rb could be bare Ruby code. in other words, it > would look like and feel top-level Ruby, but could call foo and bar > because it's really in the midst of the test_acceptance method. > > So I conclude that load() starts a new scope. I guess I could add my > methods to Object and/or Module to get them to be seen by the external > file, but I don't think that does any good either. > > But Rake does something similar, right? I think it defines the task() > method, etc. and you can refer to them in "bare" ruby code in your > rake file. > > What glue is being used in Rake that I'm missing? > Jim defined the basic rake methods [task, rule, file, directory, ...] in the global ruby context -- much the same way you would define a method in an irb session. When your Rakefile is loaded by the rake system, it automatically has access to all these rake methods. Both exist in the same global context. Your code above is defining instance methods (foo and bar) within a class. When you load a file in your test_acceptance method, that file is being loaded in the global context NOT in the context of your test case instance. To do the latter .... def test_acceptance self.instance_eval IO.readlines('acceptance.rb') end A simpler example ... ary = Array.new ary.instance_eval "length" #=> 0 Hope this helps. Blessings, TwP