NodeJS require script with different behaviour - javascript

I'm writing a serverless application which contains a file, for simplicity let's call it icecream.js. Now I have multiple build and deployment methods.
One simply takes this file, icecream.js, and moves it into lots of other code needed for the purpose of that build. Let's call the script which was built, containing the same code (at some point) as icecream.js, hotfudgesundae.js (Ice burried by delicious hot fudge). I can't control the hot fudge that makes up the rest of the built script. I also can't control the build process.
Build process number two executes a script (Let's call it sundaepie.js) which needs the module.exports value of icecream.js (We all know there must be some ice cream buried in there somewhere). It mustn't execute any of the code hotfudgesundae.js needs when requiring it.
Now there's a fourth script, SearchingSolutions.js, which require's the hotfudgesundae.js script.
The only thing I can control is sundaepie.js and icecream.js, so I can change the way that sundaepie requires icecream.js and what icecream.js includes.
PROBLEM: I need to write icecream.js in a way that the code it contains IS executed for hotfudgesundae.js, but not executed when required with sundaepie.js. The module.exports can stay the same.
What I tried: I can't just check if module.parent exists, because while hotfudgesundae.js doesn't require the script (icecream.js is baked into it when built), hotfudgesundae.js itself is required by SearchingSolutions.js.
I tried to make module.exports a function with one parameter, and if this parameter is given, return something, else execute the code that hotfudgebrownie.js needs. I would then call it like so require('icecream.js')(true) from sundaepie.js and require hotfudgesundae.js in the regular fashion from SearchingSolutions.js (since I can't control it), but it wouldn't execute the function when required without passing the brackets to invoke the function.
module.exports = function(isexport) {
if (isexport) {
return "For sundaepie";
} else {
console.log("Executing code in hotfudgesundae.js");
...
}
}
How can I get this to work? If you have any questions go leave a comment ;)

You could use a global variable (yes, that hurts):
// inside the module
if(global.isCold) /*...*/
// before you require it
global.isCold = true

Related

How to export functions for unit tests in PortalScript (ECMAScript5)

We have an application server supporting an embedded server side scripting language called PortalScript (SpiderMonkey V1.8.5), which is compliant to the ECMA-Script-262 Edition 5 (ECMAScript5) specification. The Portalserver supports numerous so-called scripting hooks and event hooks, which allow to embed our scripts. These attached scripts implement our business logic which I want to test e.g. with Jasmine, Jest, etc.
The first problem is that return statements at the end of the scripts are mandatory, and these return statements are not within functions. A minimal example could look like this:
// #import "myFctLib"
var currentModel = given_context.model;
if (!currentModel) {
return -1;
}
currentModel.setAttribute("$fieldId", "SUCCESS");
return 0;
These scripts can be quite large. So if we extract functions (within a script) to just test them, how could we call these functions from the tests? How can we export functions compliant to PortalScript? Does someone know if it's possible to use the CommonJS module system with PortalScript?
Currently we don't use a module system but a precompiler to replace code for statements like // #import "myFctLib" (see first line in the example code) in the scripts to use functions from other scripts...
In such a context, how would you write (unit) tests? How would your approach look like?
I assume PortalScript will eventually wrap the embedded script in its own function and call that. I'd also assume that for testing purposes, you don't want to execute the entire embedded script function. These two conditions seem mutually exclusive.
Would it be an option to separate the logic into two files, one defining the business logic in small, testable functions, and one file including the former and then just calling main()
myFctLib.js:
// #import "someOtherFctLib"
function setSuccessAttribute(model) {
if (!model) {
return -1;
}
model.setAttribute("$fieldId", "SUCCESS");
return 0;
}
myPortalScriptFile.js
// #import "myFctLib"
return setSuccessAttribute(given_context.model);
You'd then only test myFctLib.js, which still leaves room for errors in myPortalScriptFile.js, but that room should be fairly small.

Custom Yeoman Generator can't overwrite files

I'm trying to create a simple generator to standardize creation of node projects. In my generator I make calls to copyTpl like:
generator.fs.copyTpl(
sourcePath,
destinationPath
context,
//ignore ES6 constructs in our templates
{
interpolate: /<%=([\s\S]+?)%>/g
}
);
This works great as long as no files exist in my target directory. Unfortunately, if a file exists and I choose to overwrite it I get the following error:
Error: no writecb in Transform class
at afterTransform (/Users/gerrard00/projects/generator-mine/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:95:33)
at TransformState.afterTransform (/Users/gerrard00/projects/generator-mine/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:79:12)
at Object.callback (/Users/gerrard00/projects/generator-mine/node_modules/yeoman-generator/lib/base.js:787:7)
at /Users/gerrard00/projects/generator-mine/node_modules/yeoman-generator/lib/util/conflicter.js:79:18
at Conflicter.<anonymous> (/Users/gerrard00/projects/generator-mine/node_modules/yeoman-generator/lib/util/conflicter.js:193:12)
at PromptUI.onCompletion (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/inquirer/lib/ui/prompt.js:57:10)
at AnonymousObserver.Rx.AnonymousObserver.AnonymousObserver.completed (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:1550:12)
at AnonymousObserver.Rx.internals.AbstractObserver.AbstractObserver.onCompleted (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:1489:14)
at Subject.Rx.Subject.addProperties.onCompleted (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:5871:19)
at Subject.tryCatcher (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:63:31)
This means that my generator only works in empty folders. I've re-read the "Creating a generator" docs about twenty times, but I can't figure out what I'm missing. What do I need to add to my generator to prevent this error?
Update: The files are actually overwritten, despite the error.
It turns out that the issue was with the fact that my code was walking a directory asynchronously using the node-walk package. The calling method used the generator async method, but called the done callback synchronously. I modified it to call the done callback in the walk end event handler and the error went away.

QtWebKit bridge: call JavaScript functions

I am writing a hybrid application with HTML interface and Python code.
I can access Python functions via a shared object:
pythonPart.py:
class BO(QObject):
def __init__(self, parent=None):
super(BO, self).__init__(parent)
#Slot(str)
def doStuff(self, txt):
print(txt)
bridgeObj = BO()
# init stuff and frame...
frame.addToJavaScriptWindowObject( 'pyBridge', bridgeObj )
frame.evaluateJavaScript('alert("Alert from Python")')
frame.evaluateJavaScript('testMe()')
frame.evaluateJavaScript('alert("Starting test");testMe();alert("Test over")')
jsPart.js:
function testMe() { alert('js function testMe called'); }
pyBridge.doStuff("bla");
testMe();
Calling Python functions from JS works, as does calling testMe from JS. Calling "standard" JS functions like alert from Python works, too.
The last two Python lines won't:
evaluateJavaScript("testMe()") doesn't do anything at all.
The last line executes the first alert and won't continue after that.
EDIT: I already tried having some time.sleep() between loading and calling the evaluateJavaScript and I'm loading the webpage from the local machine.
The most likely problem is that the JavaScript just isn't loaded yet. Adding time.sleep() calls doesn't help for that, those will also block the Qt event loop from continuing, not just your Python code.
Try waiting for the page to have fully loaded instead, for example (using the loadFinished signal:
def onLoad():
frame.evaluateJavaScript('testMe()')
frame.loadFinished.connect(onLoad)
Aditionally, for getting more debug information in situations like this, you might want to implement QtWebKit.QWebPage.javaScriptConsoleMessage.
There are at least two errors in the example code.
Firstly, when you add the object to the javascript window, you call it "pyBridge", but you then try to reference it in the javascript as "bridgeObj". Obviously, this will throw a ReferenceError which will prevent any further execution of the script.
Secondly, the doStuff method is missing a self argument, which will cause a TypeError to be raised by PySide.
Dealing with those two issues should be enough to fix your example code, so long as you make sure that the bridge object is added to the javacsript window before the html is loaded. This step is required if you want to reference the bridge object in top-level javascript code. However, if the bridge object is only ever referenced in function-level code, it can be safely added to the javascript window after the html has loaded.

Starting with RequireJS, communication between modules

I am an ActionScript 3 developer who is just making his first way in building a large-scale JavaScript app.
So I understand modules and understand that AMD is a good pattern to use. I read about RequireJS and implemented it. However, what I still don't understand is how to achieve Cross-Module communication. I understand that there should be some kind of mediator...
I read articles and posts and still couldn't understand how to implement it simply.
Here is my code, simplified:
main.js
require(["Player", "AssetsManager"], function (player, manager) {
player.loadXML();
});
Player.js
define(function () {
function parseXml(xml)
{
// NOW HERE IS THE PROBLEM -- how do I call AssetsManager from here???
AssetsManager.queueDownload($(xml).find("prop").text());
}
return {
loadXML: function () {
//FUNCTION TO LOAD THE XML HERE, WHEN LOADED CALL parseXml(xml)
}
}
});
AssetsManager.js
define(function () {
var arrDownloadQueue = [];
return {
queueDownload: function(path) {
arrDownloadQueue.push(path);
}
}
});
Any "for dummies" help will be appreciated :)
Thank you.
To load up modules from another modules that you define(), you would simply set the first parameter as an array, with your module names in it. So let's say, in your code, you wanted to load Player.js into AssetsManager.js, you would simply include the string Player in the array.
This is simply possible because define's abstract implementation is equivalent to require, only that the callback passed to define expects a value to be returned, and that it will add a "module" to a list of dependencies that you can load up.
AssetsManager.js
define(['Player'], function (player) {
//... Your code.
});
However, if I can add to it, I personally prefer the use of require inside of the callback passed to define to grab the dependency that you want to load, instead of passing parameter to the callback.
So here's my suggestion:
define(['Player'], function () {
var player = require('Player');
});
And this is because it's much more in tune with CommonJS.
And this is how main.js would look like formatted to be more CommonJS-friendly:
require(["Player", "AssetsManager"], function () {
var player = require('Player');
var manager = require('AssetsManager');
player.loadXML();
});
But the CommonJS way of doing things is just a personal preference. My rationale for it is that the order in which you input the dependency names in the array might change at any time, and i wouldn't want to have to step through both the array and the parameters list.
Another rationale of mine (though, it's just pedantic), is that I come from the world of Node.js, where modules are loaded via require().
But it's up to you.
(This would be a reply to skizeey's answer, but I don't have enough reputation for that)
Another way of solving this problem without pulling in Player's AssetManager dependency via require is to pass the AssetManager instance that main.js already has around. One way of accomplishing this might be to make Player's loadXML function accept an AssetManager parameter that then gets passed to parseXml, which then uses it. Another way might be for Player to have a variable to hold an AssetManager which gets read by parseXml. It could be set directly or a function to store an AssetManager in the variable could be used, called say, setAssetManager. This latter way has an extra consideration though - you then need to handle the case of that variable not being set before calling loadXml. This concept is generally called "dependency injection".
To be clear I'm not advising this over using AMD to load it in. I just wanted to provide you with more options; perhaps this technique may come in handier for you when solving another problem, or may help somebody else. :)

Google Website Optimiser Control Javascript

Could someone explain the javascript that makes up Google's Website Optimiser Control script? Specifically: the first two lines, which seem to be empty functions, and why is the third function wrapped parentheses () ?
As far as I can tell this script is basically writing out a new <script> which presumably loads something for A/B testing.
function utmx_section(){}
function utmx(){}
(function() {
var k='0634742331',d=document,l=d.location,c=d.cookie;
function f(n) {
if(c) {
var i=c.indexOf(n+'=');
if (i>-1) {
var j=c.indexOf(';',i);
return escape(c.substring(i+n.length+1,j<0?c.length:j))
}
}
}
var x=f('__utmx'),xx=f('__utmxx'),h=l.hash;
d.write('<sc'+'ript src="'+'http'+(l.protocol=='https:'?'s://ssl':'://www')+'.google-analytics.com'+'/siteopt.js?v=1&utmxkey='+k+'&utmx='+(x?x:'')+'&utmxx='+(xx?xx:'')+'&utmxtime='+new Date().valueOf()+(h?'&utmxhash='+escape(h.substr(1)):'')+'" type="text/javascript" charset="utf-8"></sc'+'ript>')
}
)();
I've attempted to step through with the firebug debugger but it doesn't seem to like it. Any insights much appreciated.
Many thanks
inside anonymous function it shortens names of document and cookies inside it at first, function f(n) gets value of cookie under name n. Then Google reads its cookies and with help of d.write it loads its scripts (as I see they are related to Google Analytic). This way it makes On-Demand JavaScript loading... Actually you load these scripts all the time, Google just needs some additional parameters in url, so this is done this way - save parameters in cookie, which next time are used to get script again.
And finally back to the first two magic lines :) After Google loads its script (after executing d.write), there are some functions which uses utmx and utmx_section, as well as definition of these functions, or better to say overriding. I think they are empty at first just because another function can execute it before its real definition, and having empty functions nothing will happen (and no JS error), otherwise script would not work. E.g. after first iteration there is some data, which is used to make real definition of these functions and everything starts to work :)
The first 2 functions are in fact empty, and are probably overridden later on.
The third function is an anonymous self-executing function. The brackets are a convention to make you aware of the fact that it is self executing.
the "f" function looks up the value given to it in the document's cookies and returns it. Then a new script tag is written to document (and requested from server) with these values as part of its URL.

Categories

Resources