Skip to content

Instantly share code, notes, and snippets.

@kevinswiber
Last active February 15, 2020 14:39
Show Gist options
  • Save kevinswiber/6452906 to your computer and use it in GitHub Desktop.
Save kevinswiber/6452906 to your computer and use it in GitHub Desktop.

Revisions

  1. kevinswiber revised this gist Sep 5, 2013. 2 changed files with 32 additions and 8 deletions.
    21 changes: 19 additions & 2 deletions example2.js
    Original file line number Diff line number Diff line change
    @@ -21,6 +21,8 @@ Printer.prototype.print = function() {
    console.log(this.greeter.greet());
    };

    // Demo 1: Basic register/resolve behavior and component dependencies.

    locator.register('greeting', Greeting, ['Hello world!']);
    locator.register('greeter', Greeter, [locator.component('greeting')]);
    locator.register('printer', Printer, [locator.component('greeter')]);
    @@ -31,14 +33,29 @@ printer = locator.resolve('printer');
    printer.print();

    // Output: Hello world!
    ///////////////////////////

    // Demo 2: Transient lifestyle behavior and dynamic dependencies.

    var now = function() {
    return 'The time is: ' + new Date();
    };

    locator.register('greeting', Greeting, [locator.dynamic(now)]);
    locator.register('greeting', Greeting, [locator.dynamic(now)], 'transient');
    locator.register('greeter', Greeter, [locator.component('greeting')], 'transient');
    locator.register('printer', Printer, [locator.component('greeter')], 'transient');

    printer = locator.resolve('printer');
    printer.print();

    // Sample Output: The time is: Thu Sep 05 2013 14:35:16 GMT-0400 (EDT)
    setTimeout(function() {
    printer = locator.resolve('printer');
    printer.print();
    }, 3000);

    // Sample Output:
    //
    // The time is: Thu Sep 05 2013 14:53:58 GMT-0400 (EDT)
    // The time is: Thu Sep 05 2013 14:54:01 GMT-0400 (EDT)
    //
    //////////////////////////
    19 changes: 13 additions & 6 deletions service_locator.js
    Original file line number Diff line number Diff line change
    @@ -3,10 +3,11 @@ var Implementation = function(constructor, args) {
    this.args = args;
    };

    var Definition = function(name, constructor, args) {
    var Definition = function(name, constructor, args, lifestyle) {
    this.name = name;
    this.value = new Implementation(constructor, args);
    this.dependencies = [];
    this.lifestyle = lifestyle || 'singleton';
    this.instance = null;
    };

    @@ -15,8 +16,8 @@ var ServiceLocator = module.exports = function() {
    this.dependents = {};
    };

    ServiceLocator.prototype.register = function(name, constructor, args) {
    var definition = new Definition(name, constructor, args);
    ServiceLocator.prototype.register = function(name, constructor, args, lifestyle) {
    var definition = new Definition(name, constructor, args, lifestyle);
    args = args || [];

    var self = this;
    @@ -91,13 +92,19 @@ ServiceLocator.prototype.resolve = function(name) {
    // non-constructor function
    // bind args to function for entry instance
    var boundArgs = [constructor].concat(args);
    definition.instance = constructor.bind.apply(constructor, boundArgs);
    if (definition.lifestyle === 'singleton') {
    definition.instance = constructor.bind.apply(constructor, boundArgs);
    }
    } else {
    definition.instance = obj;
    if (definition.lifestyle === 'singleton') {
    definition.instance = obj;
    }
    }
    } else if (typeof constructor === 'object') {
    obj = constructor;
    definition.instance = obj;
    if (definition.lifestyle === 'singleton') {
    definition.instance = obj;
    }
    }
    }

  2. kevinswiber revised this gist Sep 5, 2013. 2 changed files with 27 additions and 10 deletions.
    12 changes: 8 additions & 4 deletions example2.js
    Original file line number Diff line number Diff line change
    @@ -22,8 +22,8 @@ Printer.prototype.print = function() {
    };

    locator.register('greeting', Greeting, ['Hello world!']);
    locator.register('greeter', Greeter, [locator.future('greeting')]);
    locator.register('printer', Printer, [locator.future('greeter')]);
    locator.register('greeter', Greeter, [locator.component('greeting')]);
    locator.register('printer', Printer, [locator.component('greeter')]);

    var printer;

    @@ -32,9 +32,13 @@ printer.print();

    // Output: Hello world!

    locator.register('greeting', Greeting, ['Hello again!']);
    var now = function() {
    return 'The time is: ' + new Date();
    };

    locator.register('greeting', Greeting, [locator.dynamic(now)]);

    printer = locator.resolve('printer');
    printer.print();

    // Output: Hello again!
    // Sample Output: The time is: Thu Sep 05 2013 14:35:16 GMT-0400 (EDT)
    25 changes: 19 additions & 6 deletions service_locator.js
    Original file line number Diff line number Diff line change
    @@ -21,7 +21,8 @@ ServiceLocator.prototype.register = function(name, constructor, args) {

    var self = this;
    args.forEach(function(arg) {
    if (typeof arg === 'object' && arg['$type'] && arg['$type'] === 'future') {
    if (typeof arg === 'object' && arg['$type']
    && arg['$type'] === 'component') {
    var $name = arg['$name'];
    definition.dependencies.push($name);
    if (!self.dependents[$name]) {
    @@ -69,9 +70,14 @@ ServiceLocator.prototype.resolve = function(name) {

    var self = this;
    tempArgs.forEach(function(arg) {
    if (typeof arg === 'object' && arg['$type'] && arg['$type'] === 'future') {
    arg = self.resolve(arg['$name']);
    definition.dependencies.push(arg['$name']);
    if (typeof arg === 'object' && arg['$type']) {
    var type = arg['$type'];
    if (type === 'component') {
    arg = self.resolve(arg['$name']);
    definition.dependencies.push(arg['$name']);
    } else if (type === 'dynamic') {
    arg = arg['$fn']();
    }
    }
    args.push(arg);
    });
    @@ -98,9 +104,16 @@ ServiceLocator.prototype.resolve = function(name) {
    return obj;
    };

    ServiceLocator.prototype.future = function(name) {
    ServiceLocator.prototype.component = function(name) {
    return {
    $type: 'future',
    $type: 'component',
    $name: name
    };
    };

    ServiceLocator.prototype.dynamic = function(fn) {
    return {
    $type: 'dynamic',
    $fn: fn
    };
    };
  3. kevinswiber revised this gist Sep 5, 2013. 2 changed files with 40 additions and 6 deletions.
    15 changes: 10 additions & 5 deletions example2.js
    Original file line number Diff line number Diff line change
    @@ -25,11 +25,16 @@ locator.register('greeting', Greeting, ['Hello world!']);
    locator.register('greeter', Greeter, [locator.future('greeting')]);
    locator.register('printer', Printer, [locator.future('greeter')]);

    var printer = locator.resolve('printer');
    var printer;

    printer = locator.resolve('printer');
    printer.print();

    /*
    Output:
    // Output: Hello world!

    locator.register('greeting', Greeting, ['Hello again!']);

    printer = locator.resolve('printer');
    printer.print();

    Hello world!
    */
    // Output: Hello again!
    31 changes: 30 additions & 1 deletion service_locator.js
    Original file line number Diff line number Diff line change
    @@ -6,15 +6,43 @@ var Implementation = function(constructor, args) {
    var Definition = function(name, constructor, args) {
    this.name = name;
    this.value = new Implementation(constructor, args);
    this.dependencies = [];
    this.instance = null;
    };

    var ServiceLocator = module.exports = function() {
    this.entries = {};
    this.dependents = {};
    };

    ServiceLocator.prototype.register = function(name, constructor, args) {
    this.entries[name] = new Definition(name, constructor, args);
    var definition = new Definition(name, constructor, args);
    args = args || [];

    var self = this;
    args.forEach(function(arg) {
    if (typeof arg === 'object' && arg['$type'] && arg['$type'] === 'future') {
    var $name = arg['$name'];
    definition.dependencies.push($name);
    if (!self.dependents[$name]) {
    self.dependents[$name] = [];
    }
    self.dependents[$name].push(definition.name);
    }
    });

    this.evict(name);
    this.entries[name] = definition;
    };

    ServiceLocator.prototype.evict = function(name) {
    var self = this;
    if (self.dependents[name]) {
    self.dependents[name].forEach(function(dep) {
    self.entries[dep].instance = null;
    self.evict(dep);
    });
    }
    };

    ServiceLocator.prototype.resolve = function(name) {
    @@ -43,6 +71,7 @@ ServiceLocator.prototype.resolve = function(name) {
    tempArgs.forEach(function(arg) {
    if (typeof arg === 'object' && arg['$type'] && arg['$type'] === 'future') {
    arg = self.resolve(arg['$name']);
    definition.dependencies.push(arg['$name']);
    }
    args.push(arg);
    });
  4. kevinswiber revised this gist Sep 5, 2013. 2 changed files with 53 additions and 4 deletions.
    35 changes: 35 additions & 0 deletions example2.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    var ServiceLocator = require('./service_locator');
    var locator = new ServiceLocator();

    var Greeting = function(message) {
    this.message = message;
    };

    var Greeter = function(greeting) {
    this.greeting = greeting;
    };

    Greeter.prototype.greet = function() {
    return this.greeting.message;
    };

    var Printer = function(greeter) {
    this.greeter = greeter;
    };

    Printer.prototype.print = function() {
    console.log(this.greeter.greet());
    };

    locator.register('greeting', Greeting, ['Hello world!']);
    locator.register('greeter', Greeter, [locator.future('greeting')]);
    locator.register('printer', Printer, [locator.future('greeter')]);

    var printer = locator.resolve('printer');
    printer.print();

    /*
    Output:
    Hello world!
    */
    22 changes: 18 additions & 4 deletions service_locator.js
    Original file line number Diff line number Diff line change
    @@ -14,9 +14,7 @@ var ServiceLocator = module.exports = function() {
    };

    ServiceLocator.prototype.register = function(name, constructor, args) {
    var entry = new Definition(name, constructor, args);

    this.entries[name] = entry;
    this.entries[name] = new Definition(name, constructor, args);
    };

    ServiceLocator.prototype.resolve = function(name) {
    @@ -38,7 +36,16 @@ ServiceLocator.prototype.resolve = function(name) {
    } else {
    var value = definition.value;
    var constructor = value.constructor;
    var args = value.args;
    var tempArgs = value.args || [];
    var args = [];

    var self = this;
    tempArgs.forEach(function(arg) {
    if (typeof arg === 'object' && arg['$type'] && arg['$type'] === 'future') {
    arg = self.resolve(arg['$name']);
    }
    args.push(arg);
    });

    if (typeof constructor === 'function') {
    obj = Object.create(constructor.prototype);
    @@ -60,4 +67,11 @@ ServiceLocator.prototype.resolve = function(name) {
    }

    return obj;
    };

    ServiceLocator.prototype.future = function(name) {
    return {
    $type: 'future',
    $name: name
    };
    };
  5. kevinswiber created this gist Sep 5, 2013.
    51 changes: 51 additions & 0 deletions example.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    var ServiceLocator = require('./service_locator');
    var locator = new ServiceLocator();

    var Greeter = function(message) {
    this.message = message;
    };

    Greeter.prototype.greet = function() {
    console.log(this.message);
    };


    var greeterFn = function(message) { console.log(message); };

    var greeterObj = {
    greet: function(message) {
    console.log(message);
    }
    };

    locator.register('greeter1', Greeter, ['1: Hello world!']);
    locator.register('greeter2', greeterFn, ['2: Hello world!']);
    locator.register('greeter3', greeterObj);

    for (var i = 0; i < 3; i++) {
    console.log('iteration:', i);
    locator.resolve('greeter1').greet();
    locator.resolve('greeter2');
    locator.resolve('greeter3').greet('3: Hello world!');
    console.log('');
    }

    /*
    Output:
    iteration: 0
    1: Hello world!
    2: Hello world!
    3: Hello world!
    iteration: 1
    1: Hello world!
    2: Hello world!
    3: Hello world!
    iteration: 2
    1: Hello world!
    2: Hello world!
    3: Hello world!
    */
    63 changes: 63 additions & 0 deletions service_locator.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,63 @@
    var Implementation = function(constructor, args) {
    this.constructor = constructor;
    this.args = args;
    };

    var Definition = function(name, constructor, args) {
    this.name = name;
    this.value = new Implementation(constructor, args);
    this.instance = null;
    };

    var ServiceLocator = module.exports = function() {
    this.entries = {};
    };

    ServiceLocator.prototype.register = function(name, constructor, args) {
    var entry = new Definition(name, constructor, args);

    this.entries[name] = entry;
    };

    ServiceLocator.prototype.resolve = function(name) {
    var definition = this.entries[name];

    if (!definition) {
    var message = 'No definition for `' + name + '` exists.';
    throw new Error(message);
    }

    var obj;

    if (definition.instance) {
    if (typeof definition.instance === 'function') {
    obj = definition.instance();
    } else if (typeof definition.instance === 'object') {
    obj = definition.instance;
    }
    } else {
    var value = definition.value;
    var constructor = value.constructor;
    var args = value.args;

    if (typeof constructor === 'function') {
    obj = Object.create(constructor.prototype);
    obj.constructor.apply(obj, args);

    if (!Object.keys(constructor.prototype).length &&
    !Object.keys(obj).length) {
    // non-constructor function
    // bind args to function for entry instance
    var boundArgs = [constructor].concat(args);
    definition.instance = constructor.bind.apply(constructor, boundArgs);
    } else {
    definition.instance = obj;
    }
    } else if (typeof constructor === 'object') {
    obj = constructor;
    definition.instance = obj;
    }
    }

    return obj;
    };