Web開発のためのErlang(1)->知人;



データベースの継続と2番目の記事で展開します



ErlangでのWeb開発に関する一連の記事を公開し始めています。 多くの人々はErlangを試してみたいと思っていますが、入門コースは主に機能言語としてのErlangに関するものであり、実際のプロジェクトとは程遠いという問題に直面しています( Learn You Some Some Erlang for good! 一方、すべてのWeb開発チュートリアルは、読者がすでにErlangをよく知っていることを意味します。



この一連の記事は、Web開発(PHP、Ruby、Java)の経験はあるが、Erlang開発の経験はない開発者向けに設計されています。



タスクはブログを作成することです。 記事のコードはhttps://github.com/denys-potapov/n2o-blog-exampleで、完成したプロジェクトはhttp://46.101.118.21:8001/で見ることができます。 プロジェクトの特徴:



プロジェクトの中心はn2o花火です。 選択は非常に主観的ですが、生きているErlangフレームワークの中で 、n2oは私にとって最も「Erlangに似ている」ように見えましたが、ChicagoBossは他の言語のMVCフレームワークに似ています。



環境をカスタマイズする



Ubuntuで環境を構成しますが、他のOSでも同様に機能するはずです。 Erlangの最新バージョンwww.erlang-solutions.com/resources/download.htmlをダウンロードしてインストールします。



依存関係マネージャー



Erlangの標準的な依存関係マネージャーはrebarです。 しかし、この記事では、鉄筋の設定と互換性があり、動作が速く、テンプレートの変更を追跡できるn2oの作成者のmadを使用します。

curl -fsSL https://raw.github.com/synrc/mad/master/mad > mad chmod +x mad sudo cp mad /usr/local/bin/
      
      





madファイルへの変更を追跡するには、inotify-toolsをインストールする必要があります。

 sudo apt-get install inotify-tools
      
      





アプリケーションのバックボーンを生成して起動します。

  mad app "blog" cd blog mad deps compile plan repl
      
      





http:// localhost:8001 /でチャットが開き、Webソケット上でリアルタイムに更新され、さまざまなウィンドウから自分とチャットできます。







Madパラメーターは、依存関係の取得とアプリケーションの起動を担当します。





プロジェクト構造



プロジェクトのファイル構造は、Erlangアプリケーションの標準です。

 ├──アプリ
     ├──rebar.config
     └──サンプル
         ├──ebin
         │├──...
         ├──priv
         │├──静的
         ││...
         │└──テンプレート
         │└──index.html
         ├──rebar.config
         └──src
             ├──index.erl
             ├──routes.erl
             ├──sample.app.src
             └──sample.erl
 ├──デプス
 ├──rebar.config
 └──sys.config


構造に関する詳細は、 公式文書に記載されています

後ほど、ほぼすべてのファイルとフォルダーに精通しますが、今のところ、Erlangアプリケーションは通常、appsフォルダーにあるいくつかのアプリケーションで構成されていることを知る必要があります。 サンプルアプリケーションが1つあります。





最初のコード



不要なファイルを削除します。

 rm -r apps/sample/priv/static/
      
      





テンプレートには、Django Template LanguageのErlang実装であるErlyDTLを使用します。 したがって、構文はDjangoのようなテンプレートエンジン(Django、Twig、Mustache)に精通している人には明らかです。



アプリ/サンプル/ priv /テンプレート/ base.html
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}Erlang blog example{% endblock %}</title> <!-- Bootstrap --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="//oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="//oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <style> .container { max-width: 40em; } </style> </head> <body> <div class="container"> {% block content %}{% endblock %} </div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> </body> </html>
      
      









アプリ/サンプル/ priv /テンプレート/ index.html

 {% extends "base.html" %} {% block title %}Latest posts{% endblock %} {% block content %} <h1>Latest posts</h1> {{ posts }} {% endblock %}
      
      





index.erlを開き、コードを次のように置き換えます。

 -module(index). -compile(export_all). -include_lib("n2o/include/wf.hrl"). -include_lib("nitro/include/nitro.hrl"). main() -> #dtl{file="index"}.
      
      





ファイルヘッダーでは、モジュールを宣言し、このモジュールからすべての関数をエクスポートすることを示し、2つのヘッダーファイルを含めます。



main / 1関数は、メインページが開かれたときに呼び出されます。 関数は、すぐにHTMLを返すか、DSL Erlangレコードを返すことができます。これについては後で説明します。 現時点では、レンダリングされたインデックステンプレートを返すだけです。 Erlangのドキュメントでは、関数は常にname / multiplicityとして記述されますここで、multiplicityは引数の数です



構文を知る



今こそ、構文の基本を理解する時です;これはwww.tryerlang.orgで最も迅速に行われます。 メインページにすべての投稿を表示します。 データベースは使用しませんが、投稿をコードに直接保存します。



