フォーチュンサモナーズ
«前の日記(2007-08-12) 最新 次の日記(2007-08-18)» 編集

Don'tStopMusic

2003|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|02|03|04|05|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|08|09|10|

カテゴリ別 2003年 | 2004年 | 2005年 | 2006年 | 2007年 | 2008年

知り合いサイト: よんだもの / 暴想 / Linuxでやる夫 / 新宿Vipper / 僕だけが幸せになればいいのに。


2007-08-14

_ [Ruby] Hpricot で XML をハッシュにする このエントリーを含むブックマーク

XML を取り扱う必要が出たのですが、最近 Hpricot づいてますので、Hpricot で XML をパースすることにしました。

対象の XML が単なるデータ表現でしたので、オブジェクト化しやすいように、ノードを辿ってハッシュ・配列化するメソッドを書いてみました。とりあえず動いてますが、もう少しコードを整理したいところです。

require 'rubygems'
require 'hpricot'
 
def traverse(node, hash = {})
  case node
  when Hpricot::Elem
    have_siblings = (node/"../#{node.name}").size > 1
    if have_siblings
      hash[node.name] ||= []
    end
    if node.children.size > 1
      child_hash = {}
      if have_siblings
        hash[node.name] << child_hash
      else
        hash[node.name] = child_hash
      end
      node.each_child do |child|
        traverse(child, child_hash)
      end
    else
      if have_siblings
        hash[node.name] << node.inner_html
      else
        hash[node.name] = node.inner_html
      end
    end
  when Hpricot::Elements
    node.each do |child|
      traverse(child, hash)
    end
  end
  hash
end
 
doc = Hpricot.XML(<<_XML_)
<Export>
  <Product>
    <SKU>403276</SKU>
    <ItemName>Trivet</ItemName>
    <CollectionNo>0</CollectionNo>
    <Pages>0</Pages>
  </Product>
  <Product>
    <SKU>104577</SKU>
    <ItemName>Dish</ItemName>
    <CollectionNo>1</CollectionNo>
    <Pages>2</Pages>
  </Product>
</Export>
_XML_
 
pp traverse(doc/:Export)
#=> {"Export"=>
      {"Product"=>
        [{"ItemName"=>"Trivet",
          "Pages"=>"0",
          "SKU"=>"403276",
          "CollectionNo"=>"0"},
         {"ItemName"=>"Dish",
          "Pages"=>"2",
          "SKU"=>"104577",
          "CollectionNo"=>"1"}]}}

XML のサンプルはerr.the_blog.find_by_title('Parse XML with Hpricot')から借りました。

_ [Ruby] 既存クラスを C 言語で拡張する このエントリーを含むブックマーク

今、Miyakoのマップスクロールとか、Miyako::Screen.updateメソッドとかが遅いと感じるときがあるので、そこをC拡張でなんとかできないかと試しています。

ただ、「既存のモジュール(require済みと仮定)にモジュールメソッドを追加する」方法が、ドキュメントを読んだだけでは分からない。

Ruby拡張ライブラリのいいソース無いかなぁ?

README.EXT だけだと難しいかもしれないですね。

Pure Ruby で定義された Hoge クラスに対して、C 言語の拡張で hoge インスタンスメソッドを追加する方法というかソース例を説明します。

ファイルを三つ用意してください。extconf.rb、C 拡張ライブラリのソース、それを使う Ruby プログラムです。

全体では以下のような流れのプログラムです。

  1. Ruby プログラムで Hoge クラスを定義
  2. C 拡張ライブラリで Hoge クラスに hoge メソッドを追加
  3. Ruby プログラムで Hoge#hoge 呼び出し

extconf.rb

Makefile 生成用。これを実行すると exthoge.c をコンパイルして exthoge.so を作成する Makefile が作成されます。

require 'mkmf'
create_makefile('exthoge')

exthoge.c

拡張ライブラリのソース。Hoge#hoge を定義します。Init_**** は require されたときに実行されるスタートアップルーチンです。**** は create_makefile した拡張ライブラリ名と一致させます。この例では、create_makefile('exthoge') したので Init_exthoge です。

Ruby ではクラスは定数に結び付けられてますので、rb_const_get で取得できます。(rb_cObject から取得していいのかはちょっと不明です。)

#include 
 
static VALUE rb_hoge_hoge(VALUE obj)
{
    return rb_str_new2("hoge");
}
 
void Init_exthoge()
{
    VALUE cHoge;
    cHoge = rb_const_get(rb_cObject, rb_intern("Hoge"));
    rb_define_method(cHoge, "hoge", rb_hoge_hoge, 0);
}

test.rb

Hoge クラスを定義し、また exthoge 拡張ライブラリを読み込んで Hoge#hoge を呼び出します。

class Hoge
end
 
require 'exthoge'
 
hoge = Hoge.new
p hoge.hoge #=> "hoge"

拡張ライブラリのビルド

extronf.rb を実行して Makefile を作成、あとは make すれば拡張ライブラリができます。Linux 環境前提ですが。

$ ruby extconf.rb
creating Makefile
$ make
i686-pc-linux-gnu-gcc -shared -o exthoge.so exthoge.o -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L.  -rdynamic -Wl,-export-dynamic    -Wl,-R -Wl,/usr/lib -L. -L/usr/lib -lruby18  -lpthread -ldl -lcrypt -lm   -lc
$ ls -l exthoge.so
-rwxr-xr-x 1 date users 6529 2007-08-14 23:46 exthoge.so

変数の取得

インスタンス変数は rb_iv_get で取得できます。後は ruby.h を眺めながら色々試すしかないですね。最悪 Ruby の eval 相当の rb_eval_string を使えば大体何でもできます。

本日のツッコミ(全3件) [ツッコミを入れる]
_ サイロス誠 (2007-09-04 23:09)

失礼をばいたしました・・・。<br>ご教授ありがとうございます。<br>試してみたのですが、かなり凄い量の関数呼び出しになりますね・・・(^^;

_ なかだ (2007-09-05 17:03)

rb_const_get(rb_cObject)してもいいのですが、<br>class/moduleに限定するならrb_path2class()という関数もあります。

_ だて (2007-09-14 14:58)

>サイロスさん<br>参考になれば幸いです。<br><br>>ながださん<br>rb_path2class は知りませんでした。便利ですね。

[]

最近のコメント:

  1. だて (09-14)
  2. a (09-09)
  3. とおりすがり (09-08)

RSS
Creative Commons License
This work is licensed under a Creative Commons License
(note: text only. w/o web design, citations, (re)distributed softwares).