From: pat eyler Date: 2006-04-21T01:04:31+09:00 Subject: Re: [SUMMARY] Refactoring (#75) On 4/20/06, Molitor, Stephen L wrote: > James, > > Great summary. Wish I had participated in the quiz! > > I liked Dave Burt's 'Removed Unused Scope' example. Would you (or > someone else) care to give examples of 'Replace Similar Methods with > Metaprogrammed Definitions' I'm not sure what James had in mind, but I think this works well as an example of post refactoring 'Replace Similar Methods with Metaprogrammed Definitions': def add_test(name, clean_or_dirty, number_of_errors, definition) eval <<"END_OF_TEST" def test_#{name} assert_class_is_#{clean_or_dirty} Class.new {#{definition}} assert_number_of_errors #{number_of_errors} end END_OF_TEST end def dont_add_test(*args) # not gonna do it end class CheckRTest < Test::Unit::TestCase def setup @checkr = CheckR.new end def test_initialize assert_kind_of CheckR, @checkr end def test_is_class_clean_exists assert_respond_to @checkr, "is_class_clean?" end def test_errors_exists assert_respond_to @checkr, "errors" end add_test :clean_if, :clean, 0, "def foo; true if true; end" add_test :clean_if_2, :clean, 0, "def foo;if true;a=1;puts a;end;end" add_test :clean_while, :clean, 0, "def foo;while a==2;break;end;end" add_test :clean_assignment_in_if_body, :clean, 0, "def foo;if a==2;a=3;a;end;end" add_test :clean_return_value, :clean, 0, "def foo;1;end" [thirty more test definitions deleted] private def assert_class_is_clean(klass) assert_equal true, check_class(klass) end def assert_class_is_dirty(klass) assert_equal false, check_class(klass) end def assert_number_of_errors(n) assert_equal n, @checkr.errors.length end def check_class(klass) @checkr.is_class_clean?(klass) end > and a 'Convert a Family of Methods to a > Single method_missing()'? I'm especially interested in the latter. I > know how method_missing works and I've seen its use in frameworks (like > Rails), but I've never actually written one myself. > > I'm sure there are opportunities to use these Rubyesque type > refactorings in my code but I tend not to see them due to lack of > experience. One of the great things about the Refactoring book for me > was that it gave examples of things that I could easily relate to my own > application code. It sharpened my nose. > > Thanks again for the quiz. > > Steve > > > -----Original Message----- > From: Ruby Quiz [mailto:james@grayproductions.net] > Sent: Thursday, April 20, 2006 9:07 AM > To: ruby-talk ML > Subject: [SUMMARY] Refactoring (#75) > > Hopefully this quiz caused some of us to read Martin Fowler's > Refactoring. I know it did exactly that for me, though it has been on > my want-to-read list for some time now. I'm half-way through it now and > I can only recommend everyone reading this pick up a copy immediately. > > Each of this week's solutions came with its own write-up so there isn't > a lot left for me to dissect. Instead, I'll take this chance to talk a > little about the most interesting part of this exercise to me. > > It's my opinion that a large majority of the refactoring patterns were > designed with the static languages in mind. I'm very intrigued by how a > language like Ruby changes the game. Let's me see if I can give some > examples. > > First, I mentioned in my write-up that part of my refactoring called for > making a method abstract. After some thought, I decided that meant > deleting the method in Ruby. (See my solution for the reasoning.) > > Here's another thought: many of the refactorings tell you to declare a > variable as final, to ensure that it isn't changing. What's the Ruby > equivalent to that? > I don't think we have one. We can #freeze the object, but that won't > help us if the variable is reassigned. I don't see a good answer there. > > But there are two sides to every coin and we have some nice advantages. > For example, Extract Method talks a lot about how the local variables > can complicate extraction, especially if many of them are changed by the > extracted code. This is much less of an issue in Ruby though, since we > can have the extracted method take a block and use the variables in > there however we need. In fact, this means we can use Extract Method > quite a bit more often, since the code we pull just needs to be close to > similar and we can handle the differences in the block. > > Dave Burt was also thinking along these lines and went all the way to > introduce some Ruby centric refactorings. Here's an example: > > Refactoring 2: Remove Unused Scope > /You have a begin...end block that introduces a scope that is > unused./ > *Remove the unused scope.* > > Thus: > > def foo > begin > bar > rescue > baz > end > end > > Becomes: > > def foo > bar > rescue > baz > end > > I would love to see many more of these. Perhaps we could come up with a > Replace Similar Methods with Metaprogrammed Definitions and a Convert a > Family of Methods to a Single method_missing() Call recipes. Food for > thought. > > A big thank you to all who supported this deviation from our usual fun > and games. I think Pat hit on a super important topic here and we would > all do well to learn more about it. > > Tomorrow, Matthew Moss is back with a quiz about txet smnraiclbg... > > > -- thanks, -pate ------------------------- http://on-ruby.blogspot.com