Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node and Lazy: How do I know when it's done?

I need to read a file line by line, and change a variable accordingly. I would normally write this in PHP... but I decided to take the challenge.

I wrote:

fs = require('fs');
Lazy = require('lazy');
path = require('path');

files = fs.readdirSync('.');
var software = {};


files.forEach( function(fileName){


  var m; 
  if( m = fileName.match(/^(.*)\.txt$/) ){
    name = m[1];

    console.log("Processing file: " + fileName);
    software[name] = {};
    console.log("Software 1: %j",software);

    var section = 'unset';
    new Lazy(fs.createReadStream(fileName)).lines.forEach(
      function(line){
        var m;
        line = line + '';
        if( m = line.match(/^([a-zA-Z_]*):$/)){
          section = m[1];
          software[name][section] = '';
          console.log("Switching to section " + m[1]);
          console.log("Software 2: %j",software);
        } else if (line == '.'){
          section = 'unset'
        } else if (line == ''){
          section = 'unset'
        } else { 
          console.log("LINE: " + line) ;
          software[name][section] = software[name][section] + line + "\n";
          console.log("Software 3: %j",software);
        }
      }

    );   
  }

});

console.log("Software 4: %j",software);

Apart from the code being very ugly and very unoptimised, I am having trouble as when the last line prints, the "software" variable is not YET populated! I am guessing Lazy is asyncronous. So, it basically works, but "at some point later". This is great, but... where do I write code when that important cycle, that fills in the software variable, is actually finished?!?

As requested: data to play with!

simply create "something.txt" and write:

name:
Name 1
.

Option 1:
Value 1
.

Option 2:
Value 2
.

Option 3:
Multi
Line
Value
.

Another_section:
Again
.

Merc.

like image 462
Merc Avatar asked Dec 07 '22 13:12

Merc


1 Answers

The instances of Lazy returned by the library are EventEmitters, and it emits en event called pipe when a "set" of operations is complete:

new Lazy(
  ...
).on('pipe', function() {
  // all done
});

Modifying your code to use this event results in (the only change is near the bottom):

fs = require('fs');
Lazy = require('lazy');
path = require('path');

files = fs.readdirSync('.');
var software = {};


files.forEach( function(fileName){


  var m;
  if( m = fileName.match(/^(.*)\.txt$/) ){
    name = m[1];

    console.log("Processing file: " + fileName);
    software[name] = {};
    console.log("Software 1: %j",software);

    var section = 'unset';
    new Lazy(fs.createReadStream(fileName)).lines.forEach(
      function(line){
        var m;
        line = line + '';
        if( m = line.match(/^([a-zA-Z_]*):$/)){
          section = m[1];
          software[name][section] = '';
          console.log("Switching to section " + m[1]);
          console.log("Software 2: %j",software);
        } else if (line == '.'){
          section = 'unset'
        } else if (line == ''){
          section = 'unset'
        } else {
          console.log("LINE: " + line) ;
          software[name][section] = software[name][section] + line + "\n";
          console.log("Software 3: %j",software);
        }
      }

    ).on('pipe', function() {
      console.log("Software 4: %j",software);
    });
  }

});

[Edit] To answer your question regarding how I found this info:

I did indeed check out the source file for the project; I knew the library had a sum method that could be chained to instances of Lazy to sum up everything at the end; the code for that method calls foldr, and the code for that method listens for an event called pipeName, which is defaulted in line 22 as pipe.

like image 109
Michelle Tilley Avatar answered Dec 11 '22 08:12

Michelle Tilley