Rubyで最近よく忘れて調べ直す項目のメモ

ちょっとしたツールを作る時に、あれ?と直ぐに思い出せなくていつも調べてしまうのでちょっとメモ。

対象は、Ruby1.9.3系(Pはいつくかに跨がってるので今回は無視)

絶対パス

指定したファイルの絶対パスを取得するには、File.expand_path(ファイル名)を利用するのが便利。Ruby1.8系でも使えるのでそこも都合つごうがいい(require "pathname"してからのPathname.newでもいいみたいだが、使ってない)。

プログラムのファイル名とパス

実行されているプログラム名を取得するには、以下の2つがある

  • __FILE__
  • $0

上記のどちらでもプログラムのファイル名が入っているが、$0はプログラムを実行する時に指定した値が入っている。__FILE__は現在実行中のプログラムの値が入っている点に注意。どちらも1つのプログラムファイルであれば、値は同じだが、requireされてる内部で使うと__FILE__はrequireされてるファイル自身を指し示してしまう。

実行されている、パス情報から、ディレクトリ名とファイル名を分離するには以下の通り

File::dirname("ファイルパス") => 最後に/が付かない状態で出てくる
File::basename("ファイルパス") => ファイル名だけが出てくる(拡張子付き)
File::extname("ファイルパス") => 拡張子だけを取り出す

ミリ秒取得

ミリ秒単位までの時刻が欲しい時には、以下の用にかけた。

time = Time.now
time.tv_usec

Webのフォーム送信(マルチパート)

httpclient (gemでインストール)がかなり便利だった
ちなみに。HTTPCLient.new(プロキシー)とかけるのもいい感じ

require "httpclient"
uri = "http://localhost:8888"
cln = HTTPClient.new
body = { 'keyword' => 'ruby', 'lang' => 'en' }
res = clnt.post(uri, body)

マルチパート版はこちら

require "httpclient"
uri = "http://localhost:8888"
cln = HTTPClient.new

File.open('/tmp/post_data') do |file|
  body = { 'upload' => file, 'user' => 'nahi' }
  res = clnt.post(uri, body)
end

公式サイトの説明が非常に分かりやすいので、細かい点はそこを見るのが吉 - Class: HTTPClient

KirbyBaseを試して見た

Ruby1.9系では長らく使えないと思っていた、KirbyBaseが1.9系にも対応していたので、早速試してみました

例によって試した環境は以下の通り

KirbyBaseはRubyで作られているデータベースなのでgemでインストールさえすれば特別なドライバが必要無いのがポイント。データベースを作る時にディレクトリを指定しておいてDBオブジェクトを作り、1テーブル=1ファイルが作られているというのが基本的な動きですね。

バッチやcronで値を記録しておきたい時とかに、yamlxml等でも大丈夫だけど検索等が絡んでくると処理がちょっと面倒だけどRDBMSを使うほどじゃないな、という時にいい感じがします。

データベースの初期化

db = KirbyBase.new(:local,nil,nil,"./")

テーブルの作成(ここで設定したテーブル毎にファイルが1個できる)

people = db.create_table(:people,:id, :Integer,:name,:String,:created_at,:Time)

create_tableの最初の引数がテーブル名、次から項目名と型の組み合わせという感じ。使える型は以下の通り

:String, :Integer, :Float, :Boolean(true/false), :Time, :Date, :DateTime, :Memo, :Blob, :YAML.

もう少し細かい設定もできるようだけど、そこは公式マニュアルを参考。

データの登録(insert)と更新(update)

require "time"
people.insert(1,"Me",Time.parse("2012/01/01 00:00:00"))
people.update(:created_at => Time.now) {|r| r.name == "me"}

更新は、ブロックの中で抽出条件を設置して、引数の方で更新値を設定する感じ。なので、selectするときも全く同じ

データの選択(select)

person = people.select() {|r| r.name == "me"}
p person.size

戻り値のサイズでとれた個数が分かる。selectの引数にテーブルの項目名を入れておくとその部分だけを抽出することも出来る。

データの削除(delete)

people.delete { |r| r.name == "me" }

削除もこんな感じ。

このぐらいが出来るとちょっとした値の格納や呼び出しには便利に使えるのではないかと思います。

公式サイト

Sinatraのポート設定

Sinatraで起動時のポート番号を設定するのに困っていたので、ちょっとメモ。

例によって環境

簡単なツールを書いてテストするときは、以下の用にしてた

$ruby XXXX.rb -@ XXXX

これで書くのはのはいかにも場当たり的なので、ソースの中に埋めたかったのだけど、書き方が分かってなかった。一番簡単に埋め込むのだと、こんな感じで良いみたい

require "sinatra"

set port,3333

get "/" do
end

これで随分スッキリした(定義ファイルにいれてもOKだし)。

