Yesod Framework の PathPieces を使ってみる
“Developing Web Applications with Haskell and Yesod”をちまちまと読みすすめてYesod Frameworkについて勉強している。
その中でPathPiecesの挙動について解説されている内容がいささか中途半端だったので、実際に試してみた。
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} import Yesod import Data.Text (Text) import qualified Data.Text as T {- アプリのデータ型としてPathPieceStudyを定義。 Template Haskell(TH)でPathPieceStudyをYesod化してもらう。 QuasiQuoter(QQ)“parceRoutes”を使ってサイトのリソース(パス)を定義。 リソース定義の際にPathPiecesの指定をするが、 “*”で可変長のピースを定義する場合TextではなくTextsとしている点に注意。 -} data PathPieceStudy = PathPieceStudy mkYesod "PathPieceStudy" [parseRoutes| / HomeR GET /show/#Text ShowR GET /show_directly/#Text ShowDirectlyR GET /show_list/*Texts ShowListR GET /factorial/#Integer FactorialR GET |] instance Yesod PathPieceStudy {- それぞれのパスへのアクセスを処理するハンドラを定義。 getHomeR については @{…}記法でリソースに対してパラメータを渡す方法に注意。 こうすることでYesod側で自動生成しているリソースのデータ・コンストラクタに 引数を与えているっぽい。 -} getHomeR :: Handler Html getHomeR = defaultLayout $ do [whamlet| <h1>Home <ul> <li> <a href=@{ShowR (head foos)}>show/foo <li> <a href=@{ShowR "こんにちは"}>show/こんにちは <li> <a href=@{ShowDirectlyR "こんにちは"}>show_directly/こんにちは <li> <a href=@{ShowListR (take 3 foos)}>show_list/foo/bar/baz <li> <a href=@{FactorialR 5}>factorial/5 <li> <a href=@{FactorialR 10}>factorial/10 |] where foos = map T.pack ["foo", "bar", "baz", "..."] {- PathPieces付きで定義されたリソースに対応するハンドラは、 PathPiecesとして定義されたパラメータを受け取る型定義を持つことになる。 ShowRリソースに対応するgetShowRハンドラの型はText -> Handler Htmlであり、 getShowListRリソースに対応するget getShowListRハンドラの型は [Text] -> Handler Htmlとなっている。 -} getShowR :: Text -> Handler Html getShowR x = defaultLayout [whamlet| <h1>show x = #{show x} <p>#{loremIpsum1000} <a href=@{HomeR}>return to home. |] getShowDirectlyR :: Text -> Handler Html getShowDirectlyR x = defaultLayout [whamlet| <h1>x = #{x} <p>#{loremIpsum1000} <a href=@{HomeR}>return to home. |] getShowListR :: [Text] -> Handler Html getShowListR xs = defaultLayout [whamlet| <h1>show xs = #{show xs} <p>#{loremIpsum1000} <a href=@{HomeR}>return to home. |] {- ところでgetFactorialRハンドラは0や1は受け取るけれど、-1は受け取らない。 数字の前に文字列があるとFactorialRの定義(/factorial/#Integer) にマッチしないらしい。 加えて、ブラウザから「/factorial/0.1」や「/factorial/2.4」、 「/factorial/100,000」といったパスでアクセスした場合には、 getFactorialRが呼び出されるけれど、ドットやカンマ以降の英数字は単に無視される。 -} getFactorialR :: Integer -> Handler Html getFactorialR n = defaultLayout [whamlet| <h1>factorial n = #{result n} <p>#{loremIpsum1000} <a href=@{HomeR}>return to home. |] where factorial n = if n <= 1 then 1 else n * factorial (n - 1) result n = if n < 10 then show (factorial n) else "too big!" {- 何となく寂しいページになるのが嫌だったのでLorem ipsumも定義…。 -} loremIpsum1000 :: Text loremIpsum1000 = "Lorem ipsum dolor sit amet, consectetur..." {- Warpサーバを立ち上げるmainを定義。 -} main :: IO () main = warp 3000 PathPieceStudy