Search code examples
javascriptfunctiondesign-patternsinterceptormethod-modifier

How does one override a method in order to intercept any call to this method?


In this widget there is a function isPermitted(). How would I intercept it and overwrite it.

I use the following to intercept other functions isPermittedDomain etc, but unable to overwrite the isPermitted function. Any suggestions?

this is the function I'm trying to intercept and overwrite:

n.prototype.isPermitted = function (t) {var n = !this.direct || 'OW2017' !== e.AppSettings.omo_username;
return !n && t && this.onFail(new e.ErrorMessage({ error: 'FEED_NOT_PERMITTED' })), n;
};

My code:

function intercept(obj, prop, callback) {
  var oldVal = null;
  Object.defineProperty(
    obj, prop, {
      get: function() {
        return oldVal;
      },
      set: function(newVal) {
        callback.call(this, newVal);
        oldVal = newVal;
      },
      enumerable: true,
      configurable: true
    });
};

intercept(Opta, 'Subscriptions', function(Subscriptions) {
  Subscriptions.isPermittedDomain = function() {
    return true;
  };
  intercept(Subscriptions, 'feeds', function(feeds) {
    const t = Opta.Trans.loadTerms({
      term_set_id: Opta.Trans.mapSportIdToTerms(1)
    });
    Opta.when(t).done(startReact);
  });
});

Solution

  • How about an approach which straightforwardly provides interception handling by wrapping the intercepting handler around the original (prototypal) isPermitted method. And for convenience reasons (code-reuse of the wrapping pattern) one would make use of an immediately invoked arrow function expression.

    // n.prototype.isPermitted = function (t) {
    //   var n = !this.direct || ('OW2017' !== e.AppSettings.omo_username);
    // 
    //   return !n && t && this.onFail(new e.ErrorMessage({
    //     error: 'FEED_NOT_PERMITTED'
    //   })), n;
    // };
    
    // test code based on the OP's provide exampe.
    
    class N {
      direct = true;
    
      isPermitted(t) {
        // const n = !this.direct || 'OW2017' !== e.AppSettings.omo_username;
        const n = !this.direct;
    
        // return !n && t && this.onFail(new e.ErrorMessage({
        //   error: 'FEED_NOT_PERMITTED'
        // })), n;
        if (!n && t) {
          this.onFail(new Error('FEED_NOT_PERMITTED'));
        }
        return n;
      }
    
      onFail(error) {
        console.log({ "error.message": error.message });
      }
    }
    
    function handleIsPermittedInterception(proceed, args, target) {
      /**
       *  - implement all functionality which is specific to the
       *    interception of the original `isPermitted` method.
       *
       *    - one does get passed in ...
       *
       *      - the original `isPermitted` method as `proceed`.
       *      - the method's arguments as a real arrray as `args`.
       *      - the method's `this` context as `target`.
       */
      console.log('+++ interception handling :: begin +++');
      console.log({ args, target, proceed });
    
      // the intercepted sole `t` parameter.
      const [ t ] = args;
    
      // implement e.g. handling upon `t`'s value.
      console.log({ t });
    
      // invocation of the original method within its correct context.
      const intermediateResult = proceed.apply(target, args);
    
      // implement e.g. handling upon the `intermediateResult`'s value.
      console.log({ intermediateResult });
      
      console.log('--- interception handling :: end ---\n\n\n');
    
      return intermediateResult // or any implementation specific value.
    }
    
    N.prototype.isPermitted = ((proceed, interceptor) => {
    
      // - wrap the handling of the interception
      //   around the original `isPermitted` method.
      return function (...args) {
    
        // - forwarding call wich passes all necessary
        //   values to the provided intercetion handler.
        return interceptor(proceed, args, this);
      };
    })(N.prototype.isPermitted, handleIsPermittedInterception);
    
    const n = new N;
    console.log('n.isPermitted(true) ...', n.isPermitted(true));
    .as-console-wrapper { min-height: 100%!important; top: 0; }