From: Alex Young Date: 2006-09-10T02:44:07+09:00 Subject: Re: Thousands of words on Ruby James Edward Gray II wrote: > On Sep 9, 2006, at 10:33 AM, Alex Young wrote: > >> James Edward Gray II wrote: >>> On Sep 9, 2006, at 9:41 AM, Alex Young wrote: >>>> Ok, so it's a real bodge to try to rename a method before runtime. >>>> What happens if we annotate the method to be renamed the next time >>>> it's run? We could run the script in question under an environment >>>> not totally unlike xmp. The first thing it would do is alter the >>>> source file according to the annotation. It would then add an >>>> appropriate method_missing to Object to do a rename in the original >>>> source file whenever the method was called, and then load() the file. >>> And what happens if the execution never calls the given method, for >>> whatever reason, or only reaches some of the places it is used? >> That's why you run your test suite through it. You do have 100% line >> coverage, right? :-) > > Well it's a clever idea. Show us the prototype. ;) Well, you asked for it :-) The usual provisos for prototype code apply: $ cat rename_method.rb $obj_replacement_table = {} class Object def method_missing(sym, *args, &block) if $obj_replacement_table.has_key? sym.to_s filename, line_num = caller[0].split(':')[0,2] l = line_num.to_i - 1 line_arr = File.readlines(filename) line_arr[l] = line_arr[l].sub(sym.to_s, $obj_replacement_table[sym.to_s]) File.open(filename, 'wb'){|f| f.write line_arr} self.send($obj_replacement_table[sym.to_s].to_sym, *args, &block) end end end def process_file(filename) line_arr = File.readlines(filename) line_arr.each_with_index do |line,i| if line.chomp =~ /(\s+)def (\w+)(.*)#\s*becomes\s+(\w+)/ line_arr[i] = "#{$1}def #{$4}#{$3}# was #{$2}\n" $obj_replacement_table[$2] = $4 end end File.open(filename, 'wb'){|f| f.write line_arr } end process_file(ARGV[0]) load(ARGV[0]) $ cat subject.rb class TestClass def my_method(foo) # becomes my_new_method puts foo end end def meth_calling_renamed(t) t.my_method('Ok2') end t = TestClass.new t.my_method('Ok1') meth_calling_renamed(t) $ ruby rename_method.rb subject.rb Ok1 Ok2 $ cat subject.rb class TestClass def my_new_method(foo) # was my_method puts foo end end def meth_calling_renamed(t) t.my_new_method('Ok2') end t = TestClass.new t.my_new_method('Ok1') meth_calling_renamed(t) There's a *lot* of scope for improvement in there, obviously, but that's the general idea. -- Alex