「lizard」とは?
コマンドラインのサイクロマティック複雑度(以下、CCN)計測ツールです。
OSSなのでフリーで使えます。
CCNについては別記事で説明しているので、そちらをご参照ください。
環境
- OS:macOS High Sierra 10.13.1
- Python:3.6.1
- pip:9.0.1
- lizard:1.14.10
- jinja2:2.10
セットアップ
Python環境の構築
lizardはPython製なので、Pythonのインストールが必要です。
Python環境の構築についてはこちらの記事をご参照ください。
私は以下のようなPython環境を作成しました。
$ pyenv virtualenv 3.6.1 CCNAnalyzer
lizardのインストール
pipでインストールします。
$ pip install lizard
Collecting lizard
Using cached https://files.pythonhosted.org/packages/25/78/4fad2f578ce5b42f9f635a27f81d1332183e9f14b506a158e298ec759f03/lizard-1.14.10-py2.py3-none-any.whl
Installing collected packages: lizard
Successfully installed lizard-1.14.10
You are using pip version 9.0.1, however version 10.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
pipが古いと怒られましたが、無事にインストールできました。
操作方法
標準出力
今回はSwiftLintのソースをお借りして、CCNを計測してみます。
-l
オプションの値は言語に応じて変更してください。
# プロジェクトのルートフォルダへ移動する
$ cd SwiftLint/Source/swiftlint/
# CCNを計測する
$ lizard -l swift
================================================
NLOC CCN token PARAM length location
------------------------------------------------
8 3 38 2 8 report@12-19@./Extensions/Reporter+CommandLine.swift
4 2 39 2 4 reporterFrom@22-25@./Extensions/Reporter+CommandLine.swift
34 6 238 0 36 scriptInputFiles@16-51@./Extensions/Configuration+CommandLine.swift
1 1 14 1 1 autoreleasepool@54-54@./Extensions/Configuration+CommandLine.swift
55 8 400 8 55 visitLintableFiles@59-113@./Extensions/Configuration+CommandLine.swift
17 6 136 5 17 getFiles@115-131@./Extensions/Configuration+CommandLine.swift
7 2 74 1 7 init@135-141@./Extensions/Configuration+CommandLine.swift
6 1 80 3 6 visitLintableFiles@143-148@./Extensions/Configuration+CommandLine.swift
6 2 68 1 6 init@152-157@./Extensions/Configuration+CommandLine.swift
4 1 34 1 4 init@161-164@./Extensions/Configuration+CommandLine.swift
14 3 79 1 15 print@19-33@./Commands/RulesCommand.swift
16 5 138 1 20 run@39-58@./Commands/RulesCommand.swift
17 7 107 2 21 ruleList@60-80@./Commands/RulesCommand.swift
8 2 73 1 8 create@90-97@./Commands/RulesCommand.swift
12 1 88 1 12 evaluate@99-110@./Commands/RulesCommand.swift
40 6 275 2 40 init@116-155@./Commands/RulesCommand.swift
9 1 51 0 9 currentWidth@159-167@./Commands/RulesCommand.swift
48 8 392 1 48 run@20-67@./Commands/LintCommand.swift
9 3 50 2 9 successOrExit@69-77@./Commands/LintCommand.swift
9 2 51 3 9 printStatus@79-87@./Commands/LintCommand.swift
6 1 51 2 6 isWarningThresholdBroken@89-94@./Commands/LintCommand.swift
13 1 65 1 13 createThresholdViolation@96-108@./Commands/LintCommand.swift
15 3 78 2 15 applyLeniency@110-124@./Commands/LintCommand.swift
5 1 185 1 5 create@142-146@./Commands/LintCommand.swift
24 1 225 1 25 evaluate@148-172@./Commands/LintCommand.swift
4 1 43 1 4 run@17-20@./Commands/VersionCommand.swift
25 6 206 1 26 run@17-42@./Commands/AutoCorrectCommand.swift
5 1 125 1 5 create@56-60@./Commands/AutoCorrectCommand.swift
17 1 143 1 18 evaluate@62-79@./Commands/AutoCorrectCommand.swift
13 3 90 1 15 run@17-31@./Commands/GenerateDocsCommand.swift
3 1 20 1 3 create@37-39@./Commands/GenerateDocsCommand.swift
6 1 47 1 6 evaluate@41-46@./Commands/GenerateDocsCommand.swift
3 1 13 1 3 init@21-23@./Helpers/Benchmark.swift
3 1 27 2 3 record@25-27@./Helpers/Benchmark.swift
3 1 30 2 3 record@29-31@./Helpers/Benchmark.swift
14 2 153 0 15 save@33-47@./Helpers/Benchmark.swift
5 1 28 1 5 pathOption@12-16@./Helpers/CommonOptions.swift
6 1 30 1 6 quietOption@27-32@./Helpers/CommonOptions.swift
10 file analyzed.
==============================================================
NLOC Avg.NLOC AvgCCN Avg.token function_cnt file
--------------------------------------------------------------
15 6.0 2.5 38.5 2 ./Extensions/Reporter+CommandLine.swift
140 16.2 3.4 130.5 8 ./Extensions/Configuration+CommandLine.swift
139 16.6 3.6 115.9 7 ./Commands/RulesCommand.swift
153 16.1 2.5 137.1 8 ./Commands/LintCommand.swift
11 4.0 1.0 43.0 1 ./Commands/VersionCommand.swift
64 15.7 2.7 158.0 3 ./Commands/AutoCorrectCommand.swift
32 7.3 1.7 52.3 3 ./Commands/GenerateDocsCommand.swift
44 5.8 1.2 55.8 4 ./Helpers/Benchmark.swift
20 5.5 1.0 29.0 2 ./Helpers/CommonOptions.swift
17 0.0 0.0 0.0 0 ./main.swift
=============================================================================================
No thresholds exceeded (cyclomatic_complexity > 15 or length > 1000 or parameter_count > 100)
==========================================================================================
Total nloc Avg.NLOC AvgCCN Avg.token Fun Cnt Warning cnt Fun Rt nloc Rt
------------------------------------------------------------------------------------------
635 13.0 2.6 104.8 38 0 0.00 0.00
メソッドごとのCCN→ファイルごとのCCN平均→全ファイルのCCN平均 の順で出力されます。
「メソッドごとのCCN」について、各列の意味は以下の通りです。
列 | 略 | 説明 |
---|---|---|
NLOC | Number Line Of Code | コードの行数(コメントを除く) |
CCN | Cyclomatic Complexity Number | サイクロマティック複雑度 |
token | - | トークン(字句)数 |
PARAM | PARAMeter | メソッドの引数の数 |
length | - | NLOCから空行を除いた行数 |
location | - | {メソッド名}@{開始行}-{終了行}@{ファイルパス} |
ファイルごとや全ファイルについての出力もほぼ同様です。
出力結果の見方がわかったところで流石のSwiftLintです。CCNが全メソッドで1桁に収まっています。
CSV出力
標準出力だと使いづらいので lizard --help
でオプションを確認したところ、他にも様々な形式で出力できることがわかりました。
--csv
オプションを付けることで、CSV形式で出力されます。
Python環境が構築されていることですし、pandasやmatplotlibを使ってグラフ化するのもよさそうです。
# 出力結果をCSVファイルへ出力する
$ lizard -l swift --csv > ~/Desktop/SwiftLint_CCN.csv
出力結果
CSVの場合はメソッドごとのCCNのみ出力されるようです。
ヘッダー(1行目)は出力されなかったので、公式のGitHubなどを参考にして付けました。
nloc,ccn,token_count,parameter_count,length,location,filepath,method_name,method_long_name,start_line,end_line
8,3,38,2,7,"report@12-19@./Extensions/Reporter+CommandLine.swift","./Extensions/Reporter+CommandLine.swift","report","report violations : [ StyleViolation ] , realtimeCondition : Bool",12,19
4,2,39,2,3,"reporterFrom@22-25@./Extensions/Reporter+CommandLine.swift","./Extensions/Reporter+CommandLine.swift","reporterFrom","reporterFrom options : LintOptions , configuration : Configuration",22,25
34,6,238,0,35,"scriptInputFiles@16-51@./Extensions/Configuration+CommandLine.swift","./Extensions/Configuration+CommandLine.swift","scriptInputFiles","scriptInputFiles",16,51
…
6,1,30,1,5,"quietOption@27-32@./Helpers/CommonOptions.swift","./Helpers/CommonOptions.swift","quietOption","quietOption action : String",27,32
HTML出力
--html
オプションを付けることで、HTML形式で出力されます。
# 出力結果をHTMLで出力する
$ lizard -l swift --html > ~/Desktop/SwiftLint_CCN.html
HTML Output depends on jinja2. `pip install jinja2` first
出力に失敗しました。
HTML形式で出力する場合、jinja2というツールも必要とのことです。
lizardと同じくpipでインストールします。
$ pip install jinja2
これで再度コマンドを実行するとHTMLで出力されます。
出力結果
標準出力やCSVよりグラフィカルで見やすいです。
CSVと同様、メソッドごとのCCNのみ出力されるようです。
SwiftLintは優秀なので出力されませんでしたが、CCNがしきい値(デフォルトだと15)を超えると[Cyclomatic complexity]列の背景色が緑から赤に変わります。