Deprewriter in Ruby
PoC
以下のようなコードを実装
code:ruby
require 'prism'
class DeprecationCorrector
class << self
def setup
RSpec.configure do |config|
corrector = DeprecationCorrector.new
config.before(:suite) do
ActiveSupport::Notifications.subscribe('deprecation.corrector') do |_name, _start, _finish, _id, payload|
corrector.add_deprecation(
)
end
end
config.after(:suite) do
corrector.correct_all
end
end
end
end
class CallNodeVisitor < Prism::Visitor
attr_reader :start_column, :end_column
def initialize(method_name, line)
@method_name = method_name
@line = line
@start_column = nil
super()
end
def visit_call_node(node)
if node.name == @method_name && node.location.start_line == @line
@start_column = node.message_loc.start_column
@end_column = node.message_loc.end_column
end
super
end
end
class Deprecation
attr_reader :caller_location, :method_name, :replacement
def initialize(caller_location:, method_name:, replacement:)
@caller_location = caller_location
@method_name = method_name
@replacement = replacement
end
def correct
content = File.read(@caller_location.path).each_line.to_a
# File.write(@caller_location.path, content.join)
end
def eql?(other)
self.class == other.class &&
@method_name == other.method_name &&
@caller_location.to_s == other.caller_location.to_s
end
def hash
end
def start_column = visitor.start_column
def end_column = visitor.end_column
def visitor
@visitor ||= begin
parsed = Prism.parse_file(@caller_location.path)
visitor = CallNodeVisitor.new(@method_name, @caller_location.lineno)
parsed.value.statements.accept(visitor)
visitor
end
end
end
def initialize
@deprecations = Set.new
end
def add_deprecation(caller_location:, method_name:, replacement:)
@deprecations << Deprecation.new(caller_location:, method_name:, replacement:)
end
def correct_all
puts "\nStart correction:\n"
@deprecations.each(&:correct)
end
end
RSpec実行のセットアップでDeprecationCorrector.setupを呼ぶ
deprecateにしたいメソッドの1行目にActiveSupport::Notifications.instrument('deprecation.corrector')を仕込む
実行されるたびにDeprecationCorrectorに記録される
Thread::Backtrace::Location、deprecated method名、置換したいmethod名を与える
同じ行に同名のローカル変数が現れることもあるので、列番号も必要 アイデア
ワンショットのスクリプトなのでもっと気軽でいいのでは
gem install deprewriterしてdeprewriter bin/rspecしたら修正されている、みたいな
参考