verbotenjs

A general application development framework for node.js, browsers, and other hosts

npm install verbotenjs
1 downloads in the last day
1 downloads in the last week
101 downloads in the last month

| | / / _/ / / / __ / / / | | / / \/ __/ \/ \/ / _ \/ _ / /_ \ | |/ / _/ / / // / // / // / / / / // // / |/\// /./_/_/__// //_//_/

zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip hg source: https://www.bitbucket.org/marcuspope/verbotenjs npm package: https://npmjs.org/package/verbotenjs

Introduction

Because everybody will think it is verboten anyway, I present to you VerbotenJS.

´┐ŻMaintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas´┐Ż

I, Marcus Pope, by imperial proclamation hereby declare ownership of Object.prototype. As sole owner I am the only authorized person to modify the prototype definition. Nope, too late I already called it and double stamped it. You can't triple stamp a double stamp!

What Is VerbotenJS?

VerbotenJS is a general application development framework designed for NodeJS & Browser JavaScript hosts. In addition to a bunch of base prototype enhancements and terse programming patterns, the framework also includes extension libraries for various domains such as databases, filesystems, shell scripts etc.

Who Should Use VerbotenJS?

Nobody, it's verboten remember?!? No I'm kidding, you can use it for any personal project you want. I don't recommend using it for production systems since it is version 1.0 and I'm just one man trying to support his own personal JS framework. I'll probably change framework logic on a whim too, because that too is considered verboten right?

Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download

that to a client?

No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery is not compatible with Object.prototype extensions. I had intended on releasing my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to inject a forked version of jQuery which added almost 350k to the footprint. My DOM wrapper will probably put the library in the 500k realm for browser hosts. For NodeJS hosts modules are dynamically included on access so the run-time memory usage requirements are dynamic based on the modules you use.

But by today's standards 750k is not really that bad except for mobile devices and cellular networks. If you must you can compress and gzip it down to 75k but with modern bandwidth and caching infrastructures it really isn't that bad.

But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?

Good for you. Play around a little, find out how good it feels to be bad for once in your life :D

Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break

My Application/Library/3rd Party Code?

Some people write bad JavaScript code, including myself. jQuery authors, for instance, recognize that their codebase has a bug that makes jQuery incompatible with object prototype extensions, however they choose to ignore the issue for various artificial reasons. ExpressJS authors just don't understand how JavaScript reflection works, and they think OPE's are code smell. And yet in other cases VerbotenJS may conflict with existing namespaces in your application. In the latter case I recommend either opening a bug if the issue is caused by a non-conforming standard on my part, or refactoring your application if you want to use VerbotenJS.

Where Do I Start?

First grab a copy of verbotenjs from npm.

npm install verbotenjs

In node hosts use:

require('verbotenjs');

For browser hosts include a reference to this file

[verbotenjs]/web/verboten.js 

There are no init functions that you have to worry about, and there is no real global entry point to the verboten framework. Everything you need is either declared globally, or attached to the prototypes of existing data types including Objects.

I Kinda Like Where This Is Going, How Do I Help?

Well, I'm not really in a position to coordinate a team of developers at the moment. I have a newborn daughter and a full time job, so to avoid the frustration of not hearing from me for a few weeks at a time, which totally happens, send me small patches, <500 lines, and I'll review them. Since I doubt this will be much of an issue either way, I'll leave it at that for now.

What If I Wanted To Create A Commercial Product?

Well, let's talk licensing and target market. But really you should probably wait until 2.0 at least before considering something for production.

What's In Store For The Future Of VerbotenJS?

Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js, Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff you'd expect from a professional open source project. The same stuff you should expect to be missing from a project named VerbotenJS.

Documentation

Ha!

No, but I'm working on it. You'll notice some documentation tags in the source code, that's about as far as I've made it on the documentation front. Much of the codebase is pretty self explanatory, much of it is not. I do have a couple of other projects and a bunch of scripts that I've written over the years that will be used as examples, but otherwise I have no documentation other than comments in the source.

Examples

Here are some before and after code samples to show how VerbotenJS can make your coding efforts easier.

Grepping The File System Without VerbotenJS:

