I’m writing a harness for some tests that use watir. Rather than having
to boilerplate code in the definition of each test like
def test_1
load test1
end
I want to read the testnames in from a file which will be easier for the
user. What I’d like to do is something along this structure (which I
adapted from a really good blog in metaprogramming Ruby, Meta-programming, and Watir | Invisible Blocks):
testlist = Array.new
File.open(‘readme.txt’, ‘r’) do |eachline|
while (line = eachline.gets)
testlist << line
end
end #puts testlist
and then call each method I’ve defined. However, I’m not sure I’m going
about this the correct way.
We (Austin Codefest of 2002) did something very like this in the tests
for Ruby scanf. If you look for test_scanf.rb in the Ruby source,
you’ll see it, near the bottom of the file. We used define_method.
(I think that was back in the days when I habitually switched the
order of actual and expected in my assertions, so you have to
compensate for that
It’s not exactly the same as yours but I’d say that define_method is
your best bet too.
File.open(‘readme.txt’, ‘r’) do |eachline|
while (line = eachline.gets)
testlist << line
end
end #puts testlist
testlist = File.open(‘readme.txt’).readlines
testlist.each { |entry|
code = <<METHOD_TEMPLATE
def test_#{entry}()
puts “testing #{entry}”
end
METHOD_TEMPLATE
}
and then call each method I’ve defined. However, I’m not sure I’m going
about this the correct way.
Use define_method whenever possible. The only case where you would put
code in a string (and then load it using eval) is if your methods need
to accept a block argument (define_method does not accept block argument
until Ruby 1.9).
class Foo
File.open(‘readme.txt’).readlines.each do |entry|
define_method “test_#{entry}”.to_sym do
puts “testing #{entry}”
end
end
end
class Foo
File.open(‘readme.txt’).readlines.each do |entry|
Well it turns out that the above line can be simplified to:
File.open(‘readme.txt’).each_line do |entry|
or even to:
IO.foreach(‘readme.txt’) do |entry|
Personally, I prefer each_line because IO.foreach sounds like “for each
IO object in …” instead of “for each line in …”.
define_method "test_#{entry}".to_sym do
puts "testing #{entry}"
end
end
end
Foo.new.test_whatever
Got a bit of help on this one and the solution I’m now going with is:
File.open(‘readme.txt’).each_line do |entry|
self.send(:define_method, entry.strip.to_sym){ puts “testing
#{entry}” } #self.send(:public, entry.strip.to_sym )
end
end
Got a bit of help on this one and the solution I’m now going with is:
File.open(‘readme.txt’).each_line do |entry|
self.send(:define_method, entry.strip.to_sym){ puts “testing
#{entry}” } #self.send(:public, entry.strip.to_sym )
end
end
define_method takes a string, so you can get rid of “to_sym”. (Same
for public in the commented-out line, if you ever use that.)
Use define_method whenever possible. The only case where you would put
code in a string (and then load it using eval) is if your methods need
to accept a block argument (define_method does not accept block argument
until Ruby 1.9).
class Foo
File.open(‘readme.txt’).readlines.each do |entry|
define_method “test_#{entry}”.to_sym do
puts “testing #{entry}”
end
end
end
Foo.new.test_whatever
I still run into undefined method errors using this format. Are there
any restrictions on the format the generated method name can take?
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.