basyura's blog

あしたになったらほんきだす。

redmine の hook が登録される流れ

チケットの誤爆登録


ちこちこやって幸せになれたと思ったら

タイトル部での Enter をキャンセルするプラグインがあった。更に幸せに慣れた。

そもそも redmine の plugin はどういうふうに登録されるのか

redmine_enter_cancel plugin のソースを覗いてみる

require 'enter_cancel_listener'

Redmine::Plugin.register :redmine_enter_cancel do
  name 'Redmine Enter Cancel plugin'
  author 'suer'
  description 'prevent unintended ticket creation by enter key'
  version '0.0.2'
  url 'https://github.com/suer/redmine_enter_cancel'
  author_url 'http://d.hatena.ne.jp/suer'
end
class EnterCancelListener < Redmine::Hook::ViewListener

  def view_issues_form_details_bottom(context)
<<SCRIPT
<script type="text/javascript">
$(document).ready(function() {
    $("#issue_subject").keypress(function(event) {
      if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) {
        return false;
      } else {
        return true;
      }
    });
  });
  </script>
  SCRIPT
end

plugin 登録用と本体のとてもシンプルな構成。シンプルだから真似してこう書けばいいのだなというのは雰囲気は分かるのだけど、なぜこう書いたらプラグインとして登録されるのかが分からん・・・。

しらべてみる

redmine のソースを覗いてみる。多少迷子になりながら。

  • redmine/lib/redmine/hook.rb
module Redmine
  module Hook
    class Listener
      include Singleton
      include Redmine::I18n

      # Registers the listener
      def self.inherited(child)
        Redmine::Hook.add_listener(child)
        super
      end
    end
    class ViewListener < Listener
      # 省略
    end
  end
end

今回のように View に関するフックを作りたい場合は、Redmine::Hook::ViewListener を継承したクラスを作ることになる。ViewListener は Listener を継承していてるので継承したクラスが定義されたタイミングで Listener.inherited メソッドが呼ばれる。すると Listener.inherited の中で Redmine::Hook.add_lister を呼ぶことで hook に登録される。

よって、init.rb で lib にあるファイルを require する必要があり、require されることでクラス定義が読み込まれて Listener への登録が行われる。

疑問

でもこれだと、init.rb では require されてるだけだから Redmine::Plugin.register の内容となんのヒモ付けもないように見える。
検証のため、init.rb で requre 以外はコメントアウトしておく。

require 'enter_cancel_listener'

#Redmine::Plugin.register :redmine_enter_cancel do
#  name 'Redmine Enter Cancel plugin'
#  author 'suer'
#  description 'prevent unintended ticket creation by enter key'
#  version '0.0.2'
#  url 'https://github.com/suer/redmine_enter_cancel'
#  author_url 'http://d.hatena.ne.jp/suer'
#end

redmine を起動すると 問題なく plugin は動作する。が、管理画面にある plugin の一覧には表示されない。

よって、

  • Redmine::Hook::ViewListener を継承した plugin が listener に登録される
  • register した内容(名前) が管理画面の plugin 一覧に表示される

となる。register した名前と実際の Listener は明確に紐付いてないけど、紐付いてなくても困らない。

ということかな (?)