function grep(dir, query, filemask, recurse, hidden, cb) {
  //grep for 'query' in 'dir'.
  //'recurse' if necessary,
  //ignore 'hidden' files if necessary.
  //'cb' required.
  if (typeof query == "string") {
    query = new RegExp(query, "i");
  }

  //optionally filter by filemask
  if (typeof filemask == "string") {
    filemask = new RegExp(filemask);
  }

  var count = 1, //file count
    async = 0, //async callback count
    out = [],
    list = [],
    fs = require('fs'),
    fp = require('path');

  dir = dir || process.cwd();

  function search(path) {
    fs.stat(path, function(err, stat){
      count--;

      if (err) throw err;

      if (stat.isDirectory()) {

        async++;

        fs.readdir(path, function(err, files){
          async--;

          if (err) throw err;

          for (var i=0; i < files.length; i++) {
            if (!hidden && files[i][0] == '.') return;
            count++;
            search(fp.join(path, files[i]));
          }
        });
      } else if (stat.isFile()) {
        //ignore unmatched file masks
        if (!filemask.test(path)) {
           return;
        }

        async++;
        fs.readFile(path, 'utf8', function(err, str){
          async--;

          if (err) throw err;

          var lines = str.split('\n');

          for (var i=0; i < lines.length; i++) {
            var line = lines[i].trim(); 
            //return matching lines & line number
            if (query.test(line)) return [i, line];
          }

          if (lines.length) {
            out.push(path);
            for (var i=0; i < lines.length; i++) {
              out.push((lines[i][0]+1) + ": " + lines[i][1]);
              list.push({
                path : path,
                line : lines[i][0],
                text : lines[i][1]
              });
            }
            out.push('');
          }

          if(count == 0 && async == 0) {
            cb(out.join("\n") || "", list);
          }
        });
      }
    });
  }

  search(dir);
};

About 50 lines of code (minus empty lines, comments and closing brackets) to implement a grep-like file system search in NodeJS. Here's the same function implemented with VerbotenJS conventions.

function grep(dir, query, filemask, recurse, hidden, cb) {
  //grep for 'query' in 'dir'.
  //'recurse' if necessary,
  //ignore 'hidden' files if necessary.
  //'cb' required.
  dir = dir || process.cwd();
  query = query.toRegex('i');
  filemask = filemask.toRegex('i');

  //recursively search the filesystem
  q.fs.ls(dir, recurse, function(list) {
    //filter files we don't need
    var files = list.ea(function(f) {
      if (!hidden && f[0] == ".") return; //things like .hg/.git
      if (!filemask.test(f)) return;
      return f;
    });

    var matches = [];

    //read each file and collect matching line info
    files.sort().ea(function(next, f) {
      q.f.utf8(f, function(txt) {
        txt.split('\n').trim().ea(function(line, i) {
          //if line matches query, return info
          if (query.test(line)) {
            matches.push({
              path : f,
              line : i,
              text : line
            });
          }
        });

        //process next file
        next();
      });
    }, function() {
      //replicate grep stdout
      var stdout = matches.ea(function(o) {
        return [o.path, o.line + 1, ": ", o.text, ''].join('\n');
      });

      //return stdout and matches obj
      cb(stdout, matches);
    });
  });
};

Here it only took 22 lines of code to implement the same logic. And in reality, the VerbotenJS version is more robust than the raw JavaScript version due to the flexibility of functions like .toRegex() and .test().

And my .ea() function operates like Array.forEach, except that it allows for Object key iteration, asynchronous or synchronous iteration based on the presence of a callback function, and enhanced iteration workflows with helpers like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to ever use for loops, for-in loops, or any of the new ES5 array extensions Array.forEach|map|filter|some|every|reduce* functions.

That's all I have time to report on now, but I'll put up some more examples as I find well isolated examples.

Conclusion

VerbotenJS has been a career long project of mine. I've renamed/rewritten the project multiple times over, for various different JavaScript hosts like WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for fun. With the growing popularity of NodeJS I think VerbotenJS has finally found a good home. And the architecture is finally to a point that I consider it stable and worthy of peer review. So get reviewing peers!

Thanks for reading, Marcus Pope

npm loves you