最新のhpricotをjruby(1.2)で利用する手順をメモしておきます。

まず、githubから最新のhpricotをcloneしてきます。

あとは、以下のようにしてjruby用のパッケージをbuildしてインストールします。

   1  % jruby -S rake package_java
   2  % sudo jgem install pkg/hpricot-0.8.235-jruby.gem

これでOK.

posted by Png genki on Thu 9 Apr 2009 at 01:52

以前、Merb用のaliasの設定をご紹介しましたが、今度はjruby版です。

   1  alias jm='PATH=./bin:$PATH jruby -S merb'
   2  alias jmi='jm -i'
   3  alias jmg='PATH=./bin:$PATH jruby -S merb-gen'

rubyとjrubyを両方使ってると、

   1  % jruby -S merb

のように書く事が多いので、aliasを設定しておくと便利ですね。

posted by Png genki on Thu 9 Apr 2009 at 01:48

思い立ってJRubyの環境を入れてみる事にしました。

ちょうどバージョン1.2が出ているようなので、ソースを落としてきます。

http://dist.codehaus.org/jruby/1.2.0/jruby-src-1.2.0.tar.gz

落としてきたファイルは/usr/local/jruby-1.2.0 あたりに展開します。 展開したら、Javaらしくantでbuildします。

   1  % ant

あとは、以下のように~/.zshrcなどで環境変数を設定します。

   1  export JRUBY_HOME=/usr/local/jruby-1.2.0
   2  export PATH=:$JRUBY_HOME/bin:$PATH

これで、ひとまずjrubyが動くようになります。

   1  % jruby -v
   2  jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-04-08 rev 6586) [i386-java]

posted by Png genki on Wed 8 Apr 2009 at 16:14

Merb/DataMapperをしばらく使っていたのですが、 少なくともバージョン0.9.10, 0.9.11では、 associationの実装にバグがあり、 レコード数が多いテーブルがあると、aggregation系の処理に時間がかかるという問題がある事が分かりました。

例えば、Post.has n, :comments な関係がある時に、 以下のようなコードを実行すると、このようになります。

   1  ?> Post.first.comments.count #=> 188
   2   ~ (0.000865) SELECT "id" FROM "posts" ORDER BY "id" LIMIT 1
   3   ~ (0.000094) SELECT "id", "post_id" FROM "comments" WHERE ("post_id" IN (1)) ORDER BY "id"
   4   ~ (0.000063) SELECT COUNT(*) FROM "comments" WHERE ("post_id" = 1)

2つ目のSQLは不要なのですが、発行されてしまいます。 例えばCommentのレコード数が多かった場合、Commentオブジェクトを大量に生成しようとしてしまうため、致命的な遅さになってしまいます。

目下この問題の解決策を探しているところですが、 Edge-DMのspec/仕様でerrorが出ている状態なので、なかなか手が付けられない感じです。 とりあえず、dm-coreのassociations/relationship.rbの中の、

   1        # @api private
   2        def get_children(parent, options = {}, finder = :all, *args)
   3          parent_value = parent_key.get(parent)
   4          bind_values  = [ parent_value ]
   5  
   6          with_repository(child_model) do |r|
   7            parent_identity_map = parent.repository.identity_map(parent_model)
   8  
   9            query_values = parent_identity_map.keys
  10            bind_values = query_values unless query_values.empty?
  11            query = child_key.zip(bind_values.transpose).to_hash
  12            collection = child_model.send(finder, *(args.dup << @query.merge(optio
  13  ns).merge(query)))
  14  
  15            return collection unless collection.kind_of?(Collection) && collection.any?

の最後の collection.any? で件のSQLが実行されているところまでは分かりました。 DataMapper::CollectionはextlibのLazyArrayを継承しているクラスなのですが、どうもそのへんの仕様が変わったのに追従できてないのかな。 モジュールを過度に分散しすぎるのも、整合性を保つのが大変になるという問題がありますね。 注意深く完全なSpecを書く事を心がけていれば防げる問題かもしれないですが。

posted by Png genki on Wed 8 Apr 2009 at 05:06

最近の釣果ならぬYak Shaving状況:

  • watch.s21g.com が重たくて固まる
  • CouchDB-adapterを疑ってmysqlに戻す
  • まだ遅いのでdm-aggregatesを調査
  • dm-core が原因っぽいのでdm-coreのソースを見る
  • dm-core のスペックが通らない
  • postgresが必要なのでインストール
  • Mac用インストーラではdo_postgresがmakeできない
  • postgresをソースからインストール <- いまここ

ということで、MacOSにPostgresを入れるためにユーザを作成する手順のメモ。

   1  # dscl . -create /Users/postgres
   2  # dscl . -create /Users/postgres UserShell /bin/bash 
   3  # dscl . -create /Users/postgres RealName "Postgres"
   4  # dscl . -create /Users/postgres UniqueID 451
   5  # dscl . -create /Users/postgres PrimaryGroupID 451
   6  # dscl . -create /Users/postgres NFSHomeDirectory /usr/local/pgsql

UID/GIDの根拠は自信が無い。UIDは500未満にしておくとログイン画面にでないようになるそうだ。

Alas, life is full of yakshaving!

See Also

posted by Png genki on Tue 7 Apr 2009 at 23:47

その1でsubmoduleをaddし、git-submodule statusコマンドでステータスを確認するところまでの作業をしました。
今度はaddした以外の人がpullして、submoduleを確認するところを書いてみます。

submoduleを取得:init & update

   1  git pull --rebase #submoduleを追加したコミットを取得
   2  git submodule 
   3  -e110f2056783465b8d719bdb1ab5fd14e7650f56 vendor/plugins/rspec