MacPro 2010にBootcampでWindows7を入れる

Macの環境に移行して使ってる我が家なのですが、時折Windowsが無いと不便な事もあるので、BootcampでWindowsの環境を作ってみようと思ってハマリましたので、メモを。

対象
MacPro2010
OS
SnowLeopard/Lion共に発生
Win
Windows7 64bit Home,32bit Home/Professional
症状
BootCampドライバをインストール後にWindowsが起動しない (BSODが発生する)

続きを読む

Kindle用電子書籍ファイルの作り方 (mobiファイル)

Kindle3はepub形式のファイルを今の頃読めませんので、独自フォーマットのmobiファイルを作る必要があります。このmobiを作るまでの手順をいくつか試行錯誤してみましたので、その結果をまとめてみました(もう周知のものばかりと思いますが、私の備忘録用ですのでご容赦を)

1.mobiファイル変換用ツールを入手

作成したファイルをmobiファイルに変換するためのツールを入手します。ツールは無償でアマゾンによって公開されています。

Kindle Publishing Programs - http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000234621

今回はMacで作業していますので、「KindleGen_Mac_i386_v1.2」をダウンロードしました。zipで圧縮されたファイルが入っていて、それを解凍しておきます。解凍して出来た「KindleGen_Mac_i386_v1.2」のフォルダに「kindlegen」というコマンドがは行っていますので、これが変換用のプログラムです(Win版は.exeが付いていると思います)。このファイルが確認できればOKです。

2.変換するためのファイル構成

電子書籍を作るための素材ファイルを作ります。素材ファイルは、以下の要素で構成されます。

  • 目次ファイル(index.html)
  • 目次定義ファイル( toc.ncx)
  • 書籍情報ファイル(書籍名.opf)
  • カバーファイル(jpgやgif等)
  • 本文(書籍名_XXX.html)

このファイルを作ると先ほどのコマンドにopfファイルを引数で渡すことにより変換が行われます。

$kindelgen 書籍名.opf => 書籍名.mobiが出力されます

この変換の時に、不足分があればerrorやwarningが表示されます。warningがあっても表示はできるようですが、kindleAmazonのメール経由で登録する場合にはwarningが1個でもあると正常では無いと認識されてはじかれるようです。

3.目次ファイルを作成
まずは目次ファイルを作成します。中身は単純なhtmlです。ファイル名も便宜上index.htmlにしていますがどんな名前でもかまいません。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>書籍タイトル</title>
</head>
<body bgcolor="#FFFFFF">
<h2>-目次-</h2>
<a name="TOC"></a>
	<p><a href="書籍名_001.html">第1章</a></p>
	<p><a href="書籍名_002.html">第2章</a></p>
<mbp:pagebreak />
</body>
</html>

目次はhtmlリンクなので、ファイルを切り換えるだけでなくてhref="書籍名_001.html#sample"といったものも定義可能です。
amazonの独自タグで改ページが入ります。必要に応じて入れてください。目次ページのレイアウトでスタイルシートやテーブルタグを使う事もできます。

4.目次定義ファイルを作成
次に目次定義ファイルを作ります。こちらはxmlファイルです。ファイル名は何でもかまいませんが、ここではtoc.ncxとします(ファイルは書籍情報ファイルで設定します)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
   <docTitle><text>書籍名</text></docTitle>
   <navMap>
      <navPoint id="index" playOrder="0">
         <navLabel><text>目次</text></navLabel><content src="index.html"/>
      </navPoint>
      <navPoint id="item1" playOrder="1">
         <navLabel><text>第1章</text></navLabel><content src="書籍名_001.html"/>
      </navPoint>
      <navPoint id="item2" playOrder="2">
         <navLabel><text>第2章</text></navLabel><content src="書籍名_002.html"/>
      </navPoint>
   </navMap>
</ncx>

"navPoint"タグを章立ての分繰り返します。playOrderの順で表示されますので(改ページしてゆくと表示される順番)0を目次にしておいて、以後は1から指定しておきます。id部分は任意ですが、書籍情報ファイルでも使いますので分かりやすい連番が良いと思います。

5.書籍情報ファイル
書籍情報ファイルを作ります。これもxmlファイルです。書籍名.opfが分かりやすいと思います。

