<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ものぐさ備忘録 &#187; Ruby</title>
	<atom:link href="http://www.ginriki.net/wd/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ginriki.net/wd</link>
	<description>ソフトウェア関係の話を中心とした備忘録的日記</description>
	<lastBuildDate>Sun, 11 Jul 2010 15:48:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>NetBeansからRuby on Rails(RoR)のリモートデバッグ</title>
		<link>http://www.ginriki.net/wd/2010/07/12/172/</link>
		<comments>http://www.ginriki.net/wd/2010/07/12/172/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 15:39:07 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[NetBeans]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[debugger]]></category>
		<category><![CDATA[RoR]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=172</guid>
		<description><![CDATA[NetBeansには、rubyのデバッガフロントエンドが同梱されています。
今回は、それを使ってRuby on Rails(以下RoR)のリモートデバッグをするためのメモです。
個人的には、RoRが動いてるマシンにssh [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://ja.netbeans.org/">NetBeans</a>には、rubyのデバッガフロントエンドが同梱されています。<br />
今回は、それを使ってRuby on Rails(以下RoR)のリモートデバッグをするためのメモです。</p>
<p>個人的には、RoRが動いてるマシンにsshでログインした後、emacsと<a href="http://www.freedom.ne.jp/toki/ruby.html">rubydb3x.el</a>を使う方がメリットがある<sup>1</sup>と思いますが、emacsの場合デバッガ用GUIはありません。GUIに慣れてる人はNetBeansの方が楽なので、そういう人向けにまとめます。</p>
<p>なお、NetBeansをインストールしたローカルマシンで、RoRも動かす場合のデバッグ方法は、<a href="http://wiki.netbeans.org/RubyDebugging">NetBeansのwiki</a>を参照してください。</p>
<p>まあ、ローカルマシン上でデバッグする場合も、リモートマシンと接続してデバッグする場合もやり方はほとんど変わりません。</p>
<p>どちらの場合も、デバッギプロセス（と同じプロセス上で動くruby-debug-ide)がTCP(デフォルトだと1234)をListenし、Netbeansからそこに接続してデバッグを開始します。Netbeansから接続するデバッギプロセスがlocalhostにいるか、リモート先のホストにいるかの違いしかないです。<br />
接続後、Netbeansからruby-debug-ideへbreakpointをしかける場所などを指示します。</p>
<p>デバッグ方法そのものは、ローカル・リモートともに一緒ですが、リモートのホストに対してローカルのNetBeansを接続してデバッグするには、リモート先のホストで以下の作業が必要です。</p>
<ol>
<li>rubyインストール (解説略)</li>
<li>RubyGemsインストール (解説略)</li>
<li>RoRインストール・プロジェクト作成 (解説略)</li>
<li>ruby-debug-ideインストール</li>
<li>リモート先のRoRプロジェクトのソースコードを、ローカルにも展開</li>
<li>ruby-debug-ide付きでRoRプロジェクトのWebサーバ起動</li>
</ol>
<p>4, 5, 6の手順は、あまりネット上で見かけないので順に解説します。</p>
<h3>ruby-debug-ideインストール</h3>
<p>Linuxだと、gemで簡単にインストールできます。(gcc, ruby-develをインストールしておけば。)<br />
Fedora8だと以下で終わりでした。</p>
<pre>
$ gem install ruby-debug
$ gem install ruby-debug-ide
</pre>
<p>Windows（のmswin版ruby）の場合、コンパイル環境の用意が面倒なので、コンパイル済みgemをダウンロードした上でインストールします。<sup>2</sup></p>
<pre>&gt; gem install -l linecache-0.43-mswin32.gem
&gt; gem install -l ruby-debug-base-0.10.3-mswin32.gem
&gt; del ruby-debug-base-0.10.3-mswin32.gem
&gt; gem install ruby-debug
&gt; gem install ruby-debug-ide -v 0.4.6</pre>
<p>コンパイル済みgem (linecache, ruby-debug-base)は以下２つのリンク先から<br />
それぞれダウンロードしてください。</p>
<ul>
<li><a href="http://rubyforge.org/frs/?group_id=5040&#038;release_id=22842">linecache</a></li>
<li><a href="http://rubyforge.org/frs/?group_id=1900&#038;release_id=28306">ruby-debug-base</a></li>
</ul>
<h3>リモート先のRoRプロジェクトのソースコードを、ローカルにも展開</h3>
<p>ローカルにもソースコードを置かないと、breakpointで止まった時にNetbeansにソースコードが読み込まれません。<br />
注意点としては、リモートと同じフルパス上にソースコードを置く必要がある点です。リモート先で、/var/www/railsprjにRoRのプロジェクトコードが置いてあるなら、ローカルでも/var/www/railsprjにプロジェクトコードを置く必要があります。<sup>3</sup></p>
<p>この辺の挙動理解には、<a href=http://wiki.netbeans.org/RubyDebugging#Checking_debugger_engine_functionality">NetBeans wikiのChecking debugger engine functionality</a>とか、<a href="http://debug-commons.rubyforge.org/protocol-spec.html">ruby-debug-ide protocol</a>とかを参考にして、実際にruby-debug-ideとtelnetで会話するといいです。</p>
<h3>ruby-debug-ide付きでRuby on RailsプロジェクトのWebサーバ起動</h3>
<p>以下な感じでRoR Webサーバ起動します。(-dも付けると、NetBeansとの通信時の処理が良く見えます。)</p>
<pre>
$ rdebug-ide --stop script/server -h 0.0.0.0
Fast Debugger (ruby-debug-ide 0.4.6) listens on 0.0.0.0:1234
</pre>
<h3>NetBeansからruby-debug-ideに接続</h3>
<p>NetBeans IDEのメニュー -> デバッグ -> 接続をクリックし、ダイアログにリモート先ホスト名とポート番号(1234)を指定して接続します。<br />
&#8211;stopを指定してあるので、RoRの処理先頭でstopするはずです。<br />
あとは、IDEからbreakpoint指定するなり、なんなり自由に操作します。<br />
watch変数として、paramsを追加しておくといい感じです。</p>
<ol class="footnotes"><li id="footnote_0_172" class="footnote">sshのポート(TCP 22)が開いてることは普通にありますが、デバッガ・デバッギ通信用のポートがfirewallで遮断されることは良くあります。</li><li id="footnote_1_172" class="footnote">最近だと、Visual C++は無料で手に入りますがmswin版rubyをコンパイルしたVisual C++と同じバージョンをインストールする必要しないと「MSC version unmatch」エラーが出てめんどくさいです。<a href="http://rubyforge.org/tracker/index.php?func=detail&#038;aid=16774&#038;group_id=1900&#038;atid=7436">http://rubyforge.org/tracker/index.php?func=detail&#038;aid=16774&#038;group_id=1900&#038;atid=7436</a></li><li id="footnote_2_172" class="footnote">WindowsとLinuxだとフルパスを一致させることが不可能なので、例えば、Windows上のNetBeansからLinux上のRoRがデバッグができないという点でかなりアレな仕様です。誰もやってないなら修正パッチ作るかな。</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2010/07/12/172/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby/Jrubyの実行時フックの低レベルAPI</title>
		<link>http://www.ginriki.net/wd/2010/04/08/129/</link>
		<comments>http://www.ginriki.net/wd/2010/04/08/129/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 19:23:03 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[ruby jruby]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=129</guid>
		<description><![CDATA[メモ。
RubyやJRubyには、特定の条件(コード行が変化したとか、メソッドを呼び出したなど）を満たした時に呼び出されるフック処理を定義することができます。
Ruby-1.8の低レベルなフック追加API(=C言語API [...]]]></description>
			<content:encoded><![CDATA[<p>メモ。</p>
<p>RubyやJRubyには、特定の条件(コード行が変化したとか、メソッドを呼び出したなど）を満たした時に呼び出されるフック処理を定義することができます。</p>
<p>Ruby-1.8の低レベルなフック追加API(=C言語API)は、<br />
<a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/thread.c?revision=27238&#038;view=markup">thread.c</a>のrb_add_event_hook関数。シグネチャは以下。</p>
<ul>
<li>
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
</li>
</ul>
<p>JRuby-1.4.0で上記関数にほぼ対応するのは、<a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/Ruby.java">Ruby.java</a>の<br />
Ruby.addEventHookメソッド。シグネチャは以下。</p>
<ul>
<li>
public void addEventHook(EventHook hook)
</li>
</ul>
<p>引数の型であるEventHookやその継承クラスは以下参照。</p>
<ul>
<li>
public abstract class EventHook (<a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/EventHook.java">runtime/EventHook.java</a>)
</li>
<li>
public class CallTraceFuncHook extends EventHook (<a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/Ruby.java">Ruby.java</a>)
</li>
</ul>
<p>フックAPIの挙動についての仕様書って、どこにもない感じだなあ。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2010/04/08/129/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JRuby実行中にjdbでアタッチしてrubyプログラムのbacktrace</title>
		<link>http://www.ginriki.net/wd/2010/01/12/114/</link>
		<comments>http://www.ginriki.net/wd/2010/01/12/114/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 22:02:46 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[JDB]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[backtrace]]></category>
		<category><![CDATA[JRuby]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=114</guid>
		<description><![CDATA[Ruby自身のデバッガだと、任意のタイミングでアタッチしてbacktrace見るといったことができない（はず）なので、もっと低レベルのデバッガを利用して、それを実現する方法についてメモ。今回はJRubyに対してjdbでア [...]]]></description>
			<content:encoded><![CDATA[<p>Ruby自身のデバッガだと、任意のタイミングでアタッチしてbacktrace見るといったことができない（はず）なので、もっと低レベルのデバッガを利用して、それを実現する方法についてメモ。今回はJRubyに対してjdbでアタッチ＆backtraceする方法についてのメモです。<br />
なお、CRubyの場合は、<a href="http://www.ginriki.net/wd/2009/11/09/80/">以前の記事</a>とか、さらにその先のリンク先を見れば良いです。<br />
ちなみに、今回試したJRubyのversionは以下の通り。OSはCentOS 5.3です。</p>
<pre>
$ jruby --version
jruby 1.3.1 (ruby 1.8.6p287) (2009-06-15 2fd6c3d) (Java HotSpot(TM) Client VM 1.6.0_16) [i386-java]
</pre>
<p><br/></p>
<h2>jdbによるbacktrace</h2>
<p><br/><br />
まず、アタッチ対象例のRubyコードとして以下を用意。</p>
<p>sample.rb</p>
<div class="igBar"><span id="lruby-2"><a href="#" onclick="javascript:showPlainTxt('ruby-2'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-2">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> foo</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#CC0066; font-weight:bold;">p</span> <span style="color:#996600;">"abc"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; bar</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#CC0066; font-weight:bold;">p</span> <span style="color:#996600;">"foge"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#CC0066; font-weight:bold;">sleep</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">1000</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">abc </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>そして、デバッガattach用のポートを開けて起動します<sup>1</sup>。</p>
<pre>
$ jruby -J-Xdebug -J-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n sample.rb
</pre>
<p>barメソッド内のsleepの実行をしているうちに、別のターミナルを開いてjdbでアタッチし、スレッドを停止させます。</p>
<pre>
$ jdb -attach 8000
> suspend
すべてのスレッドが中断されました
</pre>
<p>そして、backtraceを表示させます。以下の方法で大体表示できます(いい加減なやり方ですが)。</p>
<pre>
> threads
グループ system:
  (java.lang.ref.Reference$ReferenceHandler)0x9db Reference Handler 状況待機中
  (java.lang.ref.Finalizer$FinalizerThread)0x9da  Finalizer         状況待機中
  (java.lang.Thread)0x9d9                         Signal Dispatcher 実行中
グループ main:
  (java.lang.Thread)0x1                           main              状況待機中
> thread 0x1
main[1] where
  [1] java.lang.Object.wait (ネイティブ メソッド)
  [2] org.jruby.RubyThread.sleep (RubyThread.java:718)
  [3] org.jruby.RubyKernel.sleep (RubyKernel.java:725)
  [4] org.jruby.RubyKernel$s_method_0_1$RUBYINVOKER$sleep.call (null)
  [5] org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call (JavaMethod.java:620)
  ...(以下略)
main[1] up 4
main[5] locals
メソッド引数:
context = instance of org.jruby.runtime.ThreadContext(id=2527)
self = instance of org.jruby.RubyObject(id=2528)
clazz = instance of org.jruby.MetaClass(id=2529)
name = "sleep"
arg0 = instance of org.jruby.RubyFixnum(id=2531)
block = instance of org.jruby.runtime.Block(id=2532)
ローカル変数:
main[5] dump context.frameIndex
 context.frameIndex = 2　#frameStackの上限(たぶん)
main[5] dump context.file + ":" + context.line
 context.file + ":" + context.line = "sample.rb:7" #現在位置
main[5] dump context.frameStack[2].fileName + ": " + context.frameStack[2].name + ":" + context.frameStack[2].line
 ...(省略)... = "sample.rb: bar:2" #１つ前のスタックフレーム
main[5] dump context.frameStack[1].fileName + ": " + context.frameStack[1].name + ":" + context.frameStack[1].line
 ...(省略)... = "sample.rb: foo:10" #2つ前のスタックフレーム
main[5] dump context.frameStack[0].fileName + ": " + context.frameStack[0].name + ":" + context.frameStack[0].line
 ...(省略)... = ": null:0"　#トップレベル
</pre>
<p>以上になります。</p>
<ol class="footnotes"><li id="footnote_0_114" class="footnote"><a href="http://wiki.github.com/datamapper/do/jruby">ここ</a>の「Debugger」の項目を参考にオプション設定しました。</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2010/01/12/114/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>autoloadで自動読み込みされないファイルをユーザアクセス毎に再読み込みする</title>
		<link>http://www.ginriki.net/wd/2009/12/31/102/</link>
		<comments>http://www.ginriki.net/wd/2009/12/31/102/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 15:35:07 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=102</guid>
		<description><![CDATA[今回はRuby on Railsについてメモ。
autoloadで自動読み込みされないファイル1をcontrollerの中などでrequireを使って読み込んだ場合、そのファイルはdevelopmentモード時でもユーザ [...]]]></description>
			<content:encoded><![CDATA[<p>今回はRuby on Railsについてメモ。</p>
<p>autoloadで自動読み込みされないファイル<sup>1</sup>をcontrollerの中などでrequireを使って読み込んだ場合、そのファイルはdevelopmentモード時でもユーザアクセス毎に再読み込みされません。そのため、ファイルを編集してもwebサーバを再起動しないと変更が反映されないので、デバッグがやりづらくて困ってました。</p>
<p>解決策がないかと思って、ググってみたところ、以下のページに解決策が書いてありました。<br />
<a href="http://www.pistolfly.jp/weblog/2007/06/require-dependency.html">http://www.pistolfly.jp/weblog/2007/06/require-dependency.html</a></p>
<p>requireじゃなくて、require_dependencyでファイル読み込みすれば良いということでした。<br />
require_dependencyの挙動については、上のリンク先を参照してください。<br />
この辺り(autoload周辺)って、Ruby on Rails公式なドキュメントが見当たらないですねえ。・・・実装を読めってことか。</p>
<p>以下、問題のコード例と解決方法。(ruby 1.8.5, rails 2.3.3, WEBrick 1.3.1で実験しました。)</p>
<p>ファイル読み込みの対象となるファイルを用意します。</p>
<p>&#060;rails_project&#062;/lib/hoge_fuga.rb</p>
<div class="igBar"><span id="lruby-6"><a href="#" onclick="javascript:showPlainTxt('ruby-6'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-6">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Hoge</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> hoge</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#996600;">"abc"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>上のファイルを読み込むcontrollerを用意します。<br />
このとき、requireの代わりにrequire_dependencyでファイルを読み込みます。</p>
<p>&#060;rails_project&#062;/app/controllers/test_controller.rb</p>
<div class="igBar"><span id="lruby-7"><a href="#" onclick="javascript:showPlainTxt('ruby-7'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-7">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;">#require 'hoge_fuga'</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">require_dependency 'hoge_fuga'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> TestController &lt;ApplicationController</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> hoge</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; a = Hoge.<span style="color:#9900CC;">new</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; render<span style="color:#006600; font-weight:bold;">&#40;</span>:text =&gt; a.<span style="color:#9900CC;">hoge</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>んで、Webサーバを起動。</p>
<pre>
$ cd &#060;rails_project&#062;
$ ruby script/server
</pre>
<p>で、ブラウザからtest/hogeにアクセスすると、ブラウザ上にabcが出力されます。<br />
この状況で、&#060;rails_project&#062;/lib/hoge_fuga.rbを以下のように書き換えてみます。</p>
<div class="igBar"><span id="lruby-8"><a href="#" onclick="javascript:showPlainTxt('ruby-8'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-8">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Hoge</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> hoge</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#996600;">"123"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>変更を保存した後、ブラウザからtest/hogeにアクセスすると、ブラウザ上に123が出力されます。<br />
確かに、Webサーバを再起動しなくても、&#060;rails_project&#062;/lib/hoge_fuga.rbが再読み込みされてますね。</p>
<p>これでデバッグがしやすくなるなあ。</p>
<ol class="footnotes"><li id="footnote_0_102" class="footnote">Railsの場合、クラス定義と定義が記述されたファイルの名前が対応づいてないとautoloadで自動読み込みされません（たぶん）。例えば、FooBarというクラスの定義はfoo_bar.rbというファイルの中で行われてないとautoloadにされません。</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2009/12/31/102/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>rubyプロセスのコアファイルからバックトレースする。（おまけ: python）</title>
		<link>http://www.ginriki.net/wd/2009/11/09/80/</link>
		<comments>http://www.ginriki.net/wd/2009/11/09/80/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 22:00:34 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[FFI]]></category>
		<category><![CDATA[GDB]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[gdbscript]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=80</guid>
		<description><![CDATA[某所で、「rubyプロセスがSEGVとかした時のコアファイルから、rubyスクリプトのバックトレースは取れるの？」って聞かれたので、ちょっと調べてみました。
結論としては、「rubyメソッドの呼び出し位置(ファイル名,  [...]]]></description>
			<content:encoded><![CDATA[<p>某所で、「rubyプロセスがSEGVとかした時のコアファイルから、rubyスクリプトのバックトレースは取れるの？」って聞かれたので、ちょっと調べてみました。</p>
<p>結論としては、「rubyメソッドの呼び出し位置(ファイル名, 行番号)は取れるけど、呼び出し時の実引数を見るのは難しい」っていう感じです。<br />
rubyのスタックフレームは、当然、rubyプロセスのメモリ上に構築されるので、スタックフレームのデータ構造さえわかれば、ある程度は表示できます。</p>
<p>ただ、コアファイルを出力したrubyプロセスはすでに存在しないので、ruby実装に使われているC関数をデバッガで（正確にはrubyプロセス上で）実行することができません。<br />
そのため、オブジェクトのinspectなどを実行することが難しく、実引数のオブジェクトが何か調べることが困難です。ということで、今回はスタックフレームを表示させる方法を以下で説明します。</p>
<p>rubyスタックフレームを表示するGDBスクリプトは以下になります(rb_dump.gdb)。<br />
(moriyoshiさんのブログ「<a href="http://d.hatena.ne.jp/moriyoshi/20070927/1190910311"> GDBで実行中のスクリプト言語のスタックフレームをダンプしてみる試み</a>」のコードをほとんどそのまま使わせていただきました。ありがとうございます。)</p>
<div class="igBar"><span id="lcode-12"><a href="#" onclick="javascript:showPlainTxt('code-12'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-12">
<div class="code">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">define dump_rb_bt_from_core</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; set $t = ruby_frame</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; while $t</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; printf <span style="color:#CC0000;">"[0x%08x] "</span>, $t</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; if $t-&gt;<span style="">node</span>.<span style="">nd_file</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; printf <span style="color:#CC0000;">"(%s:%d)<span style="color:#000099; font-weight:bold;">\n</span>"</span>, $t-&gt;<span style="">node</span>.<span style="">nd_file</span>, <span style="color:#006600; font-weight:bold;">&#40;</span>$t-&gt;<span style="">node</span>.<span style="">flags</span>&gt;&gt; <span style="color:#800000;color:#800000;">19</span><span style="color:#006600; font-weight:bold;">&#41;</span> &amp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#800000;color:#800000;">1</span> &lt;&lt;<span style="color:#006600; font-weight:bold;">&#40;</span>sizeof<span style="color:#006600; font-weight:bold;">&#40;</span>NODE*<span style="color:#006600; font-weight:bold;">&#41;</span> * <span style="color:#800000;color:#800000;">8</span> - <span style="color:#800000;color:#800000;">19</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span> - <span style="color:#800000;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; else</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; printf <span style="color:#CC0000;">"(UNKNOWN)<span style="color:#000099; font-weight:bold;">\n</span>"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; end</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; set $t = $t-&gt;<span style="">prev</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; end</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">end</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">document dump_rb_bt_from_core</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; dumps the current frame stack from core file. <span style="">usage</span>: dump_rb_bt_from_core</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">end </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>今回はサンプルプログラムとして、0アドレスにアクセスするC拡張ライブラリを実行するrubyスクリプトを用意します。<br />
まず、C拡張ライブラリ(segv.c)、</p>
<div class="igBar"><span id="lc-13"><a href="#" onclick="javascript:showPlainTxt('c-13'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">C:</span>
<div id="c-13">
<div class="c">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #339933;">#include &quot;ruby.h&quot;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">VALUE do_segv<span style="color: #66cc66;">&#40;</span>VALUE self<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; *<span style="color: #66cc66;">&#40;</span><span style="color: #993333;">char</span>*<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#40;</span>0x0<span style="color: #66cc66;">&#41;</span> = <span style="color: #cc66cc;color:#800000;">0</span>;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> Qnil;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #66cc66;">&#125;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #993333;">void</span> Init_segv<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; VALUE module;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; module = rb_define_module<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"Segv"</span><span style="color: #66cc66;">&#41;</span>;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; rb_define_module_function<span style="color: #66cc66;">&#40;</span>module, <span style="color: #ff0000;">"do_segv"</span>, &amp;do_segv, <span style="color: #cc66cc;color:#800000;">0</span><span style="color: #66cc66;">&#41;</span>;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #66cc66;">&#125;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p>
で、後は適当にextconf.rbを作って、segv.soを作ります。</p>
<p>次にsegv.soを呼び出すRubyスクリプト(test.rb)。</p>
<div class="igBar"><span id="lruby-14"><a href="#" onclick="javascript:showPlainTxt('ruby-14'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-14">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'segv'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> test1<span style="color:#006600; font-weight:bold;">&#40;</span>a<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; test2<span style="color:#006600; font-weight:bold;">&#40;</span>a<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> test2<span style="color:#006600; font-weight:bold;">&#40;</span>b<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; Segv::do_segv</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">test1<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>さて、サンプルプログラムの用意ができたので、SEGVさせてみます。</p>
<pre>
$ ulimit -c unlimited
$ ruby test.rb
test.rb:8: [BUG] Segmentation fault
ruby 1.8.5 (2006-08-25) [i386-linux]

アボートしました (core dumped)
</pre>
<p>これでコアファイルが出力されたので、それをGDBで解析します。</p>
<p>今回はCentOS 5.3のyumでインストールしたrubyから出力されたコアファイルなので、<br />
GDBで解析するには、<a href="http://debuginfo.centos.org/">ここ</a>からrubyのdebuginfoをインストールしておく必要があります。</p>
<pre>
$ wget http://debuginfo.centos.org/5/i386/ruby-debuginfo-1.8.5-5.el5_3.7.i386.rpm
# rpm -i ruby-debuginfo-1.8.5-5.el5_3.7.i386.rpm
</pre>
<p>それでは、GDBでコアファイルからrubyのバックトレースをさせてみます。</p>
<pre>
$ gdb ruby core.29443
GNU gdb Fedora (6.8-37.el5)
...
(gdb) backtrace   #通常のC関数レベルのバックトレース。
#0  0x00b3a402 in __kernel_vsyscall ()
#1  0x0056fdf0 in raise () from /lib/libc.so.6
#2  0x00571701 in abort () from /lib/libc.so.6
#3  0x00c514c2 in rb_bug (fmt=<value optimized out>) at error.c:214
#4  0x00cbd80b in sigsegv (sig=<value optimized out>) at signal.c:537
#5  [signal handler called]
#6  do_segv (self=3086662140) at segv.c:4
#7  0x00c54dd5 in call_cfunc (...) at eval.c:5657
#8  0x00c5c4ab in rb_call0 (...) at eval.c:5810

(gdb) source rb_dump.gdb      #この記事の最初に作ったGDBスクリプトをロード
(gdb) dump_rb_bt_from_core  # rubyバックトレース
[0xbfc1da20] (test.rb:8)
[0xbfc1e0e0] (test.rb:4)
[0xbfc1e7c0] (test.rb:11)
[0x00d0f960] Cannot access memory at address 0x4
</pre>
<p>以上になります。</p>
<p>pythonもコアファイルからスタックフレームが取れるか調べてみましたが、<br />
<a href="http://wiki.python.org/moin/DebuggingWithGdb">DebuggingWithGDB</a>のgdbinitスクリプトを読む限り、<br />
rubyと同様に実行していたpythonスクリプトのファイル名と行番号は取れそうです。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2009/11/09/80/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>rexml vs libxml-ruby</title>
		<link>http://www.ginriki.net/wd/2008/11/15/47/</link>
		<comments>http://www.ginriki.net/wd/2008/11/15/47/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 12:28:31 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[libxml]]></category>
		<category><![CDATA[libxml-ruby]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=47</guid>
		<description><![CDATA[研究の関係で、37MBのXMLファイルに対して、XPathでデータを取り出したいという状況が起きました。
プロトタイプ実装として、Ruby標準ライブラリのrexmlでその処理プログラムを記述したのですが、
実行時にメモリ [...]]]></description>
			<content:encoded><![CDATA[<p>研究の関係で、37MBのXMLファイルに対して、XPathでデータを取り出したいという状況が起きました。</p>
<p>プロトタイプ実装として、Ruby標準ライブラリのrexmlでその処理プログラムを記述したのですが、<br />
実行時にメモリを700MB以上消費しやがります<sup>1</sup>。<br />
768MBしか積んでない私のマシンでは、メモリスワップが発生しまくりで実行が極端に重いため、<br />
別の手段を考えることにしました。</p>
<p>手段としては２通り思いつきます。</p>
<ol>
<li> メモリ使用効率の良いXMLライブラリを使う</li>
<li> SAX<sup>2</sup>を使う </li>
</ol>
<p>SAXで処理を実装するのはダルイので、今回は１番の手段にしました。</p>
<p>採用したXMLライブラリは、<a href="http://libxml.rubyforge.org/">libxml-ruby</a>っていう<a href="http://xmlsoft.org/">libxml</a>のRuby Bindingです。<br />
libxmlは、C言語で実装されたXMLライブラリで、libxml-rubyは、それをRubyで呼び出せるようにしたものです。</p>
<p>rexmlはRubyコードのみで実装されたXMLライブラリでして、libxml-rubyより実行速度が遅いです<sup>3</sup>。<br />
きっと、メモリ使用効率もlibxml-rubyの方がいいだろうと期待して、採用しました。</p>
<p>rexmlはRuby1.8では標準で入ってますが、libxml-rubyは自分でインストールする必要があります。<br />
インストールは、RubyGemsを使うと楽です。</p>
<p>私のCentOS 5環境下では以下の手順でインストールできました。</p>
<pre>
$ yum install libxml2-devel
$ yum install ruby-devel
$ gem install libxml-ruby
</pre>
<p>libxml-rubyを使って実装しなおしてみたところ、実行時の消費メモリは最大でも360MB程度になりました。<br />
これなら、私のマシンで普通に実行できます。</p>
<h4>XMLファイルサイズ、ライブラリ、メモリ消費量</h4>
<p>DOM操作にしろXPathにしろ、DOM Treeを作るのに一番メモリを消費すると<br />
思うんですが、実際、どの程度メモリを消費するのか気になったので、適当にググって見つけた<br />
リンクを貼っときます。</p>
<ul>
<li> <a href="http://tech.inhelsinki.nl/2007-08-29/">Javaの標準XMLライブラリの場合</a> </li>
<li> <a href="http://xmlsoft.org/xmlmem.html#General4"> libxml2の場合</a></li>
</ul>
<ol class="footnotes"><li id="footnote_0_47" class="footnote">途中で実行を中断したため、最大でメモリをどのくらい消費するかは不明</li><li id="footnote_1_47" class="footnote">Simple API for XMLの略</li><li id="footnote_2_47" class="footnote"><a href="http://libxml.rubyforge.org/">http://libxml.rubyforge.org/</a>参照</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2008/11/15/47/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ActiveRecordの予約語とテーブルのカラム名</title>
		<link>http://www.ginriki.net/wd/2008/10/02/43/</link>
		<comments>http://www.ginriki.net/wd/2008/10/02/43/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 19:08:44 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=43</guid>
		<description><![CDATA[RubyのActiveRecord1ライブラリを使ってDB操作をした際、ハマッたのでメモ。
ActiveRecordを使うと、DBテーブルのレコードをオブジェクトとして取り出せます。
カラムのデータを取得する際は、カラム [...]]]></description>
			<content:encoded><![CDATA[<p>RubyのActiveRecord<sup>1</sup>ライブラリを使ってDB操作をした際、ハマッたのでメモ。</p>
<p>ActiveRecordを使うと、DBテーブルのレコードをオブジェクトとして取り出せます。<br />
カラムのデータを取得する際は、カラム名をメソッド名としてオブジェクトを操作すれば良いのですが、<br />
ActiveRecordの予約語と同じカラム名が存在すると正しく動作しません。</p>
<p>例えば、type, displayなどが予約語です。</p>
<p>ためしに、下記のようにテーブルとレコードをつくり、</p>
<pre>
$ mysql -u root test

CREATE TABLE apples
(
    id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
    type VARCHAR(20) NOT NULL
);
INSERT INTO apples (type) VALUES ('fuji');
</pre>
<p>以下のRubyコードを書いたとします。</p>
<div class="igBar"><span id="lruby-17"><a href="#" onclick="javascript:showPlainTxt('ruby-17'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-17">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'rubygems'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'activerecord'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">ActiveRecord::Base.<span style="color:#9900CC;">establish_connection</span><span style="color:#006600; font-weight:bold;">&#40;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;:adapter =&gt; 'mysql',</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;:host =&gt; '<span style="color:#006666;color:#800000;">127</span>.<span style="color:#006666;color:#800000;">0</span>.<span style="color:#006666;color:#800000;">0</span>.<span style="color:#006666;color:#800000;">1</span>',</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;:username =&gt; 'root',</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;:password =&gt; '',</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;:database =&gt; '<span style="color:#CC0066; font-weight:bold;">test</span>'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Apple &lt;ActiveRecord::Base</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">a = Apple.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">p</span> a.<span style="color:#9900CC;">type</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>上記コードを実行すると下記のような例外がでます。</p>
<pre>
/usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1434
:in `instantiate': The single-table inheritance mechanism failed to locate
the subclass: 'fuji'. This error is raised because the column 'type' is reserved
for storing the class in case of inheritance. Please rename this column if you didn't
intend it to be used for storing the inheritance class or overwrite
Apple.inheritance_column to use another column for that information.
(ActiveRecord::SubclassNotFound)
</pre>
<p>typeの場合は、上記のようにわかりやすい例外がでます。displayという名前のカラムが<br />
ある場合は特に例外が発生しません。でも、a.displayと実行してもカラムのデータとは異なる値が<br />
返ってくるので厄介です。</p>
<p>対処法としてはカラム名を変更(type -> etypeとか)するのが普通です。</p>
<p>カラム名を変更したくない場合はselectで別名を指定すれば、問題を回避できます。</p>
<div class="igBar"><span id="lruby-18"><a href="#" onclick="javascript:showPlainTxt('ruby-18'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-18">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">a = Apple.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">1</span>, :<span style="color:#CC0066; font-weight:bold;">select</span> =&gt; 'type as etype'<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">p</span> a.<span style="color:#9900CC;">etype</span>&nbsp; <span style="color:#008000; font-style:italic;"># &quot;fuji&quot; </span></div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>ActiveRecordの予約語として何があるかは、下記リンクを見てください</p>
<ul>
<li><a href='http://wota.jp/ac/?date=20070925#p02'>http://wota.jp/ac/?date=20070925#p02</a></li>
<li><a href='http://d.hatena.ne.jp/satake7/20080520'>http://d.hatena.ne.jp/satake7/20080520</a></li>
</ul>
<h4>その他参考文献</h4>
<p><a href='http://uruseiyatsura.way-nifty.com/blog/2007/08/ruby_on_rails.html'>http://uruseiyatsura.way-nifty.com/blog/2007/08/ruby_on_rails.html</a></p>
<ol class="footnotes"><li id="footnote_0_43" class="footnote">ActiveRecordってデザインパターン名だったんだね。知らなかった・・・。<a href='http://ja.wikipedia.org/wiki/Active_Record'>http://ja.wikipedia.org/wiki/Active_Record</a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2008/10/02/43/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bilingual Debuggerプロジェクト紹介（だけしとく・・・)</title>
		<link>http://www.ginriki.net/wd/2008/01/24/31/</link>
		<comments>http://www.ginriki.net/wd/2008/01/24/31/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 00:00:00 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[C言語]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=31</guid>
		<description><![CDATA[
ひさびさ。
実はだいぶ前なんですが、Sourceforge.jpにプロジェクト立ち上げました。
http://sourceforge.jp/projects/bdbg
C/C++とRubyという２つの言語のデバッガ(g [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>ひさびさ。</p>
<p>実はだいぶ前なんですが、Sourceforge.jpにプロジェクト立ち上げました。</p>
<p><a href="http://sourceforge.jp/projects/bdbg" target="_blank">http://sourceforge.jp/projects/bdbg</a></p>
<p>C/C++とRubyという２つの言語のデバッガ(gdbとrdb)を切り替えて使うことを可能にするツールをアップしてあります。</p>
<p>VC# 2003以降のデバッガに備わっている、C#とC/C++デバッガの切り替え機能を想像してもらえれば大体あってます。</p>
<p>詳しくは<a href="http://sourceforge.jp/projects/bdbg/wiki/bdrb%E3%81%AE%E5%88%A9%E7%94%A8%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB" target="_blank">Wikiに書いたマニュアル</a>を見てください。</p>
<p>Fedora6でしか動作チェックしてないので、うまくコンパイルできないとかあれば、ブログコメントかSorceforgeのフォーラムにでも書いてくれれば対処します。</p>
<p>＃返事が遅くても怒らないでくだせえ</p>
<p>バイト＋就活＋レポートのトリプル攻撃のため、このプロジェクトに割り当てる時間がないれす。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2008/01/24/31/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>補足</title>
		<link>http://www.ginriki.net/wd/2007/06/05/17/</link>
		<comments>http://www.ginriki.net/wd/2007/06/05/17/#comments</comments>
		<pubDate>Tue, 05 Jun 2007 14:04:16 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=17</guid>
		<description><![CDATA[
バックトレースがうまくとれない件ですが、これに対処しようとした場合、test.rbのdebuggerメソッドでbreakした瞬間に、Ruby言語上のstack frameに関するデータ構造をアセンブラ（C言語）レベルで [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>バックトレースがうまくとれない件ですが、これに対処しようとした場合、test.rbのdebuggerメソッドでbreakした瞬間に、Ruby言語上のstack frameに関するデータ構造をアセンブラ（C言語）レベルで読み込んで解析する必要があると思います。</p>
<p>でも、これを言語実装者側のサポートなしに実現するのはかなり大変でしょう。大変な理由を思いつく限りで列挙すると、</p>
<ul>
<li> Rubyのstack frameを拡張ライブラリが直接読み込むことができない？
<ul>
<li> Rubyの実装に詳しいわけではないので、直接読み込めないというのは勘なのですが、セキュリティの観点から考えて、拡張ライブラリがstack frameをいじれないのは当然だと思う</li>
</ul>
</li>
<li> debuggerとdebuggeeが同一プロセスであるため、Rubyのstack frameに直接アクセスできたとしても、stackのどの部分がdebuggerのもので、どの部分がdebuggeeのものか区別が難しい
<ul>
<li> 同一プロセス上にあるから、gdbで言うところのprintコマンドが簡単に実現できるという利点もあるのですが、バックトレースは実装しにくくなります</li>
<li> debuggerとdebuggeeが同一プロセスであるというのは、C, Javaのデバッガと大きく異なる点でもあります</li>
</ul>
</li>
</ul>
<p>こんな感じでしょうか。</p>
<p>まあ、PythonやRubyの場合は、printやpを使ってデバッグしろってことでしょうかねえ。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2007/06/05/17/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
