開発者ブログ
リファレンス(仕様詳細) » 独自アスペクトの作り方

独自アスペクトの作り方

Last modified by ishikawa on 2016/10/11, 09:57

独自アスペクトの作り方

hifiveのアスペクトは、target, interceptors, pointCutの3つのプロパティを持つオブジェクトです。
基本的な形は以下のようになります。

var aspect = {  
  target: {String | RegExp},  
  interceptors: {Function | Function[]},  
  pointCut: {String | RegExp}  
};  

ターゲットとポイントカット

ターゲットはインターセプタをどのコントローラ、ロジックに適用するかを、ポイントカットはどのメソッドに適用するかを定義します。

  • ターゲットは、コントローラ、ロジックを定義する時の必須プロパティ__nameに対して
    指定された値で判定を行います。
  • ポイントカットは、ターゲットにマッチしたコントローラ、ロジックのメソッド名に対して
    指定された値で判定を行います。
  • インターセプタが適用されるのは、ターゲット、ポイントカットの両方にマッチした時のみです。
  • ターゲットとポイントカットは省略することができます。省略した場合、それぞれ「すべてのコントローラ、ロジック」、「すべてのメソッド」という意味になります。

ターゲット、ポイントカットには正規表現文字列を指定することができます。

正規表現の場合

指定された正規表現でそのまま判定を行います。

文字列の場合

  • *による部分一致のみが可能になります。
    • .や^など正規表現において特別な意味を持つものについては*を除いてすべてエスケープします。
  • 暗黙的に始まりと終わりを追加します(/^{指定した文字列}$/ となります)。
  • 例としてターゲットをjp.co.nssol.sample.controller*としたとします。
    • __nameプロパティが"jp.co.nssol.sample.controller.TestController"であるコントローラはマッチします。
    • __nameプロパティが"jp.co.nssol.sample2.controller.TestController"であるコントローラはマッチしません。

インターセプタ

インターセプタは実行したい処理を定義します。

var interceptor = function(invocation) {};  
インターセプタは引数invocationを取る関数として定義します。
インターセプタ内のthisはコントローラで適用された場合そのコントローラ自身を、ロジックで適用された場合そのロジック自身となります。
invocationのメソッドプロパティは以下の通りです。

args

  • 元のメソッドに渡された引数が格納されています。型はArgumentsです。

funcName

  • 元のメソッド名が格納されています。

proceed

  • 次のインターセプタ、もしくは元のメソッドを実行します。

h5.u.createInterceptor

インターセプタは定型の実装になることが多いため、ユーティリティを用意しています。

h5.u.createInterceptor(pre, post);
  • preはインターセプト先関数の実行前に呼ばれる関数です。
  • postはインターセプト先関数の実行後に呼ばれる関数です。
  • 詳細についてはこちらを参照してください。

以下は関数の実行前後にアラートを表示するインターセプタの例です。

var alertInterceptor = h5.u.createInterceptor(function(invocation, data) {  
    alert('before');  
   return invocation.proceed();  
}, function(invocation, data) {  
    alert('after');  
});  

適用方法

アスペクトはh5preinitイベントでh5.settings.aspectsに指定します。

$(document).bind('h5preinit', function() {  
 var aspect = {  
    interceptors: function() { console.log('aspect execute.'); }  
  };  
  h5.settings.aspects = aspect;  
});  

インターセプタの実行順序

  • アスペクト、またアスペクトのinterceptorsプロパティは値として配列を取ることができます。
  • 例えば以下のようにアスペクトを指定した場合、
$(document).bind('h5preinit', function() {  
 var aspect1 = {  
    interceptors: [func1, func2]  
  };  
 var aspect2 = {  
    interceptors: func3  
  };  
  h5.settings.aspects = [aspect1, aspect2];  
});  

あるメソッドにかかるインターセプタの実行順は、
func1 -> func2 -> func3 -> 本来のメソッド
となります。
インターセプタの実行順は定義した順と一致します。

  • もちろん、ターゲット、ポイントカットにマッチしない場合は、インターセプタは実行されません。

実装例

ここではボタンを押すと、ループを100万回回すロジックのメソッドの開始と終了をコンソールに出力するサンプルアプリケーションを作成します。

  • HTML
<!doctype html>  
<html>  
   <head>  
       <meta http-equiv="X-UA-Compatible" content="IE=edge">  
       <meta charset="UTF-8">  
       <meta http-equiv="Pragma" content="no-cache">  
       <meta http-equiv="Cache-Control" content="no-cache">  
       <meta http-equiv="Expires" content="-1">  
       <script src="jquery.js"></script>  
       <script src="ejs-1.0.h5mod.js"></script>  
       <script src="jquery.blockUI.js"></script>  
  
       <!-- hifiveのpreinitイベントで処理をさせるために、h5.jsより先に読み込む -->  
       <script src="h5preinit.js"></script>  
       <!-- 各モジュールのソースJSを読み込む -->  
       <script src="../../archives/current/h5.js"></script>  
       <!-- ここで作成したjsファイルを読み込む -->  
       <script src="step13-2.js"></script>  
  
       <title>hifive Aspectの適用</title>  
   </head>  
   <body>  
       <div class="browserNotification">  
        ※ブラウザはできるだけ最新のバージョンをご利用ください。<br>  
         特に、IE6/7等の古いブラウザでは正しく動作しない場合があります。  
       </div>  
       <div id="container">  
           <input type="button" id="btn" value="click"/>  
       </div>  
   </body>  
</html>  

HTMLはボタンがあるだけです。

  • アスペクト
$(document).bind('h5preinit', function() {  
  
   var aspect = {  
        target: /^loop.*$/i,  
        interceptors: function(invocation) {  
           this.log.info(invocation.funcName + 'が開始されました。');  
            invocation.proceed();  
           this.log.info(invocation.funcName + 'が終了しました。');  
        },  
        pointCut: 'lo*'  
    };  
  
    h5.settings.aspects = aspect;  
});

invocationの実行(invocation.proceed())前後にコンソールにメッセージを出力しています。
ターゲットは正規表現で指定します。意味は「大文字小文字関係なく"loop"で始まるもの」です。
ポインカットは文字列です。*を使って部分一致を行っています。意味は「loで始まるもの」です。

  • ロジック
var loopLogic = {  
    __name: 'LoopLogic',  
  
    loop: function() {  
       for (var i = 0; i < 1000000; i++) {  
           if (i % 10000 === 0) h5.log.info(i);  
        }  
    }  
};

loopメソッドはループを100万回回し、10000回ごとに周回数をコンソールに出力しています。

  • コントローラ
var loopController = {  
    __name: 'LoopController',  
  
    loopLogic: loopLogic,  
  
   '#btn click': function() {  
       this.loopLogic.loop();  
    }  
};  

h5.core.controller('#container', loopController);  
ボタンがクリックされると、LoopLogic#loopを呼んでいます。

動作確認


Copyright (C) 2012-2016 NS Solutions Corporation, All Rights Reserved.