Replace Surrounding Code With Block Method

A proposed refactoring, relevant to ruby, lisp-like languages, python (?), and could be badly emulated in PHP. Name probably needs to be adjusted (to ExecuteAroundPattern from KentBeck's SmalltalkBestPracticePatterns). Thoughts?

Replace:

def test_thing_creates_record
  before_count = record_count('foo')
  thing
  assert_equal before_count + 1, record_count('foo')
end

With:

def assert_creates_record_in_foo
  before_count = record_count('foo')
  yield
  assert_equal before_count + 1, record_count('foo')
end

def test_thing_creates_record assert_creates_record_in_foo do thing end end

See also AssertYinYang

I think a rationale and explanation would be helpful, but perhaps I'm showing my lack of Ruby knowledge. Is it obvious to Ruby programmers? -- DaveVoorhis

It's obvious to a non-Ruby programmer having been exposed to Smalltalk, Lisp and Ruby. All you need to know is 'yield' means 'call functor'. This is ParameterizedExtractMethod, or something along those lines. Or maybe ExtractAllButMethod/ExtractFrame.

Ah hah! In my mind 'yield' was evocative of the Java platform's Thread.yield(), and confusion ensued. Note to self: IwannaLearnRuby. -- DV

To me it was more evocative of 'yield' in the coroutine sense, probably because I didn't see any thread goo in the area. CeeSharp has added a yield keyword to facilitate writing iterators as some sort of half-ass coroutines, transforming the iterator's frame into a heap-allocated object. -- JH

Motivations to do so, off the top of my head (and I've just done this on a real live project, so some of these are real):

Hmm, refactoring example was doing proposed refactoring and AddParameter?. Now fixed.


The really good news is intensive research, involving hundreds of programmer-years, has not yet found a way to abuse blocks in RubyLanguage. If you are writing a method, and you don't know what to write next, you just write yield, and let the calling code figure it out.

Furtherless, ExecuteAroundPattern is a much, much better idiom for ResourceAcquisitionIsInitialization than destructors OR finally blocks. You just put the finally or ensure after the yield. --PhlIp


ExtractFrame? is the best so far, I think, but not quite accurate. ExtractDonut??

Is this just a variation on ExtractMethod where the method gets a parameter that just happens to be a code block? You could do basically the same thing in a lot of languages by passing a lambda / function pointer / subroutine reference / etc to the new function.


EditText of this page (last edited April 23, 2008) or FindPage with title or text search