Many new instances of requirejs module - javascript

I am creating a typing game which I have "app.js" as a main and loading "words.js" by requirejs.
I need to use > 2 words but I am still naive with javascript and not sure this is right to do in AMD. Anyone could point me out. I would really appreciate it.
I think it would be like following code but it doesn't work and give me error
"Uncaught TypeError: object is not a function"
[app.js]
require(['jquery','app/canvas','app/words'], function($,game_screen,words){
var words1 = new words();
var words2 = new words();
.
.
});
[words.js]
define(['app/canvas'],function(canvas){
var word_list=[{"word1"},{"word2"},...];
return {
addWord: function(new_word){
.
.
});

Right now you're returning an object from your words module: { addWord: function() {} ... }. So in app.js, when you set words to be equal to the object returned from the words module, you would invoke the functions by doing words.addWord().
If instead you want to use the new words() syntax in app.js, you would have to change your words module to return a function instead of an object (hence the error):
define(['app/canvas'],function(canvas) {
var word_list=[{"word1"},{"word2"},...]; // not sure how this is used
function words() {
// some code
}
words.prototype.addWords = function() {
// some code
}
return words;
}

Related

How to dynamically add function objects to an object function map

Hey there StackOverflow people of the world! Thank you for helping me with my question, and I apologize if this question gets a bit long winded. I just want to be clear about all the details and constraints I am working with. I found a few other related questions but nothing that was really very clear about how to get around my specific problem, unless I am missing something. Related questions:[1, 2]
Question Setup:
This is what I have and how it works, my question will be about a problem I am having
I've got a object that I've filled with named functions. The purpose of the object map is to contain many functions calls from multiple files. I am calling each function a "business rule" and they are typically very small functions that do a singular action with well-defined inputs and outputs. It also lets me chain the function calls sequentially with the output from functionCall1 becoming the input functionCall2.
All of my business rule definitions up to this point have been in a set of files that reside in a sub-folder called "Framework", but what I am trying to do now is allow the "Client" to define their own business rules in their own files and their own object map of function calls. What I would like to do is add all of the function calls to a single shared data storage.
What I am trying to avoid doing:
I am NOT trying to serialize the function calls, neither am I trying to leverage the 'eval' capability of JS. I've tried working with this before and it gets really messy!
Also I DO NOT want to declare a "class" object or use the "this" keyword for this reason:
10-most-common-javascript-mistakes
What is working:
(NOTE: Greatly simplified as I currently have hundreds of "business rules")
// rulesLibrary.js
import * as stringParsing from './Rules/stringParsing';
export const rulesLibrary = {
['Echo']: (inputData, inputMetaData) => (inputData, inputMetaData),
// Business Rules
// ********************************
// StringParsing rules in order
// ********************************
['stringToBoolean']: (inputData, inputMetaData) => stringParsing.stringToBoolean(inputData, inputMetaData),
['stringToDataType']: (inputData, inputMetaData) => stringParsing.stringToDataType(inputData, inputMetaData),
}
// stringParsing.js
export const stringToBoolean = function(inputData, inputMetaData) {
var returnData;
// Function Body...
return returnData;
};
export const stringToDataType = function(inputData, inputMetaData) {
var returnData;
// Function Body...
return returnData;
};
// ruleBroker.js
import * as rules from './rulesLibrary';
export const processRules = function(inputData, inputMetaData, rulesToExecute) {
var returnData = inputData;
for (var rule in rulesToExecute) {
if (rulesToExecute.hasOwnProperty(rule)) {
var key = rule;
var value = rulesToExecute[key];
returnData = rules.rulesLibrary[value](returnData, inputMetaData);
}
}
return returnData;
};
You can see in the code above the rulesLibrary is defining the functions in an object rulesLibrary = {}; which is also exported. Then in the ruleBroker we are calling the associated function:
rules.rulesLibrary[value](returnData, inputMetaData)....and this works great.
My Goal
My goal is to rather than store all these functionName: functionCall on the rules.rulesLibrary, I want to store them on a singleton data storage object I am calling "D".
Here is the definition of "D":
// data.js
export var data = {};
What I have tried - Attempt 1
I first tried to assign all of the contents of the rules.rulesLibrary from the rulesLibrary.js directly to "D" like so in the ruleBroker.js file:
// NOTE: I am actually doing this inside a function so I can boot-strap the rules.rulesLibrary into `D`, before the application begins going about the business of calling business rules via the ruleBroker.
import * as rules from './rulesLibrary';
var D = require('../Resources/data');
D['BusinessRules'] = {};
D['BusinessRules'] = rules.rulesLibrary;
This did not work and attempting to console.log(JSON.stringify(D)); just gave me back:
D{BusinessRules} = {};
What I have tried -- Attempt 2
So I thought maybe I should try and define the business rules map named function calls directly on "D" like so in the rulesLibrary.js file:
// NOTE: I am again doing all of this inside a boot-strap function for the same reason as above.
export const initRulesLibrary = function() {
D['BusinessRules'] = {};
D['BusinessRules'] = {
['Echo']: (inputData, inputMetaData) => (inputData, inputMetaData),
// Business Rules
// ********************************
// StringParsing rules in order
// ********************************
['stringToBoolean']: (inputData, inputMetaData) => stringParsing.stringToBoolean(inputData, inputMetaData),
['stringToDataType']: (inputData, inputMetaData) => stringParsing.stringToDataType(inputData, inputMetaData),
}
};
Again I get the same thing, contents of D are: D{BusinessRules} = {}.
Maybe console.log in combination with JSON.stringify doesn't work with function-objects?
But then again, I do have rules that return a function-object and I have been able to stringify those function-objects in the past with this same code. Granted it's a function-object so I am not expecting it to look pretty when stringified, but that's not the point. The point should be that the function-object exists on 'D' and it clearly does not, what am I missing here? How can I get all my function-objects mapped on 'D' so that I can add/merge more function-object definitions to it?
Ultimately this is what I want to be able to do:
function addClientRules(clientRules) {
Object.assign(D['BusinessRules'], clientRules['BusinessRules']);
};
Such that D now contains all of the system-defined business rules & all of the client defined business rules. Then in the ruleBroker, I would just call whatever business rule like this:
export const processRules = function(inputData, inputMetaData, rulesToExecute) {
var returnData = inputData;
for (var rule in rulesToExecute) {
if (rulesToExecute.hasOwnProperty(rule)) {
var key = rule;
var value = rulesToExecute[key];
// OLD WAY:
// returnData = rules.rulesLibrary[value](returnData, inputMetaData);
// NEW WAY:
returnData = D['BusinessRules'][value](returnData, inputMetaData);
}
}
return returnData;
};
Any ideas? Thoughts? Edits? Rants? Am I at least on the right track?
Thank you again for your help! Hopefully this will help someone else too!! :-D
Turns out I was already doing everything correctly to begin with. It's just that console.log & JSON.stringify don't work well with a object map of functions.
The function maps do contain the function calls, just don't expect your console.log even with JSON.stringify to dump that data in any way. You have to proceed with making the call as if it is there and verify that the execution is successful by putting console logs in the function that calls the rule and additionally putting console logs in the rule that is to be executed.
It does work and it's pretty cool when it does!!
I hope this can help someone else, please comment if you have any additional questions and/or if I can provide additional solution details.
Log of successful execution:
c.ccustomEcho resolves as: customEcho
BEGIN warden.executeBusinessRule function
businessRule is: customEcho
ruleInput is: Calling Custom Echo from application
ruleMetaData is: Calling Custom Echo from application
BEGIN ruleBroker.processRules function
inputData is: "Calling Custom Echo from application"
inputMetaData is: "something-nothing"
rulesToExecute are: {"0":"customEcho"}
BEGIN clientStringParsing.customEcho function
inputData is: Calling Custom Echo from application
inputMetaData is: something-nothing
returnData is: Calling Custom Echo from application clientStringParsing.customEcho
END clientStringParsing.customEcho function
returnData is: "Calling Custom Echo from application clientStringParsing.customEcho"
END ruleBroker.processRules function
returnData is: Calling Custom Echo from application clientStringParsing.customEcho
END warden.executeBusinessRule function
Cheers
~Seth

RequireJS load dynamic dependencies as variables

Is there a way load class names as variables? new window[a] does not seem to work. I'm getting an error of TypeError: window[a] is not a constructor.
require([
'myController'
], function (myController) {
// this is working fine
// new myController().init();
$(function() {
var a = $('.test').attr('class'); // this returns myController
new window[a]; // error here
});
});
To do what you want you would need to use eval like this:
eval("new " + window[a] + "()");
Working example: https://jsfiddle.net/ybjo4pn9/
NOTE: Use eval with caution.

requirejs and ByteBuffer

im an javascript newbie and google didnt helps:
I tryed to load ByteBuffer.js in an require.js module:
define(['js/ByteBufferAB'], function (ByteBufferAB) {
var MessageBase = function () {
this._version = 0; // unsinged int 16 bits
this._dataType = "";
};
MessageBase.prototype.toBytes = function () {
//console.log( new ByteBufferAB(58));
var headerBytes = new ByteBufferAB(58); // <-- here comes the error
headerBytes.clear();
return headerBytes;
};
return MessageBase;
});
with the same syntax math.js is properly loaded.
But with ByteBufferAB.js the following error comes:
Uncaught TypeError: undefined is not a function
What am I doing wrong?
Thank you for your help
In your define call you refer to the module as js/ByteBufferAB so RequireJS looks for a module named js/ByteBufferAB. However, the module defines itself as ByteBuffer:
/* AMD */ else if (typeof define === 'function' && define["amd"])
define("ByteBuffer", ["Long"], function(Long) { return loadByteBuffer(Long); });
Because the module name is hardcoded, you need to have a mapping like this in your paths in the configuration you give to RequireJS:
ByteBuffer: "js/ByteBufferAB"
and you need to refer to the module as ByteBuffer in your define call.
None of this would be required if the developers for this library had not hardcoded a name but they have, and so here we are.

Stubbing a class method with Sinon.js

I am trying to stub a method using sinon.js but I get the following error:
Uncaught TypeError: Attempted to wrap undefined property sample_pressure as function
I also went to this question (Stubbing and/or mocking a class in sinon.js?) and copied and pasted the code but I get the same error.
Here is my code:
Sensor = (function() {
// A simple Sensor class
// Constructor
function Sensor(pressure) {
this.pressure = pressure;
}
Sensor.prototype.sample_pressure = function() {
return this.pressure;
};
return Sensor;
})();
// Doesn't work
var stub_sens = sinon.stub(Sensor, "sample_pressure").returns(0);
// Doesn't work
var stub_sens = sinon.stub(Sensor, "sample_pressure", function() {return 0});
// Never gets this far
console.log(stub_sens.sample_pressure());
Here is the jsFiddle (http://jsfiddle.net/pebreo/wyg5f/5/) for the above code, and the jsFiddle for the SO question that I mentioned (http://jsfiddle.net/pebreo/9mK5d/1/).
I made sure to include sinon in the External Resources in jsFiddle and even jQuery 1.9. What am I doing wrong?
Your code is attempting to stub a function on Sensor, but you have defined the function on Sensor.prototype.
sinon.stub(Sensor, "sample_pressure", function() {return 0})
is essentially the same as this:
Sensor["sample_pressure"] = function() {return 0};
but it is smart enough to see that Sensor["sample_pressure"] doesn't exist.
So what you would want to do is something like these:
// Stub the prototype's function so that there is a spy on any new instance
// of Sensor that is created. Kind of overkill.
sinon.stub(Sensor.prototype, "sample_pressure").returns(0);
var sensor = new Sensor();
console.log(sensor.sample_pressure());
or
// Stub the function on a single instance of 'Sensor'.
var sensor = new Sensor();
sinon.stub(sensor, "sample_pressure").returns(0);
console.log(sensor.sample_pressure());
or
// Create a whole fake instance of 'Sensor' with none of the class's logic.
var sensor = sinon.createStubInstance(Sensor);
console.log(sensor.sample_pressure());
The top answer is deprecated. You should now use:
sinon.stub(YourClass.prototype, 'myMethod').callsFake(() => {
return {}
})
Or for static methods:
sinon.stub(YourClass, 'myStaticMethod').callsFake(() => {
return {}
})
Or for simple cases just use returns:
sinon.stub(YourClass.prototype, 'myMethod').returns({})
sinon.stub(YourClass, 'myStaticMethod').returns({})
Or if you want to stub a method for an instance:
const yourClassInstance = new YourClass();
sinon.stub(yourClassInstance, 'myMethod').returns({})
I ran into the same error trying to mock a method of a CoffeeScript class using Sinon.
Given a class like this:
class MyClass
myMethod: ->
# do stuff ...
You can replace its method with a spy this way:
mySpy = sinon.spy(MyClass.prototype, "myMethod")
# ...
assert.ok(mySpy.called)
Just replace spy with stub or mock as needed.
Note that you'll need to replace assert.ok with whatever assertion your testing framework has.
Thanks to #loganfsmyth for the tip. I was able to get the stub to work on an Ember class method like this:
sinon.stub(Foo.prototype.constructor, 'find').returns([foo, foo]);
expect(Foo.find()).to.have.length(2)

Windows 8 Javascript insanity - variable undefined

I'm working through some Windows 8 tutorials from the msdn website. Specifically I'm on this one.
Part of my code (copied from the tutorial is blowing my mind why it's erroring. Sample below:
(function () {
"use strict";
var list = getBlogPosts();
var groupedItems = list.createGrouped(
function groupKeySelector(item) { return item.group.key; },
function groupDataSelector(item) { return item.group; }
);
var dataPromises = [];
var blogs;
var blogPosts = new WinJS.Binding.List();
function getFeeds() {
blogs = [
{
key: "blog1",
url: 'http://windowsteamblog.com/windows/b/developers/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
// lots more entries ...
];
blogs.forEach(function (feed) {
feed.dataPromise = feed.acquireSyndication(feed.url);
dataPromises.push(feed.dataPromise);
});
return WinJS.Promise.join(dataPromises).then(function () { return blogs });
}
// more code...
})();
At the line dataPromises.push(feed.dataPromise); I get the error JavaScript runtime error: Unable to get property 'push' of undefined or null reference. You can see dataPromises is defined and initialised to an empty array near the top of the file (I've also tried initialising it with new Array();).
What am I doing wrong here??? I'm guessing I've made some stupid screw up... Incidentally, the 3 places dataPromises appears in the snippet above are the only places it appears anywhere in the project.
My first thought was hoisting but unless something magical is going on, I'm not explicitly declaring dataPromises in any local scopes that might be overriding the top function scope.
You are not following the tutorial correctly. The line
var list = getBlogPosts();
replaces the new WinJS.Binding.List() call, which occurs after the line that initializes dataPromises.
The problem is that getBlogPosts() is calling getFeeds(), and getFeeds is trying to push results onto dataPromises but the line var dataPromises = [] hasn't executed yet, so dataPromises is still undefined.
Move the call to getBlogPosts() to after the initialization of the dataPromises variable.
Stepping through the code in the debugger line by line should have exposed this problem in a fairly straightforward manner.

Categories