<?xml version="1.0" encoding="utf-8"?>
<package unique-identifier="uid">
  <metadata>
    <dc-metadata xmlns:dc="http://purl.org/metadata/dublin_core"
    xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/">
      <dc:Title>書籍名</dc:Title>
      <dc:Language>en-us</dc:Language>
      <dc:Creator>著者名</dc:Creator>
      <dc:Description>書籍説明文</dc:Description>
      <dc:Date>dd/mm/yyyy</dc:Date>
    </dc-metadata>
    <x-metadata>
         <output encoding="utf-8" content-type="text/x-oeb1-document"></output>
	  <EmbeddedCover>表示画像(jpg等)</EmbeddedCover>
    </x-metadata>
  </metadata>
  <manifest>
    <item id="index" media-type="text/x-oeb1-document" href="index.html"></item>
    <item id="toc" media-type="application/x-dtbncx+xml" href="toc.ncx"></item>
    <item id="item1" media-type="text/x-oeb1-document" href="書籍名_001.html"></item>
    <item id="item2" media-type="text/x-oeb1-document" href="書籍名_002.html"></item>
  </manifest>
  <spine toc="toc">
    <itemref idref="item1" />
    <itemref idref="item2" />
  </spine>
  <tours></tours>
  <guide>
    <reference type="toc" title="Table of Contents" href="index.html"></reference>
    <reference type="start" title="Startup Page" href="書籍名_001.html"></reference>
  </guide>
</package>

注意点としては、のカバー設定は必須でした。 cover.jpg等のように何らかを必ず定義しないとWarningが出ます。gif又はjpgを指定した場合は、600x800 pixelsの画像でないと駄目なようです(小さすぎ等と行った警告がでます)。

言語の部分は今のところen-usで固定で良いようです(jaが定義できるように将来なれば定義したほうがいいのでしょう)。

には「目次ファイル」と「目次定義ファイル」を定義します。目次定義ファイルのidはtoc固定。目次ファイルは目次定義ファイルで指定したidに併せてください。それ以後は本文に応じてitemを増やしてください。idは目次定義ファイルで設定したidに併せて下さい。

spineには、本文をitemrefのタグで本文のidを追記しておきます。最後にguideタグ配下に目次ページと最初に表示すべきページを指定して終了です。

6.mobiファイルを作成する

コンソールを開いて作ったファイルを変換します

$kindelgen 書籍名.opf => 書籍名.mobiが出力されます

作成したファイルは、Kindle for Macなどで表示できます。

これをKindleにコピーしたり、メール経由で登録したりしてよんでみて下さい。間違いありましたら是非教えてください。

7.まとめ
ここまでのファイルを作る為に集めておくべき情報を最終的に整理しておきます。

  • 書籍名
  • 著者名
  • 書籍説明文
  • 作成日時
  • カバー画像
  • 目次構成
  • 本文となるHTMLファイル

この8項目を用意しておけば良いようです。ちなみに作成されるmobiファイルは英数字で構成されていても、Kindle上では、書籍名と著者名が日本語できちんと表示されます。

8.参考サイト

以下のサイトを参考にさせていただきました。ありがとうございます。

UbuntuにRVMを使ってRuby環境を構築する

久しぶりの更新です。Ruby1.8.6系、Ruby1.8.7系、Ruby1.9.2系をそれぞれ切り換えて利用することが多くなってきたので、環境の整理もかねてRVMを使ってRuby環境を構築し直してみました(MacTextmateでrvmを使う方法も付記しました)。

環境は以下の通りです

  • Ubuntu 10.04.3 LTS
  • RVM 1.8.3

1.まずはrvmを作る為に必要なツールを入れておきます

$sudo apt-get install git-core
$sudo apt-get install curl

ほかにもreadlinesが入っていないのであれば入れておいて下さい。

2.次にRVMをインストールします

rvmの環境は~/.rvm配下に作られるのがディフォルトのようですので、先に環境を作っておきます。rvm経由でインストールしたRubyも同じフォルダ配下に入っていきます。

$ mkdir -p ~/.rvm/src/
$ cd  ~/.rvm/src
$ git clone --depth 1 git://github.com/wayneeseguin/rvm.git
$ cdrvm
$ ./install

rvmを定義する環境変数が.bashtcの最終行に追加されます。なんらかの場合で無い時には、以下の内容を.bashrcか.bash_profileに追加してください

if [[ -s /ホームディレクトリまでのパス/.rvm/scripts/rvm ]] ; then source /ホームディレクトリまでのパス/.rvm/scripts/rvm ; fi

インストールが完了したら環境ファイルを読み込んで設定完了です。

