<?xml version="1.0" encoding="utf-8" ?>


<?xml-stylesheet href="http://d.hatena.ne.jp/mingos/rssxsl" type="text/xsl" media="screen"?>


<rdf:RDF
xmlns="http://purl.org/rss/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xml:lang="ja">
<channel rdf:about="http://d.hatena.ne.jp/mingos/rss">
<title>是非に及ばず</title>
<link>http://d.hatena.ne.jp/mingos/</link>
<description>是非に及ばず</description>

<dc:creator>mingos</dc:creator>
<dc:date>2012-10-09T16:49:38+09:00</dc:date>
<items>
<rdf:Seq>
<rdf:li rdf:resource="http://d.hatena.ne.jp/mingos/20121009/1349768835"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/mingos/20110929/1317263628"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/mingos/20110926/1317060601"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/mingos/20110215/1297788794"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/mingos/20110119/1295453856"/>
</rdf:Seq>
</items>
</channel>



<item rdf:about="http://d.hatena.ne.jp/mingos/20121009/1349768835">
<title>[Node.js] Node.jsをCentOS5.xにインストールする手順</title>
<link>http://d.hatena.ne.jp/mingos/20121009/1349768835</link>
<description> node.jsをCentOS5.xにインストールする手順のメモ。 検証環境と前提 CentOS5.8 64bit Node.js0.98 Python2.7.3 インストール手順 最新のPythonをインストール CentOS 5.8の標準で入るPyhtonのバージョンは、2.4.3となっているが、 Node.jsのビルドでは、2.6以上が必要なので</description>

<content:encoded><![CDATA[
<div class="section">
<p>node.jsをCentOS5.xにインストールする手順のメモ。</p>
<h4> 検証環境と前提</h4>

<table>
<tr><td>CentOS</td><td>5.8 64bit</td></tr>
<tr><td>Node.js</td><td>0.98</td></tr>
<tr><td>Python</td><td>2.7.3</td></tr>

</table>
<h4> インストール手順</h4>
<h4> 最新のPythonをインストール</h4>
<p>CentOS 5.8の標準で入るPyhtonのバージョンは、2.4.3となっているが、
Node.jsのビルドでは、2.6以上が必要なのでそのままではうまく行かない。<br>
そこで、Python公式サイトから最新のソースをダウンロードしてビルドする事にする。<br>
ただし、/usr/localなど標準で参照されるパスに入れてしまうと、CentOSの他のツールなどと競合して問題になる。
そこで、$HOME/local以下にインストールする事で影響が出ないようにする。</p>
<pre class="syntax-highlight">
$ mkdir -p ~/download
$ mkdir -p ~/build
$ cd ~/download
$ wget http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz
$ cd ../build/
$ tar xvzf ../download/Python-2.7.3.tgz
$ cd Python-2.7.3
$ sudo yum install bzip2-devel -y
$ ./configure --prefix=$HOME/local/python-2.7.3
$ make
$ make install
$ ln -s $HOME/local/python-2.7.3 $HOME/local/python

.bash_profileのPATHに$HOME/local/python/binを追加する。

$ source ~/.bash_profile
$ python -V
Python 2.7.3
</pre>

<h4> Node.jsをインストール</h4>
<pre class="syntax-highlight">
$ cd ~/download
$ wget http://nodejs.org/dist/v0.8.9/node-v0.8.9.tar.gz
$ cd ../build
$ tar xvzf ../download/node-v0.8.9.tar.gz
$ cd node-v0.8.9/
$ ./configure --prefix=$HOME/local/node-v0.8.9
$ make
$ make install

$HOME/local/node-v0.8.9/binをPATHに追加

$ source ~/.bash_profile
$ node -v
v0.8.9
</pre>

<p>以上で導入は完了。<br>
jsdomはほとんどの場合で必要になるので、ついでに入れておく。</p>
<pre class="syntax-highlight">
$ npm install -g jsdom
</pre>

<p>さらにTypeScriptも入れておく。<br>
npmのパッケージとして提供されているのですぐに利用できる。</p>
<pre class="syntax-highlight">
$ npm install -g typescript
</pre>

</div>
]]></content:encoded>
<dc:creator>mingos</dc:creator>
<dc:date>2012-10-09T16:47:15+09:00</dc:date>
<dc:subject>Node.js</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/mingos/20110929/1317263628">
<title> [Subversion] Subversionリボジトリのバックアップ方法についてまとめてみた</title>
<link>http://d.hatena.ne.jp/mingos/20110929/1317263628</link>
<description> Gitが流行っている中、Subversionリポジトリのバックアップ方法をまとめるという残念なエントリ。 でも、正直自分が使うだけならGitでも構わないがメンバーが多くなってくると、 Gitは説明が面倒だし、Subversionのほうが楽だよなぁ・・・ 結論 結論から言うと、svnadmin du</description>

