Open Side Menu Go to the Top

12-27-2014 , 07:47 AM
Just trying it to see if it's useful or not. The basic idea of "build a website with HTML/CSS/JS"...poof apps...sounds good enough to give it a try.
Last time I looked at it was before they had the plugin system. Looks quite a bit better these days just from a high level POV.

+something that forces me to do a bit more JS is a nice bonus.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD **
$25m Guaranteed WPM on CoinPoker
Join the action now
Daily Rewards • Splash Pots • CoinRaces
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD **
12-27-2014 , 09:22 AM
Quote:
Originally Posted by suzzer99
$100 to the first person who references this post if I don't have something up on github within a month.

suzzer99,


Do you have a github account I can follow, and can you pay via bitcoin?
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 01:32 PM
Yeah but I think I should make another one that doesn't have my real name on it – for various reasons. Paypal or BofA.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 07:06 PM
Ok JS whiz's here's a tricky one. Let's say I have an array of arguments I want to feed to a function but for some reason myFunc.apply(this, [myArgs]) doesn't work.

This is straight from express where you initialize a route like so:
app.get(route, middleware1, middleware2, ... etc.)

So you would think app.get.apply(this, [route, middleware1, middleware2, ...]) would work. But I get this error:

lifecycle bail: TypeError: Object #<Object> has no method 'use'
at app.(anonymous function) (/Users/449706/lab/dtve/node_modules/express/lib/application.js:428:33)

Note I also tried using null instead of this as the first argument to apply. I have no idea why it's not working, maybe some kind of express magic is going on and app.get isn't really a true function somehow?

So for now I am going to make a middleware string that looks like this "middleware[0], middleware[1], ..." then do a big fat eval to get it to work. Which I don't mind because this only happens at app boot time.

But I have a feeling there is some much more elegant way that doesn't involve eval. Ideas?
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 07:15 PM
My eyes - the goggles they do nothing!

