Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #6810: aspect.diff

File aspect.diff, 8.8 kB (added by Tobie, 2 years ago)

js + tests

  • test/unit/base.html

    old new  
    4949    } 
    5050     
    5151  var globalBindTest = null; 
    52  
     52   
     53  var BankAccount = Class.create(); 
     54  BankAccount.prototype = { 
     55    initialize: function(name, initialDeposit){ 
     56      this.owner = name; 
     57      this.currentBalance = initialDeposit; 
     58    }, 
     59     
     60    transaction: function(amount){ 
     61      this.currentBalance += amount; 
     62      return 'transaction was successfully processed'; 
     63    }, 
     64    toString: function(){ 
     65      return this.owner + '\'s bank account'; 
     66    } 
     67  }; 
     68   
     69  TransactionAspects = { 
     70    transactionFee: function(returnedValue, amount) { 
     71      if(returnedValue == 'transaction was successfully processed') 
     72        this.currentBalance -= (0.1 * Math.abs(amount)); 
     73    }, 
     74     
     75    logTransaction: function(amount) { 
     76     if(!this.log) this.log = []; 
     77     this.log.push('transaction request for $ ' + amount); 
     78    }, 
     79     
     80    limitCredit: function(proceed, amount) { 
     81      var message; 
     82      if(!this.log) this.log = []; 
     83      if(this.currentBalance + amount > 0) { 
     84        message = proceed(amount); 
     85        this.log.push(message); 
     86        return message; 
     87      } 
     88      message = 'cannot process transaction'; 
     89      this.log.push(message); 
     90      return message; 
     91    }, 
     92     
     93    welcomeGift: function(){ 
     94      this.currentBalance += 50; 
     95    }  
     96  } 
     97   
    5398  new Test.Unit.Runner({ 
    5499     
    55100    testFunctionBind: function() { with(this) { 
     
    123168          this.assertEqual.bind(this,arg3), arg1, arg2, arg3 ); 
    124169        call(eventTest); 
    125170      } 
    126     } 
     171    }, 
     172        testAddBeforeAdviceOnInstance: function() {with(this) { 
     173      var account = new BankAccount('happy few', 1000);       
     174      Object.extend(account, Aspect);      
     175      account.addBeforeAdvice('transaction', TransactionAspects.logTransaction); 
     176      account.transaction(2000); 
     177      assertEqual(3000, account.currentBalance); 
     178      assertEqual('transaction request for $ 2000', account.log[0]); 
     179    }}, 
     180     
     181    testAddAfterAdviceOnInstance: function() {with(this) { 
     182      var account = new BankAccount('happy few', 1000);       
     183      Object.extend(account, Aspect);           
     184      account.addAfterAdvice('transaction', TransactionAspects.transactionFee); 
     185      account.transaction(2000); 
     186      assertEqual(2800, account.currentBalance); 
     187    }}, 
     188     
     189    testAddAroundAdviceOnInstance: function() {with(this) {      
     190      var account = new BankAccount('so and so', 100);       
     191      Object.extend(account, Aspect); 
     192       
     193      account.addAroundAdvice('transaction', TransactionAspects.limitCredit); 
     194      account.transaction(-1000); 
     195      assertEqual(100, account.currentBalance); 
     196      assertEqual('cannot process transaction', account.log.last()); 
     197       
     198      account.transaction(-10); 
     199      assertEqual(90, account.currentBalance); 
     200      assertEqual('transaction was successfully processed', account.log.last()); 
     201    }}, 
     202     
     203    testMultipleAdvicesOnInstance: function() {with(this) {      
     204      var account = new BankAccount('so and so', 100);       
     205      Object.extend(account, Aspect); 
     206       
     207      account.addAroundAdvice('transaction', TransactionAspects.limitCredit); 
     208      account.addBeforeAdvice('transaction', TransactionAspects.logTransaction); 
     209      account.addAfterAdvice('transaction', TransactionAspects.transactionFee); 
     210       
     211      account.transaction(-1000); 
     212      assertEqual(100, account.currentBalance); 
     213      assertEqual('transaction request for $ -1000', account.log.first()); 
     214      assertEqual('cannot process transaction', account.log.last()); 
    127215 
     216      account.transaction(-10); 
     217      assertEqual(89, account.currentBalance); 
     218      assertEqual('transaction request for $ -10', account.log[2]); 
     219      assertEqual('transaction was successfully processed', account.log.last()); 
     220    }}, 
     221     
     222    testCachingOriginalMethods: function() {with(this) {      
     223      var account = new BankAccount('anyone', 100);       
     224      Object.extend(account, Aspect); 
     225       
     226      account.addBeforeAdvice('toString', Prototype.emptyFunction); 
     227      assertIdentical(BankAccount.prototype.toString, account.originalMethods._toString); 
     228       
     229      // check that the cached method is not overwritten 
     230      account.addBeforeAdvice('toString', Prototype.emptyFunction); 
     231      assertIdentical(BankAccount.prototype.toString, account.originalMethods._toString); 
     232      account.restoreOriginalMethod('toString'); 
     233       
     234      ['addBeforeAdvice', 'addAfterAdvice', 'addAroundAdvice'].each(function(advice) { 
     235        account[advice]('toString', Prototype.emptyFunction); 
     236        assertIdentical(BankAccount.prototype.toString, account.originalMethods._toString); 
     237        account.restoreOriginalMethod(advice); 
     238      }); 
     239    }}, 
     240     
     241    testRestoreOriginalMethods: function() {with(this) { 
     242      account = new BankAccount('Anyone', 100);       
     243      Object.extend(account, Aspect); 
     244      account.addBeforeAdvice('toString', Prototype.emptyFunction); 
     245      account.addBeforeAdvice('transaction', Prototype.emptyFunction); 
     246       
     247      account.restoreOriginalMethod('toString'); 
     248      assertIdentical(BankAccount.prototype.toString, account.toString); 
     249      assertNotEqual(BankAccount.prototype.transaction, account.transaction); 
     250       
     251      account = new BankAccount('Anyone', 100);       
     252      Object.extend(account, Aspect); 
     253      account.addBeforeAdvice('toString', Prototype.emptyFunction); 
     254      account.addBeforeAdvice('transaction', Prototype.emptyFunction); 
     255      account.restoreOriginalMethod('toString', 'transaction'); 
     256      assertIdentical(BankAccount.prototype.toString, account.toString); 
     257      assertIdentical(BankAccount.prototype.transaction, account.transaction); 
     258    }}, 
     259     
     260    testAspectAppliedDirectlyToPrototype: function() {with(this) { 
     261      Object.extend(BankAccount.prototype, Aspect); 
     262      BankAccount.prototype.addAfterAdvice('initialize', TransactionAspects.welcomeGift); 
     263      BankAccount.prototype.addAroundAdvice('transaction', TransactionAspects.limitCredit); 
     264      BankAccount.prototype.addBeforeAdvice('transaction', TransactionAspects.logTransaction); 
     265      BankAccount.prototype.addAfterAdvice('transaction', TransactionAspects.transactionFee); 
     266      BankAccount.prototype.addBeforeAdvice('toString', Prototype.emptyFunction); 
     267       
     268      var account = new BankAccount('You', 10000); 
     269      assertEqual(10050, account.currentBalance); 
     270       
     271      account.transaction(-1000); 
     272      assertEqual(8950, account.currentBalance); 
     273      assertEqual('transaction request for $ -1000', account.log.first()); 
     274      assertEqual('transaction was successfully processed', account.log.last()); 
     275 
     276      account.transaction(-10000); 
     277      assertEqual(8950, account.currentBalance); 
     278      assertEqual('transaction request for $ -10000', account.log[2]); 
     279      assertEqual('cannot process transaction', account.log[3]); 
     280 
     281      BankAccount.prototype.restoreOriginalMethod('initialize'); 
     282 
     283      var account_2 = new BankAccount('Him', 1000); 
     284      assertEqual(1000, account_2.currentBalance); 
     285 
     286      BankAccount.prototype.restoreOriginalMethod('toString', 'transaction'); 
     287      account.transaction(-10000); 
     288      assertEqual(-1050, account.currentBalance); 
     289      assertUndefined(account.log[4]); 
     290      assertUndefined(account.log[5]); 
     291    }} 
    128292  }, 'testlog'); 
    129293 
    130294// ]]> 
  • src/base.js

    old new  
    6060  } 
    6161} 
    6262 
     63var Aspect = { 
     64  originalMethods: {}, 
     65  addBeforeAdvice: function(method, advice) { 
     66    var original = this[method]; 
     67    if(!this.originalMethods['_' + method]) this.originalMethods['_' + method] = original; 
     68    var original = this[method]; 
     69    this[method] = function() { 
     70      advice.apply(this, arguments); 
     71      return original.apply(this, arguments); 
     72    } 
     73  }, 
     74  addAfterAdvice: function(method, advice) { 
     75    var original = this[method]; 
     76    if(!this.originalMethods['_' + method]) this.originalMethods['_' + method] = original; 
     77    this[method] = function() { 
     78      var returnedValue = original.apply(this, arguments); 
     79      return advice.apply(this, [returnedValue].concat($A(arguments))); 
     80    } 
     81  }, 
     82  addAroundAdvice: function(method, advice) { 
     83    var original = this[method]; 
     84    if(!this.originalMethods['_' + method]) this.originalMethods['_' + method] = original; 
     85    this[method] = function() { 
     86      return advice.apply(this, [original.bind(this)].concat($A(arguments))); 
     87    } 
     88  }, 
     89  restoreOriginalMethod: function() { 
     90    $A(arguments).each(function(method) { 
     91      this[method] = this.originalMethods['_' + method]; 
     92      delete this.originalMethods['_' + method]; 
     93    }.bind(this)); 
     94  } 
     95} 
     96 
    6397Object.extend(Number.prototype, { 
    6498  toColorPart: function() { 
    6599    var digits = this.toString(16);