Tuesday, January 31, 2012

ubuntu11.10にruby 1.9.2, Rails 3.2をインストール

会社でUbuntu上にRailsをインストールしようとして、若干手間取ったのでメモ。(Ubuntuはまっさらからのインストール)

(最終的な)環境は以下の通り。

  • OS: Ubuntu 11.10
  • Ruby 1.9.2
  • Rails: 3.2.1

関連パッケージのインストール

Git, RVM, Rubyをインストールする。会社環境はプロキシ内なので、そのあたりも注意。

まずはプロキシの設定。必要に応じて.bashrcなりにも追記。

$ export http_proxy="your.proxy.name:8080"
$ export https_proxy="your.proxy.name:8080"
ついでcurl, Git, build-essentialインストール。
$ sudo apt-get install curl
$ sudo apt-get install git
$ sudo apt-get install build-essential
で、~/.gitconfigに以下を追記。
[http]
  proxy = %http_proxy%
Ubuntuのデフォルトでは各種devパッケージが入っていないようなので、zlib1g-dev libssl-dev libreadline-gplv2-dev libxml2-dev libsqlite3-devを追加インストール。参考
$ sudo apt-get install zlib1g-dev libssl-dev libreadline-gplv2-dev libxml2-dev libsqlite3-dev

Rubyインストール

rvmでRuby本体をインストール。

$ rvm install 1.9.2
このままだとgem installが失敗するので、zlibをコンパイル。参考
$ cd ~/.rvm/src/ruby-1.9.2-p290/ext/zlib
$ ruby extconf.rb
$ make
$ make install
同様に、bundleで使うsslのためにopensslもコンパイル。
$ cd ~/.rvm/src/ruby-1.9.2-p290/ext/openssl
$ ruby extconf.rb
$ make
$ make install

Railsインストール

ここでようやくrailsインストール。

$ gem install rails
$ rails -v
Rails 3.2.1
$ rails new testapp
$ cd testapp
ただ、ここでscaffoldするとExecJS::RuntimeUnavailableが発生、と怒られるので、Gemfileにexecjs, therubyracerを追加。 参考
gem 'execjs'
gem 'therubyracer'
ここでもう一度bundle install(ここで、上記build-essentialが入っていないとg++がなくてコンパイルできない)
$ bundle
ようやくscaffoldを実行し、動作確認。
$ rails g scaffold user user_name:string age:integer
$ rake db:migrate
$ rails server
できた。

Thursday, January 26, 2012

Gitのリモート(bare)リポジトリの扱い

Gitで、リモートにあるbareリポジトリ(repo.gitのようなリポジトリ)の扱いについてメモ。

ここでは以下のようなリポジトリ構成になっているものとします。

  • CENTER.git : チーム外で管理しているリポジトリ
  • MAIN.git : チームの開発者が普段pushするリポジトリ
  • LOCAL : 開発者が利用するリポジトリ

bareリポジトリでのマージ

bareリポジトリ(MAIN.git)上ではマージはできない。これは第一にbareリポジトリにはwork copyがないから。work copyがないと、マージで衝突したときに解決する手段がない。bareリポジトリ上のブランチのマージは、一度開発環境(LOCAL)など別のリポジトリ上にプル/チェックアウトし、そこでマージしたうえでリモートにpushする。

外部リポジトリからの取り込み

CENTER.gitで修正があり、それをMAIN.gitに取り込むにはgit fetchを使う。これだけで取り込みはOKのはずだが、fetchで取り込んだだけではHEADが更新された最新に移動しないので、reset --softする(work copyがないので、softでないとエラーとなる)。

# 以下、MAIN.git上での操作
$ git fetch <CENTER.git>
$ git reset --soft HEAD
この後でgit logすると、最新の変更がログに出力される。

ブランチを指定してpush

たとえばoriginに指定されているリモートリポジトリのdev-remoteブランチに、ローカルのdev-localブランチをpushする場合:

$ git push origin dev-local:dev-remote

リモートのブランチからクローンする

リモートリポジトリ(MAIN.git)のdev-remoteブランチを、ローカルにdev-localブランチとして取得する場合、まずgit cloneした後、リモートのブランチを指定してcheckoutする。

git clone <MAIN.git>
git checkout -b dev-local remotes/origin/dev-remote

リモートにタグを反映する

ローカルで作成したタグをリモートに反映する

$ git push --tags

RAILS_ENVの追加や環境ごとの違いへの対応方法

Railsではデフォルトでdevelopment, test, productionという環境に対応できるように作られているのはご存知の通り。 この環境ごとの設定や、新しい環境の追加方法などについて、簡単にまとめる。

