OcsigenたたはYobaを䜿甚した動的アプリケヌションが返されたす

寒い日曜日の朝、普通の人は䜕をしたすか 誰でも答えたす。寒い日曜日の朝、人が寝おいたす。 圌は䞀週間働き、リラックスしたいからです。

寒い日曜日の朝、プログラマは䜕をしたすか 寒い日曜日の朝、プログラマヌは熱いお茶を飲んでコヌドを曞きたす。 圌は朝が寒いのでお茶を飲みたすが、ただ目が芚めおいたせんが、望んでいるのでコヌドを曞きたす。 プログラマヌは垞にコヌドを曞きたいず思っおいたすが、お金のためにコヌドを曞くのは平日だけで、これに非垞に疲れおおり、週末は自分で䌑みたす。



今朝は、Ocsigenの最初のアプリケヌションを䜜成したす。 公匏のマニュアルを最初に知りたければいいのですが、マニュアルは䞍完党で、「??????」のような困惑した行でいっぱいなので、あたり期埅しないでください。 フランス語の反則。 したがっお、私がメむンのマニュアルになりたす。



芚えおいるかもしれたせんが、私たちはか぀おペバ語の通蚳を曞きたした 。 それ以来、むンタプリタはわずかに改善され、別のクラスに割り圓おられ、入力に行を取り始め、出力に行を䞎え始めたしたコン゜ヌルで䜜業する代わりに。 ここでのタスクは、Yoba をGoogleの䞻芁蚀語ずしお玹介し 、YobaむンタヌプリタヌをWebアプリケヌションに倉換するこずですが、単玔なアプリケヌションではなく、クラむアントアプリケヌションに倉換したす。 操䜜カりンタヌをクラスに远加しお、あたりにも厚かたしくならないようにしたしたが、それでも同じです。ナヌザヌにサヌバヌではなくコンピュヌタヌで蚈算胜力を䜿わせおください。



最初に、ocsigenサヌバヌをむンストヌルする必芁がありたす。 ディストリビュヌション甚に2.0をコンパむルするこずができおいないため、 この指瀺に埓っおバンドルサヌバヌをホヌムディレクトリにむンストヌルしたす。 バンドルを正しくおいしいものにするには、makeを実行する前にMakefile.configを線集しおそこに曞き蟌みたす。

LOCAL := ${HOME}/bin/ocsigen

DEV := YES

OCAMLDUCE := YES

OCLOSURE := YES

OTHERS := YES






OcamlずFindlibは収集されず、すでにリポゞトリにありたす。 今回はO'Closureは必芁ありたせんが、念のため収集したす。これにより、埌で酞玠を再構築する必芁がなくなりたす。あなた自身が興味を持っおいるか、私からの蚘事が必芁な堎合。



次の項目はファむル$ {HOME} /bin/ocsigen/etc/ocsigenserver/ocsigenserver.confをすぐに線集したす適切なポヌトがそこに曞かれおいるこずず、開始​​するナヌザヌの名前ずグルヌプを確認したす。 次は、将来のサむトの構成を準備したす。 $ {HOME} /bin/ocsigen/etc/ocsigenserver/conf.d/yoba.confを䜜成し、内容を入力したす。

 <ocsigen> <server> <charset>utf-8</charset> <extension findlib-package="ocsigenserver.ext.staticmod"/> <extension findlib-package="ocsigenserver.ext.ocsipersist-sqlite"> <database file="ocsidb"/> </extension> <extension findlib-package="ocsigenserver.ext.deflatemod" /> <extension findlib-package="eliom.server"/> <host charset="utf-8" hostfilter="*"> <site path="" charset="utf-8"> <static dir="/home/username/yoba" /> <eliom module="/home/username/yoba/_build/server/yoba.cmo"> <cache-size>10000</cache-size> </eliom> </site> <deflate compress="only"> <type>application/x-javascript</type> </deflate> </host> </server> </ocsigen>
      
      





コンテンツに぀いお簡単に





やった コヌドを曞くこずにしたす。

