そうか,クロージャって役に立つんだ

どうもいまいちクロージャの有用性が分かっていなかったのですが,階層カテゴリー部分の表示を作っていて,やっと役に立つことが分かったような気がしました。

具体的に言うと,<%categorylist%>で表示する部分というのは既に作ってあったのですが,今回,アイテム投稿画面を作るときに,またカテゴリーのツリー表示が必要なことに気付いたわけです。最初はコピペして,同じようなことをやらせようとしたのですが,どうも効率が悪いし,アルゴリズムにバグがあったり,データ構造を変えたら両方直す必要があります。

そこで,Blogモデルの中に表示ルーチンを移し,そこからブロックを呼び出すような形に変えてみました。
  def category_tree
      tempbuffer = ""
      level = 0
      self.categories.inject(nil) do |last_right, cat|
         
        # cat is under the last leaf
        if !last_right || (last_right > cat.cleft)
          level += 1
          tempbuffer += yield(:level_up, level)
        
        elsif (last_right + 2 <= cat.cleft)
          tempbuffer += yield(:item_close, level)
          (last_right+2..cat.cleft).each do |i|
            level -= 1
            tempbuffer += yield(:level_down, level)
          end
        else
          tempbuffer += yield(:item_close, level)
        end
        tempbuffer += yield(:item, level, cat)
        last_right = cat.cright
      end
      if (level > 1)
        tempbuffer += yield(:level_down, level)
      end
      (level..1).each do |i|
        tempbuffer += yield(:item_close, level)
      end
      tempbuffer += yield(:level_down, level)
      return tempbuffer        
  end

これをスキン変数の実行部分では
    def parse_categorylist params
      blog = params[2] ? Blog.find_by_bname(params[2]) : @controller.blog
      templatename  = params[1]
      template = Template.find_by_tdname(templatename)
      bd = blog.basic_data
      data = Hash.new
      
      blog.category_tree do |type, level, cat|
        data['level'] = level.to_s
        case type
        when :level_up
          fill(template['CATLIST_HEADER'], bd.merge(data))
        when :level_down
          fill(template['CATLIST_FOOTER'], bd.merge(data))
        when :item
          data['catlink'] = url_for(:controller=>'categories', :catid=>cat.catid, :action=>'show')
          fill(template['CATLIST_LISTITEM'], data.merge(cat.attrs))
        when :item_close
          fill(template['CATLIST_LISTITEM_END'], bd.merge(data))
        end
      end
      
    end

といった形でblog.category_treeにブロックを与える格好で呼び出します。かなりすっきりしたような気がします。管理画面でカテゴリーツリーが必要なときもblog.category_treeを使えばロジックは不要になります。
さらに,こういった構造に変えるメリットとして,スキン/テンプレートの実行部分とデータ構造を切り離せます。プラグインのイベント呼び出しを,これまではスキン/テンプレートの中からやる形だったのですが,モデル側に全部移せそうです。今後,スキン・エンジンを新たに作るときなどに,負担が大きく減るはずです。


22 Jul, 2008 | Foodyn ( 実装メモ , スキン , 作業メモ ) | | Andy
« Prev item - Next Item »
---------------------------------------------

Comments


No comments yet. You can be the first!


Leave comment

© 2007 yoursite.com | Designed by DesignsByDarren
Ported to Nucleus CMS: Suvoroff