Fork me on GitHub

crosscutting.js

crosscutting는 오브젝트 기반의 AOP 를 제공하는 간단한 자바스크립트 라이브러리입니다.

Download .zip Download .tar.gz View on GitHub

설치

  • nodejs

    $ npm install crosscutting
  • browser

    <script type="text/javascript" src="/path/to/crosscutting.min.js"></script>

사용법

Basic

crosscutting.weave

객체와 관심을 특정 대상과 시점에 묶는 메서드입니다. 인자를 4개 받습니다.

crosscutting.weave([aopTarget], [pointcut], [adviceType], [advice])
  • aopTarget - Object, Array[Object]

    aop를 적용할 객체입니다. 빌트인 (Built-In) 타입의 프로토타입은 AOP를 적용할 수 없으며 적용하려고 하면 TypeError 가 던져집니다.
    여러 객체에 일괄 적용하고 싶다면 배열로 줄 수도 있습니다.

    적용 불가능한 객체들
    • String.prototype
    • Number.prototype
    • Boolean.prototype
    • Date.prototype
    • Array.prototype
    • Date.prototype
    • RegExp.prototype
    • Function.prototype
  • pointcut - RegExp, function(boolean 반환 필요)

    aopTarget 에 적용될 메서드를 구별해내는 인자입니다.
    정규표현식, 함수, Boolean 값이 될 수 있습니다. 함수를 사용한다면 인자를 받는데, 다음과 같습니다. 포인트컷 함수는 반드시 boolean 값을 반환해야 합니다.
    Boolean 값을 줄 경우 true면 모든 메서드에 대해 적용하게 됩니다.

    fnPointcut([Method Name]):boolean
    Method Name - String
    객체의 메서드 이름입니다. 이것으로 AOP 적용 여부를 판단하는 함수 몸체를 만들면 됩니다.
  • adviceType - crosscutting.Aspect

    어드바이스 타이밍입니다. 4종류가 있습니다. (crosscutting.Aspect.(BEFORE|AFTER|EXCEPTION|AROUND))

    crosscutting.Aspect.BEFORE
    객체의 메소드가 실행되기 전 어드바이스가 실행됩니다.
    crosscutting.Aspect.AFTER
    객체의 메소드가 실행된 뒤 어드바이스가 실행됩니다.
    crosscutting.Aspect.EXCEPTION
    객체의 메소드가 무언가를 throw 하게 되면 실행됩니다. 당신은 어드바이스 함수에 전달되는 인자객체의 "exception" 속성을 사용하여 던져진 객체에 접근할 수 있습니다.
    crosscutting.Aspect.AROUND
    객체의 메소드가 실행되지 않고 어드바이스가 실행됩니다. 대신 객체의 메소드는 어드바이스 함수의 첫번째 인자로 전달됩니다. 일반적인 인자 객체는 두번째 인자로 전달됩니다.
  • advice - function

    어드바이스 함수입니다.
    어드바이스 함수는 일반적으로 인자 객체를 인자로 전달 받습니다. 다만 어드바이스 타이밍이 AROUND 일 경우 첫번째 인자로 객체 메소드가 오므로 인자 객체는 두번째 인자가 됩니다.
    인자 객체의 속성은 다음과 같습니다.

    args
    객체 메서드에 전달되는 Arguments 객체입니다. 이 값을 조작하면 실제 객체 메서드의 인자도 바뀝니다. Arguments 객체에 대해서는 MDN 문서를 참고하세요
    // Simple arguments control Example
    var obj = {
        // return argument received
        echo: function(value) { return value; }
    };
    crosscutting.weave(
        obj,
        true,
        crosscutting.Aspect.AdviceType.BEFORE,
        function(options) {
            // change first arguments.
            options.args[0] = "yaho!";
        }
    );
    // same result. "yaho!".
    console.log(obj.echo("ok?")); // "yaho!";
    console.log(obj.echo("hello?")); // "yaho!";
    
    target - Object
    AOP가 적용되는 객체입니다. 어드바이스는 이 객체를 컨텍스트(this)로 하여 실행됩니다.
    todo - function
    실제 수행될 메서드입니다
    advice - function
    weave 시 인자로 준 어드바이스 함수입니다.
    type - crosscutting.Aspect
    weave 시 인자로 준 어드바이스 타이밍입니다.
    method - String
    pointcut에 의해 join 된 메서드의 이름입니다.
    exception - Error
    어드바이스 타입이 EXCEPTION이고 객체 메서드가 객체를 throw할 경우 객체 메서드에서 던져진 객체를 가지고 있습니다.

