プログラミング芸術論スマートフォン用の表示で見るプログラミング芸術論この広告は、90日以上更新していないブログに表示しています。Web前回の記事HaskellでYesodを使ってWebアプリケーションを作ってみている際のメモ記事です。間が開いてしまいましたが、前回はディレクトリ構造のチェックとトップページ・コンタクトページへのルートの追加を行いました。ウィジェット今回は前回作ったトップページとコンタクトページをそれなりの見た目に整形していこうと思います。DSLの構文を見る前に、Yesodでのビューの扱い方について少し知っておく必要がありました。Yesodでは他のフレームワークとは少し違う、ウィジェットと呼ばれる概念を使ってページの構成を行なっています。ウィジェットはページテンプレートで扱うコンテンツの柔軟性を向上し、テンプレートファイルを複数に分割したり、例外的なビューを作るたびにテンプレートファイル内に分岐を追加するようなことを防いでくれる、シンプルですが非常に有用な概念です。ウィジェットではページのコンテンツを以下の7種類に分類して保持します。ページタイトル外部スタイルシート外部JavaScriptスタイルシートファイルJavaScriptファイルHEADタグ内のコンテンツBODYタグ内のコンテンツHamletなどで作成したページコンテンツはtoWidget関数を用いるだけでウィジェットに変換することができ、その際にちゃんとCassiusやLuciusのデータはSTYLEタグで囲まれ、JuliusのデータはSCRIPTタグで囲まれます。toWidget関数ではデフォルトで、CassiusやLuciusのデータはHEADタグ内のコンテンツ、HamletやJuliusのデータはBODYタグ内のコンテンツとしてウィジェットに変換しますが、代わりに以下の関数を用いることで、変換する種類を特定できます。Bodyタグ内のコンテンツちなみに、「外部〜」と「〜ファイル」は、指定するURLが外部の絶対URLであるかプロジェクト内のルートであるか、というだけの違いです。それで、これをどう使うか、ですが、ここで前回さらっと流してしまったdefaultLayout関数もう一度見てみます。"templates/default-layout-wrapper.hamlet")なお、この中のwidgetToPageContentは大体以下の様な定義の関数です。pc}という行があります。defaultLayout関数はwidgetToPageContent関数に全てのウィジェットを生成するdo構文の式を適用して、ページのコンテンツとして埋め込める形にウィジェット達を整形してpcという変数へ束縛し、その整形結果を埋め込むよう目論んだtemplates/default-layout-wrapper.hamletを変数pcのスコープ内でwithUrlRenderer関数に適用することで、その式が評価された時にはバラバラに追加されたウィジェット達がレイアウトの中に整然と並ぶよう仕向けているのです。上の7つの関数の使い所はわかりづらいので、defaultLayout関数の呼び出し元も確認してみます。前回書いたHandler/Home.hsと、補足としてtemplates/default-layout.hamletも以下に貼り付けました。"home/index")という式はdefaultLayout関数内でwidgetという変数に束縛され、それがdefaultLayout関数内のdo構文の中で展開されているtemplates/default-layout.hamletの中に埋め込まれています。defaultLayout関数の引数として先の関数達をつなげたdo構文を渡せば、それが最終的なHTMLにもうまく反映される、ということです。実際にHandler/Home.hsとHandler/Contact.hsを編集してみます。"contact/index")ちゃんとタイトルが付いたかと思います。これらのことはRoRなどでもできないことはありませんが、遅延評価とモナドの力がなければこれほど自然には書けず、多くの暗黙的ルールをドキュメントで学ばないと使いこなせない代物になってしまっていたのではないでしょうか。Hamletの構文YesodではHTMLのテンプレート言語としてHamletを用いているので、まずはその構文をについて知る必要があります。Templatesの項に書いありますが、Hamletの特徴としては大体以下のような点があるように思いました。インデントでタグのスコープを見るために閉じタグが要らない型安全にHaskellの値を埋め込むことができる呼び出されたスコープを引き継ぐ(引数で渡したりすることなく、束縛されている値や関数を参照できる)手続き的なディレクティブで分岐やループ、パターンマッチを扱える1つめはそのままですが、2つめの埋め込める値は文字列や数字だけでなく、ToHtmlクラスのインスタンスとなっている全ての型の値となります。ToHtmlクラスの型はtoHtml関数とfromHtml関数でHtml型と行き来できる必要があります。3つめはこれまで見てきたコードからも分かる通り、テンプレートファイル内のスコープはそのテンプレートが展開される関数のスコープに属することを表します。RoRでは呼び出したコントローラを表現するクラスがスコープとなっていたので、クラス変数の汚染があり、特定のアクションのための変数を他のアクションから分離できませんでした。それを、そもそもHaskellではそういったスコープが存在しないので、普通にしていると引数を使う必要が出てきますが、TemplateHaskellでHamletファイルを評価する関数を呼び出したスコープのクロージャにすることでいいとこ取りをした、ということですかね。4つめが非常に煩雑なのですが、Hamletでは分岐やループ、パターンマッチといった構文を必要とする動的なコンテンツの挿入に$記号から始まる特殊なディレクティブを用います。Syntaxの項に網羅されているので、ここでは今後出てきた都度に紹介する形にしようかと思います。HamletではHTMLをそのまま書くよりもIDやクラス、その他の属性値を簡単に設定できるようになっていますが、これらも今後出てきた際に都度紹介します。レイアウトファイルの移動さて、説明が長くなってしまいましたが、Hamletを用いたコーディングの方法がだいたいわかったので、主にレイアウトファイルをいじって、前回作成したトップページとコンタクトページをまあまあまともなページにしてみたいと思います。ディレクトリ階層が浅いと後々不便になるかと思うので、レイアウト用のHamletファイルをlayoutディレクトリ以下に移動し、名前も分かりやすいものに変更します。layout/wrapper.hamletこの変更にともなって、Foundation.hsの中のdefaultLayout関数で指定しているファイル名を変更する必要があります。develのプロセスがカタカタと動いてリビルドした上でエラーがあったら提示してくれるというのは、RoRでGuardを使ってテスト駆動開発をしている時と同じくらいの快適さと安心感ですね。テストコードは1行も書いていないというのに...。こんなんだったら、ユニットテストなどほとんど必要なくなるように思えます。次に、ずっと放置していましたがこの際なので、Normalize.cssを最新版にバージョンアップします。ついでにBootstrap.jsもバージョンアップしようかと思いましたが、個人的にこれが入るとCSSが格段に書きづらくなるため、ひとまずBootstrap.jsは便利なGlyphicon部分だけ残して、後は削除してしまうこととしました。本記事を描いた時点でNormalize.cssはバージョン3.0.1、Bootstrap.jsはバージョン3.2.0でした。各サイトからファイルをダウンロードして、Bootstrap.jsはコピーライト表示とGlyphiconに関する部分だけを抜き出したファイルを作成し、必要なファイルをstaticディレクトリ以下に配置します。筆者のstaticディレクトリ内は以下の様になりました。filesこれに伴ってFoundation.hsのdefaultLayout関数の中身を再び多少変更します。"templates/layout/wrapper.hamlet")このcombineStylesheetsおよびcombineScripts関数はSettings/StaticFiles.hsで定義されています。combineSettingsまた、その上のコメントに書かれている通り、css_normalize_cssやcss_glyiphicon_cssはSettings/StaticFiles.hsをコンパイルした際に定義される、静的ファイルのパスを表現する変数です。develのプロセスを起動しっぱなしにしている場合、staticディレクトリ以下の変更だけではSettings/StaticFiles.hsはリビルドされないため、Vimでファイルを開いて:wで保存するなどしないと、上の変更はエラーになります。buildコマンドをプロジェクトルートで走らせます。おわりにHamletファイルとCassiusファイルを編集してそこそこ使い物になりそうなレイアウトを作るところまで行くつもりでしたが、思いの外説明が長くなってしまったのでここで一度記事を切ろうかと思います。次回はレイアウトをして、静的なWebページとして公開できるくらいまでアプリケーションの完成度を高めます。»プロフィールid:demmy_s全く的はずれなことをしている場合もあるかもしれませんが、プログラミングなどについてWeb上のリソースを少しでも増やせたらと思い、自分のメモをブログという形で公開することにしました。(2)月別アーカイブ参加グループプログラミングはてなブログをはじめよう!demmy_sさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。