- 単に
app/views/issues/*.api.rsb
に対応するplugins/my_plugin/app/views/issues/*.api.rsb
を置くだけでした - つまりhtmlを出力する.erbテンプレートと同じ手順でAPIの出力も改変できます
- なんで気づかなかったんだろうこれ・・・orz
-
*.api.rsb
だけ置き換えるとActionView::Template::Error
が発生するので、*.html.erb
も同時にコピーせよとのことです
このへんをいじればいけそう。
module Redmine
module Views
class ApiTemplateHandler
def self.call(template)
"Redmine::Views::Builders.for(params[:format], request, response) do |api|; #{template.source}; self.output_buffer = api.output; end"
end
end
end
end
template.source はテンプレート(app/views/issues/index.api.rsb など)のソースコードを返しているので、pluginからself.callを横取りすれば任意の別のテンプレートを差し込めるっぽい。
どのコントローラ/アクションのテンプレートを呼び出しているかは template.virtual_path を見ればいいっぽい。
まだ試したわけじゃないんでそのうち試す。
試したし動いた。
module ApiTemplateHandlerPatch
module ClassMethods
def hello
puts 'Hello, from plugin'
end
def call(template)
case template
when 'app/views/issues/show.api.rsb' then
template = 'plugins/my_plugin/app/views/issues/show.api.rsb' # 改変済みの.rsbファイル
end
p template
super(template)
end
end
def self.prepended(base)
class << base
prepend ClassMethods
end
end
end
ActionDispatch::Callbacks.to_prepare do
Redmine::Views::ApiTemplateHandler.send(:prepend, ApiTemplateHandlerPatch)
end
Redmineのプラグインでは alias_method_chain
を使ってメソッドの再定義を行っている例が多いけど、ruby2.0以降のみで動けばいいなら Module#prepend
を使うと見通しがよくなる。
- ruby - How to prepend classmethods - Stack Overflow
- Ruby2.0のModule#prependは如何にしてalias_method_chainを撲滅するのか!? TECHSCORE BLOG
template.sourceを直接いじるには?
Redmineのプラグインテンプレートである.rsb(中身はただのrubyのDSLっぽい)をコピーして改変したものをプラグイン側にもたせておくのはあまりスマートでない気がする(コードを流用するとなるとRedmineのライセンスに従わないといけないとか; まあMITライセンスなのであんま問題にならないけど)んで、文字列で渡されるテンプレートのソースコードをコードから変更する案。
RipperでAST(抽象構文木)が取得できるので、template.sourceをASTに変換して、ASTをいじってソースコードに変換すればよさそう。
ASTからソースコードへの再変換はsorcererが使えるっぽい。
- http://www.todesking.com/blog/2014-04-29-highlight-ruby-local-variables-in-vim/
- http://stackoverflow.com/questions/4878032/how-would-i-recompile-rippers-ast-back-to-ruby-code
こちらに関してもまだ一切何も試してない。