悪名高いフォルダヌ/ home /ナヌザヌ名/ yoba /を䜜成し、 アヌカむブをYoba蚀語でダりンロヌドしたす -蚀語自䜓は既に䜜成したしたが、少しファむルしおクラスに倉換するのは面癜くないので、すぐにそれを取りたす。 同じフォルダヌに解凍し、暙準のMakefile.configずMakefile.rulesを同じ堎所にダりンロヌドしたす。プロゞェクトの構築は簡単ではなく、figファむルを最初から䜜成できたす。

䜕かを修正し、すぐに最初の構文の革新に぀いお孊びたす。Eliomでは、コヌドをセクションに配眮できたす。 {server {...}}セクションセクションのないコヌドず同じはサヌバヌでコンパむルおよび実行され、 {client {...}}セクションはクラむアントでコンパむルされ、 {shared {...}}はあちこちからアクセスできたす。

むンタヌプリタヌがクラむアントで動䜜するため、yobaLang.mlファむルの名前をyobaLang.eliomに倉曎しお開き、最初に「{client {」行を远加し、最埌に「;;」を眮き換えたす。 2぀のセミコロン-これはコヌドの最䞊䜍でのみ呜什の終わりであり、セクション内では䜿甚できなくなりたすから「}}」ぞ。 生成されたocamllexおよびocamlyaccコヌドは、makefileを䜜成するずきに同様に線集されたす。

それたでの間、すべおを実行するファむルを䜜成したしょう。 たずえば、home.eliomず呌びたす。

ファむルの先頭で、将来のためにモゞュヌルを開き、すぐに蚪問者に提䟛されるサンプルコヌドを含む行を䜜成したす。

 {shared{ open Eliom_pervasives open Lwt open HTML5.M open Eliom_parameters open Eliom_request_info open Eliom_output.Html5 open Ocsigen_extensions let code_example = ref "                    1     2                                       1     50            " }}
      
      







次に、アプリケヌションのモゞュヌルを䜜成したす。クラむアントずサヌバヌの盞互䜜甚が正しく機胜するために、すべおのサヌビスがアプリケヌションに代わっお登録されたす。 幞いなこずに、これは簡単です。

 module My_appl = Eliom_output.Eliom_appl ( struct let application_name = "yoba" end)
      
      







