• As mentioned in the previous post, the string containing a complete module can be pretty big and could lead to run out of memory. Therefore the question:

    How can a module be broken up into small(er) pieces and composed at runtime from such pieces.

    In order to have the a piece of code working as a module, it is good enough to have a 'hock object' as the first or core component in the Modules cache to which more components can 'be attached' to. To attache components to a module core component, the module has to be required from the cache and then the components can 'be attached' to it. After all, the module - in this case the 'class'/prototype definition - is just a function object - one and the same whether in the cache or in the application code.

    Since the constructor function is such a first and core component, let's try to attache a the .getTemp() as a component.

    Intentionally, the module was retrieved into a temporary variable tempTemp - line 37 - to prove that the module is the very same object that is later retrieved into the original variable Temperature - line 57 - and includes now the complete Temperature 'class'/prototype definition.

    The split up module code into core component - lines 4..34 - and other component(s) - lines 49/41..48 - and attaching the other component(s), such as a method method - line 40 - represents composing a complete module from components component by component. The code for it looks like this:

    // TemperatureDevTest2.js
    
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature",`
    // Temperature.js
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    
    exports = Temperature;
    `);
    
    // require the Temperature module into a temporary tempTemp var:
    var tempTemp = require("Temperature");
    
    // attach the .getTemp() method
    tempTemp.prototype.getTemp = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    
    },6000);
    

    There is one comment to make: if the to-attach module component is retrieved over the network or read from a storage it is retrieved as a string and not as an object... but that is no issue what so ever... we just 'ab-use' the Modules.addCached(...) and require(...) infrastructure as a stepping stone:

    • add the to-attach component to the Modules cache as a module with Modules.addCached(...) - lines 36..49.
    • retrieve the to-attach component as module from the Modules cache with require() - line 55.
    • attach it to the core module retrieved from the Modules cache as done before - line 55.

    The code with all module components as strings looks then like:

    // TemperatureDevTest2.js
    
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature",`
    // Temperature.js
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    
    exports = Temperature;
    `);
    
    // add .getTemp() method as moduleComponent to the Modules cache
    Modules.addCached("moduleComponent",`
    var moduleComponent = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    exports = moduleComponent;
    `);
    
    // require the Temperature module into a temporary tempTemp var:
    var tempTemp = require("Temperature");
    
    // require and attach the .getTemp() method as module component
    tempTemp.prototype.getTemp = require("moduleComponent");
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    
    },6000);
    

    ...and works - and we get two (2) warnings about module not found on upload as expected... of course it runs... no magic... just JavaScript brilliantly and to it's true nature implemented by @Gordon.

About

Avatar for allObjects @allObjects started