«Prev || 1 | 2 | 3 | 4 | 5 | 6 | 7 || Next»

ダック・タイピング

アイテムでもブログでも区別しないで権限を調べられるように,両者に同じメソッドを作ってアクセスするようにしています。これもダック・タイピングと呼んでいいのかな?

先日デザインパターンの本を読んだのですが,なかなかおもしろかった半面,記述がJavaだったため,Rubyだとどうなるのだろうと気になるところもありました。Javaではインタフェースを中心にデザインパターンを構築することが多いようですが,Rubyだとインタフェースという機能はありません。その代わりにmoduleを使ってミックスインしたり,今回のように特に宣言なく同じAPIを用意して呼び出すといったことができます。こういった特質により,デザインパターンの実装も変わってくると思います。

Web上にはまつもとさんが書かれたものも含め,いくつかRubyによるデザインパターンの実装がありますが,できたら体系だって本として読みたいところ。

20 Jun, 2008 | Foodyn ( つぶやき , 作業メモ ) , Rails | | Andy | Leave comment - 0 -

ブログRole追加だけで終わってしまった

システム系はどういうRightsが必要か考えるのが結構大変だ。
でもやっておかないとね,後から拡張するんでもいいけど。

07 Jun, 2008 | Foodyn ( つぶやき , 作業メモ ) | | Andy | Leave comment - 0 -

アクセス制御の枠組み

アクセス制御のためのデータ構造が大体決まりました。たぶんこれで行けるでしょう。
アクセス管理
ちょっと分かりにくいので図にしてみました。
アクセスはロールごとに決めますが,ロールにはシステム・レベルのものとブログ・レベルのものがあります。システム・レベルのロールはmemberテーブル内に書きますが,ブログ・レベルのものはteamテーブルで指定します。本当は権限については独立したテーブルを用意し,中間テーブルを作ってマッチングさせるのが拡張性が高いのですが,実行速度を重視して,ロールのテーブル内のフィールドとして各権限を設定するようにしました。また,ブログレベルのロールとシステムレベルのロールを区別するためのissystemというフィールドを作っています。このほか,アイテム単位で制御方法を変えられるようにするためにアイテムとロールによるテーブルも作ります。
クエリーの効率が心配ですが,たぶんこれでやりたいことはできる枠組みではないかと思います。

05 Jun, 2008 | Foodyn ( 実装メモ , 仕様 , つぶやき ) | | Andy | Leave comment - 0 -

タグとカテゴリが曲がりなりにも動いたので

そろそろ次のフェーズ(管理画面)に入ろうかと。
あー腰が重い。
まずは投稿画面からかな。

01 Jun, 2008 | Foodyn ( つぶやき ) | | Andy | Leave comment - 0 -

設計とメソッド名と内部構造

どうも頭がまだ手続き型言語から抜けていないようで,メソッド名を付けるときに,ついつい「get~~」みたいに動詞を入れてしまいがちです。

ということに気付いたのは,あるブログに属するカテゴリー一覧を取得するとき。実はこれまでCategoryクラスの方でget_listというメソッドを作ってブログオブジェクトをパラメータに取得するようにしていました。こうしておくと,ブログが指定されないときの一覧やブログが複数あるときの一覧とかも同じメソッドで取れるというのがメリットなのですが,見直してみるとCategory.get_list ... と入るのはあまりきれいじゃないです。やはり blog.categories と書いた方がスマート。

これだと順序付けができないのかと思って,この記述を使っていなかったというのもあるのですが,APIを見たら has_many のリレーション指定の中で :order を使って指定できることが分かったので,今回はそちらに切り替えました。

ただ,しっくりこない面がないわけではありません。これだとBlogクラスの中でCategoryのテーブルの内部情報を使って :order のところを書くことになるため,Categoryの実装に完全に依存してしまいます。Categoryの内部構造が変わったらBlogクラスも変えなければいけないのでメンテナンス性が悪くなります。

どうするのがベストなんでしょう。

13 May, 2008 | Foodyn ( つぶやき ) , Rails | | Andy | Leave comment - 0 -

美しくない解決法

いろいろ調べるうちに,FoodynPlugin::Baseというクラス・オブジェクトが二つ存在していることが分かってきました。「なんてこった」って感じです。クラスはシングルトンじゃないんでしょうか。
愚痴りたい気持ちはやまやまですが,とにかく動くようにすることが先決なので,なんとか解決法を考えました。

  def self.list
    @pluginlist ||= Array.new
    if @pluginlist.size == 0
      @pluginlist = Class.constants.select do |c|
        cclass = c.constantize
        if (cclass.is_aModule) && (cclass.constants.include'Base')
          klass = (c+'::Base').constantize
          klass.ancestors.any? {|anc| anc.name == 'FoodynPlugin::Base'}
        end
      end
    end
    @pluginlist
  end
  
  def self.plugin_class plugin_name
    if (pl = list.find {|p| p.downcase == plugin_name.downcase})
      return (pl + '::Main').constantize
    end
  end

プラグイン・クラスの一覧を取るアルゴリズムですが,まずはClassレベルにおける定数を調べ,そこでModuleに属するものを選び,さらに,Module内の定数で「Base」を含んでいるものを選びます。この中から,Base付きのクラスの先祖のクラスを調べ,そこにFoodynPlugin::Baseがあるかどうかで判断しています。本来ここはクラスレベルで判定できるはずですが,上記の理由によって,わざわざ文字列に変換して比較しています。

