Perlのサーバー側のJavascriptテンプレートエンジン

クライアント側とサーバー側で同じテンプレートを使用すると便利であるということから始めました( javascript template engine )。 猫は、このアプローチの既製のバージョンに涙を流しました。 血が頭に押し寄せ、私たちは決断を下すことにします。



初期データと問題の概要を説明します





テンプレートエンジンのテンプレートがあるとします。 サーバーでは、perlによって処理されます。 最終的には、利用可能なテンプレートの一部、または別のファイルに配置されていないテンプレートの一部をクライアント側で使用する必要があります。 最小限の費用(機能の損失)でhtml生成手順を再現する必要があります。 テンプレートを処理した結果、javascriptライブラリの形式で装飾された事前に指定されたテンプレートとブロックのセットを取得します。 すぐに言ってやった。



による予約...





次に、記述されたパーサーの実装例が提供されますが、サーバー言語でのパーサーの説明はまだないという修正があります...つまり、スキーム、サーバー上のテンプレート->コンパイルでのテンプレートエンジンの作業、ソースコード、およびサンプルを見ることが可能になります。 js-> JSON形式のデータに基づくHTML生成。 それでは、飛行機が離陸したら、メルレゾンバレエの第16幕に行くことができます。



何が必要ですか?





テンプレートエンジンはperlを実行しています。 必要なもの:

-テンプレートと.jsライブラリ(すべてのテンプレートを1つのファイルに収めたくない)とテンプレートエンジンに必要なデータを記述する構成ファイル。

-.pmモジュール自体。テンプレートを解析するためのさまざまなメソッドが含まれています。

-起動することにより、ライブラリをコンパイルするスクリプト。

-奇妙なことに、パターン;

要件に従って、次のファイルとディレクトリの構造が形成されます(気にしない場合は、私の人生を簡素化するためにパスを匿名のものに書き換えませんが、すぐに作業バージョンを提供します):



#

/Users/zaur/www/blacktiger

#

/Users/zaur/www/blacktiger/bin/Core/JS/Config.pm

#

/Users/zaur/www/blacktiger/bin/Core/JS/Parse.pm

#

/Users/zaur/www/blacktiger/bin/jsgen

#

/Users/zaur/www/blacktiger/tpl

/Users/zaur/www/blacktiger/inc

# ( )

/Users/zaur/www/blacktiger/source_js

# ,

/Users/zaur/www/blacktiger/js/tpl

# html ,

/Users/zaur/www/blacktiger/html




* This source code was highlighted with Source Code Highlighter .








何を実現できますか?





機能を説明する前に、実際に何が起こるかについて少し説明します。 JavaScriptコードをコンパイルしました。 さまざまな関数、演算子、条件を、文字列と変数を交互に単純に連結して呼び出すことにより、出力変数(out)の変数値が形成されます。 コードが実行されると、配列の要素を繰り返し処理し(基本的に、ハッシュの配列を順に調べ、さらに、ネストされた構造へのリンクも含みます)、現在のハッシュでスタックを埋めます。 例では、内部変数の値を出力することでこのパズルを解読しようとします。 失意しないでください。



上記のJSONデータに加えて、テンプレートに実装できるもののリストを以下に示します。

-さまざまなレベルのネストを持つ変数へのアクセス。

-配列要素の反復;

-条件文if / else if / else;

-包含物;

-テンプレート内のブロックの再利用。

-テンプレートで選択されたhtmlブロックを生成するために使用します(別のファイルを作成する必要がないという唯一の例外を除き、包含のアナログ)。



さあ始めましょう...



模様