단축 메서드들

AdviceType을 따로 인자로 주지 않고 축약한 단축 메서드로 쓸 수 있습니다

// same action
crosscutting.before(
    { hello: function() {} },
    /hello/,
    function(){}
);
crosscutting.waeve(
    { hello: function() {} },
    /hello/,
    crosscutting.Aspect.BEFORE,
    function(){}
);
crosscutting.before
crosscutting.Aspect.BEFORE 동작과 같습니다
crosscutting.after
crosscutting.Aspect.AFTER 동작과 같습니다
crosscutting.around
crosscutting.Aspect.AROUND 동작과 같습니다
crosscutting.exception
crosscutting.Aspect.EXCEPTION 동작과 같습니다

Example Codes

예제에서 사용할 AOP를 적용할 객체입니다. 간단한 덧셈 뺄셈 프로그램입니다.

// Simple Calculator
var calculator = {
    plus: function(a, b) {
        return a + b;
    },
    minus: function(a, b) {
        return a - b;
    }
};

전달된 인자가 모두 숫자형인지 검사하는 AOP 적용(BEFORE 어드바이스) 예제

숫자형이 아닐 경우 TypeError를 Throw 하도록 했습니다.

// Validator Advice
var argumentCheck = function(options) {
    var args = options.args;
    for(var i = 0, len = args.length; i < len; i++) {
        if(typeof args[i] !== 'number') {
            throw new TypeError("all arguments must be number type");
        }
    }
};

crosscutting.before(calculator, true, argumentCheck);

// maybe throw TypeError.
calculator.plus("one", "two");

객체의 메서드가 실행될 때 로그를 찍는 BEFORE 어드바이스 예제

메서드 실행 전 메서드의 이름과 함께 로그가 찍힐 것입니다.

var logAdvice = function(options) {
    console.log("method " + options.method + " execute");
};

// plus method aop apply, type BEFORE
crosscutting.weave(
    calculator,
    function(name) {
        return name === "plus";
    },
    crosscutting.Aspect.AdviceType.BEFORE
    logAdvice
);

// console.log("method plus execute")
var result = calculator.plus(1, 1);

AROUND 어드바이스 예제

타겟 메서드의 실행을 제어할 수 있고 결과의 조작도 할 수 있습니다. 이 예제에서는 calculator의 결과를 문자열로 변환하여 반환하겠습니다.

var stringify = function(todo, options) {
    var result = todo();
    return result + ""; // toString
};

crosscutting.around(calculator, true, logAdvice);

// print console "string"
console.log(typeof calculator.plus(1, 1));

EXCEPTION 어드바이스 예제

위에 나왔던 인자가 숫자인지 검증하는 AOP를 적용 했다고 가정합니다. 이 예제에서는 일부러 오류를 내고 있습니다.

var throwHandler = function(options) {
    var exception = options.exception;
    console.log("Error! " + exception.name + ". cause : " + exception.message);
    if(exception.stack) console.log(exception.stack);
};

// aop apply, type EXCEPTION
crosscutting.exception(calculator, /^plus/, throwHandler);

// string arguments
var result = calculator.plus("one", "two");
/*
Error: arguments must be number type
at Object.calculator.plus ( ... )
at ... some stacktrace ...
*/

Contributer