Redmine プラグイン その2
昨日の続きです。
Redmine プラグインの雛形の作成
Redmine のプラグインを作成するには、以下のようなコマンドを実行します。
Redmine 1.2.1 では、まだ Rails 2.3.X 系統なので、ruby script/generate
でプラグインを作成します。
1 | ruby script /generate redmine_plugin sample_plugin |
このコマンドにより、vendor/plugins
ディレクトリの下にredmine_sample_plugin
というディレクトリが作られ、プラグインの雛形が生成されます。
プラグインの仕組み
今回は、簡単のためにデータベースへの保存などは行わず、表示方法をカスタマイズしたり、機能を追加したりする場合について書きます。
init.rb
からrequire
する
この雛形に含まれるファイルで、最重要なものはinit.rb
です。
このファイルは、Redmine が起動する際に自動で読み込まれます。
また、読み込まれる順序は、Redmine の Core ファイルが読み込まれた後です。
前回のオープンクラスの部分で書きましたが、この順序で読み込まれることが保証されているので、init.rb
の中で Redmine 関係のクラス (例えばIssue
クラス) を再定義することにより、自由にメソッドを追加、削除、上書きすることができます。
例えば、以下のように書いたファイルをlib
以下に置き、init.rb
からrequire
すると、Issue
クラスにopen?
メソッドを追加することができます。
(ただし、後で書くように、普通はもう少し整理された定型の書き方があります。)
1 2 3 4 5 6 7 8 | # vendor/plugins/redmine_sample_plugin/lib/test.rb # init.rb で require される。 class Issue def open? return !( self .closed?) end end |
このように書いたファイルをinit.rb
からrequire
することで、新たにIssue
クラスに新しいメソッドを追加することができます。
重要なポイントは、Issue
クラスという既存のクラスへの変更が、既存のファイルであるapp/models/issue.rb
をまったく変更することなく可能となっている点です。
これは、Issue
クラスのメソッドの全体が分かりにくいという大きな欠点もできますが、プラグインを配布する際に、特定のディレクトリにファイルを展開するだけでよいという、モジュールの可搬性という点において大きな利点を生むことになります。
実際のファイルは、以下のようにして、インスタンスメソッドやクラスメソッドを分離して記述することが多いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # vendor/plugins/redmine_sample_plugin/lib/test.rb # init.rb で require される。 module SamplePluginPatch def self .included(base) # (1) インスタンスメソッドを追加 base.send( :include , InstanceMethod) base.class_eval do # メソッドの上書きや削除をしたい場合は、ここで行う。 # クラスは常にオープンなので、ここで後からメソッドを変更できる。 # e.g. 下記の Issue のメソッドを上書き # def to_s # "#{tracker} ##{id}: #{subject}" # end def to_s "<issue: #{tracker} ##{id}: #{subject} >" end end end module InstanceMethod # 追加したいメソッドの場合は、ここに記述することで、 # (1) によりインスタンスメソッドとして追加される。 def open? return !( self .closed?) end end end # 以下のコードにより、Issue クラス内で include(SamplePluginPatch) と # 書いたかのような挙動を取らせる Issue.send( :include , SamplePluginPatch) |
app
以下で上書きする
これとは別に、app
ディレクトリ以下に直接ファイルを置くことによって、既定の動作を上書きして変更することもできます。
例えば、app/views/issues/_edit.rhtml
の内容を少し変更したものをvendor/plugins/redmine_sample_plugin/app/views/issues/_edit.rhtml
に置くことにより、もともとの_edit.rhtml
ではなく、redmine_sample_plugin
以下に置かれた_edit.rhtml
を使わせることができます。
これは、Rails がファイルを検索する順序として、各プラグインのapp
以下を探し、見つからなければルートディレクトリ直下のapp
ディレクトリを探すとなっているためです。
そのため、同名のファイルをプラグインのapp
以下に同じディレクトリ構成で置いてやることにより、自由にデフォルトのファイルを置き換えることができます。
簡単に表示やデフォルトの挙動をカスタマイズする程度であれば、このあたりを理解するだけで比較的自由に変更することができると思います。
一方で、あまりに自由度が高いので、これをやりすぎると、全体の見通しが悪くなったり、他のプラグインとの関係で思わぬ副作用が出たりするかもしれません。
Rails は、そもそも組込みのクラスにもいろいろなメソッドを (勝手に) 追加しています。こういう部分は、きちんとした設計のもとに行えば、非常に使い勝手が上がりますが、下手に追加すると、混乱を招くだけです。
Rails では、きちんとした設計のもとに行うことで、利便性を実現しています。
それと同じように、プラグインに対してもユーザーが自由にカスタマイズできるようにしておき、「自己責任でプログラマが自由にしてね」という余地をあえて残すような設計にしているのかもしれません。
0 件のコメント:
コメントを投稿