$source ~/.bashrc
$rvm -v
rvm 1.8.3 by Wayne E. Seguin (wayneeseguin@gmail.com) [https://rvm.beginrescueend.com/]

3.次にRubyをインストールしていきます

まずインストール可能なrubyの一覧を表示して確認します。

$rvm list known

ここでは、MRI Rubiesから1.8.7[-p352]と1.9.2[-290]をインストールします。[]の中は省略可能です

$rvm install 1.8.7
$rvm install 1.9.2

インストールされたRubyは以下のフォルダに入っています

~/.rvm/rubies

これで環境構築が完了です。

4.RVMでよく使うコマンド群を整理してみました

利用するRubyバージョンの指定
$rvm use XXXXX (例:$rvm use 1.8.7)
特定のバージョンをディフォルトで動作させる
$rvm use XXXXX --default
インストール済みのRubyをリスト表示
$rvm list
インストール可能なRubyをリスト表示
$rvm list known
インストール可能なRubyリストを更新
$rvm reload
インストール済みのRubyを更新する
$rvm upgrade 旧バージョン 新バージョン (例:$rvm upgrade ruby-1.9.2-p136 ruby-1.9.2-p180)
rvm自身の更新
$rvm get
rvmのバージョン確認
$rvm -v
rvmのRubyを切り離してOS環境のRubyを使う
$rvm system

5.cron等RVM以外の環境からRubyを呼び出す場合
次のTextmateの場合と似ていたので割愛していたので、あまり触れられていないようなので書いておきます。

cron等からRVMでインストールした配下のRubyを呼び出すと直接rubyモジュールをコールしてもgem等が正常に見えずにトラブルが発生します。

こうした事を解決するためにwrapperコマンドを使います

$rvm wrapper XXXX ラップ名 (例:$rvm wrapper 1.8.7 cron)

このコマンドを入力すると指定したバージョンの環境設定が入ったシェルファイルができあがります。できるシェルファイルは~/.rvm/bin/ラップ名_ruby (ruby以外にirb等も出来てます)となっています。

このラップしてできたファイルをcron等で呼び出す元のrubyとして指定することにより特定の環境でrubyが動作します。

6.Mac環境でTextmateと一緒に使う場合のおまけです

textmateからrvm配下のrubyを呼び出す用のシェルを作る

$rvm wrapper バージョン textmate
例)$rvm wrapper 1.8.7 textmate

(~/.rvm/bin/textmate_rubyというファイルができるのでtextmateの環境設定でTM_RUBYを追加しそのパスを入れる)

以後は利用環境を切り替える時にuseコマンドとwrapperコマンドを併用すればOK

$rvm use 1.9.2
$rvm wrapper 1.9.2 textmate

駆け足ですがRVMの環境とよく使うコマンドをまとめてみました。RVMのバージョンアップに伴って変更となるものも多いと思いますので、動かない場合は公式サイトを確認してください - http://beginrescueend.com/

PGPool2のレプリケーションモードを試す

以前にも一度テストしていますが、少し組み合わせが変わったので再テストしてみました。

今回の目的は、pgpool-2のレプリケーションモードを使っている状態でフェールオーバーが正常に稼働するかというものの検証です。以前は複数のDBに対して同期をSoly-Iに任せるという運用にしていたのだけど、もう少し単純化したいのでpgpool-2でレプリケーションと縮退運転の両方を満たせるか試しています。

テストした環境は以下の通り。

本当は3台の環境でテストするのが望ましいと思うけれど、今回は2台の環境でテスト。1台にpgpoolとpostgresqlを同居させて、もう1台にはpostgresqlしか無い状態にしてあります(どちらも仮想環境)。

インストールで気になったのは以下の点

  • PostgreSQL8.4系からinitdb時のロケール処理が変わっているようなので文字コード設定などは要注意
  • pgpoolは標準で/usr/local/配下 (bin/etc等)に入るのでそれが困る方は要注意
  • postgresql.confにlocalhost以外からのアクセスは許可するように設定する必要あり

この状態で設定したpgpool.confは以下の通り(sampleからの差分)。replicationモードを有効にしてhealth_checkを20秒に1回にしてあります。

63,64c63
< replication_mode = true
    • -
> replication_mode = false 72,73c71 < replication_stop_on_mismatch = true
    • -
> replication_stop_on_mismatch = false 98,99c96 < health_check_period = 20
    • -
> health_check_period = 0 102,103c99 < health_check_user = 'postgres'
    • -
> health_check_user = 'nobody' 190,195d185 < backend_hostname0 = '192.168.0.140' < backend_port0 = 5432 < backend_weight0 = 1 < backend_hostname1 = '192.168.0.136' < backend_port1 = 5432 < backend_weight1 = 1

この設定でpgpoolを起動してアクセスすると、指定したバックグラウンドのdbに接続します。よく分かっていないのが以下の点です

  • ターミナルから接続すると同じDBサーバーばかりにアクセスが行われている。backend_weightが効いてないように感じる
  • 上記条件から一度接続して繋がっていない側のPostgreSQLは停止しても全く問題なく稼働する
  • 2つのDBに接続されているはずだが、希に繋がっているPostgreSQLを停止すると接続先可能な相手が全て停止したというメッセージがでて、縮退運転に切り替わらない場合がある

切り替わらない場合があるのが致命的なので、もう少しテストは必要ですね。ただ、20秒に1回で自動チェックは有効なようで、接続しているPostgreSQLを停止してしばらくしてからアクセスするときちんと切り替わっているのが不思議なところです。

この辺はもう少し詳しくテストしてみるつもりです。