macOS
$ curl -sSL https://get.haskellstack.org/ | sh
Windows
下記サイトよりインストーラーをダウンロード
Get Started with Haskell WindowsLinux
$ wget -qO- https://get.haskellstack.org/ | sh
詳しくは下記サイトを参照
Get started with Haskellよりシンプルにするために、プロジェクトを手動で作ります。
$ mkdir yesod-web
$ cd yesod-web
$ mkdir src
「yesod-web」プロジェクト内に、次の内容の「yesod-web.cabal」というファイルを 作ります。
name: yesod-web
version: 0.1.0.0
category: Web
build-type: Simple
cabal-version: >=1.10
executable yesod-web
main-is: Main.hs
build-depends: base >=4.10 && <4.11
, yesod
, text
, time
, yesod-form
hs-source-dirs: src
default-language: Haskell2010
「yesod-web」プロジェクト内の「src
」ディレクトリ内に、
次の内容の「Main.hs
」というファイルを作ります。
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} import Control.Applicative ((<$>), (<*>)) import Data.Text (Text) import Data.Time (Day) import Yesod import Yesod.Form.Jquery data App = App mkYesod "App" [parseRoutes| / HomeR GET /person PersonR POST |] instance Yesod App -- 標準の英語のメッセージを使用するようにアプリケーションに指示します。 -- 国際化が必要な場合は、代わりに翻訳機能を提供することができます。 instance RenderMessage App FormMessage where renderMessage _ _ = defaultFormMessage -- そしてjQueryライブラリの場所を教えてください。 デフォルトを使います。 -- これはGoogle CDNを指しています。 instance YesodJquery App -- フォームから受け取りたいデータ型 data Person = Person { personName :: Text , personBirthday :: Day , personFavoriteColor :: Maybe Text , personEmail :: Text , personWebsite :: Maybe Text } deriving Show personForm :: Html -> MForm Handler (FormResult Person, Widget) personForm = renderDivs $ Person <$> areq textField "Name" Nothing <*> areq (jqueryDayField def { jdsChangeYear = True -- give a year dropdown , jdsYearRange = "1900:-5" -- 1900 till five years ago }) "Birthday" Nothing <*> aopt textField "Favorite color" Nothing <*> areq emailField "Email address" Nothing <*> aopt urlField "Website" Nothing -- GETハンドラはフォームを表示します getHomeR :: Handler Html getHomeR = do -- 表示するフォームを生成する (widget, enctype) <- generateFormPost personForm defaultLayout [whamlet| <p> 生成されたウィジェットはフォームの内容のみを含みます。 フォームタグ自体ではありません。 <form method=post action=@{PersonR} enctype=#{enctype}> ^{widget} <p>送信ボタンも含まれていません。 <button>Submit |] -- POSTハンドラがフォームを処理します。 -- 成功した場合は、解析されたPersonが表示されます。 -- それ以外の場合は、エラーメッセージとともにフォームを再度表示します。 postPersonR :: Handler Html postPersonR = do ((result, widget), enctype) <- runFormPost personForm case result of FormSuccess person -> defaultLayout [whamlet|
#{show person}|] _ -> defaultLayout [whamlet| <p>Invalid input, let's try again. <form method=post action=@{PersonR} enctype=#{enctype}> ^{widget} <button>Submit |] main :: IO () main = warp 3000 App
ビルド
$ stack init
$ stack build
初回のビルドは「Yesod」の開発環境と実行環境をインストールするため、 非常に時間がかかります。2回目からのビルドはすぐに終わります。 「stack init」は、初回の1回だけで構いません。
なお、「Yesod」のオフィシャルページでは、「Yesod コマンド」 をインストールしなければならないことになっていますが、 インストールしなくても問題なくビルドできます。 もしビルドできない場合は次のようにして、 「yesod コマンド」をインストールしてください。
$ stack install yesod-bin
インストールには、すごく時間がかかります。
実行
$ stack exec yesod-web
ブラウザを起動して「https://localhost:3000/
」
へアクセスすると次のように表示されます。
日本語も入力できますが、送信後は正しく表示されません。
終了させるには、 ターミナルで、Controlキーを押しながらc
を押します。
^C
Main.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Applicative
import Data.Text (Text)
import Yesod
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App
instance RenderMessage App FormMessage where
renderMessage _ _ = defaultFormMessage
data Person = Person
{ personName :: Text
, personAge :: Int
}
deriving Show
personForm :: Html -> MForm Handler (FormResult Person, Widget)
personForm extra = do
(nameRes, nameView) <- mreq textField "this is not used" Nothing
(ageRes, ageView) <- mreq intField "neither is this" Nothing
let personRes = Person <$> nameRes <*> ageRes
let widget = do
toWidget
[lucius|
##{fvId ageView} {
width: 3em;
}
|]
[whamlet|
#{extra}
<p>
Hello, my name is #
^{fvInput nameView}
\ and I am #
^{fvInput ageView}
\ years old. #
<input type=submit value="Introduce myself">
|]
return (personRes, widget)
getHomeR :: Handler Html
getHomeR = do
((res, widget), enctype) <- runFormGet personForm
defaultLayout
[whamlet|
<p>Result: #{show res}
<form enctype=#{enctype}>
^{widget}
|]
main :: IO ()
main = warp 3000 App
「yesod-web.cabal」は「サンプル 1」と同じものを使います。
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} import Control.Applicative import Data.Text (Text) import Yesod data App = App mkYesod "App" [parseRoutes| / HomeR GET /input InputR GET |] instance Yesod App instance RenderMessage App FormMessage where renderMessage _ _ = defaultFormMessage data Person = Person { personName :: Text , personAge :: Int } deriving Show getHomeR :: Handler Html getHomeR = defaultLayout [whamlet| <form action=@{InputR}> <p> My name is <input type=text name=name> and I am <input type=text name=age> years old. <input type=submit value="Introduce myself"> |] getInputR :: Handler Html getInputR = do person <- runInputGet $ Person <$> ireq textField "name" <*> ireq intField "age" defaultLayout [whamlet|
#{show person}|] main :: IO () main = warp 3000 App
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Applicative
import Data.Text (Text)
import Data.Time
import Yesod
newtype UserId = UserId Int
deriving Show
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET POST
|]
instance Yesod App
instance RenderMessage App FormMessage where
renderMessage _ _ = defaultFormMessage
type Form a = Html -> MForm Handler (FormResult a, Widget)
data Blog = Blog
{ blogTitle :: Text
, blogContents :: Textarea
, blogUser :: UserId
, blogPosted :: UTCTime
}
deriving Show
form :: UserId -> Form Blog
form userId = renderDivs $ Blog
<$> areq textField "Title" Nothing
<*> areq textareaField "Contents" Nothing
<*> pure userId
<*> lift (liftIO getCurrentTime)
getHomeR :: Handler Html
getHomeR = do
let userId = UserId 5 -- again, see the authentication chapter
((res, widget), enctype) <- runFormPost $ form userId
defaultLayout
[whamlet|
<p>:Previous result: #{show res}
<form method=post action=@{HomeR} enctype=#{enctype}>
^{widget}
<input type=submit>
|]
postHomeR :: Handler Html
postHomeR = getHomeR
main :: IO ()
main = warp 3000 App