February 28, 2009

これだから PHP は

PHPのsort関数は相当おかしい – hnwの日記

ま、PHP はテンプレート言語だからちゃんと sort できないケースがあっても別にいいのかな。
でも PHP がテンプレート言語だからといって言語仕様が腐っててもいい理由にはならないよな。
PHPer はそんなことあんまり気にしないのかな。
もしくはすでにこの問題は PHPer の間では常識なのかな。

追記:
array_unique関数がPHP5.2.9から後方互換性を失いました – hnwの日記
ネタが尽きない PHP w

February 26, 2009

gitosis を使って Git リポジトリの管理をお手軽に〜♪

gitosis とは

gitosis は、Git リポジトリの管理やアクセス制御などを簡単に行えるようにするツールです。

入れてみた

gitosis を実際にサーバーに入れてみました。

前提

OS は CentOS 5.2 です。

事前準備

サーバーに python-setuptools が入ってなかったので以下のようにしてインストールしました。

sudo yum install python-setuptools

git は前にすでにインストールしてました。
一応、インストール方法は以下。

sudo yum install git

gitosis のインストール

リポジトリから gitosis のソースを取ってきてインストールします。

git clone git://eagain.net/gitosis.git
sudo python setup.py install

python なんですね。

git ユーザーの作成

gitosis 用に git という名前のユーザーを作成します。

sudo adduser --shell /bin/sh --home /home/git git

gitosis の初期化

自分の公開鍵を使って gitosis の初期化を行います。
以下のようにします。

sudo -H -u git gitosis-init < id_dsa.pub

「id_dsa.pub」は自分の公開鍵です。

初期化を行うと git ユーザーのホームディレクトリ(/home/git)にいろいろ作られます。

hook のパーミッションを 755 に

gitosis は hook でいろいろやってるようです。
なので、hook のパーミッションを適切に設定しておく必要があります。
以下のようにします。

sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

管理用リポジトリをローカルに持ってくる

※ 以降の操作はすべてローカルマシンで行います

gitosis の初期化を行うと gitosis-admin というリポジトリが作られます。
これは管理用のリポジトリで、設定ファイルとユーザーの公開鍵が置かれています。
gitosis の管理者はこのリポジトリのファイルを操作することで権限の管理等を行います。

以下のようにして gitosis-admin リポジトリをローカルに持ってきます。

git clone git@ホスト名:gitosis-admin.git

gitosis-admin リポジトリのディレクトリ構成は以下のようになっています。