<content:encoded><![CDATA[
<div class="section">
<p>Gitが流行っている中、Subversionリポジトリのバックアップ方法をまとめるという残念なエントリ。</p>
<p>でも、正直自分が使うだけならGitでも構わないがメンバーが多くなってくると、</p>
<p>Gitは説明が面倒だし、Subversionのほうが楽だよなぁ・・・</p>
<h4> 結論</h4>
<p>結論から言うと、svnadmin dumpとsvnsyncの両方を使う。</p>
<p>svnadmin dumpで差分バックアップをするという方法もあるようだけど、</p>
<p>差分だとうまく元に戻せる気がしない。</p>
<p>バックアップの目的は、任意の時点の状態に復元できる事のはず。</p>
<p>それなのに正しく復元できないとしたら、バックアップなど意味がないのだ。</p>
<p>だから、復元が簡単なフルバックアップをするほうがいい。</p>
<p>しかし、フルバックアップでは時間が非常にかかるので、1日に1回とか</p>
<p>そのくらいの頻度にしたほうがいい。</p>
<p>でも、それではデータの損失が大きい・・・</p>
<p>そこで、差分バックアップ的な感じで最新のリポジトリの状態を作れるsvnsyncを併用する。</p>
<p>フルバックアップには、svnadmin hotcopyを使う方法もあるようだけど、</p>
<p>アーキテクチャ依存なので微妙な感じ。</p>
<p>svnadmin dumpにはリビジョン欠けが起きる可能性があるという情報を目にしたが、</p>
<p>そう書いてる人たちは自分で経験した事もなくただネットで見たから・・</p>
<p>という事で書いている事が多いようだ。</p>
<p>そういう事は自分で経験してから書くもんだと思う。</p>
<p>なので、自分が経験するまではsvnadmin dumpを使います。</p>
<h4> svndumpでフルバックアップ</h4>
<p>※ここでは、リポジトリのパスを/var/svn/sampleとして説明する。</p>
<h4> バックアップ方法</h4>
<pre class="syntax-highlight">
svnadmin dump /var/svn/sample &#62; sample.`date +%Y%m%d%H%M%S`.svn.dump
</pre>

<h4> 復元方法</h4>
<p>まず、現在のリポジトリを移動し、同じパスに空の状態のリポジトリを作成する</p>
<pre class="syntax-highlight">
$ sudo su -
# mv /var/svn/sample /var/svn/sample.old
# svnadmin create /var/svn/sample
# chown -R apache:apache /var/svn/sample
</pre>

<p>ダンプファイルから復元する</p>
<pre class="syntax-highlight">
# svnadmin load /var/svn/sample &#60; sample.`date +%Y%m%d%H%M%S`.svn.dump
</pre>

<br>

<h4> svnsync</h4>
<p>準備として、バックアップ先のサーバで分かりやすいように同じパスに空のリボジトリを作り、</p>
<p>hookスクリプトにsvnsyncy用のファイルを作る。</p>
<p>ここでは、コピペでファイルを作れるようにechoの内容をファイルにリダイレクトしている。</p>
<p>echoの部分は、1行で出来るはずだけど、よく分からんので2行に分けているのがちょっとかっこ悪い・・・</p>
<pre class="syntax-highlight">
$ sudo su -
# rep=/var/svn/sample
# svnadmin create $rep
# echo &#39;#!/bin/sh&#39; &#62; $rep/hooks/pre-revprop-change
# echo &#34;exit 0&#34; &#62;&#62; $rep/hooks/pre-revprop-change
# chmod +x $rep/hooks/pre-revprop-change
# chown -R apache:apache $rep
</pre>

<p>svnsyncの初期化。なお、リモートのリポジトリを<a href="https://example.com/svn/sample" target="_blank">https://example.com/svn/sample</a> として説明する。</p>
<pre class="syntax-highlight">
# svnsync init file:///var/svn/sample https://example.com/svn/sample --source-username &#92;
ユーザ名 --source-password パスワード
</pre>

<p>うまく行ったら、次回からは以下のコマンドだけで良い。</p>
<p>これは差分だけ取得して来るので時間はかからないから、例えば5分ごとにcronで動かすとかやっても問題ないと思う。</p>
<pre class="syntax-highlight">
# svnsync sync file:///var/svn/sample --source-username ユーザ名 &#92;
--source-password パスワード
</pre>

</div>
]]></content:encoded>
<dc:creator>mingos</dc:creator>
<dc:date>2011-09-29T11:33:48+09:00</dc:date>
</item>
<item rdf:about="http://d.hatena.ne.jp/mingos/20110926/1317060601">
<title>[プログラミング][Ruby] オブジェクト指向を理解したければRubyを使え！</title>
<link>http://d.hatena.ne.jp/mingos/20110926/1317060601</link>
<description> 普通の構造化プログラマーがオブジェクト指向の存在意義を理解するコツ を読んで脊髄反射してみる。 自分自身がRuby信者(笑)なので、Rubyをおすすめするわけなんだけども、中途半端にオブジェクト指向機能が入っている言語で学習したところで構造化プログラミングから抜け出</description>