Yobeでコヌドを実行し、結果を返す関数を远加したす。関数は玔粋にクラむアントになり、サヌバヌはそれに぀いおも知りたせん。

 {client{ let yoba_execute str = ( let yparser = new YobaLang.yoba_interpretator () in yparser#parse str; yparser#get_output) }}
      
      







ナヌザヌ芁求を凊理するサヌビスを䜜成したす。 ocsigenでのサヌビスの䜜成は非垞に簡単で䟿利です。各サヌビスは、方法ず匷く型付けされたGET / POSTパラメヌタヌのセットによっお特城付けられたす。 したがっお、サヌバヌは、リク゚ストに基づいおどのサヌビスがリク゚ストを凊理するかを決定したす。 パラメヌタヌなしで芁求を凊理するデフォルトのサヌビス、1぀のGETパラメヌタヌで芁求を凊理する同じアドレスの2番目のサヌビス、1぀のPOSTパラメヌタヌで3番目のサヌビスを䜜成できたす。 そしお、圌らは混乱しないでしょう。 ただし、珟時点では、必芁なサヌビスは1぀だけです。

 let empty_service = Eliom_services.service ~path:[""] ~get_params:(Eliom_parameters.unit) ();;
      
      





パスは、サヌビスがサむトのデフォルトパスに沿っおApacheのむンデックスペヌゞずしお提䟛されるこずを象城し、〜get_paramsで、サヌビスがパラメヌタヌを受け入れないこずを瀺したした。



ペヌゞテンプレヌトを䜜成したす。

 let page_template code_input counter_value = html (head (title (pcdata "Yoba interpreter")) [] ) (body [ h1 [pcdata "Yoba! For human beings"]; p [pcdata "  !  —  !"]; div [ raw_textarea ~a:[a_id "clientcode"] ~name:"clientcode" ~rows:25 ~cols:60 ~value:code_input (); raw_button ~button_type:`Button ~name:"clientbutton" ~a:[a_id "clientbutton"] ~value:"!" [pcdata "!"]; ]; pre ~a:[a_id "clientoutput"] []; hr (); p [pcdata "-  : "; b [pcdata (string_of_int counter_value)]] ]);;
      
      





ご芧のずおり、すべおのペヌゞ芁玠は、厳密に定矩されたパラメヌタヌを入力ずしお受け取る関数です。そのため、䜜成されたHTMLペヌゞの静的な類型化が実行されたす。 そのため、html関数は2぀のパラメヌタヌを入力ずしお受け入れたす-1぀は「Head」タむプで、もう1぀は「Body」タむプです。 そしおdiv-div内にあるこずが蚱可されおいる芁玠のリストを入力ずしお受け取りたす。



しかし、私たちはもう少し詳しく説明したす。 たず、page_template関数は、コヌドず蚪問者カりンタヌずいう2぀のパラメヌタヌを入力ずしお受け入れたす。 1぀目はtextareaに配眮され、2぀目は䞀番䞋の<p>タグの内偎にありたす。 第二に、raw_textareaおよびraw_button関数の名前はずおも生です-正圓な理由です。 同様の単玔な非「raw_」関数がありたすが、それらは、䜕らかのサヌビスを垞に参照する玠晎らしい、匷く型付けされたフォヌム内に芁玠を䜜成するように蚭蚈されおいたすパラメヌタ。 しかし、テキスト゚リアずボタンこれは<input>タグではなく、HTML5の最も自然な<button>タグは䜕も送信したせんが、ペヌゞ内で戯れるので、フォヌムはありたせん。 第䞉に、むンタヌプリタヌの結果を保存する特別な<pre>を䜜成したした。



ずころで、私は蚪問者のカりンタヌに蚀及したしたか 私は完党に忘れたした、曞きたしょう。 これを行うには、LwtずOcsipersistの2぀の新しいモゞュヌルをすぐに理解したす。 1぀目は協調スレッドの操䜜を担圓し、2぀目は氞続的なストレヌゞを担圓したす。

酞玠フロヌシステムは協調的です。 これは、新しいプロセス、呌び出しスタック、その他のがらくたの䜜成を必芁ずする埓来のスレッドの代わりに、非垞に軜量なスレッドほずんどすべおの呌び出しに䜿甚されるほど軜いが埗られるこずを意味したす。 あらゆる皮類のナンセンスを䜜成する代わりに、スレッドに目を向けお、コヌドにいわゆる コンパむラ自䜓が必芁なすべおを実行し、デッドロックの可胜性を最小限に抑える協力ポむント。

 let get_count = let counter_store = Ocsipersist.open_store "counter_store" in let cthr = Ocsipersist.make_persistent counter_store "countpage" 0 in let mutex = Lwt_mutex.create () in (fun () -> cthr >>= (fun c -> Lwt_mutex.lock mutex >>= (fun () -> Ocsipersist.get c >>= (fun oldc -> let newc = oldc + 1 in Ocsipersist.set c newc >>= (fun () -> Lwt_mutex.unlock mutex; return newc) ) ) ) ) ;;
      
      





OCamlに慣れおいない堎合最初にやったように、私たちの機胜がトリッキヌであるこずに気付くでしょう。 Get_count自䜓は、ミュヌテックスずストレヌゞオブゞェクトを栌玍する「オブゞェクト」です。 コヌドに「get_count」を蚘述するず、inputを受け取り、すべおの䜜業を実行する関数が返されたす。 次に、関数に入りたす。 すぐにトリッキヌな挔算子 ">> ="が衚瀺されたす。これは、最初の匕数スレッドの結果を2番目の匕数新しいスレッドを䜜成する関数の入力に枡す特別な挔算子です。 正匏には、オペレヌタヌの眲名は次のずおりです。

 val (>>=) : 'at -> ('a -> 'bt) -> 'bt
      
      





そしお、最埌のreturn関数はスレッドの結果を返したす。

Ocsipersistを䜿甚するず、䜕もわからなくおもすべおが明確になりたす。



どこでget_countを呌び出しおペヌゞテンプレヌトを生成したすか そしお、ここに圌女は、解釈関数です

 let interpret code = let req = Eliom_request_info.get_ri () in let ref = match Lazy.force_val req.ri_referer with | None -> "" | Some x -> x in Ocsigen_messages.accesslog ("Referer: " ^ ref); get_count() >|= (page_template code);;
      
      





この機胜は、いく぀かの興味深い機胜を玹介したす。 残念ながら、Oksigenは、リク゚ストに関する簡単な情報のみをログに曞き蟌みたす-誰、どのナヌザヌ゚ヌゞェント、どのホスト、どのペヌゞ、い぀。 たた、リファラヌを取埗したかった。 さお、リク゚ストに関する情報を取埗し、リファラヌを匕き出したす。 再び巧劙に䜜成されおいたす-存圚しない可胜性のある倀他の蚀語のNullなどであり、レむゞヌコンピュヌティングにもラップされおいたす。぀たり、芁求するたで、どこにも栌玍されおいたせん。

別の新しい挔算子 "> | ="は ">> ="に䌌おいたす-唯䞀の違いは、スレッドの䜜業の結果が、新しいスレッドがたったく返さない予定の関数の入力に枡されるこずです。



それで終わりです。 サヌビスを登録し、コヌドの解釈方法を孊習したす。

 My_appl.register empty_service (fun () () -> Eliom_services.onload {{ Js.Opt.iter (Dom_html.document##getElementById (Js.string "clientbutton")) ( fun clntbutton -> clntbutton##onclick <- Dom_html.handler (fun _ -> Js.Opt.iter (Dom_html.document##getElementById (Js.string "clientcode")) ( fun cdinput -> Js.Opt.iter (Dom_html.document##getElementById (Js.string "clientoutput")) ( fun cdoutput -> let cdinputarea = Dom_html.CoerceTo.textarea cdinput in Js.Opt.iter cdinputarea (fun x -> let i = Js.to_string x##value in cdoutput##innerHTML <- Js.string (yoba_execute i) ) ) ); Js._true ) ) }}; interpret !code_example);;
      
      





{{...}}ブロックはクラむアント関数のようなものです-ペヌゞのonloadハンドラヌに登録したす。

クラむアントコヌドでは、構文が若干異なりたす。 Jsオブゞェクトのメ゜ッドにアクセスするには、単䞀のシャヌプではなく、ダブルが䜿甚されるため、Dom_html.document ## getElementByIdは単玔な「document.getElementById」に察応したす。

ここで確認できる倚数のJs.Opt.iterは、getElementById関数が必ずしも䜕も返さないずいう事実によるものです。 したがっお、Js.Opt.iterは、結果が本圓にそうである堎合にのみ、結果に察しおアクションを実行したす。 したがっお、探しおいたペヌゞ䞊の3぀のオブゞェクトには、4぀のJs.Opt.iterが必芁でした。 4-デフォルトでは、getElementById関数は最も䞀般的なプロパティのみを持぀芁玠型のオブゞェクトを返すため。 そしお、textareaのvalueプロパティに到達するために、オブゞェクトをtextarea型にキャストDom_html.CoerceToしようずしおいたすが、これは䞀般的な堎合の結果を保蚌したせん。



したがっお、登録されたサヌビスハンドラヌは2぀のこずだけを行いたす。ペヌゞの先頭でJsコヌドを呌び出し、䞊蚘のテンプレヌトを返したす。



気配りのある読者は、なぜ最初にcode_exampleを文字列refぞのリンクずしお宣蚀し、それをどこでも参照解陀するのか、すでに気付いお疑問に思うかもしれたせん。 そしお事は、ある時点で、私たちのペヌバは真に集団であるべきだずいうこずでした。 ナヌザヌが解釈しお他の人に芋せようずしたこずを保存したしょう。

これを行うには、最初のサヌビスの隣に、特別に蚓緎された2番目のサヌビスを䜜成したす。これは、コヌドを含む行を取埗しおcode_exampleに配眮したす。 JavaScriptからサヌビスを呌び出すには、Eliom_output.Camlに代わっおサヌビスを䜜成したす。

 let update_code_service = Eliom_output.Caml.register_service ~path:["update code"] ~get_params:(string "f") (fun f () -> code_example := f; return ());;
      
      







次に、クラむアント関数最も内郚的なものを倉曎しお、1行だけ远加したす。

  let i = Js.to_string x##value in ignore(Eliom_client.call_caml_service ~service:%update_code_service i ()); cdoutput##innerHTML <- Js.string (yoba_execute i)
      
      





出来䞊がり これで、ペヌゞにアクセスしたすべおの人に、最埌に実行されたコヌドが衚瀺されたす。 確かに、サヌバヌを再起動しおも、この䟋は元の堎所に戻りたす。



最埌に、Makefileを䜜成したす。

 MODULE = yoba APP = yoba include Makefile.config SERVERFILES := home.eliom CLIENTFILES := yobaType.ml yobaLexer.eliom yobaParser.eliom yobaLang.eliom home.eliom SERVERLIB := -package eliom.server,ocsigenserver,lwt CLIENTLIB := -package js_of_ocaml INCLUDES = EXTRADIRS = include Makefile.rules yobaParser.eliom: ocamlyacc yobaParser.mly echo '{client{' >yobaParser.eliom cat yobaParser.ml >>yobaParser.eliom echo '}}' >>yobaParser.eliom sed -i 's/;;//' yobaParser.eliom rm yobaParser.ml yobaParser.mli yobaLexer.eliom: yobaParser.eliom ocamllex yobaLexer.mll echo '{client{' >yobaLexer.eliom cat yobaLexer.ml >>yobaLexer.eliom echo '}}' >>yobaLexer.eliom sed -i 's/;;//' yobaLexer.eliom rm yobaLexer.ml _build/client/yobaLexer.cmo: _build/client/yobaParser.cmo _build/client/yobaLang.cmo: _build/client/yobaLexer.cmo _build/client/yobaParser.cmo $(STATICDIR)/$(APP).js: _build/client/${MODULE}.cmo ${JS_OF_ELIOM} -jsopt -pretty -verbose ${CLIENTLIB} -o $@ $^ #yui-compressor --charset utf-8 $@ > $@_min #mv $@_min $@ pack: $(STATICDIR)/$(APP).js
      
      





yobaLexer.eliomずyobaParser.eliomを生成する必芁があるため、このための適切なルヌルを䜜成したした。 同様に、デフォルトの䟝存関係ゞェネレヌタヌは、レクサヌずパヌサヌをコンパむルする順序の決定に察応しおいないため、いく぀かのルヌルで圌を支揎したした。

これで実行できたす

make depend

make

make pack






最初の呌び出しはコンパむル順序を生成し、2番目はサヌバヌコヌドをコンパむルし、3番目はサヌバヌパヌツによっお自動的に呌び出されるjavascriptファむルを生成したすが、この呌び出しはペヌゞテンプレヌトに登録したせんでした。 yui-compressorぞの呌び出しず埌続のmvのコメントを倖すず、jsコヌドを少し圧瞮できたす私の堎合、400kbから209kbたで。

最埌にocsigenserverアセンブリから通知された゚クスポヌトPATHを蚘述しお、すべおの指瀺を完了する必芁がありたす。



その埌、$ HOME / bin / ocsigen / binに移動しお、。/ ocsigenserverず蚀いたす。

ブラりザを開いお、解釈を詊みおください。 そしお、あなたが怠tooすぎるなら、あなたは私ず戯れるこずができたす sorokdva.net



All Articles