よたらぼ
自分の興味の赴くままにIT技術系のネタを取りとめもなくメモっています。
Ruby言語やLinuxのネタが多いです。

August 08, 2002

[tDiary] 本日のリンク元表示プラグイン-2.1.0 is out!

また表示方法を変えました。検索エンジン単位に表示する形にしてあります。すっきり。

2.0.1と互換性を持たせようと思ったんだけどやめました。どーしても前の方が良いという方はバージョンアップしないようにしてください。

ソースの方もゴッソリ書き換えました。(前に比べると)だいぶマシになったと思います。

それから、smbdさんのご要望にも対応しました。更新画面では全てのリファラが表示されます。

さ、Ruby-GNOMEに戻るか...。

本日のツッコミ(全1件) [ツッコミを入れる]

smbd [ありがとうございます〜]


August 08, 2003

[Ruby-GNOME2] Ruby/GtkHtml2

とうとう、CVSにチェックインされちゃいました...。でも武井さん作のものではなく、Martin Povoln???(文字化け(^^;))によるものです。直接ruby-gnome2-devel-en MLにポストされたので断れませんでした。ごめんちゃい。

[Ruby-GNOME2] そろそろリリース準備するか....

なぜか、先行で予告リリースされてるし.....。誰だよ、一体。プレッシャーかけやがって....(T_T)。

[Misc] 今日はまつもとさんを囲む会か...

参加できず残念、っと思ってたら、偶然、さかいさんが都内に来ると言うことで、一緒に食事をすることに。楽しかったですYO!