美しくはありませんが,ともかくこれでスキン変数が動くようになりました。なんだかどっと疲れました。

わけが分からない

昨日の続きでまだうまくいきません。というかRuby(Rails?)の動きが理解できません。

結局,プラグインの子クラスの一覧を取る機能は次のように実現しました。
  def self.list
    @@pluginlist ||= Array.new
    if @@pluginlist.size == 0
      @@pluginlist = Class.constants.select do |c|
        cclass = c.constantize
        if (cclass.is_aModule) && (cclass.constants.include'Base')
          FoodynPlugin::Base > (c+'::Base').constantize
        end
      end
    end
    @@pluginlist
  end

最初にpluginlistにArrayを入れてサイズを調べるといったまだるっこしいところをしているのは,またもやリロードのときにpluginlistが空になってしまうという問題に対応するためです。

中身はClassでの定数の配列を獲得し,それがModuleの名前かどうかを調べ,次にさらにそのモジュールでBaseという定数が定義されているかどうかを調べて,最後にFoodynPlugin::Baseと比較しています。

ところが,リロードすると最後の比較のときにtrueにならなきゃいけないところがなぜかnilに。理解できない。こまったなあ。

現象は分かったけど,どうしたものか

プラグインのスキン変数がうまく動いていなかった件,前進しましたが解決にいたらず。ちょっと困惑しています。プラグインのベースのクラスFoodynPlugin::Baseのクラスメソッドでは次のようなメソッドを用意しています。
  def self.inherited subclass
    @@pluginlist ||= Array.new
    @@pluginlist.push subclass
  end
  
  def self.list
    @@pluginlist ||= Array.new
  end
  
  def self.plugin_class plugin_name
    if (pl = list.find {|p| p.pname.downcase == plugin_name.downcase})
      return (pl.pname + '::Main').constantize
    end
  end

  def self.pname
    self.name =~ /^(.*)::/
    return $1 # default name
  end
ここで,inheritedというのは,そのクラスを親とする子クラスが定義されるときに自動的に呼ばれるメソッド。これを使って@@pluginlistというクラス変数にプラグインのベース・クラスの配列を入れています。スキンをパースするときに,エンジンが持っているparse_~~というルーチンとマッチしないと,FoodynPlugin::Base.plugin_classメソッドを使って,そのプラグインが存在しているかどうかを調べます(今思ったのですが,このメソッドは割と呼び出し回数が多いので,この中で名前を調べているのはだいぶ無駄な感じがします。名前自体を持たせる方がいいかも)。

プラグインが存在すると,そのメイン部分のクラスを返します(ここもインスタンスを返すようにしたほうがいいかも)。そうするとパーサ側でこのプラグインのインスタンスに対してdo_skin_varメソッドを発行するわけです。

これで動くのですが,よく分からないのは,ページをリロードすると@@pluginlistがなくなってしまうこと。ですから1回目はスキン変数を表示しますが,リロードすると表示しません。クラスはロードしたままだけど,変数は消してしまうということでしょうか。そうだとするとinheritedに頼ることはできないので,このロジック自体考え直す必要がありそうです。ちょっといやらしい実装です。

25 Apr, 2008 | Foodyn ( プラグイン , つぶやき ) | | Andy | Leave comment - 0 -

プラグインはクラスで実装すべきかインスタンスにするべきか

プラグインのスキン変数の実装でちょっとバグっています。簡単に取れそうなのに,案外手間がかかってしまっています。

その理由の一つはプラグインの実装をインスタンスでしているのに呼び出し側はクラスを呼んでしまっていたところにありました。

そもそもあるプラグインのインスタンスはシステムに一つしかない必要があります。そのため,いわゆるシングルトンのデザインパターンになります(RubyではSingletonモジュールをクラスに読み込むだけですが)。クラスはもともとシングルトンなので,プラグインをクラスで実装しても構わないということになります。

ところが,実際に書いてみると,クラスでプラグインを実装するとかなり分かりにくくなることが判明しました。具体的には,プラグインのベースクラス(プラグインを実行するかどうかにかかわらず,必ず読み込む部分)では,読み込まれたプラグインの一覧をクラス変数に確保するためにクラスメソッドを用意しています。それとプラグイン本体の部分とがごちゃごちゃになってしまうという分かりにくさがありました。

一方で,プラグインを呼び出すときは,プラグインのクラスに直接メソッドを送った方が話が早いので,ついそう書きたくなってしまうのです。結局プラグインの名前を抽出するメソッドをクラス・メソッドにもインスタンス・メソッドにも置くなど,なんだか汚いコードになってしまっています。少し設計を整理した方がいいのかもしれません。

23 Apr, 2008 | Foodyn ( プラグイン , つぶやき ) | | Andy | Leave comment - 0 -

デバッガーが~

ちょっとショック。RadRailsの現行バージョンでは,デバッガーが起動するときにエラーになります。1.0.2では直るようなのですが,まだ公開されていないみたいだし。早くしてくれ~。

23 Apr, 2008 | Foodyn ( つぶやき ) | | Andy | Leave comment - 0 -
«Prev || 1 | 2 | 3 | 4 | 5 | 6 | 7 || Next»

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