Monthly Archives: 9月 2013

Xcode 5.0 で不調になった Haskell 環境をなんとかする

iOS 7 のリリースに合わせて Xcode 5.0 がリリースになり、思わずアップデートしてしまった人はきっと私だけじゃないはず。しかし、これによって私の Haskell 環境は調子が悪くなってしまいました。特に Haskell コード中のシングルクォートの扱いがおかしいケースが目立ちました。

なお、私の Haskell 環境は Homebrew でインストールしたものです。

GHC に使わせる gcc を変更する

問題の原因は、Xcode 5.0 付属の gcc のようです。そこで、gcc のバージョン 4.7 を別途インストールします。

brew tap homebrew/versions
brew install gcc47

GHC の設定を変更するため /usr/local/Cellar/ghc/7.6.3/lib/ghc-7.6.3/settings を修正します。

2
 ("C compiler command", "/usr/bin/gcc"),

↑これを↓このように修正します。

2
 ("C compiler command", "/usr/local/bin/gcc-4.7"),

これでだいたい良さそうでしたが、これだけでは Yesod が依存している entropy のコンパイルが通りませんでした。どうも単純にパス上の gcc を見ているくさいのです。ですので、Homebrew を使っているのでしたら、/usr/bin よりも /usr/local/bin を優先してパスを通しているかと思いますので、ここにシンボリックリンクを作成してしのぎましょう。

ln -s /usr/local/bin/gcc-4.7 /usr/local/bin/gcc

ただしこれをやると、ほとんど Xcode の gcc をパス上から隠蔽することになるわけですから、その点十分に注意してください(コマンドラインで Xcode に依存するような開発をする場合など)。

それから、haskell-platform も念の為に再インストールしたほうがいいかもしれません。

brew uninstall haskell-platform
brew install haskell-platform

Yesod-Auth の HashDB を使うサンプルできたよ

日々のすきをみてドン亀のごときペースで Haskell の勉強をしているのですが、入門書片手に学ぶのも飽きてきたので、実際になんか作ってみようとしています。

そこで Haskell の Web  アプリケーションフレームワーク「Yesod」に挑戦しています。

Yesod はデフォルト状態(プロジェクトを作成直後の状態)ですでにログイン認証の仕組みが使えるようになっているのですが、この認証方式が Google の仕組みを使う一種のシングルサインオン方式になっているのです。これはこれで技術的に興味深いのですが、しかしじゃあ実際にどれぐらい使うんだというと、実案件ではそうそう使うものではないと思います。実際によく使う方式といえばやはり DB にユーザ名とパスワードを保存しておき、入力値がそれにマッチするかを見る方式が多いのではないでしょうか?

Yesod には標準で Yesod-Auth という認証の仕組みがあって、このサブパッケージによって前述の Google を使った認証方法や BrowserID を使った認証方法など様々な認証方法を提供しています。そして当然 DB を使った認証方法も提供しています。それが Yesod.Auth.HashDB パッケージ(以下 HashDB)です。

しかし、これを使うためのドキュメントでわかりやすいのがなかなか見つからないのです! 英文のリーディング自体がたどたどしい Haskell と Yesod の初学者にはイバラの道以外の何物でもないような状態だと私は感じました。しかしなんとか最低限何をすればいいのかまとめることができましたので紹介します。

なお、今回使用した Yesod のバージョンは 1.2.3.3 です。この記事に関するソースコードは Github で公開しています。diff を見てみるとどこに手を付けたのかわかりやすいかもしれません。

手を付けるべきファイルは3つ

そもそもデフォルトの状態から最低どのファイルに手をいれるべきかもなかなか定かにならなかったのですが、以下の3つが修正対象です。

  • config/models
  • Models.hs
  • Foundation.hs

config/models

まず、デフォルトでもユーザ情報を格納するためのテーブル定義を行っているのですが、HashDB で使用するには若干手直ししなければなりません。ポイントは以下の点です。

  • パスワードは必須項目でなければなりません。
  • salt カラムが必要です。

デフォルトでは password カラムに Maybe がついているのでパスワードが必須項目になっていません。また、HashDB ではパスワードは SHA-1 でハッシュ化して扱います。その際に salt の値を使います。具体的な例をあげると、パスワードが “secret”、salt が “shio” だとすると “shiosecret” をハッシュ化した値を使用するわけです。この salt を保存するカラムが必要になります。

以上を踏まえると、config/models の User 定義は以下のようになります。

1
2
3
4
5
6
User
    ident Text
    password Text
    salt Text
    UniqueUser ident
    deriving Typeable

Model.hs

config/models の定義によってモデルが User 型が定義されますが、HashDB で使用するには HashDBUser 型クラス制約を満たさなければなりません。それのための修正を Model.hs で行います。まず、HashDB を Import します。

5
import Yesod.Auth.HashDB (HashDBUser(..))

次に型インスタンスの作成です。

17
18
19
20
21
22
instance HashDBUser User where
  userPasswordHash = Just . userPassword
  userPasswordSalt = Just . userSalt
  setSaltAndPasswordHash s h p = p { userSalt = s
                                  , userPassword = h
                                  }

Foundation.hs

最後の Foundation.hs で認証方式を設定します。まず、BrowserID 認証方式と GoogleEmail 認証方式を使用しないので、以下の Import は削除してかまいません。

7
8
import Yesod.Auth.BrowserId
import Yesod.Auth.GoogleEmail

かわりに HashDB のための Import を追加します。

7
import Yesod.Auth.HashDB (authHashDB, getAuthIdHashDB)

getAuthId と authPlugins を修正します。

124
125
126
127
    getAuthId = getAuthIdHashDB AuthR (Just . UniqueUser)
 
    -- You can add other plugins like BrowserID, email or OAuth here
    authPlugins _ = [authHashDB (Just . UniqueUser)]

以上で完了です。

その他、使い方等は Github にあげている readme.md を参照してください。

The NERD Commenter がちょいとばかりお馬鹿

最近 Emacs の勉強をしていたのですが、結局よく使うのは Vim だよなということで、Vim についてまじめに学び始めた @itoasuka です。こんにちは。

こんな私ですから .vimrc は日々変わり続けているわけですが、目下の悩みはコメントアウト用のプラグインは何を使おうかということです。

とりあえず「The NERD Commenter」を使っていますが、こいつの「NERDCommenterToggle」がちょいとばかりお馬鹿で困っています。

たとえば、以下の3行をビジュアルモードで選択するとします。

" Nerd_Commenter の基本設定
let g:NERDCreateDefaultMappings = 0
let NERDSpaceDelims = 1

これに NERDCommenterToggle をかけると以下のようになります。

Nerd_Commenter の基本設定
let g:NERDCreateDefaultMappings = 0
let NERDSpaceDelims = 1

一行目しか見てねぇ!

もちろん下みたいになるのを望んでいました。

" " Nerd_Commenter の基本設定
" let g:NERDCreateDefaultMappings = 0
" let NERDSpaceDelims = 1

設定? それともそもそもできない?