こんにちは、mzpです。最近はBuckleScriptで、OCamlをJavaScriptに変換して遊んでいます。
先日、Misoca開発チームでfrozen_string_literal
を有効にするようにしたので、そのときの話を紹介したいと思います。
🔥有効にする前に起きたこと
Ruby 3.0からfrozen_string_literalが標準で有効になるという話もあって、一部のコードに # frozen_string_literal: true
が登場するようになりました。
次第に、 # frozen_string_literal: true
を書いてないと、レビューで指摘が入るようになりました。
🚓 Rubocopの設定変更
機械的にチェックできる項目をレビューで指摘するのは好きではないので、RubocopのStyle/FrozenStringLiteralCommenteを有効にし、自動でチェック・修正できるようにしました。
その際、既存のコードにはすべて ruboocp:disable
をいれて、このルールに検知されないようにしました。
# 既存コードは frozen_string_literal: true を書いてなくても許す %w(app lib spec config).each do |name| Dir["#{name}/**/*.rb"].each do |path| content = File.read(path, encoding: 'utf-8') if content !~ /\A# frozen_string_literal: true/ File.write(path, "# rubocop:disable Style/FrozenStringLiteralComment\n" + content) end end end
🔪Ripperによる自動書き換え
大半のファイルに rubocop:disable
が書いてあるのは微妙かなと思ったので、安全に書き換えれるファイルでは frozen_string_literal
を有効にするようにしました。
具体的にはRipperで全ファイルを走査して、文字列リテラルを使っていないファイルではfrozen_string_literal
を有効にするようにしました。
require 'ripper' class FindStringLiteral < Ripper::Filter def on_tstring_beg(_, data) data = true end def on_tstring_content(_, data) data = true end def heredoc_beg(_, data) data = true end end def string_literal?(path) content = File.read(path) FindStringLiteral.new(content).parse(false) end %w(app lib spec config).each do |name| Dir["#{name}/**/*.rb"].each do |path| unless string_literal?(path) content = File.read(path, encoding: 'utf-8') if content =~ %r{\A# rubocop:disable Style/FrozenStringLiteralComment} File.write(path, content.gsub(/\A.*/, "# frozen_string_literal: true")) end end end end
🚀今後の予定
残ったファイルは自動では修正できないので、別の修正するたびにちょっとづつ書き直しています。ボーイスカウトルールです。
🔉宣伝
Misocaではコードを綺麗にしていくエンジニアを募集しています。