Hi Ruby Quiz,
Sorry, this is likely to be rather uninteresting, and I'm not even quite
following the rules, I think, but here is a refactoring that's not on
(Fowler's) official lists, even though it applies to Java as much as to
Ruby, that I did the other day; let's call them "Merge Redundant
Exception Handlers." Also, there's the more Ruby-exclusive "Remove
Unused Scope"
This code is from the Gem Server tutorial for win32/service on
RubyForge. It's by Daniel Berger, and refactored publicly without his
permission; I hope he doesn't mind.
http://rubyforge.org/docman/view.php/85/126/gemserver_tutorial.txt
def service_main
begin
@s.mount_proc("/yaml") { |req, res|
res['content-type'] = 'text/plain'
res.body <<
Gem::Cache.from_installed_gems(File.join(Gem.dir, "specifications")).to_yaml
}
rescue Exception => e
File.open(@logfile,'w+'){ |f| f.puts "Start failed: #{e}" }
service_stop
end
begin
@s.mount_proc("/") { |req, res|
specs = []
specifications_dir = File.join(Gem.dir, "specifications")
Gem::Cache.from_installed_gems(specifications_dir).each do
|path, spec|
specs << {
"name" => spec.name,
"version" => spec.version,
"full_name" => spec.full_name,
"summary" => spec.summary,
"rdoc_installed" =>
Gem::DocManager.new(spec).rdoc_installed?,
"doc_path" => ('/doc_root/' + spec.full_name +
'/rdoc/index.html')
}
end
specs = specs.sort_by { |spec| [spec["name"].downcase,
spec["version"]] }
template = TemplatePage.new(DOC_TEMPLATE)
res['content-type'] = 'text/html'
template.write_html_on(res.body, {"specs" => specs})
}
rescue Exception => e
File.open(@logfile,'w+'){ |f| f.puts "Start failed: #{e}" }
service_stop
end
begin
{"/gems" => "/cache/", "/doc_root" => "/doc/"}.each do
|mount_point, mount_dir|
@s.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
File.join(Gem.dir, mount_dir), true)
end
rescue Exception => e
File.open(@logfile,'w+'){ |f| f.puts "Start failed: #{e}" }
service_stop
end
begin
@s.start
rescue Exception => e
File.open(@logfile,'w+'){ |f| f.puts "Start failed: #{e}" }
service_stop
end
end
Refactoring 1: Merge Redundant Exception Handlers
/You have a series of exception handling blocks with identical handlers./
*Merge the code into a single exception handling block.*
Thus:
begin
foo
rescue Exception => e
barf e
end
begin
bar
rescue Exception => e
barf e
end
Becomes:
begin
foo
bar
rescue Exception => e
barf e
end
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
Here is the refactored code:
def service_main
@s.mount_proc("/yaml") { |req, res|
res['content-type'] = 'text/plain'
res.body << Gem::Cache.from_installed_gems(File.join(Gem.dir,
"specifications")).to_yaml
}
@s.mount_proc("/") { |req, res|
specs = []
specifications_dir = File.join(Gem.dir, "specifications")
Gem::Cache.from_installed_gems(specifications_dir).each do
|path, spec|
specs << {
"name" => spec.name,
"version" => spec.version,
"full_name" => spec.full_name,
"summary" => spec.summary,
"rdoc_installed" =>
Gem::DocManager.new(spec).rdoc_installed?,
"doc_path" => ('/doc_root/' + spec.full_name +
'/rdoc/index.html')
}
end
specs = specs.sort_by { |spec| [spec["name"].downcase,
spec["version"]] }
template = TemplatePage.new(DOC_TEMPLATE)
res['content-type'] = 'text/html'
template.write_html_on(res.body, {"specs" => specs})
}
{"/gems" => "/cache/", "/doc_root" => "/doc/"}.each do
|mount_point, mount_dir|
@s.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
File.join(Gem.dir, mount_dir), true)
end
@s.start
rescue Exception => e
File.open(@logfile,'w+'){ |f| f.puts "Start failed: #{e}" }
service_stop
end
Cheers,
Dave