From: Luke Kanies Date: 2006-12-20T06:36:35+09:00 Subject: Re: class_eval and using a block instead of a String? On Dec 19, 2006, at 2:47 PM, Mariano Kamp wrote: > Hi, > > given the following contrived example I am wondering how to use a > block with class_eval instead of using the string like in the code > below?! > > Any ideas? > > Cheers, > Mariano > > require 'test/unit' > include Test::Unit::Assertions > > class Base > class << self > def enhance(*attributes) > class_eval do > attr_reader *attributes > end > > initializer = "def initialize(#{attributes.join(", ")})" > attributes.each {|a| initializer << "@#{a}=#{a}\n"} > initializer << "end" > > # ------ > class_eval initializer # <------- > # ------ > end > end > end > class Derived < Base; end > > 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 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. -- Some people are afraid of heights. I'm afraid of widths. -- Stephen Wright --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com