gitosis-admin/
|-- gitosis.conf         <= 設定ファイル
`-- keydir
    |-- jugyo.pub        <= 公開鍵
    ...

gitosis.conf が設定ファイルで、keydir は公開鍵を置いておくためのディレクトリです。
初期状態では自分の公開鍵だけが keydir に入っています。

gitosis の設定

gitosis の設定はとても簡単です。
設定ファイル(gitosis.conf)は初期状態で以下のようになっています。

[gitosis]

[group gitosis-admin]
writable = gitosis-admin
members = jugyo

設定の意味は以下の通り。

[gitosis]

[group gitosis-admin]     <= gitosis-admin という名前のグループを定義
writable = gitosis-admin  <= アクセス可能なリポジトリを指定
members = jugyo           <= グループのメンバーを指定

ユーザーの追加

公開鍵を keydir ディレクトリに置くことでユーザーの追加が行えます。
「jugyo」というユーザーを追加したい場合、jugyo さんから公開鍵をもらい、「jugyo.pub」という名前で keydir に置きます。

グループの設定

以下のような感じでグループを定義できます。

...
[group グループ名]
writable = リポジトリ1 リポジトリ2
members = ユーザー1 ユーザー2
...

writable と members にはスペース区切りで複数のリポジトリおよびユーザーを指定することができます。
writable の他に readonly というのも指定できるようです。

リポジトリ作成の流れ

リポジトリ作成の流れを説明します。
試しに foo というリポジトリを作ってみることにします。

<<<追記

すみません、大事なことを書き忘れてました!
リポジトリを追加(push)する前に、gitosis-admin リポジトリにある設定ファイル(gitosis.conf)のグループの記述のところに新規作成するリポジトリ(今回の例だと foo)を追加しておく必要があります!

例:

[group グループ名]
writable = リポジトリ1 リポジトリ2 foo <= foo を追加
members = ユーザー1 ユーザー2

>>>追記

まず、git リポジトリを作成し、適当なファイルを追加します。

mkdir foo
cd foo
git init
touch README
git add README
git commit README -m 'init'

remote の設定を行います。

git remote add origin git@ホスト名:foo.git

push します。

git push origin master

これで完了です。

簡単ですね!

ちなみに

ちなみに、yum に gitosis パッケージがあったりします(後で気づいた…)。
yum を使ってインストールした場合は gitosis というユーザーが作られ、ホームディレクトリは /var/lib/gitosis になるようです。

UPDATE

一人のユーザー(例えば jugyo さん)が複数の公開鍵を使いたいこともあると思います。
そういう場合は gitosis-admin/keydir ディレクトリに設置されている公開鍵ファイル(例えば jugyo.pub)に複数の公開鍵を書いておけばよいようです。

参考

以下が大変参考になりました。

scie.nti.st » Hosting Git repositories, The Easy (and Secure) Way
gitosis - Git リポジトリ群の管理とアクセス制御 vol.0 - openbooth
gitosis - Git リポジトリ群の管理とアクセス制御 vol.1 - openbooth
gitosis - Git リポジトリ群の管理とアクセス制御 vol.2 - openbooth

February 24, 2009

3月14日・15日に琵琶湖近辺で開発合宿をやります

3月14日・15日に滋賀県の琵琶湖近辺で開発合宿をやります。
合宿のテーマはあんまり明確に決まっていなくて、というかもともと Termtter の開発者同士で集まって開発しようみたいな話から発展して、なんでもありな開発合宿になりました。
で、僕は主に Termtter の開発をやる予定です。
興味ある方はぜひご参加くださいー。

ATND にイベントを作りましたー。
参加登録はこちらから〜。
http://atnd.org/events/388

termtter (at Lingr)
↑ここで合宿について話して決めてます。

特典:

もれなく Termtter のコミッタになれます。

関連記事:

rubyneko – オープンな開発合宿を行います
3/14に開発合宿をやります。 – hitode909のダイアリー

February 22, 2009

Filetter – ファイルの変更を監視してあれこれするためのツール

Filetter というアプリケーションを作りました。
GitHub で開発してます。

http://github.com/jugyo/filetter

Filetter って何?

ファイルの変更を監視してあれこれするためのツールです。

Filetter の wiki によると。

Filetter はファイルの変更を監視してさまざまなことを行うためのプログラムです。

例えば、ファイルの変更を検知してブラウザをリロードしたり(mozrepl モード)、ファイルを作成するだけで Twitter にメッセージを投稿したり(twitter モード)、フォルダに画像を置くだけで flickr にアップロードしたり(flickr モード)できます。

とのこと。
いろいろできるようです。

詳しくは Filetter の wiki を参照してください。

ネットはなんであるか

ネットをメディアであるととらえている人間とはどうもそりが合わない気がする。
とか、前々から考えてた。

CGM とかいう言葉が出てくるそのセンスがもうすでに、なんていうか、ださい。
僕自身も含め、各々が自分の価値観でしかネットというものを理解できていないというか、理解しようとしていないのかもなー。
うーん、全然考えがまとまってない。

ビジネス・金儲けの観点からネットを見ているとありきたりな発想しか出てこない気がする。
ありきたりな発想ではお金は儲からない。

じゃあ、ネットで金儲けしようとしている会社はどうしたらいいのか。
そんなことは僕にはわかりません。
別にネットで儲けなくてもいいんじゃないでしょうか。

February 18, 2009

ruby1.8 と ruby1.9 で instance_eval の挙動が違う

今日は万葉のオフィスで Merb 勉強会をやってました。
Merb を Ruby1.9 に対応させよう!、ということで spec のエラーを調査したり、それ以前にライブラリのインストールに悪戦苦闘したりしてました。

で、いろいろ調べてて気づいたのが ruby1.8 と ruby1.9 での instance_eval メソッドの挙動の違い。
instance_eval メソッドにブロックを渡した場合、レシーバーを引数としてブロックが call される、とリファレンスマニュアルには書いてあります。

instance method Object#instance_eval

instance_eval(expr, filename = “(eval)”, lineno = 1) -> object
instance_eval {|obj| … } -> object

オブジェクトのコンテキストで文字列 expr またはオブジェクト自身をブロック引数とするブロックを評価してその結果を返します。

確かに ruby1.8 だとその通りに動くのですが、ruby1.9 だとそうはなりません。
ブロックの引数にレシーバが入ってきません。

以下のコードで確認しました。

http://gist.github.com/65770

ruby1.8 と ruby1.9 でそれぞれ以下が出力されます。

ruby1.8

"hoge"

ruby1.9

nil

これ、ruby1.9 のバグですかね?

この挙動の違いによって、Merb の spec のいくつかが ruby1.9 においてエラーになってました。
そもそも instance_eval によって call されたブロック内では self がレシーバを参照しているはずなのでブロック引数を使う必要はないんですよねぇ。

ちなみに、以下のバージョンの ruby を使って検証しました。

ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9]
ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-darwin9]

追記:
[ruby-dev:38082] Re: was: Re: [ruby-list:45877] Re: ruby1.8 と ruby1.9 の instance_eval の挙動の違いについて
なんだか 1.9 で instance_eval の仕様が変わりそう(つまり現状の動作のまま)な雰囲気。

February 17, 2009

Rails2.3 の Nested Attributes を試す

Rails2.3 の Nested Attributes の機能を試してみました。

rails 2.3 のインストール

rails 2.3 は以下のようにしてインストールしました。

sudo gem install rails --source http://gems.rubyonrails.org

アプリケーションの作成

アプリケーションを作り、モデルをいくつか作成します。

% rails nested_attributes_sample
% cd nested_attributes_sample
% script/generate model book title:string
% script/generate model author name:string book_id:integer
% script/generate model page text:text book_id:integer
% rake db:migrate

モデルファイルに関連の情報を書きます。

app/models/book.rb

class Book < ActiveRecord::Base
  has_one :author
  has_many :pages

  accepts_nested_attributes_for :author
  accepts_nested_attributes_for :pages, :allow_destroy => true
end

accepts_nested_attributes_for メソッドを呼び出しているところがポイントです。
これにより authorpages に対して Nested Attributes の機能が使えるようになります。
さらに pages に関しては :allow_destroy => true とすることで親(Book)から削除できるようにしています。

app/models/author.rb

class Author < ActiveRecord::Base
  belongs_to :book
end

app/models/page.rb

class Page < ActiveRecord::Base
  belongs_to :book
end

確認

script/console でちゃんと動作するか確認してみます。

% script/console

One-to-one

まずはデータの作成。

>> book = Book.create({:title => 'ruby book', :author_attributes => {:name => 'foo'}})
>> book.author.name
=> "foo"

ちゃんと book.author が作成されてますね!

次にデータの更新。

>> book.update_attributes({:author_attributes => {:name => 'jugyo'}})
>> book.author.name
=> "jugyo"

ちゃんと更新されてますね!

One-to-many

次は「一対多」の場合のデータ作成のやり方です。
こんなふうにします。

>> book = Book.create({
              :title => 'rails book',
              :pages_attributes => {
                'new_1' => {:text => 'aaaaaaaaa'},
                'new_2' => {:text => 'bbbbbbbbb'},
                'new_3' => {:text => 'ccccccccc'},
              }
       })
>> book.pages.size
=> 3
>> book.pages[0].text
=> "aaaaaaaaa"

おお、ちゃんとできてるっぽい!
page に対応する 各 Hash のキーは 'new' という文字列から始まっている必要があるようです。

データを更新してみます。

>> book.attributes = {:pages_attributes => {1 => {:text => 'AAAAAAA'}}}
>> book.pages[0].text
=> "AAAAAAA"

データを削除してみます。

>> book.attributes = {:pages_attributes => {1 => {'_delete' => '1'}}}
>> book.save
>> book.pages.size
=> 3

ん?、book.pages.size が 3 のままですね。
でも DB を見てみるとちゃんと削除されてたのでとりあえずはよしとします。

参考URL:
http://weblog.rubyonrails.org/2009/1/26/nested-model-forms
http://api.rubyonrails.com/classes/ActiveRecord/NestedAttributes/ClassMethods.html