Rubyコードのリンティング
リンティングは、潜在的な問題を検索するためにコードを静的に分析するプロセスです。
この場合、問題を構成するものは、プログラミング言語間、または同じ言語内のプロジェクト間でさえ異なる可能性があります。これらの問題をいくつかの異なるカテゴリに分類します。
- プログラマティック
- セキュリティ
- 文体
- パフォーマンス
それぞれの例をいくつか見てみましょう。
文体の問題
コードのスタイルを設定するための客観的に正しい方法はありません。それはすべて読者の好みに関するものだからです。重要なのは一貫性です。議論の一般的なポイントは次のとおりです。
- 二重引用符と一重引用符
- タブとスペース
- 最大行長
- 以下に示すように、複数行の呼び出しのインデント:
# always single-line
foo(:a, :b, :c)
# aligned with first argument
foo(:a,
:b,
:c
)
# aligned with function name
foo(
:a,
:b
)
これらは完全に主観的なものですが、コードベース全体の一貫性を保つために、特定のプロジェクトごとに標準について合意することは通常有益です。
プログラム上の問題
ここに次のような問題を含めます:
- 非常に長いメソッド本体。これにより、読みやすさと保守性の問題が発生します。
- 循環的複雑度、コードの複雑度を測定するために一般的に使用される指標
- 条件内の割り当て。ほとんどの場合、
if x = true
と入力すると 、実際にはif x == true
を意味します 。そして、あなたが割り当てを意味したとしても、それはまだ直感的ではないアプローチです
セキュリティの問題
一部の機能またはプラクティスには、開発者が気付かない可能性のある潜在的なセキュリティ問題があります。
たとえば、Rubyでは、Kernel#open
は、ファイルまたは外部URLを開くことができる柔軟な機能です。ただし、open("| ls")
などの奇妙な呼び出しを使用して、任意のファイルシステムにアクセスすることもできます。 したがって、開発者に警告して、より安全なアプローチ(File#open
)を使用できるようにするのが賢明です。 、IO.popen
、URI.parse#open
)、または行動を自己責任で維持することを明示的に決定します。
パフォーマンスの問題
コンテキストに応じて、一部のオプションを他のオプションよりもパフォーマンスの高いものにするRubyの内部動作に関する詳細が多数あります。
それらについて警告するリンターは、プログラムの詳細を最適化しながら、途中で学習するのに役立ちます。
たとえば、Ruby2.5ではString#delete_suffix
が導入されました 文字列の末尾から部分文字列を削除します。これらの2行は同等ですが、後者の1行は、一般的な文字列regexmatchに依存しないため、パフォーマンスが向上します。
str = 'string_with_suffix'
# bad
str.gsub(/suffix\z/, '')
# good
str.delete_suffix('suffix')
自動修正
リンターの重要な側面は、見つかった問題の一部またはすべてを自動的に修正する機能です。線の長さなどのスタイリングの側面は簡単に自動化されるため、開発者の負担を取り除くのが理にかなっています。その他の問題は主観的であるか、人間の介入が必要な場合があります。大規模なメソッドのリファクタリング。このような場合、自動化は不可能です。
慣習または構成
ルールが理にかなっているコミュニティやプロジェクト内では、多くの場合、激しい議論があります。
従来の解決策は、各チームがメンバーの好みに合わせてリンティングルールを構成できるようにすることで、メンバー内の議論を解決できるようにすることですが、近年、複数の言語にまたがって単一の規則に標準化することが求められていますが、これはそうではありません。どこにでも適用されるので、一般的な考え方は、コードをスタイリングするときに開発者が持っている精神的なオーバーヘッドを完全に取り除くことです。どの行の長さが最も効果的かを議論する代わりに、誰もがコミュニティで合意されたルールを使用するだけです。
Rubyでは、これは多かれ少なかれ2つの既存のリンターに変換されます。完全な構成を可能にするRuboCopと、反対のアプローチを取り、共通の標準を定義するStandardRBです。
RuboCop
文書化された一連のルールを提供する通常のアプローチを採用し、それぞれが特定の問題を探します。開発者は、自分のプロジェクト内のルールを無効にしたり、微調整したりできます。
# configure max allowed line length
Layout/LineLength:
Max: 80
# disable cyclomatic complexity
Metrics/CyclomaticComplexity:
Enabled: false
すでに適切なデフォルトが含まれているため、構成は変更する特定のルールに対してのみ必要です。
bundle exec rubocop
を実行しています RuboCopにコードベース全体を分析させ、検出されたすべての問題を一覧表示します:
# test.rb
def badName
if something
return "inner result"
end
"outer result"
end
$ bundle exec rubocop
Inspecting 1 file
C
Offenses:
test.rb:1:1: C: [Correctable] Style/FrozenStringLiteralComment: Missing frozen string literal comment.
def badName
^
test.rb:1:5: C: Naming/MethodName: Use snake_case for method names.
def badName
^^^^^^^
test.rb:2:3: C: [Correctable] Style/IfUnlessModifier: Favor modifier if usage when having a single-line body. Another good alternative is the usage of control flow &&/||.
if something
^^
test.rb:3:12: C: [Correctable] Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
return "inner result"
^^^^^^^^^^^^^^
test.rb:6:3: C: [Correctable] Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
"outer result"
^^^^^^^^^^^^^^
1 file inspected, 5 offenses detected, 4 offenses auto-correctable
次に、bundle exec rubocop --auto-correct
を実行できます。 、および問題の大部分は構成に応じて修正されます。
bundle exec rubocop
の設定 CIパイプラインの一部として、最初にリンティングルールを満たさない限り、コードが通過しないようにします。
StandardRB
より最近のプロジェクトでは、実際に内部でRuboCopを使用しています。StandardRBの主な目標は、完全に別個のリンターを構築することではなく、議論する代わりに誰もが使用できる標準に到達することです。
それが最初に発表されたライトニングトークは、動機についてかなり明確です。人々が構文の詳細について議論する時間を減らし、コミュニティ全体の合意の決定に従うだけで、本当に重要なこと、つまり優れた製品やライブラリの構築にもっと時間を費やすことができます。
RuboCopが下で使用されているため、取得する出力は実際には同じ形式になります。唯一の違いは、どのルールもカスタマイズできないことです。
StandardRBは最近1.0.0に達しました。これは、使用するルールに関するほとんどの議論が問題ページですでに行われていることを意味します。特定のルールに関心があるか同意しない場合は、そこに関連する議論が表示される可能性があります。
しかし、最終的には、それがある程度深く議論されたと確信することができます。コミュニティ全体がすべての点で100%合意することは不可能です。このアプローチの哲学は、人々は柔軟であり、意見の相違や決定へのコミットメントを行うことができるということです。
最終的な考え
過去のプロジェクトでリンティングルールを選択することに誇りを持っているよりも多くの時間を費やした後、StandardRBのアプローチに価値があることは間違いありません。可能な限り、それを使用することをお勧めします。
議論のオーバーヘッドを取り除きながら一貫性のすべての利点を維持し、ほとんどのルールの自動修正により、より優れたソフトウェアをより効率的に提供し、本当に重要なことに集中することができます。
他の言語は、同様の低構成可能コードフォーマッターを採用しています。 mix formatter
Elixirで、rustfmt
Rustでは、どちらもある程度の構成が可能ですが、コミュニティは驚くべきことに、標準の範囲内にとどまっています。
そうは言っても、皮肉なことに、この感情に同意できない場合でも、RuboCopは完全に有効なオプションです。
P.S。 Ruby Magicの投稿をマスコミから離れたらすぐに読みたい場合は、Ruby Magicニュースレターを購読して、投稿を1つも見逃さないでください。
-
Ruby2.6の9つの新機能
Rubyの新しいバージョンには、新しい機能とパフォーマンスの改善が含まれています。 変更についていきますか? 見てみましょう! 無限の範囲 Ruby 2.5以前のバージョンは、すでに1つの形式の無限範囲をサポートしています( Float ::INFINITY を使用) )、しかしRuby2.6はこれを次のレベルに引き上げます。 新しい無限の範囲 次のようになります: (1..) これは、(1..10)のような終了値がないため、通常の範囲とは異なります。 。 使用例 : [a, b, c].zip(1..) # [[a, 1], [b, 2], [c, 3]] [1,2,3,
-
Rubyでの静的分析
ソースコードを解析して、すべてのメソッド、それらが定義されている場所、およびそれらが取る引数を見つけたいとします。 どうすればこれができますか? あなたの最初のアイデアはそれのために正規表現を書くことかもしれません… しかし、もっと良い方法はありますか? はい! 静的分析 は、ソースコード自体から情報を抽出する必要がある場合に使用できる手法です。 これは、ソースコードをトークンに変換する(解析する)ことによって行われます。 さっそく始めましょう! パーサージェムの使用 Rubyには標準ライブラリで利用可能なパーサーがあります。名前はRipperです。出力を操作するのは難し