(-がついているので)この時点ではrspec submoduleが初期化されていません。よって下記のコマンドで初期化します:

   1  git submodule init
   2  git submodule update

又は

   1  git submodule update --init

updateすることによりソースファイルを取得します。
これで、addした以外の人もsubmoduleを追加することができました。しかし、まだこれで終わりではなくて実はいくつか検討すべき点があります:

  • submoduleに修正を加えないかどうか
  • どのバージョンを使うか:commit hash
  • (railsの)deployはどうするか:Capistrano
  • submoduleの削除

外部のrepoをそのままか、forkしてからか

submoduleをaddする前に検討すべき事項です(!):
追加するremoteリポジトリを変更したくなる可能性があるかどうか検討する必要があります。例えばrailsやrspecなら変更を加えるというのはほとんどないように思われますが、完成度の低いpluginだと自分で修正したり、追加したりすることが考えられます。そのような場合、下記のようなシナリオが考えられます:

  1. remoteをsubmodule(変更しない)
  2. Githubであればforkして、それをsubmoduleにする
  3. 自分のローカルにcloneして、それをsubmoduleにする
  4. サーバにrepoを作ってremoteのファイルを追加、それをsubmoduleにする

1,2はなんとなく想像できますが、3,4は運用が面倒そうです...
また、railsまでsubmoduleにする記事もあったのですが、毎回deploy時にコピーすることになるのでdeployに時間がかかるだろうし、容量も食うので運用には向いていないかもしれません。

どのコミットをsubmoduleとして採用するか

submoduleを利用する際、外部のbleeding edgeブランチを積極的に採用したくはありません。なので、タグか特定のバージョン(コミット)を利用するのが適切です:

   1   cd vendor/plugins/rspec/rspec
   2   git tag 
   3  1.1.10
   4  (略)
   5  1.2.1
   6  1.2.2
   7   git checkout 1.2.2
   8   cd ../../..

rspecのタグ1.2.2を採用しました。このあとRAILS_ROOTに戻ってcommit, pushすればokです。
この後、他の人がこの変更を反映するには下記の作業を行います:

   1  git pull --rebase #submoduleを追加したコミットを取得
   2  git submodule update

Capistranoでsubmoduleを使えるようにする

一行追加するだけ!

   1  set :git_enable_submodules, 1

via http://github.com/guides/deploying-with-capistrano

submoduleの削除

rspecを例に:

  1. .gitmodulesファイルから該当する行を削除
       1  [submodule "vendor/plugins/rspec"]        
       2  path = vendor/plugins/rspec        
       3  url = git://github.com/dchelimsky/rspec.git
    
  2. .git/configファイルから該当する行を削除

       1  [submodule "vendor/plugins/rspec"]        
       2  url = git://github.com/dchelimsky/rspec.git
    

  3. git rm --cached path_to_submodule
    パスの最後に/(スラッシュ)がない状態で:

       1  git rm --cached vendor/plugins/rspec
    

  4. git commit、pushでおしまい

via http://git.or.cz/gitwiki/GitSubmoduleTutorial

.gitmodulesファイル

初めてsubmoduleを追加すると、下記のファイルが追加されます:

   1  .gitmodules

その他に.git/configも変更されます。

submoduleをもっとよく理解するRefs

posted by Png satoko on Tue 7 Apr 2009 at 21:24

桜が散る前に、4/8の夜21時よりMerbJog#2を開催いたします。

詳細・参加申請は以下のサイトをご覧ください。

飛び入り参加もOKです。

よろしくお願いします。

posted by Png genki on Tue 7 Apr 2009 at 06:01

DataMapperはSQLを解さないアダプタも利用可能なので、この方法でSQLが実行できるかどうかはアダプタを選びますが、一般的には以下のようにすれば直接SQLを実行できます。

   1  Post.repository.adapter.execute("sql string")

結果は、例えばmysqlを使っている場合にはDataObjects::Mysql::Resultが帰ってきます。

posted by Png genki on Tue 7 Apr 2009 at 00:57

DataMapperでSetterメソッドを上書きして、プロパティの設定をコントロールするには、以下のようにします。

   1    def uri=(uri)
   2      attribute_set :uri, ::URI.parse(uri).normalize.to_s
   3    end

posted by Png genki on Sun 5 Apr 2009 at 06:56

度々忘れるのでメモしておきます。

   1  Merb::ControllerExceptions.constants.sort #=> ["Accepted", "ActionNotFound", "BadGateway", "BadRequest", "Base", "ClientError", "Conflict", "Continue", "Created", "ExpectationFailed", "Forbidden", "GatewayTimeout", "Gone", "HTTPVersionNotSupported", "Informational", "InternalServerError", "LayoutNotFound", "LengthRequired", "MethodNotAllowed", "MovedPermanently", "MovedTemporarily", "MultiPartParseError", "MultipleChoices", "NoContent", "NonAuthoritativeInformation", "NotAcceptable", "NotFound", "NotImplemented", "NotModified", "OK", "PartialContent", "PaymentRequired", "PreconditionFailed", "ProxyAuthenticationRequired", "Redirection", "RequestEntityTooLarge", "RequestRangeNotSatisfiable", "RequestTimeout", "RequestURITooLarge", "ResetContent", "STATUS_CODES", "SeeOther", "ServerError", "ServiceUnavailable", "Successful", "SwitchingProtocols", "TemplateNotFound", "TemporaryRedirect", "Unauthorized", "UnsupportedMediaType", "UseProxy"]

posted by Png genki on Sat 4 Apr 2009 at 22:58