<content:encoded><![CDATA[
<div class="section">
<p><a href="http://d.hatena.ne.jp/ryoasai/20110926/1317044975" target="_blank">普通の構造化プログラマーがオブジェクト指向の存在意義を理解するコツ</a></p>
<p>を読んで脊髄反射してみる。</p>
<p>自分自身がRuby信者(笑)なので、Rubyをおすすめするわけなんだけども、中途半端にオブジェクト指向機能が入っている言語で学習したところで構造化プログラミングから抜け出せないんじゃないかなと思う。</p>
<p>環境が人を作るという事もあるので、まずは全てがオブジェクトであるRubyでしばらくプログラムしていれば、オブジェクトの世界で自分がどう歩くべきか自然と分かるんじゃないかな。</p>
<p>なにしろ、Rubyの世界にはオブジェクトしかないわけで、int型とかなくて1とか2とかの数字は実はFixnumクラスのインスタンスだったりする。だから、1.to_sだとか、1.absなんてのが実行できるし、1.methodsで1が持つメソッド一覧を取得できたりする。</p>
<p>なにそれ、すげー！と感じたら、あなたは分かっている、または分かりかけている人です。<br>プログラムって論理的なイメージがあるけど、かなり感覚的だと思う。<br>人間のやる事だし。</p>
<p>例えば、構造化プログラミングだと、1という数字の絶対値を求める処理は、</p>
<pre class="syntax-highlight">
abs(<span class="synConstant">1</span>);  <span class="synComment"># 絶対値を求める関数に1を引数として渡して、結果を返してもらう</span>
</pre>

<p>という感じだけど、オブジェクト指向なら</p>
<pre class="syntax-highlight">
<span class="synConstant">1</span>.abs  <span class="synComment"># 1に対して、絶対値を聞く(教えてもらう)</span>
</pre>

<p>だろ？</p>
<p>という感じなんだけど、この感覚をなるほど！と思えるかどうか。</p>
<p>それがオブジェクトを理解しているかどうかなんだろうな。</p>
<p>オブジェクトの事はオブジェクトに聞けという事でね。</p>
<p>1に関する情報は、1が知ってるだろ？</p>
<p>だから1の絶対値を求める処理(メソッド)は1の方に実装するんだって感じ。</p>
<p>文章力がないため、うまく説明できないが、とりあえず自分の中ではこういう感じなのだ。</p>
</div>
]]></content:encoded>
<dc:creator>mingos</dc:creator>
<dc:date>2011-09-27T03:10:01+09:00</dc:date>
<dc:subject>プログラミング</dc:subject>
<dc:subject>Ruby</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/mingos/20110215/1297788794">
<title>[android] Androidでテキストをマーキー表示するカスタムビューの作り方</title>
<link>http://d.hatena.ne.jp/mingos/20110215/1297788794</link>
<description> 前置き Androidアプリでテキストをマーキー表示したいって事あるよね？ でも、そんなに簡単には出来なかったりする(汗 ここでいうマーキーの動作は、HTMLのmarqueeタグのイメージ。 標準のTextViewのandroid:ellipsize=”marquee”で実現できるかな？と思ったら全然ダメだった</description>

<content:encoded><![CDATA[
<div class="section">
<h4> 前置き</h4>
<p>Androidアプリでテキストをマーキー表示したいって事あるよね？</p>
<p>でも、そんなに簡単には出来なかったりする(汗</p>
<p>ここでいうマーキーの動作は、HTMLのmarqueeタグのイメージ。</p>
<p>標準のTextViewのandro<a href="http://d.hatena.ne.jp/ellipsize/">id:ellipsize</a>="marquee"で実現できるかな？と思ったら全然ダメだった。</p>
<h5> TextViewのダメなところ</h5>

<ul>
<li> テキストが短いとスクロールしない</li>
<li> 文字のスクロール速度を自由に調整できない</li>
<li> フォーカスが当たっていないとスクロールしない（つまり、複数のTextViewで同時にマーキー表示とか無理)</li>
</ul>
<p>以上の欠点により、TextViewでは自分のやりたい事は出来ない事が分かった。</p>
<p>次に、アニメーション機能でTextViewを画面の右から左へ移動させたらどうだろうと考えて試してみた。</p>
<p>見事に玉砕したけど（後述</p>
<h5> アニメーション(TranslateAnimation)でTextViewを移動するのがダメな理由</h5>

<ul>
<li> TextViewは画面サイズに収まらない長いテキストを設定した場合、自動的に画面サイズに収まる長さにテキストがカットされてしまう仕様となっている</li>
</ul>
<p>この時点で終了(笑</p>
<p>そこで、最後の切り札。カスタムビューですよ！(無事解決)</p>
<p>Androidアプリの経験が浅い事もあり、マーキー表示のためだけに1週間くらい試行錯誤していたorz</p>
<p>でも、ようやく解決してうれしいので、ブログにまとめておく。</p>
<p>結論からいうと、独自のビューを定義してonDraw()で好きなようにしろって事なんだけど、</p>
<p>たどり着くまでが長かった。分かってしまえば、簡単なんだけどね(当たり前)</p>
<h4> ソース</h4>
<p>マーキー表示用のビューという事で、シンプルにMarqueeViewという名前にした。</p>
<p>カスタムビューの作り方については、<a href="http://wikiwiki.jp/android/?%A5%AB%A5%B9%A5%BF%A5%E0%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8%A4%CE%BA%EE%C0%AE" target="_blank">ここ</a>が分かりやすい。</p>
<p>また、ここに載せているMaqrueeViewの画面サイズの取得とか初期化のやり方は</p>
<p>リファレンスの<a href="http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html" target="_blank">LabelViewの例</a>を参考にした。</p>
<h5> res/values/attrs.xml</h5>
<pre class="syntax-highlight">
<span class="synComment">&#60;?</span><span class="synType">xml version</span>=<span class="synConstant">&#34;1.0&#34;</span><span class="synType"> encoding</span>=<span class="synConstant">&#34;utf-8&#34;</span><span class="synComment">?&#62;</span>
<span class="synIdentifier">&#60;resources&#62;</span>
    
    <span class="synIdentifier">&#60;declare-styleable </span><span class="synType">name</span>=<span class="synConstant">&#34;MarqueeView&#34;</span><span class="synIdentifier">&#62;</span>
        <span class="synIdentifier">&#60;attr </span><span class="synType">name</span>=<span class="synConstant">&#34;text&#34;</span><span class="synIdentifier"> </span><span class="synType">format</span>=<span class="synConstant">&#34;string&#34;</span><span class="synIdentifier"> /&#62;</span>
        <span class="synIdentifier">&#60;attr </span><span class="synType">name</span>=<span class="synConstant">&#34;textColor&#34;</span><span class="synIdentifier"> </span><span class="synType">format</span>=<span class="synConstant">&#34;color&#34;</span><span class="synIdentifier"> /&#62;</span>
        <span class="synIdentifier">&#60;attr </span><span class="synType">name</span>=<span class="synConstant">&#34;background&#34;</span><span class="synIdentifier"> </span><span class="synType">format</span>=<span class="synConstant">&#34;color&#34;</span><span class="synIdentifier"> /&#62;</span>
        <span class="synIdentifier">&#60;attr </span><span class="synType">name</span>=<span class="synConstant">&#34;textSize&#34;</span><span class="synIdentifier"> </span><span class="synType">format</span>=<span class="synConstant">&#34;dimension&#34;</span><span class="synIdentifier"> /&#62;</span>
        <span class="synIdentifier">&#60;attr </span><span class="synType">name</span>=<span class="synConstant">&#34;repeatLimit&#34;</span><span class="synIdentifier"> </span><span class="synType">format</span>=<span class="synConstant">&#34;integer&#34;</span><span class="synIdentifier"> /&#62;</span>
        <span class="synIdentifier">&#60;attr </span><span class="synType">name</span>=<span class="synConstant">&#34;textMoveSpeed&#34;</span><span class="synIdentifier"> </span><span class="synType">format</span>=<span class="synConstant">&#34;integer&#34;</span><span class="synIdentifier"> /&#62;</span>
    <span class="synIdentifier">&#60;/declare-styleable&#62;</span>
<span class="synIdentifier">&#60;/resources&#62;</span>
</pre>

<h5> res/layout/main.xml</h5>
<pre class="syntax-highlight">
<span class="synComment">&#60;?</span><span class="synType">xml version</span>=<span class="synConstant">&#34;1.0&#34;</span><span class="synType"> encoding</span>=<span class="synConstant">&#34;utf-8&#34;</span><span class="synComment">?&#62;</span>
<span class="synIdentifier">&#60;LinearLayout</span>
<span class="synIdentifier">    </span><span class="synType">xmlns</span><span class="synComment">:</span><span class="synType">android</span>=<span class="synConstant">&#34;http://schemas.android.com/apk/res/android&#34;</span>
<span class="synIdentifier">    </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">id</span>=<span class="synConstant">&#34;@+id/LinearLayout&#34;</span>
<span class="synIdentifier">    </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">layout_height</span>=<span class="synConstant">&#34;fill_parent&#34;</span>
<span class="synIdentifier">    </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">layout_width</span>=<span class="synConstant">&#34;fill_parent&#34;</span>
<span class="synIdentifier">    </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">background</span>=<span class="synConstant">&#34;@color/white&#34;</span>
<span class="synIdentifier">    </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">orientation</span>=<span class="synConstant">&#34;vertical&#34;</span>
<span class="synIdentifier">&#62;</span>
     <span class="synIdentifier">&#60;net</span><span class="synComment">.</span><span class="synIdentifier">easyjp</span><span class="synComment">.</span><span class="synIdentifier">android</span><span class="synComment">.</span><span class="synIdentifier">widget</span><span class="synComment">.</span><span class="synIdentifier">MarqueeView</span>
<span class="synIdentifier">        </span><span class="synType">xmlns</span><span class="synComment">:</span><span class="synType">app</span>=<span class="synConstant">&#34;http://schemas.android.com/apk/res/net.easyjp.marquee_view&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">id</span>=<span class="synConstant">&#34;@+id/marqueeView1&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">layout_width</span>=<span class="synConstant">&#34;wrap_content&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">layout_height</span>=<span class="synConstant">&#34;wrap_content&#34;</span>
<span class="synIdentifier">        </span><span class="synType">app</span><span class="synComment">:</span><span class="synType">text</span>=<span class="synConstant">&#34;test&#34;</span>
<span class="synIdentifier">        </span><span class="synType">app</span><span class="synComment">:</span><span class="synType">textSize</span>=<span class="synConstant">&#34;25sp&#34;</span>
<span class="synIdentifier">        </span><span class="synType">app</span><span class="synComment">:</span><span class="synType">textColor</span>=<span class="synConstant">&#34;#FFFFFFFF&#34;</span>
<span class="synIdentifier">        </span><span class="synType">app</span><span class="synComment">:</span><span class="synType">background</span>=<span class="synConstant">&#34;#FF000000&#34;</span>
<span class="synIdentifier">        </span><span class="synType">app</span><span class="synComment">:</span><span class="synType">textMoveSpeed</span>=<span class="synConstant">&#34;15&#34;</span>
<span class="synIdentifier">        </span><span class="synType">app</span><span class="synComment">:</span><span class="synType">repeatLimit</span>=<span class="synConstant">&#34;3&#34;</span>
<span class="synIdentifier">    /&#62;</span>
    
    <span class="synIdentifier">&#60;net</span><span class="synComment">.</span><span class="synIdentifier">easyjp</span><span class="synComment">.</span><span class="synIdentifier">android</span><span class="synComment">.</span><span class="synIdentifier">widget</span><span class="synComment">.</span><span class="synIdentifier">MarqueeView</span>
<span class="synIdentifier">        </span><span class="synType">xmlns</span><span class="synComment">:</span><span class="synType">marquee</span>=<span class="synConstant">&#34;http://schemas.android.com/apk/res/net.easyjp.marquee_view&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">id</span>=<span class="synConstant">&#34;@+id/marqueeView2&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">layout_width</span>=<span class="synConstant">&#34;fill_parent&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">layout_height</span>=<span class="synConstant">&#34;wrap_content&#34;</span>
<span class="synIdentifier">        </span><span class="synType">android</span><span class="synComment">:</span><span class="synType">paddingTop</span>=<span class="synConstant">&#34;30dp&#34;</span>
<span class="synIdentifier">        </span><span class="synType">marquee</span><span class="synComment">:</span><span class="synType">text</span>=<span class="synConstant">&#34;test&#34;</span>
<span class="synIdentifier">        </span><span class="synType">marquee</span><span class="synComment">:</span><span class="synType">textSize</span>=<span class="synConstant">&#34;30sp&#34;</span>
<span class="synIdentifier">        </span><span class="synType">marquee</span><span class="synComment">:</span><span class="synType">textColor</span>=<span class="synConstant">&#34;#FFFFFFFF&#34;</span>
<span class="synIdentifier">        </span><span class="synType">marquee</span><span class="synComment">:</span><span class="synType">background</span>=<span class="synConstant">&#34;#FFFF0000&#34;</span>
<span class="synIdentifier">        </span><span class="synType">marquee</span><span class="synComment">:</span><span class="synType">textMoveSpeed</span>=<span class="synConstant">&#34;15&#34;</span>
<span class="synIdentifier">        </span><span class="synType">marquee</span><span class="synComment">:</span><span class="synType">repeatLimit</span>=<span class="synConstant">&#34;1&#34;</span>
<span class="synIdentifier">    /&#62;</span>
<span class="synIdentifier">&#60;/LinearLayout&#62;</span>
</pre>

<h5> MainActivity.java</h5>
<pre class="syntax-highlight">
<span class="synPreProc">package</span> net.easyjp.marquee_view;

<span class="synPreProc">import</span> net.easyjp.android.widget.MarqueeView;
<span class="synPreProc">import</span> net.easyjp.marquee_view.R;
<span class="synPreProc">import</span> android.app.Activity;
<span class="synPreProc">import</span> android.os.Bundle;

<span class="synType">public</span> <span class="synType">class</span> MainActivity <span class="synType">extends</span> Activity {
    <span class="synPreProc">@Override</span>
    <span class="synType">public</span> <span class="synType">void</span> onCreate(Bundle savedInstanceState) {
        <span class="synType">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        String text1 = <span class="synConstant">&#34;マーキーのテスト(wrap_content)&#34;</span>;
        MarqueeView marqueeView1 = (MarqueeView)findViewById(R.id.marqueeView1);
        marqueeView1.setText(text1);
        marqueeView1.startMarquee();

        String text2 = <span class="synConstant">&#34;少し長めのテキスト(fill_parent)。あいうえおかきくけこさしすせそ１２３４５６７９０&#34;</span>;
        MarqueeView marqueeView2 = (MarqueeView)findViewById(R.id.marqueeView2);
        marqueeView2.setText(text2);
        marqueeView2.startMarquee();
    }
}
</pre>

<h5> MarqueeView.java</h5>
<pre class="syntax-highlight">
<span class="synPreProc">package</span> net.easyjp.android.widget;

<span class="synComment">/**</span>
<span class="synSpecial">============================================</span>
<span class="synSpecial">  使用方法およびドキュメント</span>
<span class="synSpecial">============================================</span>

<span class="synSpecial">(1) res/values/attrs.xmlに以下を記述</span>
<span class="synSpecial">ここでMarqueeViewにXMLから設定できるパラメータ名とデータの形式を定義している</span>
<span class="synSpecial">実際にこの値を使用しているかどうかは、コンストラクタの</span>
<span class="synSpecial">MarqueeView(Context context, AttributeSet attrs)の内容を見れば分かる</span>
<span class="synSpecial">---------------------------------</span>
<span class="synIdentifier">&#60;?xml </span><span class="synType">version</span><span class="synIdentifier">=</span><span class="synConstant">&#34;1.0&#34;</span><span class="synIdentifier"> encoding=</span><span class="synConstant">&#34;utf-8&#34;</span><span class="synIdentifier">?&#62;</span>
<span class="synIdentifier">&#60;</span>resources<span class="synIdentifier">&#62;</span>
<span class="synSpecial">    </span>
<span class="synSpecial">    </span><span class="synIdentifier">&#60;</span>declare-styleable<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;MarqueeView&#34;</span><span class="synIdentifier">&#62;</span>
<span class="synSpecial">        </span><span class="synIdentifier">&#60;</span>attr<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;text&#34;</span><span class="synIdentifier"> format=</span><span class="synConstant">&#34;string&#34;</span><span class="synIdentifier"> /&#62;</span>
<span class="synSpecial">        </span><span class="synIdentifier">&#60;</span>attr<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;textColor&#34;</span><span class="synIdentifier"> format=</span><span class="synConstant">&#34;color&#34;</span><span class="synIdentifier"> /&#62;</span>
<span class="synSpecial">        </span><span class="synIdentifier">&#60;</span>attr<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;background&#34;</span><span class="synIdentifier"> format=</span><span class="synConstant">&#34;color&#34;</span><span class="synIdentifier"> /&#62;</span>
<span class="synSpecial">        </span><span class="synIdentifier">&#60;</span>attr<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;textSize&#34;</span><span class="synIdentifier"> format=</span><span class="synConstant">&#34;dimension&#34;</span><span class="synIdentifier"> /&#62;</span>
<span class="synSpecial">        </span><span class="synIdentifier">&#60;</span>attr<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;repeatLimit&#34;</span><span class="synIdentifier"> format=</span><span class="synConstant">&#34;integer&#34;</span><span class="synIdentifier"> /&#62;</span>
<span class="synSpecial">        </span><span class="synIdentifier">&#60;</span>attr<span class="synIdentifier"> </span><span class="synType">name</span><span class="synIdentifier">=</span><span class="synConstant">&#34;textMoveSpeed&#34;</span><span class="synIdentifier"> format=</span><span class="synConstant">&#34;integer&#34;</span><span class="synIdentifier"> /&#62;</span>
<span class="synSpecial">    </span><span class="synIdentifier">&#60;/</span>declare-styleable<span class="synIdentifier">&#62;</span>
<span class="synIdentifier">&#60;/</span>resources<span class="synIdentifier">&#62;</span>
<span class="synSpecial">---------------------------------</span>

<span class="synSpecial">(2) res/layout/xxx.xml</span>
<span class="synSpecial">使用したいアクティビティのレイアウトファイルに以下を記述。</span>
<span class="synSpecial">xmlns:app=の行は必須。以下の例のnet.easyjp.marquee_viewは</span>
<span class="synSpecial">使用するプロジェクトのパッケージ名になるので、注意する事。</span>
<span class="synSpecial">またxmlns:appの部分は任意で良い。xmlns:marquee=&#34;&#34;とした場合は、</span>
<span class="synSpecial">各属性の指定もmarquee:textSize=&#34;25sp&#34;に置き換える必要がある</span>
<span class="synSpecial">---------------------------------</span>
<span class="synIdentifier">&#60;</span>net<span class="synIdentifier">.easyjp.android.widget.MarqueeView</span>
<span class="synIdentifier">    xmlns:app=</span><span class="synConstant">&#34;http://schemas.android.com/apk/res/net.easyjp.marquee_view&#34;</span>
<span class="synIdentifier">    android:</span><span class="synType">id</span><span class="synComment">=&#34;@+id/marqueeView&#34;</span>
<span class="synComment">    android:layout_width=&#34;wrap_content&#34;</span>
<span class="synComment">    android:layout_height=&#34;wrap_content&#34;</span>
<span class="synComment">    app:text=&#34;test&#34;</span>
<span class="synComment">    app:textSize=&#34;25sp&#34;</span>
<span class="synComment">    app:textColor=&#34;#FFFFFFFF&#34;</span>
<span class="synComment">    app:background=&#34;#FF000000&#34;</span>
<span class="synComment">    app:textMoveSpeed=&#34;15&#34;</span>
<span class="synComment">    app:repeatLimit=&#34;3&#34;</span>
<span class="synComment">/</span><span class="synError">&#62;</span>
<span class="synComment">---------------------------------</span>

<span class="synComment">(3) アクティビティ内でMarqueeViewを取得し、startMarquee()でマーキー開始</span>
<span class="synComment">---------------------------------</span>
<span class="synComment">MarqueeView marqueeView = (MarqueeView)findViewById(R.id.marqueeView);</span>
<span class="synComment">marqueeView.setText(&#34;マーキーさせる文字列を設定&#34;);</span>
<span class="synComment">marqueeView.startMarquee();</span>
<span class="synComment">---------------------------------</span>

<span class="synComment">*/</span>

<span class="synPreProc">import</span> net.easyjp.marquee_view.R;
<span class="synPreProc">import</span> android.content.Context;
<span class="synPreProc">import</span> android.content.res.TypedArray;
<span class="synPreProc">import</span> android.graphics.Canvas;
<span class="synPreProc">import</span> android.graphics.Paint;
<span class="synPreProc">import</span> android.util.AttributeSet;
<span class="synPreProc">import</span> android.view.Display;
<span class="synPreProc">import</span> android.view.View;
<span class="synPreProc">import</span> android.view.WindowManager;
<span class="synPreProc">import</span> android.util.Log;


<span class="synComment">/**</span>
<span class="synComment"> *</span><span class="synSpecial"> テキストのマーキー表示を行うカスタムビュー</span>
<span class="synComment"> *</span><span class="synSpecial"> </span>
<span class="synSpecial"> </span><span class="synComment">*/</span>
<span class="synType">public</span> <span class="synType">class</span> MarqueeView <span class="synType">extends</span> View {
    <span class="synType">private</span> Paint mTextPaint;
    <span class="synType">private</span> String mText;
    <span class="synType">private</span> <span class="synType">int</span> mAscent;
    
    <span class="synType">private</span> <span class="synType">int</span> mRepeatCount;      <span class="synComment">// リピートした回数</span>
    <span class="synType">private</span> <span class="synType">int</span> mRepeatLimit;      <span class="synComment">// 最大リピート回数</span>
    <span class="synType">private</span> <span class="synType">int</span> mCurrentX;         <span class="synComment">// 現在のテキストの位置</span>
    <span class="synType">private</span> <span class="synType">int</span> mTextMoveSpeed;    <span class="synComment">// 1フレームで動く距離</span>
    <span class="synType">private</span> Thread mThread = <span class="synConstant">null</span>; <span class="synComment">// テキストを移動させるスレッド</span>

    <span class="synComment">// マーキー表示処理(テキストの移動＋表示)</span>
    <span class="synType">private</span> Runnable runnable = <span class="synStatement">new</span> Runnable() {
        <span class="synType">public</span> <span class="synType">void</span> run() {
            <span class="synComment">// 左端と判断するX座標</span>
            <span class="synType">int</span> lastX = getLastX();

            <span class="synStatement">while</span>(mRepeatCount &#60; mRepeatLimit) {
                mCurrentX = getMarqueeStartX(); <span class="synComment">// テキスト位置を戻す</span>

                <span class="synType">long</span> beforeTime = System.currentTimeMillis();
                <span class="synType">long</span> afterTime = beforeTime;
                <span class="synType">int</span> fps = <span class="synConstant">30</span>;
                <span class="synType">long</span> frameTime = <span class="synConstant">1000</span> / fps;

                <span class="synComment">// 1回のマーキー処理</span>
                <span class="synStatement">while</span>(<span class="synConstant">true</span>) {               
                    <span class="synComment">// 左端まで到達したらリピート1回としてカウント</span>
                    <span class="synStatement">if</span>(mCurrentX &#60;= lastX) {
                        mRepeatCount += <span class="synConstant">1</span>;
                        <span class="synStatement">break</span>;
                    }

                    mCurrentX -= mTextMoveSpeed;
                    postInvalidate();
                
                    afterTime = System.currentTimeMillis();
                    <span class="synType">long</span> pastTime = afterTime - beforeTime;
                    
                    <span class="synType">long</span> sleepTime = frameTime - pastTime;
                    
                    <span class="synStatement">if</span>(sleepTime &#62; <span class="synConstant">0</span>) {
                        <span class="synStatement">try</span> {
                            Thread.sleep(sleepTime);
                        }<span class="synStatement">catch</span>(Exception e){}
                    }
                    beforeTime = System.currentTimeMillis();
                }
                
            }
        }
    };
    
    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> マーキー処理を停止する</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synType">public</span> <span class="synType">void</span> clearMarquee() {
        mCurrentX = getMarqueeStartX();
        mRepeatCount = <span class="synConstant">0</span>;
        mThread = <span class="synConstant">null</span>;
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> マーキー処理を開始する</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synType">public</span> <span class="synType">void</span> startMarquee() {
        clearMarquee();
        mThread = <span class="synStatement">new</span> Thread(runnable);
        mThread.start();
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> コンストラクタ(XMLを使用しない場合)</span>
<span class="synComment">     *</span><span class="synSpecial"> </span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> context</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> MarqueeView(Context context) {
        <span class="synType">super</span>(context);
        initMarqueeView();
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> コンストラクタ(XMLを使用する場合)</span>
<span class="synComment">     *</span><span class="synSpecial"> </span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> context</span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> attrs</span><span class="synComment"> XMLで定義した属性</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> MarqueeView(Context context, AttributeSet attrs) {
        <span class="synType">super</span>(context, attrs);
        initMarqueeView();

        <span class="synComment">// XMLから属性を取得</span>
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MarqueeView);

        String s = a.getString(R.styleable.MarqueeView_text);
        <span class="synStatement">if</span>(s != <span class="synConstant">null</span>) {
            setText(s);
        }

        <span class="synType">int</span> textSize = a.getDimensionPixelOffset(R.styleable.MarqueeView_textSize, <span class="synConstant">0</span>);
        <span class="synStatement">if</span> (textSize &#62; <span class="synConstant">0</span>) {
            setTextSize(textSize);
        }

        setTextColor(a.getColor(R.styleable.MarqueeView_textColor, <span class="synConstant">0xFFFFFFFF</span>));
        setBackgroundColor(a.getColor(R.styleable.MarqueeView_background, <span class="synConstant">0xFF000000</span>));
        setRepeatLimit(a.getInteger(R.styleable.MarqueeView_repeatLimit, <span class="synConstant">1</span>));
        setTextMoveSpeed(a.getInteger(R.styleable.MarqueeView_textMoveSpeed, <span class="synConstant">5</span>));

        a.recycle();
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> 初期化処理</span>
<span class="synComment">     *</span><span class="synSpecial"> このメソッドは必ずコンストラクタ内で呼び出す必要がある</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synType">private</span> <span class="synType">final</span> <span class="synType">void</span> initMarqueeView() {
        mTextPaint = <span class="synStatement">new</span> Paint();
        mTextPaint.setAntiAlias(<span class="synConstant">true</span>);
        mTextPaint.setTextSize(<span class="synConstant">16</span>);
        mTextPaint.setColor(<span class="synConstant">0xFFFFFFFF</span>);
        mTextMoveSpeed = <span class="synConstant">5</span>;
        mRepeatCount = <span class="synConstant">0</span>;
        setRepeatLimit(<span class="synConstant">1</span>);
        setText(<span class="synConstant">&#34;&#34;</span>);
        setPadding(<span class="synConstant">0</span>, <span class="synConstant">0</span>, <span class="synConstant">0</span>, <span class="synConstant">0</span>);
        setBackgroundColor(<span class="synConstant">0xFF000000</span>);
    }
    
    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> リピート回数を設定する</span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> repeatLimit</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> <span class="synType">void</span> setRepeatLimit(<span class="synType">int</span> repeatLimit) {
        <span class="synStatement">if</span>(repeatLimit &#62; <span class="synConstant">0</span>) {
            mRepeatLimit = repeatLimit;
        }<span class="synStatement">else</span> {
            mRepeatLimit = <span class="synConstant">1</span>;
        }
    }
    
    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> テキストの移動速度(px)を設定する</span>
<span class="synComment">     *</span><span class="synSpecial"> </span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> speed</span><span class="synComment"> 移動速度(ピクセルで指定)</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> <span class="synType">void</span> setTextMoveSpeed(<span class="synType">int</span> speed) {
        <span class="synStatement">if</span>(speed &#62; <span class="synConstant">0</span>) {
            mTextMoveSpeed = speed;
        }
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> テキストを設定する</span>
<span class="synComment">     *</span><span class="synSpecial"> </span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> text</span><span class="synComment"> 表示するテキスト</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> <span class="synType">void</span> setText(String text) {
        mText = text;
        requestLayout();
        invalidate();
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> テキストサイズを設定する</span>
<span class="synComment">     *</span><span class="synSpecial"> </span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> size</span><span class="synComment"> フォントサイズ</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> <span class="synType">void</span> setTextSize(<span class="synType">int</span> size) {
        mTextPaint.setTextSize(size);
        requestLayout();
        invalidate();
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> テキストカラーを設定する</span>
<span class="synComment">     *</span><span class="synSpecial"> </span>
<span class="synComment">     * </span><span class="synSpecial">@param</span><span class="synIdentifier"> color</span>
<span class="synComment">     */</span>
    <span class="synType">public</span> <span class="synType">void</span> setTextColor(<span class="synType">int</span> color) {
        mTextPaint.setColor(color);
        invalidate();
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> ビューのサイズを設定する</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synPreProc">@Override</span>
    <span class="synType">protected</span> <span class="synType">void</span> onMeasure(<span class="synType">int</span> widthMeasureSpec, <span class="synType">int</span> heightMeasureSpec) {
        setMeasuredDimension(
            measureWidth(widthMeasureSpec),
            measureHeight(heightMeasureSpec)
        );
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> ビューの幅を返す</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synType">private</span> <span class="synType">int</span> measureWidth(<span class="synType">int</span> measureSpec) {
        <span class="synType">int</span> result = <span class="synConstant">0</span>;
        <span class="synType">int</span> specMode = MeasureSpec.getMode(measureSpec);
        <span class="synType">int</span> specSize = MeasureSpec.getSize(measureSpec);

        <span class="synStatement">if</span> (specMode == MeasureSpec.EXACTLY) {
            <span class="synComment">// We were told how big to be</span>
            result = specSize;
        } <span class="synStatement">else</span> {
            <span class="synComment">// Measure the text</span>
            result = (<span class="synType">int</span>) mTextPaint.measureText(mText) + getPaddingLeft()
                    + getPaddingRight();
            <span class="synStatement">if</span> (specMode == MeasureSpec.AT_MOST) {
                <span class="synComment">// Respect AT_MOST value if that was what is called for by measureSpec</span>
                result = Math.min(result, specSize);
            }
        }

        <span class="synStatement">return</span> result;
    }

    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> ビューの高さを返す</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synType">private</span> <span class="synType">int</span> measureHeight(<span class="synType">int</span> measureSpec) {
        <span class="synType">int</span> result = <span class="synConstant">0</span>;
        <span class="synType">int</span> specMode = MeasureSpec.getMode(measureSpec);
        <span class="synType">int</span> specSize = MeasureSpec.getSize(measureSpec);

        mAscent = (<span class="synType">int</span>) mTextPaint.ascent();
        <span class="synStatement">if</span> (specMode == MeasureSpec.EXACTLY) {
            <span class="synComment">// We were told how big to be</span>
            result = specSize;
        } <span class="synStatement">else</span> {
            <span class="synComment">// Measure the text (beware: ascent is a negative number)</span>
            result = (<span class="synType">int</span>) (-mAscent + mTextPaint.descent()) + getPaddingTop()
                    + getPaddingBottom();
            <span class="synStatement">if</span> (specMode == MeasureSpec.AT_MOST) {
                <span class="synComment">// Respect AT_MOST value if that was what is called for by measureSpec</span>
                result = Math.min(result, specSize);
            }
        }
        <span class="synStatement">return</span> result;
    }
    
    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> マーキーの開始位置のX座標を返す</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synType">private</span> <span class="synType">int</span> getMarqueeStartX() {
        WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        <span class="synType">int</span> measureText = (<span class="synType">int</span>)mTextPaint.measureText(mText);
        <span class="synType">int</span> measureWidth = getMeasuredWidth();

        <span class="synStatement">if</span>(display.getWidth() == measureWidth) {
            <span class="synStatement">return</span> measureWidth;
        }<span class="synStatement">else</span> <span class="synStatement">if</span>(measureText &#62; display.getWidth()) {
            <span class="synComment">// テキストが画面サイズを超える場合</span>
            <span class="synStatement">return</span> display.getWidth();
        }<span class="synStatement">else</span> <span class="synStatement">if</span>(measureWidth &#62; measureText) {
            <span class="synStatement">return</span> measureWidth;
        }<span class="synStatement">else</span> {
            <span class="synStatement">return</span> measureText;
        }
    }
    
    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> 左端と判定するX座標</span>
<span class="synComment">     * </span><span class="synSpecial">@return</span>
<span class="synComment">     */</span>
    <span class="synType">private</span> <span class="synType">int</span> getLastX() {
        WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
    
        <span class="synType">int</span> measureText = (<span class="synType">int</span>)mTextPaint.measureText(mText);
        <span class="synType">int</span> measureWidth = getMeasuredWidth();

        <span class="synStatement">if</span>(measureText &#62;= display.getWidth()) {
            <span class="synComment">// テキストが画面サイズを超える場合</span>
            <span class="synStatement">return</span> -measureText;
        }<span class="synStatement">else</span> <span class="synStatement">if</span>(measureWidth &#62; measureText) {
            <span class="synComment">// テキストの幅がビューのサイズより小さい</span>
            <span class="synStatement">return</span> -measureWidth;
        }<span class="synStatement">else</span> {
            <span class="synStatement">return</span> -measureText;
        }
    }
    
    <span class="synComment">/**</span>
<span class="synComment">     *</span><span class="synSpecial"> 描画処理</span>
<span class="synSpecial">     </span><span class="synComment">*/</span>
    <span class="synPreProc">@Override</span>
    <span class="synType">protected</span> <span class="synType">void</span> onDraw(Canvas canvas) {
        <span class="synType">super</span>.onDraw(canvas);
        
        <span class="synType">int</span> x = getPaddingLeft() + mCurrentX;
        <span class="synType">int</span> y = getPaddingTop() - mAscent;
        canvas.drawText(mText, x, y, mTextPaint);
    }
}
</pre>

</div>
]]></content:encoded>
<dc:creator>mingos</dc:creator>
<dc:date>2011-02-16T01:53:14+09:00</dc:date>
<dc:subject>android</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/mingos/20110119/1295453856">
<title>[Ruby] Rubyで任意のテキストにふりがなを付ける(Yahooのテキスト解析/ルビ振りを利用する)</title>
<link>http://d.hatena.ne.jp/mingos/20110119/1295453856</link>
<description> 概要 ここでは、RubyとYahooデベロッパーネットワーク/テキスト解析＞ルビ振りAPIを利用して任意の文字列にふりがなを付ける方法を示す。 やる事は非常に単純で以下の3ステップだけなので、非常にお手軽である。 APIにアクセスするためのリクエストURLを作成 Net::HTTPを使</description>

<content:encoded><![CDATA[
<div class="section">
<h4> 概要</h4>
<p>ここでは、Rubyと<a href="http://developer.yahoo.co.jp/webapi/jlp/furigana/v1/furigana.html" target="_blank">Yahooデベロッパーネットワーク/テキスト解析＞ルビ振りAPI</a>を利用して任意の文字列にふりがなを付ける方法を示す。</p>
<p>やる事は非常に単純で以下の3ステップだけなので、非常にお手軽である。 </p>

<ol>
<li> APIにアクセスするためのリクエストURLを作成 </li>
<li> Net::HTTPを使ってURLにアクセスし、XMLを取得(UTF-8で返ってくる) </li>
<li> NokogiriでXMLをパースし、ふりがなの部分を取得する </li>
</ol>
<h4> 環境</h4>
<p>Ruby 1.8.7</p>
<p>Nokogiri 1.4.4</p>
<p>CentOS 5.x</p>
<p>スクリプト、コンソールともにUTF-8を前提とする</p>
<h4> 準備</h4>

<ul>
<li> nokogiriが入っていなければ、gem install nokogiriでインストールする </li>
</ul>
<pre class="syntax-highlight">
$ sudo gem install nokogiri
</pre>


<ul>
<li> <a href="http://developer.yahoo.co.jp/webapi/jlp/furigana/v1/furigana.html" target="_blank">Yahooデベロッパーネットワーク/テキスト解析＞ルビ振りAPIのページ</a>にアプリケーションIDの登録のリンクがあるので、</li>
</ul>
<p>そこからYahooアカウントでログインして登録し、アプリケーションIDを取得する。</p>
<p>なお、今回のサンプルは自分のIDをそのまま載せているので、Yahooに登録しなくても動作させる事が出来る </p>
<h4> サンプル</h4>
<h5> yahoo_api.rb</h5>
<pre class="syntax-highlight">
<span class="synPreProc">require</span> <span class="synSpecial">'</span><span class="synConstant">jcode</span><span class="synSpecial">'</span>
<span class="synPreProc">require</span> <span class="synSpecial">'</span><span class="synConstant">rubygems</span><span class="synSpecial">'</span>
<span class="synPreProc">require</span> <span class="synSpecial">'</span><span class="synConstant">nokogiri</span><span class="synSpecial">'</span>
<span class="synPreProc">require</span> <span class="synSpecial">'</span><span class="synConstant">net/http</span><span class="synSpecial">'</span>
<span class="synPreProc">require</span> <span class="synSpecial">'</span><span class="synConstant">cgi</span><span class="synSpecial">'</span>
<span class="synPreProc">module </span><span class="synType">YahooApi</span>
  <span class="synIdentifier">APP_ID</span> = <span class="synSpecial">&#34;</span><span class="synConstant">6acb699c6333bdb1fd5e189899359935</span><span class="synSpecial">&#34;</span> <span class="synComment"># アプリケーションID</span>

  <span class="synComment"># テキスト解析/ルビ振りAPI</span>
  <span class="synComment"># http://developer.yahoo.co.jp/webapi/jlp/furigana/v1/furigana.html</span>
  <span class="synPreProc">class </span><span class="synType">Furigana</span>
    <span class="synIdentifier">BASE_URL</span> = <span class="synSpecial">&#34;</span><span class="synConstant">http://jlp.yahooapis.jp/FuriganaService/V1/furigana</span><span class="synSpecial">&#34;</span>

    <span class="synComment"># 指定したテキストのふりがなを返す</span>
    <span class="synComment">#</span>
    <span class="synComment"># YahooApi::Furigana.new.parse(&#34;東京&#34;)</span>
    <span class="synComment"># =&#62; &#34;とうきょう&#34;</span>
    <span class="synPreProc">def </span><span class="synIdentifier">parse</span>(text, opts={})
      url = get_request_url(text, opts)
      response = <span class="synConstant">nil</span>
      <span class="synConstant">3</span>.times {
        response = get_response(url)
        <span class="synStatement">if</span> response.kind_of?(<span class="synIdentifier">Net</span>::<span class="synIdentifier">HTTPOK</span>)
          <span class="synStatement">break</span>
        <span class="synStatement">end</span>
        sleep <span class="synConstant">0.5</span>
      }
      <span class="synStatement">return</span> <span class="synConstant">nil</span> <span class="synStatement">unless</span> response

      doc = <span class="synIdentifier">Nokogiri</span>::<span class="synIdentifier">XML</span>.parse(response.body, <span class="synConstant">nil</span>, <span class="synSpecial">&#34;</span><span class="synConstant">UTF-8</span><span class="synSpecial">&#34;</span>)
      <span class="synStatement">return</span> doc.search(<span class="synSpecial">&#34;</span><span class="synConstant">Furigana</span><span class="synSpecial">&#34;</span>).text
    <span class="synPreProc">end</span>

    <span class="synPreProc">def </span><span class="synIdentifier">get_request_url</span>(text, opts={})
      params = {
        <span class="synSpecial">&#34;</span><span class="synConstant">appid</span><span class="synSpecial">&#34;</span> =&#62; <span class="synIdentifier">APP_ID</span>,
        <span class="synSpecial">&#34;</span><span class="synConstant">sentence</span><span class="synSpecial">&#34;</span> =&#62; text,
        <span class="synSpecial">&#34;</span><span class="synConstant">grade</span><span class="synSpecial">&#34;</span> =&#62; opts[<span class="synIdentifier">:grade</span>]
      }
      tmp = []
      params.keys.sort.each <span class="synStatement">do</span> |<span class="synIdentifier">key</span>|
        <span class="synStatement">next</span> <span class="synStatement">if</span> params[key].nil?
        tmp &#60;&#60; <span class="synSpecial">&#34;#{key}</span><span class="synConstant">=</span><span class="synSpecial">#{CGI.escape(params[key])}&#34;</span>
      <span class="synStatement">end</span>
      query = tmp.join(<span class="synSpecial">'</span><span class="synConstant">&#38;</span><span class="synSpecial">'</span>)
      <span class="synStatement">return</span> <span class="synSpecial">&#34;#{BASE_URL}</span><span class="synConstant">?</span><span class="synSpecial">#{query}&#34;</span>
    <span class="synPreProc">end</span>

    <span class="synPreProc">def </span><span class="synIdentifier">get_response</span>(request_url)
      <span class="synStatement">begin</span>
        headers = {
          <span class="synSpecial">'</span><span class="synConstant">User-Agent</span><span class="synSpecial">'</span> =&#62; <span class="synSpecial">'</span><span class="synConstant">Ruby/WebClient</span><span class="synSpecial">'</span>
        }
        uri = <span class="synIdentifier">URI</span>.parse(request_url)
        client = <span class="synIdentifier">Net</span>::<span class="synIdentifier">HTTP</span>.new(uri.host, uri.port)
        client.open_timeout = <span class="synConstant">1</span>
        client.read_timeout = <span class="synConstant">2</span>
        client.start{|<span class="synIdentifier">http</span>|
          response = http.get(uri.request_uri, headers)
          <span class="synStatement">return</span> response
        }
      <span class="synStatement">rescue</span> <span class="synIdentifier">Exception</span> =&#62; e
      <span class="synStatement">end</span>
      <span class="synStatement">return</span> <span class="synConstant">nil</span>
    <span class="synPreProc">end</span>

  <span class="synPreProc">end</span> <span class="synComment"># end of Furigana</span>

<span class="synPreProc">end</span>
</pre>

<h5> furigana.rb</h5>
<pre class="syntax-highlight">
<span class="synPreProc">#!/opt/ruby/bin/ruby -Ku</span>
<span class="synPreProc">require</span> <span class="synSpecial">'</span><span class="synConstant">yahoo_api</span><span class="synSpecial">'</span>

<span class="synStatement">if</span> <span class="synIdentifier">ARGV</span>.size == <span class="synConstant">0</span>
  puts <span class="synSpecial">&#34;</span><span class="synConstant">Usage: </span><span class="synSpecial">#{$0}</span><span class="synConstant"> {text}</span><span class="synSpecial">&#34;</span>
  <span class="synStatement">exit</span> <span class="synConstant">1</span>
<span class="synStatement">end</span>

puts <span class="synIdentifier">YahooApi</span>::<span class="synIdentifier">Furigana</span>.new.parse(<span class="synIdentifier">ARGV</span>[<span class="synConstant">0</span>])
</pre>

<h4> 実行方法</h4>
<pre class="syntax-highlight">
$ chmod +x furigana.rb
$ ./furigana.rb 東京都千代田区日本橋
とうきょうとちよだくにほんばし
</pre>

</div>
]]></content:encoded>
<dc:creator>mingos</dc:creator>
<dc:date>2011-01-20T01:17:36+09:00</dc:date>
<dc:subject>Ruby</dc:subject>
</item>
</rdf:RDF>
