Skip to content

Instantly share code, notes, and snippets.

@sinsoku
Last active July 13, 2017 08:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sinsoku/2c37b2efed514c7ac212203dc867e045 to your computer and use it in GitHub Desktop.
Save sinsoku/2c37b2efed514c7ac212203dc867e045 to your computer and use it in GitHub Desktop.
Calculate AbcSize. MIT LICENSE
#!/usr/bin/env ruby
# frozen_string_literal: true
# AbcSize を範囲ごとにカウントして CSV に出力する
#
# 実行方法
# $ ruby calc_abcsize.rb
#
# tmp/abcsize.csv の例)
# 20..29,30..39,40..49,50..59,60..69,70..79,80..89,90..99,100..
# 48,22,7,4,0,4,1,1,3
require 'csv'
require 'json'
require 'rubocop'
require 'tempfile'
ABC_SIZE_MAX = 20
CONFIG = <<~EOF
AllCops:
TargetRubyVersion: 2.3
DisabledByDefault: true
Exclude:
- 'tmp/**/*'
- 'db/schema.rb'
- 'node_modules/**/*'
Metrics/AbcSize:
Max: #{ABC_SIZE_MAX}
EOF
MESSAGE_REGEXP = %r{\[(.+)/#{ABC_SIZE_MAX}\]$}
CSV_PATH = 'tmp/abcsize.csv'
def config
@config ||= Tempfile.new.tap do |f|
f.write(CONFIG)
f.close
end
end
def out
@out ||= Tempfile.new.tap { |f| f.close }
end
def run_rubocop
args = ['--parallel', '--config', config.path, '--format', 'json', '--out', out.path]
RuboCop::CLI.new.run(args)
JSON.parse(File.read(out.path))
end
def calc_result(json)
result = Hash.new(0)
json['files'].each do |file|
file['offenses'].each do |offense|
message = offense['message']
m = message.match(MESSAGE_REGEXP)
abcsize = m[1].to_i
key = abcsize > 100 ? 10 : abcsize / 10
result[key] += 1
end
end
result
end
def write_csv(result)
range = (ABC_SIZE_MAX / 10).upto(10)
head = range.map do |n|
base = n * 10
n < 10 ? "#{base}..#{base + 9}" : "#{base}.."
end
CSV.open(CSV_PATH, 'w') do |csv|
csv << head
csv << range.map { |n| result[n] }
end
end
json = run_rubocop
result = calc_result(json)
write_csv(result)
#!/usr/bin/env ruby
# frozen_string_literal: true
# 2014/1 から月初のコミットを checkout し、 AbcSize を計測します。
# このスクリプトの実行後は `detached HEAD` をチェックアウトした状態になるので注意してください。
# 不安なら、 `git worktree` コマンドで別の作業ディレクトリを用意するのがオススメです。
#
# 実行方法
# $ ruby trace_abcsize.rb
# $ echo 'date,20..29,30..39,40..49,50..59,60..69,70..79,80..89,90..99,100..' >> result.csv
# $ for f in $(ls 20*.csv); do echo ${f%.csv},$(tail -1 ${f}) >> result.csv; done
#
# result.csv の例)
# date,20..29,30..39,40..49,50..59,60..69,70..79,80..89,90..99,100..
# 20140203_1152,48,22,7,4,0,4,1,1,3
# 20140303_1506,47,20,7,4,0,5,1,1,3
RUBOCOP_CONFIG = '.rubocop.yml'
RBENV_FILE = '.ruby-version'
CSV_PATH = 'tmp/abcsize.csv'
def git_log(since:, format:)
`git log --all --merges --since='#{since}' --format='#{format}' | tail -1`.chomp
end
def each_month(&block)
(2014..2017).each do |year|
(1..12).each do |month|
yield(year, month)
end
end
end
def run_abcsize(year, month)
since = "#{year}-#{month}-1"
puts "## start #{since}"
hash = git_log(since: since, format: '%H')
return if hash.empty?
`git checkout #{hash}`
File.delete(RBENV_FILE) if File.exist?(RBENV_FILE)
File.delete(RUBOCOP_CONFIG) if File.exist?(RUBOCOP_CONFIG)
`./calc_abcsize`
at = git_log(since: since, format: '%at')
to = Time.at(at.to_i).strftime('%Y%m%d_%H%M')
File.rename(CSV_PATH, "#{to}.csv")
`git checkout #{hash} .`
puts "## finish #{since}"
end
each_month { |y, m| run_abcsize(y, m) }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment