redmine 読み (6)
そもそもの目的としては Rails の理解なので menu_item という redmine ローカルな手続きでまごまごしてるのは微妙。ちょっとハンドルを切って、いっちゃんてっぺんに出力されてる top-menu な id の div 要素のあたりを確認。
app/views/layouts/base.html.erb によれば以下のあたりなのかな。
<div id="top-menu"> <div id="account"> <%= render_menu :account_menu -%> </div> <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> </div>
むむ。何故か右から、って形になってるのも気になるな。
つうかここでも render_menu が出てきましたね。基本的に menu が ul な箇条書きになってて CSS あたりで見栄えを調整してるのでこんな括り方ができるのか。
特に account な div の中身はログインしてるかどうかで出力が異るはずなんですが、render_menu 一発なあたりが凄いですね。むむむと言いつつ grep してみたら以下な結果。
$ find app lib |xargs grep account_menu app/views/layouts/base.html.erb: <%= render_menu :account_menu -%> lib/redmine/plugin.rb: # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu lib/redmine.rb:Redmine::MenuManager.map :account_menu do |menu|
ええと、lib/redmine.rb で :top_menu とか :account_menu とか :project_menu とかの map の初期化な記述がありますね。つうか、lib/redmine.rb てどの契機で呼び出されるんだろ。
色々探してみるに lib/redmine/plugin.rb らしい。
$ find lib app |xargs grep autoload lib/redmine/plugin.rb: # Adds the app/{controllers,helpers,models} directories of the plugin to the autoload path lib/redmine/plugin.rb: ActiveSupport::Dependencies.autoload_paths += [dir] lib/redmine/plugin.rb: ActiveSupport::Dependencies.autoload_paths += [lib]
上記命令は一体? と思いつつググッてみたら config.autoload_path が云々って記述は結構ありつつ以下を発見。
がしかし、そもそもこの lib/redmine/plugin.rb を云々してるのは誰だろ。探してみるに require してるのは
$ find lib app |xargs grep redmine/plugin lib/redmine.rb:require 'redmine/plugin'
なんスけど微妙にループしてる感あり。うーん。でも redmine/plugin を require してるのは上記 lib/redmine.rb のみですね。うんうん唸りつつ load_path で grep してみると config 配下で以下な出力。
./config/application.rb: config.autoload_paths += %W(#{config.root}/lib) ./config/application.rb: # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] ./config/initializers/00-core_plugins.rb: ActiveSupport::Dependencies.autoload_paths += [lib]
lib/*.rb は autoload 対象ってことで良いかな。
何してたのか忘れたorz
lib/redmine.rb 確認中だったのか。account_menu が面白いですね。
Redmine::MenuManager.map :account_menu do |menu| menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? } menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? } menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? } menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? } end
面白いというかむしろ凄い。これで sign in/sign out な状態によって出力を変えることができるんだからすばらですね。変換してるのは render_menu_node に見えます。
caption, url, selected = extract_node_details(node, project) return content_tag('li', render_single_menu_node(node, caption, url, selected))
extract_node_details メソドはどこで定義なのかな。menu_manager.rb ですね。てか push でどう登録されるのか、を確認したい。Redmine::MenuManager.map は以下な定義で
def map(menu_name) @items ||= {} mapper = Mapper.new(menu_name.to_sym, @items) if block_given? yield mapper else mapper end end
ブロック渡しになってるので mapper が menu として渡されるんですね。ブロックの中では push メソドが呼び出されているのか。で、基本的には MenuItem のオブジェクトにされて云々、な模様。
caption 云々が微妙に気になってて extract_node_details メソドで
caption = item.caption(project)
みたいな取り出しかたしてます。これも謎。と思ったら MenuItem#caption がありました。おそらくは以下を通過なのかどうか。
if @caption.nil? l_or_humanize(name, :prefix => 'label_')
なんでここまで拘っているかというと
menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
なソレの表示が "Sign in" なんスよね。demo のソレと手元のソースの違い、なのかどうなのか。ここも瑣末なのでスルーします。