Haskell 環境をローカル(プロジェクト毎)に生成するコマンド hsenv <URL:http://hackage.haskell.org/package/hsenv>。
rbenv & ruby-build を調べたのはついでで、実際はこちらが先。 hsenv は python の virtualenv を参考に作ったとあり、似たようなものに rvm があるなあ、 と見てみると最近は rbenv の方が好まれているらしい。 ということで調べてみたら、結構おもしろかったのでまとめてみた。
hsenv は、最初は rbenv のように ghc の各バージョンや、ghc 以外の Haskell を切り替えて使えるようなツールかと思っていたが、 どちらかというと cabal-dev に近く、 hsenv コマンドを実行したカレントディレクトリに .hsenv/ を生成しその下に必要なパッケージをインストールしていく形。 cabal-dev install ではなく cabal install を使えるように .hsenv/bin/ 以下に ghc, ghci, ghc-mod, runghc, cabal、そしてそれらを有効にする activate を置く。 source activate をしたシェルを使っている間(exit するまで)、 または deactivate_hsenv を実行するまでは、cabal install したパッケージは ~/.cabal/ 以下ではなく .hsenv/cabal/ 以下にインストールされ、system(global) や user へ影響しないようにする。 (※Haskell は The Haskell 2010 report をサポートする実装が ghc しかなく、ビルドも面倒なため、 Python や Ruby と比べ他の実装と切り替えて使用するということが少ないんだろうと思う。)
以下は hsenv の説明から。
まず、Haskell 環境をサンドボックス化したいディレクトリを選ぶ(例えば cabal 化したプロジェクトなど)。 ディレクトリに移動する。
$ cd ~/projects/foo
次に、隔離した Haskell 環境を生成する(環境ごとに1回だけ実行する)。
$ hsenv
あとは、このHaskell 環境を使いたいときに毎回、以下を実行して環境を有効化する。
$ cd ~/projects/foo $ source .hsenv/bin/activate
これで、生成した Haskell 環境に PATH が通り、cabal のインストール先も切り替えるなどする。 cabal でインストールしたパッケージは system(global) や user へ影響しないよう、 ~/projects/foo/.hsenv/cabal 以下にインストールされる。 また、基本的なパッケージのみ(ghc と Cabal、それらが依存するパッケージ)を Haskell 環境にコピーするため、 これらのパッケージ以外の影響も受けない。
Haskell 環境を使い終わったら、以下のコマンドを実行するか、現在のシェルを終了する。
$ deactivate_hsenv
異なる GHC のバージョンを使用することができる。 開発中のコードが違うバージョン(nightly buildも含め)でのテストに使える。
まず、バイナリ配布の GHC を取得して、 以下を実行して新しい Haskell 環境を生成する。
$ hsenv --ghc=/path/to/ghc_something.tar.gz2
あとは、Basic usage 同様にして [de]activation する。
hsenv を調べたのは、penny をインストールしようとしたら、penny-lib が依存している bytestring (0.10.*) と、 既にインストールしている bytestring 0.9.2.1 がコンフリクトしており、--reinstall --force-reinstalls を指定して cabal install を実行する必要があったため。 少しスマートな方法は無いか調べてみた。
調べてみると cabal-dev と同様な仕組みであることが分かった。 実運用上は cabal-dev を使っていればよく、cabal-dev shell のようにして ./cabal-dev/ 以下にインストールしたパッケージやコマンドを実行できればより便利と思われる。 (cabalize する予定のパッケージでも、いろいろ依存関係がある大規模S/Wなら開発(設計)中は hsenv で作って、 必要なパッケージが固まってきたら *.cabal を書いて cabal-dev に移行するのがスマートかもしれない。)
結局 penny-bin パッケージをインストールする場合は、hsenv で作成した Haskell 環境に bytestring が含まれており、 それらに依存している regex-compat, regex-posix, regex-base パッケージをインストールしなおす必要があると cabal に怒られる。そのため、
$ cabal-dev install --force-reinstalls penny-bin
で、必要な cabal パッケージを含めて cabal-dev 以下に配置するしかない。
(隔離環境で hsenv や cabal-dev で新しくパッケージをインストールするのに、 既に system(global) や user にインストールしている(ビルド済みの)パッケージを元に依存関係を生成してエラーを出すのは、 cabal のバグの気がする。)
今更だけどrvmからrbenvに乗り換えるときの個人用メモ <URL:http://d.hatena.ne.jp/sandmark/20121122/1353625485>
rbenv & ruby-build の使い方メモ <URL:http://qiita.com/items/b07beebca21ba7ed8e7f>
OS X で rbenv を使って ruby 1.9.3 or 2.0.0 の環境を作る <URL:http://qiita.com/items/9dd797f42e7bea674705>
Rails開発環境の構築(rbenvでRuby導入からBundler、Rails導入まで) <URL:http://qiita.com/items/a60886152a4c99ce1017>
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ mkdir -p ~/.rbenv/plugins $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init -)"
設定を反映する。 (※上記設定で $HOME/.rbenv/shims にもPATHが通る。)
以下でインストール可能なRubyの一覧が見れる。
$ rbenv install -l
インストール前に、make のオプションを指定しておく。 一般的にCPUコアの数+1を -j で指定しておくと効率がよい。
$ export MAKEOPTS="-j9"
1.9系の最新版をインストール
$ rbenv install 1.9.3-p392 --verbose
2.0の最新版もインストール
$ rbenv install 2.0.0-p0 --verbose
自分でコンパイルしてインストールする場合は以下の手順。 さくらインターネットのレンタルサーバだと bison が入ってなくて ruby-2.0.0-p0 が コンパイルできず、新しい bison を入れようとすると m4 が古いと怒られたので、 以下のような手順となる。 ($HOME/bin に PATH が通っている前提。 git を素の Makefile でビルドして $HOME/bin 以下にインストールしたため、 他のツールもここに入れてしまうことにする。最近契約するともう少し新しいんだろうか。 事前にデフォルト shell も .login に exec /usr/local/bin/bash -l を書いて bash にしておく(でないと上記の rbenv init が実行できない))
$ cd ~/tmp $ wget http://www.ring.gr.jp/archives/GNU/bison/bison-2.4.3.tar.gz $ tar zxf bison-2.4.3.tar.gz $ cd bison-2.4.3 $ ./configure --prefix=$HOME $ gmake install $ cd .. $ wget http://ftp.ruby-lang.org/pub/ruby/ruby-2.0.0-p0.tar.gz $ tar zxf ruby-2.0.0-p0.tar.gz $ cd ruby-2.0.0-p0 $ mkdir dist $ ../configure --prefix=$HOME/.rbenv/versions/2.0.0-p0c $ gmake $ gmake install
動きとしては1.9と2.0に大きな差は無いので、2.0をデフォルトにする。
$ rbenv global 2.0.0-p0 $ rbenv rehash $ ruby --version ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
rbenv 導入後は gem install で $HOME/.rbenv/versions/<ruby-version>/lib/ruby/gems 以下にインストールされる。 (rbenv 導入前は $HOME 以下にインストールするため --user を指定する必要がある。)
$ gem install rdtool
生成した実行ファイルを呼び出せるように、gem install 後 rbenv rehash を実行する必要がある。 ($HOME/.rbenv/versions/<ruby-version>/bin 以下にある実行ファイルを呼び出せるように $HOME/.rbenv/shims/ 以下に同名の実行ファイルを生成する)
$ rbenv rehash
これで rd2 コマンドが実行できるようになる。
ついでに nanoc も。
$ gem install nanoc $ rbenv rehash
Bundler とは、Gemfile に必要な rubygems を記述しておくことで、 どこでも bundle install 一発で依存する rubygems をインストールすることができるようにしたもの。
Bundler: The best way to manage a Ruby application's gems <URL:http://gembundler.com/>
bundler は gem でインストール。
$ gem install bundler $ rbenv rehash
Rails 最新版でプロジェクトを開始しようとした場合を例に進める。 一時ディレクトリを作成。
$ mkdir ~/tmp/pj $ cd ~/tmp/pj
必要な rubygems を Gemfile に記述しておく。ここでは rails 最新版を指定。 (※インストールされたのが 3.2.13 だったので、以下はそのバージョンを前提)
source 'http://rubygems.org' gem 'rails'
(※Rails4 はまだリリースされていなかったので、インストールには明示的なバージョン指定が必要。)
source 'http://rubygems.org' gem 'rails', '4.0.0.rc1'
bundle コマンドで vendor/bundle 以下に rails をインストール。
$ bundle install --path vendor/bundle
インストールした rails でプロジェクト <project-name> を作成。 (--skip-bundle を指定しないと、この時点で bundle install が実行されてしまう。)
$ bundle exec rails new <project-name> --skip-bundle
生成したプロジェクトの Gemfile を元に、実際に使用する rubygems を vendor/bundle 以下に インストールする。
$ cd example $ bundle install --path vendor/bundle
(Rails3 の場合) bundle install した rubygems の実行ファイルを実行するには bundle exec <実行ファイル> を 呼び出すが、毎回書くのは面倒なので、bin/ 以下に stub を生成しておく。 こうすると、例えば rspec を bundle でインストールした時に bundle exec rspec ではなく bin/rspec で実行することができる。
$ bundle install --binstubs
(Rails4 の場合) Rails4 から script/ が無くなり、bin/ 以下に bundle, rails, rake が生成されるようになった。 bundle install --binstubs を指定するとこれらが上書きされてしまう。 使用するコマンドについては bundle binstubs <command> で逐一追加する形となる。
$ bundle binstubs rspec
あとは .gitignore に bundle install で生成したファイル/ディレクトリを追加。
/vendor/bundle #/bin # Rails4の変更があるので、bin/ 以下は履歴管理対象としておいた方がよいと思う。
git で履歴管理。
$ git init $ git add . $ git commit -m "initial."
以降、git clone した場合はまず以下のコマンドを実行することで、同じ環境が構築できる。 (Gemfile.lock がある場合(履歴管理対象とした場合)には、そのバージョンも含めて。)
$ bundle install --path vendor/bundle
Gemfile.lock を更新したい場合は bundle update を実行する。
production 環境用には、 bundle install --deployment を実行する。 この指定で、以下のような動作になる。
vendor/bundle 以下に必要な rubygems をインストールする。 Gemfile.lock を更新する。(development 環境と production 環境は必要な rubygems が異なることが多い) (※よく分からないが、bundle package を実行していた場合の動作にも違いがある)
(※Gemfile.lock を更新するということは、bundle update と --deployment 指定のタイミングは あまり離れない方がよいということか?)
少し前の IE の更新により、iso-2022-jp を使用したページが文字化けして表示されるようになってしまった (正確にはなると聞いて確認した)ので、良い機会と思い日記の更新を計画。 ( <URL:http://support.microsoft.com/kb/2467659/> をあてると直るらしいのだが、手元の Vista は問題解消せず。 Windows7 の方は未確認(UbuntuとWindows7デュアルブートなので再起動が面倒だった)) 10年前から変わらずほとんど手作業で更新していたので、いい加減それは無いだろう、と。 (書く時間が95%で、サーバへのアップロードくらいしか自動化していない。 非定型作業が多いなら自動化する意味はあまりないし)
欲しい機能は、
というあたりが最低限。
今回追加したい機能としては、
あたり。
そういう機能をもつプログラムを書いてもいいが、最近は時間が取れなくて挫折しがちなので、 出来合いのものを活用することにする。で探したのが、nanoc。 選択理由としては、
など。(詳細は Basic Concepts を参照)
とりあえず、更新手順をどういう形とするか、 いままでのサイトに合わせたディレクトリ構造をどう出力させるのか、などを現在考え中。
ただし、一番の難点は、この nanoc のサイトを開くと firefox がフリーズすること (Ubuntu 10.10 (x86)限定。Vistaでは発生しない)。 あまりWEB上での活用事例も多くはないので、まだ他人には勧めにくい。
actual (実際に状態を確認する対象)で使用可能なメソッドを呼び出して、成否を判断する。 Matcher に使用するメソッドと、actual で呼び出されるメソッドは以下のように関係づけられる。
Matcher: be_〜 → actual で呼び出すメソッド: 〜?
例えば、be_nil という名前の Matcher を指定すると、actual で呼び出す nil? を使用して判断する。 より英語として読みやすいように、be_〜、be_a_〜、be_an_〜 という指定の仕方が出来る。 (例えば be_an_instance_of(Klass) → instance_of?(Klass) という指定が可能)
定義場所:
lib/spec/matchers/be.rb # be_true(), be_false, be_nil, be など lib/spec/matchers/be_close.rb # be_close lib/spec/matchers/be_instance_of.rb # be_(an_)?instance_of lib/spec/matchers/be_kind_of.rb # be_(a_)?kind_of lib/spec/matchers/method_missing.rb # ここ経由で Spec::Matcher::BePredicate (be.rb) から他の be_〜 形式が呼び出される。
Matcher: have_〜 → actual で呼び出すメソッド: has_〜?
be_〜 と同様に名前を読み替えて、呼び出すメソッドで確認する。
Matcher: ==, <, >, <=, >=, ===, =~
lib/spec/matchers/be.rb で定義している Spec::Matcher::BeComparedTo を使用して、 それぞれ定義されているメソッドを使用して expected と比較する。!= は使用不可(should_not == expected を使う)。
参照先
gem server 実行後の RDoc 参照先
昨日に引き続き、特殊キーを含んだ場合のキーボードショートカットについて。
コンソールアプリケーションと GUI アプリケーションで使用可能なキーを分けるのは、 ncurses (termcap または terminfo) で対応しているキーの組み合わせかどうか、という点。 この対応表には Shift キーによる修飾があるかどうかの情報も含まれているため、 コンソールアプリケーションで特殊キー単体押下と、Shift キーなどの修飾キー + 特殊キー押下が区別できるか、 という境目も ncurses に依存する。
端末エミュレータと ncurses (termcap または terminfo) の呼び方、TERM 環境変数の値などで 動作は異なるが、ここでは GNOME 端末、ncurses-5.7、 TERM=gnome という環境で動作させている。
コンソールアプリケーションで扱える特殊キーを分類すると、以下のようになる。
コンソールアプリケーションで認識できない(端末エミュレータでブロックされるなどで通知されない)特殊キーは以下。
というと、以下の理由。
修飾キー (Ctrlキー、Altキー、場合によっては Shift キー)と組み合わせることで特殊な操作を行う、 キーボードショートカットの役割分担についてちょっと考えてみる。 なお、入力できるキーは JIS キーボード基準で考察 (101キーボードだと少し違う)。
この時、キーボードから入力できるのは、
この時、キーボードから入力できるのは、
Shift キーを押す・押さないで、ASCII の 0x21 〜 0x7e までの全範囲を入力することが出来る。 (0x20 はスペースキー、0x7f は DELETE キーなので範囲外)
Ctrlキーを押すことで、0x00 〜 0x1f の範囲を入力することが出来る。 これは、Ctrlキーを 0x40 〜 0x5f ('@'、'A' 〜 'Z'、'['、'\\'、']'、'^'、'_') と合わせて押下し、 押されたキーから 0x40 引いた文字コードを入力したとみなすことで実現している (例:Ctrlキー + '@' → 0x00)。
ただし、通常 'A' 〜 'Z' を入力するには Shift キーを押さないといけない。 杓子定規に当てはめるとCtrlキーの時は必ず Shift キーを押さないといけないことになるが、 それは面倒なので、'A' 〜 'Z' の部分は 'a' 〜 'z' で代用する。
つまり、文字コードベースで考えると Ctrl キーと組み合わせてコードを生成できるのは、 '@'、'a' 〜 'z'、'['、'\\'、']'、'^'、'_' のキーのみ。 これ以外のキーは Ctrl キーと合わせて使用しても、対応する文字コードが無いため有効とはならない。
Altキーは、入力したキーに 0x80 を加えた文字コードを生成する。(例:Altキー + 'a' (0x61) → 0xe1)
ここで、ショートカットに割り振ることができる修飾キーの組み合わせについて考える。
まずはコンソールアプリケーション。
という前提条件がある場合、ショートカットキーに使用できるのは以下のキーのみ。
他にカーソルキーやファンクションキーなどがあるが、取り合えず今は割愛。 特殊キーには、コントロールキーを用いて入力可能なもの (例:TAB キー = Ctrlキー + 'i')があるため、 それらと Ctrl キーの同時押しは認識されない、などの制限が出てくる。
GUI アプリケーションの場合、文字コードによる組み合わせの制限がなくなるため、 コンソールアプリケーションの場合よりも多い、以下の組み合わせが使用可能となる。
GUI アプリケーションまでで Shift キー、Ctrl キー、Alt キーの全組合わせが使用可能であるため、 ウインドウシステムのように全体に影響を与えるような機能に対してショートカットを割り当てるには、 以下のような拡張が必要となる。
といいつつ役に立たない関数を定義する関数(マクロ)を。
(defmacro define-futility (fname args &rest body) `(defun ,fname ,args (prog1 (progn ,@body) (fset (quote ,fname) nil)))) (define-futility useless1 () (+ 1 1)) (useless1) 2 (useless1) #=> Debugger entered--Lisp error: (void-function useless1) (define-futility useless2 (a) (* 2 a)) (useless2 3) 6 (useless2 3) #=> Debugger entered--Lisp error: (void-function useless2)
関数を定義できるが、その関数が実行されると自分自身を削除する関数にする。
しかしその関数が実行されていないという情報を持っているわけだから、なんか役に立つんじゃなかろうか、などと考えたり。
「SPINによる設計モデル検証」(近代化学社)参照で、前回の修正。 前回の progress については説明が適切では無かったので。
成立してはいけない性質をオートマトンで記述し、特別なプロセスとして検査したい性質を記述するため、 Never Claim という特別なプロセスを記述する。
SPIN では有限の記号列、無限の記号列に対応したオートマトンを利用することができる。
で、だいたい動かし方が分かってきたところで PROMELA について、 と行きたい所だが、WEB に結構情報があるので(例えば、Basic Spin Manual など)、 次の例題を考え中。
基本的な形は、複数のプロセスが共通の資源(グローバル変数や channel など)に対して操作を行うモデルを実装し、以下の点を検証する形となる。
処理のその時点で満たすべき条件を確認する。条件を満たさない場合をエラーとして検出する。
assert(判定条件)
デッドロックでは無い終了状態に到達することを確認する。そのために、プログラム中で終了状態とみなす箇所を追加する構文がある。 (何も指定していないと、生成した全てのプロセスが最後まで実行され、かつ全ての channel が空であるときを終了状態とみなす)
end: /* end〜 と言うように end の3文字で始まるユニークな名前のラベルで指定する */
処理が進む(無限ループに陥らない)ことを確認する。そのために、プログラム中のループで処理が進む箇所を示す構文がある。 処理が進まないループがある (= non-progress cycles がある)事を検出するには、pan.c をコンパイルするときのオプションで -DNP を渡し、 pan -l を実行する。
progress: /* progress〜 と言うように progress の8文字で始まるユニークな名前のラベルで指定する */
後はよく分かっていない。
PAN (Process ANalyser) をコンパイルするときに、いくつかの定義を渡すことで使用メモリのサイズや対応する機能などを変更できる。
動作を変更するコンパイルオプションとして、例えば以下がある。
gcc -DNP -o pan pan.c
これは non-progress サイクルを検出する検証器を含んだコードを生成する。
pan の実行時にもいくつかのオプションを渡すことができる。
例えばコンパイル時に -DNP を指定し、pan 実行時にオプション -l を渡すことで、 non-progress cycle を検出する。
pan -l