最近使ったモジュールとか
Data.ConfigFile
設定ファイル読み込み用のパッケージ。
こんな感じでよく使ってる。
printUsage = print "..." main = do args <- getArgs case args of [] -> pringUsage (configFile:_) -> do val <- readfile emptyCP{optionxform = id} configFile let cp = forceEither val -- 設定ファイル読み込みに失敗したら死ねばいい start cp
emptyCP の optionxform はデフォルトで toLower になってて、キー値が小文字にされちゃって嫌なので何もしないようにしてたり。
あと自分は "DEFAULT" しか使わなかったり、キー値が無ければさっさと終わってくれていいようなケースが多いので、
getDefault :: Get_C a => ConfigParser -> OptionSpec -> Either CPError a getDefault cp opt = get cp "DEFAULT" opt getForce :: Get_C a => ConfigParser -> OptionSpec -> a getForce cp opt = forceEither $ getDefault cp opt
こんな補助関数使ってる。
System.Posix.Daemonize
その名の通りデーモン化してくれるパッケージ。
デーモン化するかどうかを Data.ConfigFile で読む設定ファイルに書いておけば便利かも。
-- "daemonize" の設定が true なら、デーモン化してから program cp を実行する -- "daemonize" の設定が false なら、デーモン化せずに program cp を実行する -- "daemonize" 設定が見つからなかったら例外投げて終了する startWithDaemonize :: ConfigParser -> (ConfigParser -> IO ()) -> IO () startWithDaemonize cp program = daemonizeIf (getForce cp "daemonize" :: Bool) where daemonizeIf True = daemonize $ program cp daemonizeIf False = program cp
デーモン化は、GHC7.1 までは -threaded を付けてコンパイルするとおかしなことになってたらしいのだけど、GHC7.2 以降では直ってるらしい。
System.Log
ログ表示用のパッケージ。
Data.ConfigFile でどういう風にログ出力するかを書いておくと便利かも。
openDebugLog :: ConfigParser -> String -> IO () openDebugLog cp name = do -- ここでのエラーは全部無視する handle (\(SomeException s) -> print s) $ do -- log.path でどのファイルに出力するか決められる let path = getForce cp "log.path" -- log.priority でどのレベル以上を出力するか決められる let priority = either (const WARNING) (read :: String -> Priority) $ getDefault cp "log.priority" h <- fileHandler path priority -- log.format でどんなフォーマットで出力するか決められる let format = either (const "[$time : $loggername : $prio] $msg") (id :: String -> String) $ getDefault cp "log.format" let fh = setFormatter h $ simpleLogFormatter format updateGlobalLogger name (setLevel priority . addHandler fh)
で、これを呼んでログファイルを開いたら、後はそこへ出力するだけ。
program cp = do openDebugLog cp "hogelog" infoM "hogelog" "info" errorM "hogelog" "error"
Database.MongoDB
MongoDB に繋いで各種処理を行うパッケージ。
詳細はあまり理解してないのだけど、繋いで適当にクエリ投げて結果取得するだけなら、サンプル見ればすぐ分かって便利。
あとはまあ、例外処理とか RAII とかやれば安心な気がする。
import Control.Exception (SomeException(SomeException),bracket,handle) import Data.UString (UString) import qualified Database.MongoDB as M import Database.MongoDB (u,(=:)) -- MongoDB へ接続。失敗したら例外が投げられる connectMongoDB :: M.HostName -> IO M.Pipe connectMongoDB h = M.runIOE $ M.connect $ M.host h -- クエリ関数。 -- find するとカーソルが得られるので、そこから rest で全部一気に持ってきてリストにして返す find :: (MonadMVar m, Functor m) => UString -> M.Action m [M.Document] find name = M.find (M.select [u"name"=:name] (u"things")) >>= M.rest dbMain = do -- 何か問題が起きたらここでハンドルする handle (\(SomeException s) -> print s) $ do -- RAII 的なことをする bracket (connectMongoDB "xxx.xxx.xxx.xxx") M.close $ \pipe -> do -- エラーかどうかが Either で返されるので、 -- Left だった場合に例外発生させるなら forceEither を使う resultOrError <- M.access pipe M.master (u"test") (find $ u"hoge") let result = forceEither resultOrError print result
Happstack
HTTP サーバーが簡単に作れるパッケージ。
とりあえずこれだけでサーバーが動く状態に。
import Happstack.Server main = simpleHTTP nullConf $ ok "Hello, World!"
アクセスされたメソッドや URL に応じて処理を変えるには Routing の関数を msum する。
import Control.Monad (msum,mzero) import Happstack.Server -- URL で得られた解析を使って何かする。 -- ただし引数は 3 つまで。 doQuery :: [String] -> ... doQuery xs | length xs >= 4 = mzero | otherwise = ... -- URL を nullDir になるまで再帰的に解析 paths f = paths' f [] where paths' f xs = msum [nullDir >> f (reverse xs), path (paths' f.(:xs))] main = simpleHTTP nullConf $ msum [ -- GET メソッドかつ hello/xxxx という URL を受けたら "Hello, xxxx" と表示する dir "hello" $ (\s -> methodM GET >> ok $ "Hello, "++s), -- query/xxx/yyy/zzz/... という URL を [xxx,yyy,zzz,...] というリストにして doQuery 関数を実行する dir "query" $ paths doQuery] {- http://sample.com/hoge → エラー http://sample.com/hello/hoge → Hello, hoge http://sample.com/hello/hoge/fuga → エラー http://sample.com/query/hoge → doQuery [hoge] の実行結果 http://sample.com/query/hoge/fuga/moke → doQuery [hoge,fuga,moke] の実行結果 http://sample.com/query/hoge/fuga/moke/hage → エラー -}
これと、あとは URL のクエリ部分を探すパッケージだけあればとりあえずやりたいことは出来たのでいいのだけど、他にもパッケージを見た感じだと Happstack.Server にはクッキー、ファイルサービング、ベーシック認証、プロキシサーブ、Validation、XSLT といろいろありすぎるし、HTML を動的に作るためのパッケージもチュートリアルの中で紹介されてたりとかしてやばい。HTTP サーバーってこんなに簡単に作れるのかとちょっと感動。