Code:
function registerRoutes(middlewares) {
  var middlewareString = middlewares.reduce(function(prev, curr, index, array) {
    return prev + ', middlewares[' + index + ']';
  }, '');

  console.log(middlewareString); // ", middlewares[0], middlewares[1], middlewares[2], middlewares[3], middlewares[4], middlewares[5], middlewares[6], middlewares[7], middlewares[8]"

  _.each(routes, function(route) {
        
    eval('app[route.verb](route.path' + middlewareString + ')');
Well maybe it's not that bad. This is part of what I'm going to publish to git/npm though. So I don't want to look like a caveman.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 09:27 PM
Quote:
Originally Posted by suzzer99
Yeah but I think I should make another one that doesn't have my real name on it – for various reasons.

That's a pretty good idea. There's lots of unsavory creatures trawling the internet.



Quote:
Originally Posted by suzzer99
Paypal or BofA.
If I win, I'll just have you give it to a charity.

Cheers!
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 10:22 PM
Quote:
Originally Posted by suzzer99
This is straight from express where you initialize a route like so:
app.get(route, middleware1, middleware2, ... etc.)

So you would think app.get.apply(this, [route, middleware1, middleware2, ...]) would work. But I get this error:

lifecycle bail: TypeError: Object #<Object> has no method 'use'
at app.(anonymous function) (/Users/449706/lab/dtve/node_modules/express/lib/application.js:428:33)
Shouldn't it be:

app.get.apply(app, [route, middleware1, middleware2, ...])

?
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 11:30 PM
Quote:
Originally Posted by catsec
That's a pretty good idea. There's lots of unsavory creatures trawling the internet.





If I win, I'll just have you give it to a charity.

Cheers!
Sigh, I meant in a month when I hadn't done it. Not now.

Whatever I already have my little repo up and working. So technically that probably counts. But I will still ship you $100 if I don't get the big repo up in a month.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-27-2014 , 11:36 PM
Quote:
Originally Posted by candybar
Shouldn't it be:

app.get.apply(app, [route, middleware1, middleware2, ...])

?
Yes, that seems to work. DERP! Thanks.

Last edited by suzzer99; 12-27-2014 at 11:48 PM.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:05 AM
Quote:
Originally Posted by suzzer99
My eyes - the goggles they do nothing!
My roommate and I in college were busting up for hours at that line when that episode first aired.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:12 AM
I'm confused, there should be no difference between x.apply(x, [args]) and x([args]) anyways, right? Why even bother with apply if you're not going to change the value of this?
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:18 AM
Quote:
Originally Posted by suzzer99
Yes, that seems to work. Can you please explain to me like I'm dumb - what is supposed to go in that first argument of apply - and why app works here while this and null fail?
In Javascript, every function/method call has "this" context, regardless of whether it looks like a function call or a method call and "this" context, which can be referenced as "this" within the function/method body, can be explicitly set, as opposed to most class-based OO languages where it is fixed.

The first argument of apply is used to set that context object for the method call. When you do make app.get(), let's say, somewhere within the body of .get(), there's a reference to "this" like:

var abc = this.abc;

If you simply invoked .get() with app.get(), you'd expect this.abc to refer to app.abc, right? That's how it works in most other languages and Javascript mimics behavior by having "this" automatically set to the object last referenced before the function was fetched - in other words, the expression before the last dot. But this isn't strict behavior and apply/bind/call allows you to get around this. For example, if you invoke .get() with:

app.get.apply(x, []);

Instead of app being "this" within the body of .get() method, x gets passed as "this" which changes the meaning of the method call entirely. In your case, by doing app.get.apply(this, [...]), you're taking the current "this" object and telling .get() to use that as "this", instead of app.

This does a better job of explaining "this" in more detail than I can:

http://www.digital-web.com/articles/...in_javascript/
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:21 AM
Dammit of course you saw that and responded before I looked it up. Thanks, your explanation is much better.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:23 AM
Quote:
Originally Posted by Grue
I'm confused, there should be no difference between x.apply(x, [args]) and x([args]) anyways, right? Why even bother with apply if you're not going to change the value of this?
Because express expects route, then n-number of individual middleware functions as arguments (not in an array).
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:28 AM
Quote:
Originally Posted by Grue
I'm confused, there should be no difference between x.apply(x, [args]) and x([args]) anyways, right? Why even bother with apply if you're not going to change the value of this?
Not quite - x.apply(x, [arg1, arg2, ...]) is the same as x(arg1, arg2, ...). Function.prototype.apply is useful if the function takes a variable number of arguments and you have an array that needs to be passed a list of arguments. For example, you may want to do something like arr.push.apply(arr, arr2) to append arr2 to arr.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:35 AM
Ok another dumb one. I have my little git repo and now I'd like to write some tests for it. I can't get past the first step of initializing my module.

When I run this command: ./node_modules/.bin/mocha test/nodule.nu.js

I get this error:
Code:
  1) app should initialize:
     Error: Cannot find module 'glob'
      at Function.Module._resolveFilename (module.js:338:15)
Here is my test:
Code:
var assert = require('assert');

var app = {};
var appConfig = {};

describe('app', function(){
  it('should initialize', function(done){
    var nodule = require('../nodule.js')(app, appConfig);
    assert(true === true);
    done();
  })
});
And here is the relevant part of the actual code I'm trying to test:
Code:
var glob = require('glob');
var path = require('path');
var _ = require('lodash');

module.exports = function(app, appConfig, customDebug) {
So how do we handle 3rd party dependencies when testing node components? This seems to be one of those things that's so basic I can't even find anything on google. I'm definitely at the wtf phase right now.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:36 AM
Quote:
Originally Posted by suzzer99
Dammit of course you saw that and responded before I looked it up. Thanks, your explanation is much better.
Haha, np, thanks. It took way too long to write that and only when I was mostly done with it had it occurred to me that someone else must have written something more comprehensive. I didn't see your response to Grue either - I'm operating with a time lag today
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:48 AM
For example, I look at this test here: https://github.com/segmentio/nsq.js/...unit/framer.js

It initializes and tests this file: https://github.com/segmentio/nsq.js/.../lib/framer.js

Yet it doesn't choke and say, "can't find module Emitter".

Hmmmm.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:50 AM
Quote:
Originally Posted by suzzer99
Ok another dumb one. I have my little git repo and now I'd like to write some tests for it. I can't get past the first step of initializing my module.

When I run this command: ./node_modules/.bin/mocha test/nodule.nu.js

I get this error:
Code:
  1) app should initialize:
     Error: Cannot find module 'glob'
      at Function.Module._resolveFilename (module.js:338:15)
Here is my test:
Code:
var assert = require('assert');

var app = {};
var appConfig = {};

describe('app', function(){
  it('should initialize', function(done){
    var nodule = require('../nodule.js')(app, appConfig);
    assert(true === true);
    done();
  })
});
And here is the relevant part of the actual code I'm trying to test:
Code:
var glob = require('glob');
var path = require('path');
var _ = require('lodash');

module.exports = function(app, appConfig, customDebug) {
So how do we handle 3rd party dependencies when testing node components? This seems to be one of those things that's so basic I can't even find anything on google. I'm definitely at the wtf phase right now.
Are the 3rd party modules installed and mocha is somehow not running in the proper context within which to locate them or are they not installed at all? Is there a package.json that specifies dev and production dependencies? I actually haven't really used node.js/npm at all so I can't really help with specifics, but I did look into the mechanics of publishing a package a while back.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 12:55 AM
Okay I'm an idiot. Somehow my node_modules folder got wiped out and only mocha was in there - so no glob, no lodash. package.json was fine. I just had to run npm install again.

Probably time to put the keyboard down.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 01:41 AM
Ok one last question for the brain trust.

The repo I just put up "discovers" these things I'm calling "nodules" in specified directories, then initializes them. The nodules are basically analogous to an HTML page, or partial page, or JSON call. In the Java world they would be a JSP.

I'm wrestling with a kind of messy syntax that's needed to fire up each of these things. Any ideas are appreciated.

One important detail is that we need the filename and path for various "magic" things like if you put a template in the same folder with the same name the framework will just use that template w/o the developer having to specify it (but this can be easily overridden of course, and templates can even be chosen at request time if desired).

So here is the function which finds and initializes them using standard AMD:
Code:
  function loadNodules(dir) {
    glob.sync('./**/*.js', { cwd: dir })
      .forEach(function(nodule) { require(nodule)(app); });
  }
This is what the initNodule method looks like inside the nodules themselves, (notice the first parameter - the built-in node variable __filename - we need this):
Code:
module.exports = function(app) {
  app.initNodule(__filename, {
  
    route: '/home',
    apiPath: '/cms/page',
    etc.

    someFunction: function() {...},
   
   ... everything except util functions and constants lives inside here ...
  
  };
}
So for those not totally familiar with node or AMD, what's happening here is the require function in the first block is basically loading and parsing the file in block 2, and executing everything outside module.exports. When (app) is called on the result of the require(...) closure, that calls the module.exports function.


And here is the initNodule function which each nodule actually calls when it is initialized by the framework. It's probably not too important to get mired in the details of this function. Just know that it needs the file argument, and that it sets up the routes to be registered with express by the framework.
Code:
  
  // create seedNodule (cloned at the start of each request) for each nodule and set up routes in order that they should be registered with express
  app.initModule = function initModule(file, config) {
    var seedNodule = _.extend(_.cloneDeep(defaultConfig), config); // merge config properties onto default config
    seedNodule.path = path.dirname(file);
    seedNodule.name = path.basename(file, '.js');

    // nodules can have multiple routes
    var routeArray = (typeof seedNodule.route === 'string') || (seedNodule.route instanceof RegExp) ? [seedNodule.route] : seedNodule.route;
    _.each(routeArray, function(routePath) {
      seedNodules[routePath] = seedNodule; // routes must me unique
      
      // use routeIndex to control what order routes are initialized with express
      if (!routes[seedNodule.routeIndex])
        routes[seedNodule.routeIndex] = [];
      routes[seedNodule.routeIndex].push({path:routePath, verb:seedNodule.routeVerb});
    });
  }
The whole idea is to make these things "self discoverable" meaning they never have to be specified in a config file somewhere, and can be moved around or deleted with no problem - just like say a JSP would be. Except in this case the route is not tied to the filename or folder structure - which is a drastic improvement over JSPs imo.

(Yes I know Java web app routes don't have to be tied to the JSP filename and path -it's just they usually start out that way and then things get messy.)

It all works really well. I'm just kind of worried that the wonky syntax inside the nodules might turn people off. Ideally I'd like to figure out a way to get each of the nodules to look like this:
Code:
module.exports = function(app) {
  
  route: '/home',
  apiPath: '/cms/page',
  etc.

  someFunction: function() {...},
   
  ... everything except util functions and constants lives inside here ...

}
without the extra function wrapped inside. I wonder if there's some kind of clever way I could wrap the insides of the module programmatically before initializing, w/o touching the actual file. I think that __filename parameter is the big sticking point though.

Last edited by suzzer99; 12-28-2014 at 02:01 AM.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 02:12 AM
can't you have an util function that does the wrapping part for you and has the refrence to __filename? then you'd just be passing you json config to the util, and the util would return the function you want module.exports to equal. don't have a ton of node experience, so there may be something preventing that from working i'm not thinking of
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 02:27 AM
Maybe. One issue though is I think the function needs to be executed from the context of the file to pick up the correct __filename built-in var.

However I'm starting to wonder why I need the __filename var at all when I already have the full filename and path from the glob in the first step. Tinkering with that now.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 04:01 PM
Ok well that worked. Now I just get to change every page/component on the site.
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
12-28-2014 , 07:57 PM
Ok back to scratching my head again. How would I test this function which my component exposes?

Code:
  
  return {
    loadNodules: loadNodules,
    registerRoutes: registerRoutes
  };
  
  function loadNodules(dir, exclude) {
    var root = dir || process.cwd(); // TOOD - should this be process.cwd() + '/app' ?
    glob.sync('./**/*.js', { cwd: root })
      .filter(doesntMatch.apply(this, exclude))
      .forEach(function(file) { initNodule(path.join(root, file)); });
  }
My stub test looks like this: it('should find and init all .js files but exclude .nu.js files')

Glob is a 3rd party module which is looking at the actual file system. How could I mock something like that? Also initNodule is an internal method that is not exposed by the component. Is there any way to fake/spoof/spy on that?

I could start rewriting my code to expose more private methods and variables just for test purposes (with like __ prefix or something). But that seems like a fundamentally bad idea. Thoughts?

Devs with lots of unit-test experience - to what level will you go to make your code more test-friendly if it means convoluting the code? Is this something you wouldn't even bother writing a test for because it's so low level and hard to mock/spy on?
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD ** Quote
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD **
$25m Guaranteed WPM on CoinPoker
Join the action now
Daily Rewards • Splash Pots • CoinRaces
** UnhandledExceptionEventHandler :: OFFICIAL LC / CHATTER THREAD **

      
m