/Users/zaur/www/blacktiger/tpl/sambuka.htm





  1. < h3 > {$ cfg.host} </ h3 >
  2. < h4 > {#title} </ h4 >
  3. < ul >
  4. {%topics}
  5. < li id = "li-{#id}" {?#id == 3 } class = "sel" {/?} > {#title} </ li >
  6. {/%topics}
  7. </ ul >
*このソースコードは、 ソースコードハイライターで強調表示されました。


JavaScriptコードとデータ:

var d1 = {

title: ' – !' ,

topics: [

{title: '' , id: 1},

{title: '' , id: 2},

{title: '' , id: 3},

{title: '' , id: 4}

]

};

var jstpl = new myfirst();

var html1 = jstpl.tpl( 'tpl_sambuka' ,d1);



* This source code was highlighted with Source Code Highlighter .






結果のhtml



< h3 > blacktiger </ h3 >

< h4 > – ! </ h4 >

< ul >

< li id ="li-1" > </ li >

< li id ="li-2" > </ li >

< li id ="li-3" class ="sel" > </ li >

< li id ="li-4" > </ li >

</ ul >



* This source code was highlighted with Source Code Highlighter .






それを理解しましょう...



テンプレートの行に沿って進みます。

1. Config.pmファイルにa%jsdハッシュがあります。 {$ cfg.host}を記述することにより、$ jsd {'host'}の値を取得します。 たとえば、{$ cfg.path.to.element}のようにこの式を複雑にする場合、値$ jsd {'path'} {'to'} {'element'}を代入します。 これは、異なるアクセスレベルの変数へのアクセスです。

2.テンプレートでは、ハッシュd1を渡しました。 この場合のエントリ{#title}は、d1.titleと同等です。 この場合、jstpl.data.cur_arg.titleは実際にそこに転送されました。

3.穏やかに、これは単純なhtmlです。

4.、6。{%topics} {/%topics}型構造に変換されました

for ( var i=0; i<d1.topics.length; i++) {

//...

}




* This source code was highlighted with Source Code Highlighter .






サービス操作、スタックへの移行、イテレータの計算などにハングアップしました。

この構成は、データオブジェクトと呼ばれます 。 これは通常、ハッシュの配列ですが、場合によっては配列の配列を使用します。 以下では、データソース、スライス、各反復で実行されるメソッドの指定を含む、オブジェクトを呼び出すための完全な構文について説明します。

5. a。 変数{#title}の呼び出しがあります。 前回とは異なり、この変数を呼び出すためのコンテキストは、トピック配列の現在の反復ハッシュです。 このコンテキスト内でd1.title値を取得する方法は? テンプレート引数 'tpl_sambuka'を使用する必要があります。{@ tpl_sambuka.title}のようになります。 変数d1.topics [i] .titleの呼び出しの完全な構文は{#topics.title}です。つまり、 常にオブジェクトの名前で始まります。 オブジェクトのネストされた要素へのアクセスは、常にオブジェクトの名前を指定することから始まります。

5. b。 if(exp){then}の条件演算子。 expとして、上記の変数を使用できます(ただし、中括弧なし)およびjavascript演算子。 そして、ここで注意する必要があります。 テンプレートはサーバー言語でも使用されるため、互換性について覚えておく必要があります。

7.そして、ここもまたhtmlであり、単なるhtmlです。



オペレーターについてもう少し


-変数、彼らが食べるものとその使用方法:

1. {$ cfg.path.to.element} $ jsd {'path'} {'to'} {'element'}へのアクセス

{#title}、{#topics.title}、{#_current.title}はすべて同じ変数への参照です

{#list.path.to.element}リストオブジェクトのネストされた要素

2. {@irow [#topics._level_irow-1] title}オブジェクトとテンプレート引数の現在のハッシュのスタック。 #topics._level_irowtopicsオブジェクトの現在のハッシュのネストレベル。 合計これはd1.title変数の値です

3.可変ループイテレーター。

{#}、{#topics。#}、{#_ iterator}、{#topics._iterator}

これらはすべて、1で始まる唯一の条件(マシンロジックではなく、人間の場合)を持つ1つの変数(サイクル内のi)の値です。つまり、インデックス0 ... 5のサイクルでは、変数は値1 ... 6を取ります。

4.完全なオブジェクト構文

{%nameobj =>#source.obj [3..5]:myloopfunction} ... {/%nameobj}

これは、オブジェクトを呼び出すための完全な構文です。

ソース(#source.obj)を指定しない場合、データは現在のハッシュの変数{#nameobj}から取得されます。

5.ブロック

タグ{@myblockname} html {/ @ myblockname}でコードをラップすると、後で同じテンプレートでこのブロック{@ block.myblockname.html}を使用できます-この場所は、タグで囲まれたものに置き換えられます以前。 同時に、.sub修飾子はフレーム付きセクションを挿入し、タグで囲まれたテンプレートを実行します。

6.外部テンプレートからのブロック

Config.pmのエントリの例

@jslib = (

{

name = > 'myfirst',

list_tpl = > [

'tpl_sambuka'

],

blocks = > {

tpl_auth = > [

'auth_form'

]

}

}

);




* This source code was highlighted with Source Code Highlighter .






tpl_authテンプレートのauth_formブロックを使用することを書きました。 テンプレートで使用できます

{@ block.tpl_auth.auth_form.html} htmlのように貼り付け

{@ block.tpl_auth.auth_form.sub}指定されたコードを実行してテンプレートに貼り付けます

6.インクルージョン

{&tpl_myother_tpl}

tpl_myother_tplを現在のテンプレートに挿入します。その中の現在のハッシュは、呼び出されたコンテキストからのハッシュになります。 ああ、なんて紛らわしい。

{&tpl_myother_tpl =>#source.data}

この方法でインクルージョンを呼び出すことにより、現在のハッシュ#source.dataとしてインクルードを示します。これは、

myotherテンプレート内の{@ tpl_myother_tpl.title}は#source.data.titleと同等です



ブロック、インクルージョン、再帰の例





最後の例は、外部テンプレートのブロック、インクルージョン、現在のテンプレートのブロックを使用して、再帰的なツリートラバーサルを作成する例です。

Tpl / area.htmテンプレート





  1. < h1 > {#title} </ h1 >
  2. {&inc_header = > #headerinfo}
  3. {@tree}
  4. < ul >
  5. {%menu = > #childs}
  6. < li id = "li-{#id}" >
  7. < p > [{#}] {#title} </ p >
  8. {?#childs}
  9. {@ block.tree.sub}
  10. {/?}
  11. </ li >
  12. {/%menu}
  13. </ ul >
  14. {/ @ツリー}
  15. < h4 >別のテンプレートのブロック</ h4 >
  16. {@ block.tpl_auth.auth_form.html}
*このソースコードは、 ソースコードハイライターで強調表示されました。




tpl / auth.htmテンプレートのauth_formブロック

{@auth_form}

< div id ="d-auth" >

: < input type ="text" value ="" >< br >

: < input type ="password" value ="" >< br >

< input type ="button" value ="" >

</ div >

{/@auth_form}




* This source code was highlighted with Source Code Highlighter .








JavaScriptコードとデータ

var d2 = {

headerinfo : {

title: ' '

},

title: ' – !' ,

childs : [

{ id : 1, title : ' ' },

{

id : 2,

title : ' ' ,

childs : [

{ id : 5, title : ' ' },

{

id : 6,

title : ' ' ,

childs : [

{ id : 8, title : ' ' },

{ id : 9, title : ' ' }

]

},

{ id : 7, title : ' ' }

]

},

{ id : 3, title : ' ' },

{ id : 4, title : ' ' }



]



};

var jstpl = new myfirst();

var html2 = jstpl.tpl( 'tpl_area' ,d2);




* This source code was highlighted with Source Code Highlighter .








このhtmlを取得します。

< h1 > – ! </ h1 >

< h3 > </ h3 >

< ul >

< li id ="li-1" >< p > [ 1 ] </ p ></ li >

< li id ="li-2" >

< p > [ 2 ] </ p >

< ul >

< li id ="li-5" >< p > [ 1 ] </ p ></ li >

< li id ="li-6" >

< p > [ 2 ] </ p >

< ul >

< li id ="li-8" >< p > [ 1 ] </ p ></ li >

< li id ="li-9" >< p > [ 2 ] </ p ></ li >

</ ul >

</ li >

< li id ="li-7" >< p > [ 3 ] </ p ></ li >

</ ul >

</ li >

< li id ="li-3" >< p > [ 3 ] </ p ></ li >

< li id ="li-4" >< p > [ 4 ] </ p ></ li >

</ ul >

< h4 > </ h4 >

< div id ="d-auth" >

: < input id ="login" class ="inp" value ="" type ="text" >

: < input id ="pswd" class ="inp " value ="" type ="password" >

< input id ="btn-login" value ="" type ="button" >

</ div >




* This source code was highlighted with Source Code Highlighter .








私たちはそれを整理します...





テンプレートを編集した後、。/ bin / jsgenを実行するたびにスクリプトを実行する必要があることは一度も言及していません。これはソリューションの暗い側面の1つです。 変更されたテンプレートのみが再生成されます(ファイルの変更時間のタイムスタンプが監視されます)。 すべてのテンプレートを強制的に再生成するには、-allキーを使用してスクリプトを実行する必要があります

./bin/jsgen -all

対応するjsgenに権利を置くことを忘れないでください

chmod 775

別のポイント。 Config.pmには配列があります

@templates = (

{ pm = > "Tpl", ext = > '.htm', dir = > "tpl" },

{ pm = > "Inc", ext = > '.inc', dir = > "inc" }

);




* This source code was highlighted with Source Code Highlighter .






ルートディレクトリにはtplincの 2つのフォルダーがあり、それぞれ拡張子が.htmと.incのテンプレートファイルが含まれていると彼は言います。 これらのフォルダーにサブフォルダーが存在する場合があります(これは構成に反映する必要はありません)。 ファイルを作成したとしましょう

株式会社/ニュース/ルーブリック/ index.inc

「inc_news_rubric_index」という名前でこのテンプレートにアクセスする必要があります



myfirst.jsファイルは/ js / tplディレクトリにあります(Config.pm => $ cfg {jstpl})



上記のように、さまざまなテンプレートのビルドを行います。

Config.pmのエントリの例を再度示します。

@jslib = (

{

name = > 'myfirst',

list_tpl = > [ ... ],

blocks = > {...}

},{

name = > 'mysecond',

list_tpl = > [ ... ],

blocks = > {...}

}

);




* This source code was highlighted with Source Code Highlighter .






@jslib配列には、そのようなアセンブリに関する情報が含まれています。

name-同時にファイルとクラスの名前。

list_tpl-すべてのテンプレート(tplフォルダーとincの両方、およびユーザーが追加したもの(データには含まれない)および構成に記述されたその他のもの)

ブロック-アセンブリで使用するテンプレートとその中のブロックの名前



area.htmテンプレートの行番号:

2. includ inc / header.incを呼び出し、d2.headerinfoを現在のハッシュとして渡します

4.、15。 ツリーブロックを宣言する

6.、13。 メニューオブジェクトを宣言します。現在のハッシュの#childsがデータソースとして渡されます。 再帰では、これがルート要素と子孫で同じであることが重要です。 データの例を上記に示します。

10.指定されたブロックを関数として呼び出します。 つまり、ブロックタグで囲まれたすべてのコードは現在のハッシュで実行されます(条件は#childsの子孫の存在をチェックします)

18. tpl / auth.htmテンプレートからプレーンhtmlとして外部auth_formブロックを呼び出します



終わり





そのため、外観が非常に面倒で、JavaScript用の非常に多機能なテンプレートエンジンが用意されています。 サーバースクリプトで動作するテンプレートエンジン(独自のニュアンス)ほど劣っていません。 また、コンパイルされたコードには正規表現がないため、安定したパフォーマンスを誇っています。 時々私を殺すマイナスは、テンプレートを変更した後に再生成スクリプトを実行する必要があることです...



すべてを複雑に説明した場合、申し訳ありませんが、詳細なドキュメントはまだありません。 誰かが興味を持っている場合は、説明を続けることができますが、サーバー側のperlテンプレートエンジンを使用して、束全体をカバーします



上記のすべてのファイルのソースコード、 リンク

ファイルbin / Core / JS / Config.pmを修正することを忘れないでください



All Articles