....ってか一方的に私がしゃべりまくりだったような....(汗。

でも、次回はまつもとさんを囲む会の方に参加したいですね>さかいさん(^^;)

class Person
   def initialize(name)
      @name = name
   end
end
                                                                                
obj1 = Person.new("Masao")
obj2 = Person.new("Masao")
                                                                                
p obj1 == obj2  #(1)

この例ではobj1, obj2が同一なのでしょうか。それとも違うのでしょうか...。違います((1)でfalseが返る)。って、この例では当たり前に感じるかもしれません。

では、一体、どういう状態が等しい状態と言えるのでしょうか?

等しい状態というのはそのクラスによって条件が異なります。その条件を定義してあげない限り等しくなりません。

#実際はObjectクラスで条件が定義されているので、そのサブクラスである全てのオブジェクトはデフォルトでその条件に従います。

そこで、そのような条件をクラス毎に指定します。例えば、上の例で、「nameが等しい場合は同一のオブジェクト」と定義してみると例えば以下のようなコードになります。

#eql?とhashをオーバーライドすることもありますが、ここでは==だけ。詳しくはこちら

class Person
   attr_reader :name
   def initialize(name)
      @name = name
   end
   def ==(other)
      @name == other.name
   end
end
                                                                                
obj1 = Person.new("Masao")
obj2 = Person.new("Masao")
                                                                                
p obj1 == obj2

この場合、trueが返ります。つまり、このPersonクラスのインスタンスの同一性というのはPersonクラス自身に決めさせることができます。

同様に、Fixnumの場合は、そのインスタンスが持つ数値が同じならばtrueを返すようになっているだけです。

mputさんの言葉を借りて表現すると「Ruby において同じ値の Fixnum インスタンス同士は”完全に違う”」、「即値の 1 と 2-1 の計算結果は全く違うオブジェクト」なわけです。違うのだけど、そのままでは「(インスタンスとしては)同一でないにもかかわらず(クラスで等しいという条件に一致しているため)それが判定できない」わけです。

というのが、私の理解です。間違えてたらご指摘してくださると勉強になりますですm(__)m。

本日のツッコミ(全1件) [ツッコミを入れる]

mput [いいえ、 Fixnum のインスタンスは id まで含めて完全に同一ですよ。 % ruby -e'p 1.id, ..]


August 08, 2005

[Ruby-GNOME2] WikiRPC Client by ZnZさん

今のところHiki専用だそうです。Ruby/GTK2, Ruby/Libglade2を使って頂いてます。

[Ruby-GNOME2] 大バグ発見

元ネタはこちら。実はこれ、昔から気づいてたんだけど今まで放置しちゃったんだよなぁ。てへっ。
とまぁ、ちょっと頭を整理するためにここにメモしてみる。

まず、以下のPureRubyWindow, GtkWindowという仮想的なクラスを例としてあげる。

(1)
class PureRubyWindow
   def child
      @child
   end
   def set_child(value)
      @child = value
      self
   end
end
 
(2)
class GtkWindow
   def child
       gtk_widget_get_child(self)      #実際のCのコードを呼び出すイメージ
    end
    def set_child(val)
       gtk_widget_set_child(self, val) 
       #=> valはGTKの内部でCのポインタとしてchildが管理されている。
       self
    end
end

この例で、以下のようなコードを書いたとする。Ruby-GNOME2ではよく見るコードだと思う。

def create_window
   child = Button.new
   window = PureRubyWindow.new
#   window = GtkWindow.new
   window.set_child(child)
end
 
window = create_widget

このコードではchildの有効な生存期間はwindowの生存期間と同じ、となるのが直感的だ。実際にウインドウが表示されているときに、自分が生成したボタンのインスタンスが実は無くなっているっていうのは気持ち悪いよね。つまり使用者はPureRubyWindowみたいな動作を期待するはず。

が、しかし。

GtkWindow版では、それぞれCのAPIを呼び出すだけになっており、実体としてCのライブラリ側ではchildは生き続けるが、Rubyオブジェクトとしてcreate_windowが呼び出された後はGCの対象になってしまう(はず)。

で、実は現在のRuby-GNOME2の実装は上記のGtkWindowになっている。

GtkWindow#childが返す値はC言語のポインタとしては同じものを指しているものの、それをラップするRubyオブジェクトが毎回違う、ということが発生する(GCのタイミングにもよるみたい)。

もうちょっと厳密に言うと、一度Rubyオブジェクト→Gtkオブジェクトに変換される際にGtkオブジェクト自身にRubyオブジェクトのポインタを覚えさせることをしているので上記のcreate_windowのような順番では問題ないのけど、それは話の本筋と異なるので割愛する。

これにより問題となるのは、GtkWindow自体を自分で拡張したりサブクラスを作成したときにRuby側で定義したオブジェクト内の情報(インスタンス変数や特殊メソッド等)が正しく引き継げないことだ(Rubyとしては新しいオブジェクトが生成・返されてしまう)。

それでは、GtkWindowをどのような実装にすればよいか。

以下のようなソースを見てみる。

class GtkWindow
   def initialize
      @store = {}
   end
   def child
       val = gtk_widget_get_child(self)      #実際のCのコードを呼び出すイメージ
       @store["child"] << val
       val
    end
    def set_child(val)
       gtk_widget_set_child(self, val) 
       @store["child"] << val
       self
    end
end

つまり、GTKのAPIに渡した情報であったとしても、PureRubyWindowと同様な動きが期待されるメソッドでは、GtkWindowのインスタンス変数としてcreate_windowで渡されるchildを保存しておくということだ(childそれ自身に覚えさせておくのではない、というのがポイント)。

こうしておくことで、少なくともGtkWindowの生存期間とchildの生存期間を合わせることができる....はず。

実はRuby-GNOME2では、これの局所的な問題解決用にG_RELATIVE2というマクロが定義されている(正直忘れてた....(^^;))。

で、それを使って上記のGtkWindowをもうちょっとCっぽく書いてみる。

#ただ、今見直すと、第3引数が不要と思われるのでここでは省略。

class GtkWindow
   def child
       val = gtk_widget_get_child(self)      #実際のCのコードを呼び出すイメージ
       G_RELATIVE2(self, val, "child");  //"child"はHashのkey。
                      //この"child"は文字列ではない方が良いかも。
       val
    end
    def set_child(val)
       gtk_widget_set_child(self, val) 
       G_REMOVE_RELATIVE(self, "child"); 
       G_RELATIVE2(self, val, "child"); 
       self
    end
end

要はこれをRuby-GNOME2全体に適用すればよいのだけど...。もうちょっと整理しないとしないとだなぁ。ということで以下にTODOをあげておく。

  1. まず、どういった基準で上記を適用するか、全てのCのWrapperメソッドで適用していいのか。
  2. 上記のマクロは実装も含めもう少し整理した方が良いな。
    GOBJ2RVAL3(key, self, gobj)/RVAL2GOBJ3(key, self, val)みたいなのを作っても良いかもしれない。
  3. G_RELATIVE/G_RELATIVE2の実装は見直したほうがいいなぁ...。
  4. 上記はsetter/getterの組み合わせで成立する。addとかinsertとか、同じ変数(らしきもの)に値がどんどん追加されるようなものはもう少し検討が必要そう。
  5. プロパティやシグナルなど、自動的に生成されるRubyオブジェクトにも同様な仕掛けを入れ込むが必要あるかも。

さてさて。どうしたもんかなぁ。まぁ、問題自体が今になって顕在化するようなものだから今さら焦ってもしょうがないよね(?)。ゆっくりやるとするか...。ってかホントにこれで大丈夫なのか不安だ(苦笑)。

しかし、このTomaszって人すごいなぁ。こんな短期間によくここまで考察できたなぁ。いっそのこと彼に書き直してもらえないかな(^^;)。


追記