be carefull to use Meta class *
不用意にメタ・クラスを多用するとコードがわかりづらくなるだけでなく、
オブジェクトやクラスの意味自体を変えてしまう事もあります。
[Ruby] evil-ruby
コンセプトはわからないけど、become とか superclass= とか
Class#as_module
こんなのないかなぁ。。。と思っていたものがここにあった。
やってることは、おそらくCでの構造体レベルでのデータを変更したりしてる(はず
だけど、dl/structを使ってrubyのみで書かれてるのがすごい。
./test/tc_*.rb 試してみた所、テストが全部通らなかった。
- rprofile付きで実行した時と結果が代わるので、不安定なのかな。
ソースのコメント内にも FIXME memory leak と書いてある。(汗
-
-
- -
-
自分でも数日前に丁度似たような目的のモジュールを書いた事があったので、
その時のコードを載せてみる。
#include "ruby.h" static VALUE mop_set_superclass(self, klass) VALUE self; VALUE klass; { if (TYPE(klass) != T_CLASS) rb_raise(rb_eTypeError, ""); if (RCLASS(self)->super != rb_cObject) rb_clear_cache(); RCLASS(self)->super = klass; return self; } void Init_mop(void) { rb_mMop = rb_define_module("MetaObjectProtocol"); rb_define_method(rb_mMop, "superclass=", mop_set_superclass, 1); }
ruby -rmkmf -e "create_makefile('mop')" && make
#!/usr/bin/env ruby require 'mop.so' Foo = Class.new{define_method("say_hello"){puts "hello, foo"}} Bar = Class.new{define_method("say_hello"){puts "hello, bar"}} c = Class.new(Foo).extend(MetaObjectProtocol) o = c.new o.say_hello # hello, foo c.superclass = Bar # 動的にスーパークラスを変更 o.say_hello # hello, bar
superclassへの代入だけでは、
superclassを何回か変更した時にメソッド名が衝突すると、
cache内の以前のsuperclassのメソッドを呼び出してしまう事があった。
(evilのforumにもpostしてみた)
let binding
def let(*values); yield *values; end
def let(*values, &block) block.call(*values) if block_given? end
example:
let (metainfo['info']) { |info| info['name'] = name info['pieces] = pieces.join info['piece length'] = 2**18 }
If write this with lambda or proc.
lambda {|info| # : same }.call(metainfo['info'])
Since ruby's function can take a block argument, and have closure,
It works like let binding. but its in limited context,
there was an exception which i dont expect
def let(*values); yield *values; end n = num = 0 s = str = "Hello" p n, num p s, str let (num) { |n| p n; n = n } # left n is global, right n is local... let (str) { |s| p s; s = "world" } p n, num p s, str
In the block, p n shows value of num,
but n = 1000 changes global variable 'n'. its not local variable !?
seem this is known problem at ruby.
I'm thinking how to define 'with' statement.
Aversa [Ruby][BitTorrent]
Aversa is a little utility for creating and viewing BitTorrent metainfo files.
メタ情報ファイル(.torrentファイル)の表示と生成のみだけど、
トラッカーも作りそうな雰囲気。Net::BitTorrentモジュールとか作ってたので
プロジェクトにマージお願いしてみた。
元々、興味があったのは peer-wire-protcol の部分のみだったので、
実験用にダウンロード出来る最小限のコードだけ書いて
アプリケーションまでは作らずに放置していたのだけど、
この機会にもう少し手入れしてみる事にする。
ダウンローダーとかトラッカーはみんな作ってると思うので、
焦点をずらして、BitTorrentの応用技術に注目してみようと思う。
- BitTorrentを用いたファイルの同期ツール (#bittorrentで聞いてた人がいた)
- BitTorrentとRSSを組み合わせた broadcast system
- BitTorrent peer wire protocol uploader proxy (友達が必要だったので)
- BitTorrent用のクローラー(検索エンジン等があったので)
- BitTorrent + RubyGem (rubyforge.orgのfeature requestにあった)
rubyforge.orgがトラッカーを提供し始めたので、検索機能と連係できるかも知れない。
データベースを共有すればクローラーは必要ないかな。
ちなみにプロジェクトのadminはrubyforge.orgのサポートもやってる(?らしい)
- MetaInfoのRDF版 (textで保存/編集できる、XSLで表示しやすいなどの利点)
メタ情報ファイルのXML化はWikiにもアイデアが挙がってた。
実装はまだ見たことない。
バイナリが問題なりそうだけど、適切にエンコードすれば no problem
例えば pieces は、
: ...
トラッカーがRDFとかでデータ返してくれるとうれしい。
BEncodeよりXMLの方が普及しているし、大抵の開発環境でXMLが使える。
メタ情報ファイルの文字エンコードの問題も解決する。
欠点は、当然データが冗長になる事。pieceseがbase64だと 4/3 倍 + タグや
ヘッダの分増加。ただし、これは HTTP/gzip による圧縮が期待できる。
出来るかどうかわからないけどアイデアだけ書き綴っておく。
他にも wiki に BitTorrent Spec2 拡張のアイデアが多数あり。
[JavaScript] (mozilla)
var code = uneval(this["function_name"]) code = code.replace("...", "...") // codeを編集 this["function_name"] = eval("(" + code + ")")
uneval/evalを使って、macroの様な事が出来る。
これの応用でJavaScriptで継続を実装なんてデモがあった。
LISPなら、S式=構文木=codeだから、リスト操作で済むのだけど
javascript/evalの場合は、
コードを再度パースするか、正規表現&置換でコードを編集しないといけない。
tokenくらい簡単に得られたらなぁ、、
関数オブジェクトは上記の方法で得られるので、
AOPのPointCutみたいなのは匿名関数と組み合わせで出来る。
(先日のProthonでの例みたいに)
this["foo"] = function () { return afterFunc(this["foo"](arguments)) }
[PrUnit]
ソースを全部張り付けるには多き過ぎたので、
"test"で始まるメソッドを呼び出す処理の部分のみ。
def run(): for attrs in self.attrs_.items(): name = attrs[0] func = attrs[1] if name[:4] == "test": self.setUp() func{self}() # or self.attrs_[func]() self.tearDown() self.report()