ちなみに執筆時点では以下の実行環境を利用している。

  • Ruby: 1.9.2
  • Ruby on Rails: 3.0.5

環境名を取得する

Rubyのコードの中から現在の環境名(development|test|productionなど)を取得するのは、Rails.envを利用する。

新しい環境設定を追加する

例えばstagingという環境を新規に追加するには、以下の作業をする。

  1. RAILS_HOME/config/environmentsにあるproduction.rbをstaging.rbにコピーする
  2. database.ymlにstagingの項目を追加する
もちろんその他に環境依存の設定ファイルなどがあれば、そちらにもstagingを追加する。これで例えば以下のようにすればstagingの設定でrailsを起動できる。
$ rake db:create RAILS_ENV=staging
$ rake db:migrate RAILS_ENV=staging
$ rails server -e staging

環境ごとに違うgemを使う

たとえばdevelopmentとproductionで違うgemを利用する場合、Gemfileに以下のように記述する。

group :development, :test do
  gem 'sqlite3-ruby'
end
group :staging, :production do
  gem 'mysql2', '0.2.7'
end
bundle installする際には、以下のようにすると特定の環境で必要なgemを除外できる。
$ bundle install --without test development
参考: Bundler : Using Groups

Saturday, January 14, 2012

scala のパーサーコンビネーターで数式を評価

Scalaのパーサーコンビネーターの練習のため、数式をパースして計算してみる。

参考にしたのはコップ本と、以下のサイト。

実行

実行引数に数式を文字列で与えると計算結果を標準出力にプリントする。

$ scala ArithmeticParser.scala "(2 + 3) * -2.5"
-12.5

数式の文法定義

ValueからParenまでのクラスは、数式をモデリングするためのもの。ここはパーサーからは独立している。

ArithmeticParserで、これらのクラスに入力の数式をマッピングしていく。

def factor: Parser[Value] = (
  floatingPointNumber ^^ { case n => Number(n.toDouble) }
  | "-"~>floatingPointNumber ^^ { case n => Number(n.toDouble * -1.0) }
  | "("~>expr<~")" ^^ { case e => Paren(e) }
)
factorがもっとも細かい単位にマッチする。つまり、数値か括弧()。数値を表すfloatingPointNumberは継承元のJavaTokenParsersで定義されていて、浮動小数表現にマッチする。マッチしたあとの処理(返り値の計算)は^^で定義する。この箇所のように複数種類の要素にマッチする場合は、それぞれを | で列挙する。"-"~>floatingPointNumber で負の数(-2.5など)にマッチさせる。最後の"("~>expr<~")"で括弧表記にマッチさせる。"x"~>という表記は、読み取った"x"を捨てる。逆に"x"~という表記であれば"x"を解析結果として利用できる。

def expr: Parser[Value] = term~rep(addSub)     ^^ { case f1~rest => Formula(f1, rest) }
def term: Parser[Value] = factor~rep(multiDiv) ^^ { case f1~rest => Formula(f1, rest) }
termはfactorの掛け算/割り算の連続(2 * 3など)。連続ということをrepで表現している。exprは同様にterm同士の足し算/引き算の連続(2 + 3など)。またfactorのうち括弧表現のときは、内容としてexprを含む。

def multiDiv: Parser[Rest] = ("*"|"/")~factor ^^ { case op~v => Rest(op, v) }
def addSub: Parser[Rest]   = ("+"|"-")~term   ^^ { case op~v => Rest(op, v) }
multiDivは掛け算のうち、記号と後ろ側の数値にマッチする(/ 2など)。したがって1 * 2 / 3というtermは、イメージとしては[1, [[*, 2], [/, 3]]]という形にパースされる。addSubも同様。

パースと計算の実行

parseAll(expr, e).get.eval
パースの実行はparseAllで。第一引数に、入力全体にマッチさせる関数を指定。第二引数にパースする文字列を渡す。結果としてパース結果のオブジェクトが帰って来るので、getで最終的な^^で指定したパース結果を取得する。今回はValue型で帰って来るので、evalで計算している。

最初は全然よくわからなかったが、ちょっと書いてみると確かに強力そうな気がしてきた。

Thursday, January 12, 2012

RubyでTwitterのユーザーがフォローしているユーザーのリストを取得する方法

TwitterのAPIでは、次の二つを使う。

Rubyでは以下のような感じ。

require 'twitter'
ids = Twitter.friend_ids("daixque").ids[0, 10]
users = Twitter.users(ids)

取得できる量に制限があるので(最大100件)、先頭の10件に絞っている。