TL;DR
最近为 Rails 项目加了一个代码分析工具叫 Reek ,用来检查代码中的坏味道。因为项目已经有一段时间了,一跑就几百个提示。平时也没工夫专门优化代码。于是我想到一个折中的办法:只检查 feature branch 中修改了的文件,针对性地优化。
思路
像大多数 CLI 一样,Reek 也可以接受额外的参数来检查指定的文件。大概如此:
$ bundle exec reek file1 file2
而同时,Git 的 diff
可以比对两个分支的改动,加一个参数 --name-only
就可以只输出改动的文件名。以下假定当前分支是 feature branch ,对比 staging 分支的情况。
# assume current branch is feature branch
$ git diff --name-only staging
file1
file2
...
我们可以写个 rake task ,通过 Ruby 调用 git diff
命令,把返回的文件名转换成一行,再传给 reek
命令。就可以达到目的。
实现
实现起来挺简单的,就只放代码了:
# lib/tasks/reek.rake
namespace :reek do
desc "Check code smells for changed files (based on staging)"
task :changed, [:branch] do |t, args| # 加一个 branch 参数
branch = args[:branch] || 'staging'
# 获取改变的文件名,剔除掉被删的文件
re = `git diff --name-only #{branch}`
files = re.split("\n").delete_if { |name| !File.exist?(name) }
if files.blank?
puts "\nNo files changed\n"
return
end
# 打印一下文件列表
puts "\nReek changed files:"
files.each do |file|
puts " #{file}"
end
puts
# 调用 reek
system "bundle exec reek #{files.join(' ')}"
end
end
需要注意的有几点:
这个 task 可以通过 branch 参数修改要比较的分支,方便查看。
调用
git diff
命令使用的是 "`" ,这样方便获取返回值。调用
bundle exec reek
得用system
,因为需要把输出显示在屏幕上。
使用起来很简单:
# 默认情况,对比 staging 和当前分支
./bin/rake reek:changed
# 对比 master 分支,换成 commit 也行
./bin/rake reek:changed[master]
小结
代码分析工具是好东西,可以潜默移化地改变人的编程习惯,即使对很有经验的程序员也能起到查漏补缺的作用。但世事无绝对,分析规则是否跟项目匹配,工作流程如何改进,这些都是因人而异的,需要不停地思考和总结。
参考资料
Reek
Can I make git diff only show the changed file names and line numbers?