ヘッダーファイル/apps/sample/include/records.hrlで、投稿を保存するためのエントリを記述します。

 -record(post, {id, title, text, author}).
      
      





投稿を保存するためのモジュール/apps/sample/src/posts.erlを作成します。 モジュールは2つの関数をエクスポートします。get / 0-すべての投稿を返し、 get / 1 -Idによる投稿を返します。

 -module(posts). -export([get/0, get/1]). -include("records.hrl"). get() -> [ #post{id=1, title="first post", text="interesting text"}, #post{id=2, title="second post", text="not interesting text"}, #post{id=3, title="third post", text="very interesting text"} ]. get(Id) -> lists:keyfind(Id, #post.id, ?MODULE:get()).
      
      







Erlangのレコードは構文上の砂糖であり、コンパイラはレコードをタプルに、フィールドをインデックスに置き換えます。 たとえば、#post.idは0に置き換えられます。



DSL



上で書いたように、関数はHTMLに変換されたErlangレコードを返すことができます。 index.erlを変更して、ページにすべての投稿のリストが表示されるようにします。

 -module(index). -compile(export_all). -include_lib("n2o/include/wf.hrl"). -include_lib("nitro/include/nitro.hrl"). -include_lib("records.hrl"). posts() -> [ #panel{body=[ #h2{body = #link{body = P#post.title, url = "/post?id=" ++ wf:to_list(P#post.id)}}, #p{body = P#post.text} ]} || P <- posts:get()]. main() -> #dtl{file="index", bindings=[{posts, posts()}]}.
      
      





投稿ページを作成するには、パスを処理するモジュールを/apps/sample/src/routes.erlで指定します。

 route(<<"post">>) -> post;
      
      





apps / sample / src / post.erlモジュールは、投稿データを含むテンプレートを表示するだけです:

モジュール

 -module(post). -compile(export_all). -include_lib("n2o/include/wf.hrl"). -include_lib("records.hrl"). main() -> {Id, _} = string:to_integer(binary_to_list(wf:q(<<"id">>))), Post = posts:get(Id), #dtl{file="post", bindings=[{title, Post#post.title}, {text, Post#post.text}]}.
      
      





テンプレート:

 {% extends "base.html" %} {% block title %}{{ title }}{% endblock %} {% block content %} <h1>{{ title }}<br /> <small>by {{ author }}</small> <p>{{ text }}</p> <h3>Comments</h3> {{ comments }} {% endblock %}
      
      







Webソケット



ここで最も興味深いのは、ブラウザとWebソケットを介したサーバーとの接続です。 投稿にコメントを作成し、リアルタイムで更新します。 これを行うには、ベーステンプレートにn2o初期化ライブラリを追加します。

  <script>{{script}}</script> <script src='/n2o/protocols/bert.js'></script> <script src='/n2o/protocols/client.js'></script> <script src='/n2o/protocols/nitrogen.js'></script> <script src='/n2o/validation.js'></script> <script src='/n2o/bullet.js'></script> <script src='/n2o/utf8.js'></script> <script src='/n2o/template.js'></script> <script src='/n2o/n2o.js'></script> <script>protos = [ $bert, $client ]; N2O_start();</script>
      
      





また、post.erlモジュールで、イベントハンドラーとコードを追加してコメントを表示します。

 main() -> Id = wf:to_integer(wf:q(<<"id">>)), Post = posts:get(Id), #dtl{file="post", bindings=[{title, Post#post.title}, {text, Post#post.text}, {comments, comments()}]}. comments() -> [#textarea{id=comment, class=["form-control"], rows=3}, #button{id=send, class=["btn", "btn-default"], body="Post comment",postback=comment,source=[comment]} ]. event(comment) -> wf:insert_bottom(comments, #blockquote{body = #p{body = wf:html_encode(wf:q(comment))}}).
      
      





ボタンが表示されたら、トリガーされるイベント(ポストバック)とサーバーに送信されるパラメーター(ソース)を示します。 イベント(コメント)関数では、リストの下部にコメントを追加するコードをクライアントに送信します。 このコメントは他のクライアントには届きませんが、修正します。

 event(init) -> wf:reg({post, post_id()}); event(comment) -> wf:send({post, post_id()}, {client, wf:q(comment)}); event({client, Text}) -> wf:insert_bottom(comments, #blockquote{body = #p{body = wf:html_encode(Text)}}).
      
      





ページがロードされるとinitイベントが発生し、プール{post、post_id()}からメッセージを受信するプロセスを登録します。



イベントイベント(コメント)にコメントを表示する代わりに、新しいコメントを含むメッセージをプールに送信します。 そして、コメント出力はイベントハンドラー({client、Text})で行われます。 これで、投稿の下で楽しいチャットができ、アプリケーションのバックボーンとしてmadを生成したコードをほぼ繰り返しました。



次の記事では、投稿とコメントをデータベースに保存し、Facebook経由で承認を追加します。



All Articles