From: Mariano Kamp Date: 2006-12-20T20:27:10+09:00 Subject: Re: class_eval and using a block instead of a String? On Dec 19, 2006, at 10:36 PM, Luke Kanies wrote: > Something like thie following should work: > > require 'test/unit' > include Test::Unit::Assertions > > class Base > class << self > def enhance(*attributes) > attr_accessor *attributes > > define_method(:initialize) do |*ary| > attributes.each do |a| > send(a.to_s + "=", ary.shift) > end > end > end > end > end > class Derived < Base; end > > class Testing < Test::Unit::TestCase > def test_initialize > Derived.enhance(:a, :b, :c) > d = Derived.new("a", "b", "c") > > assert_equal "a", d.a > assert_equal "b", d.b > assert_equal "c", d.c > end > end > > I didn't really do what you want, because I'm not actually using > class_eval here at all, but the assertions pass, anyway, which I > assume is the real goal. > > Note that I'm using attr_accessor here instead of attr_reader, > because it's much easier to set the attributes this way. You could > just about as easily use instance_variable_set or whatever the > method is, but I prefer this for my own code. > > Note also that if you call enhance() multiple times on the same > class, you'll recreate the initialize() method each time, which is > probaby a bad thing; as long as this is just for testing, you > should be fine, but I'd be wary of putting this into production > anywhere. > > One of the things I love about ruby is I can usually use a block > instead of a string with the eval methods, but what I love even > more is being able to skip the eval methods entirely. Hi Luke, thanks. That should work for my example. Well, generally speaking I love the idea that you can transform one concept into another and if this works nicely it most of the time looks elegant to me. So I was hoping that I just didn't get how to do that with code in strings as opposed to blocks. So it seems, that there are things that you can do with one of the concepts but not with the other. I am currently trying to figure out what the hard rules are on when to use a String and when to use a block. I like the String approach as it is pretty close to how you would write the method by hand, but I hate about it that it is just heap of characters. But the latter might be just me as my thoughts are often still in the Java world, where you like to do things explicitly and give the compiler/editor a chance to help you. Coming back to the example it seems that the two approaches do not provide the same functionality. When using the String approach the parameters to the initialize method are explicit. On consequence is that if I would call Derived.new ("a", "b") I would get an error saying that I just provided two of three parameters. This doesn't happen with the block approach. Of course I could always explicitly code to check for the ary length, but this is kind of redundant. Cheers, Mariano