はじめに
今年8月のエントリーで、任意のメソッド呼出を監視し、任意のコードを実行するgem「Okuribito」の作成を報告しました。
その後、gemの機能や、使われ方の思想が結構変わったので、改めて「Okuribito」の使い方を紹介したいと思います。
Okuribitoとは
Okuribitoは任意のメソッド呼出を監視し、任意のコード実行をできるようにするRubyのgemです。
このgemを使えば、例えば、メソッド呼び出しが行われた際にログファイルに書き出すことや、Slack通知を行えるようにするということができるようになります。
また、yamlファイルによって外から監視メソッドを指定するため、コードをほぼ(※)汚すことがない、というのも本gemの目玉となっております。
※ 監視開始を指示する部分と、任意のコードを記述するブロック部分は、どうしてもコーディングする必要があります
使い方
以下のようなコードにOkuribitoを適用する例を通じて、使い方を説明していきたいと思います。
class TestTarget def self.deprecated_self_method puts "deprecated_self_method" end def deprecated_method puts "deprecated_method" end end TestTarget.deprecated_self_method TestTarget.deprecated_self_method test1 = TestTarget.new test2 = TestTarget.new test1.deprecated_method test2.deprecated_method
インストール
まず、Gemfile
に次の記述を追加してbundle install
します。
gem 'okuribito'
監視したいメソッドの記述
監視したいメソッドをyamlファイルに記述し、配置します。
以下のように、クラス名にネストしてメソッド名を記述していきます。
メソッド名を記述する際は、クオテーションで囲み、それがクラスメソッドなのかインスタンスメソッドなのかのシンボルを記述する必要があります。
TestTarget: - ".deprecated_self_method" - "#deprecated_method"
requireの追加
以下を追記し、コードからOkuribitoを使えるようにしましょう。
require "okuribito"
Okuribitoの適用を記述
以下のように、Okuribitoのインスタンス生成時に、メソッド呼び出し検出時に実行したいコードを記述します。
apply
した以降は、Okuribitoによるメソッド呼び出し監視が有効になります。
okuribito = Okuribito::OkuribitoPatch.new(once_detect: true) do |method_name, obj_name, caller_info| puts "#{obj_name} #{method_name} #{caller_info[0]}" end okuribito.apply("okuribito.yml")
渡す仮引数は以下をサポートしています。
- method_name:メソッド名を取得できます
- obj_name:オブジェクトを文字列に変換したものを取得できます
- caller_info:バックトレース(メソッドの呼び出し履歴)を取得できます
- class_name:クラス名を取得できます
- method_symbol:クラスメソッド(.)かインスタンスメソッド(#)かの文字を取得できます
また、Okuribitoのインスタンスを生成する際、以下のオプションをハッシュで指定することができます。
- once_detect:
true
の場合、Okuribitoは同じメソッドの2回目以降の呼び出しを無視してくれるようになります
運用
Okuribitoを適用した最終的なコードは以下のようになっているとします。
require "okuribito" class TestTarget def self.deprecated_self_method puts "deprecated_self_method" end def deprecated_method puts "deprecated_method" end end okuribito = Okuribito::OkuribitoPatch.new(once_detect: true) do |method_name, obj_name, caller_info| puts "#{obj_name} #{method_name} #{caller_info[0]}" end okuribito.apply("okuribito.yml") TestTarget.deprecated_self_method TestTarget.deprecated_self_method test1 = TestTarget.new test2 = TestTarget.new test1.deprecated_method test2.deprecated_method
プログラムを実行すると、TestTarget.deprecated_self_method
、TestTarget#deprecated_method
の呼び出しがそれぞれ一度だけ検出され、結果、以下のような標準出力が得られます。
TestTarget deprecated_self_method okuribito.rb:18:in `<main>' deprecated_self_method deprecated_self_method #<TestTarget:0x007f9c61c96080> deprecated_method okuribito.rb:22:in `<main>' deprecated_method deprecated_method
課題
一通り、欲しい機能は作れたかなと思っています。
が、現状、名前空間に対応していないのが課題です。
後、(自分が把握している範囲で)誰かに使ってもらった訳ではないので、バグがまだあるかもしれない、というのが悩みです。
何で Okuribito って名前なの?
元々、未使用のメソッドを安全に削除するのを支援する目的で作ったgemだからです。
メソッドの最後を看取る......という想いを込めて、Okuribito。
おわりに
周囲に「どんなgemがあると嬉しいか?」というのをヒアリングしながら作ったので、コードの汚さはともかく、機能的には良いモノができたと思っています。
使ってみて、もしもバグと思える動作が発生した際は、issue の登録をお願い致します!(もちろん、要望も歓迎します!)
また、機能やコードを改善するPull Requestもお待ちしています!
少しでも「いいね」と思っていただけた方は、リポジトリにStarをつけていただけると幸いです \(^o^)/