Node redis doesn't like function.apply() - javascript

I'm trying to wrap a redis client in node but I seem to be having some issues with calling node-redis functions with .apply().
This is causing issues when I tried to do it, which I was able to work around, but now async is calling its functions using .apply() as well which is now causing issues.
Below is a simplification of what I'm doing:
var client = redis.createClient( myOptions );
function set(){
// do other stuff
client.set.apply( null, arguments );
}
However, when I do this I'm getting the following error:
TypeError: Cannot read property 'send_command' of null
at RedisClient.(anonymous function).RedisClient.(anonymous function) (E:\sitesroot\0\node_modules\redis\lib\commands.js:45:24)
The code works perfectly when I pass in the arguments manually like so:
function set( key, value ){
// do stuff
client.set( key, value );
}
This approach won't work though for the likes of wrapping hgetall which has an unspecified number of arguments...
Any insight on what might be causing this?

As #Bergi pointed out in the comment above, you need to pass the correct context when you apply.
client.set.apply( client, arguments );

Related

How can I replace a call argument of a function with Sinon?

I am using sinon to make my tests, and I faced a problem that I can't find a proper solution
lets say, for simplicity, that I want, when I call console.log(),that the proper console.log receives the argument that I want in my test.
I have tryied:
Sinon.replace( console, 'log', () => console.log('mytestparam'))
Sinon.stub( console, 'log').callsFake( console.log('mytestparam'))
But it creates some kind of circular dependency that crashes
I cant simply make a full stub of the function, because it contains code that I want to run, I only want to replace the argument used for the call.
I have researched the sinon docs but I can't find any function that allows to call the original function changing the args
Any idea?

Avoid declaring large object in getDefaultProps prior to an event

The title might not be the best way to describe the problem, but I was wondering if there was a better practice to declaring an object in getDefaultProps?
In my render method I call several keys from from a prop/state that get updated on a click event i.e. this.props.player.name. The problem is that on page load this.props.player is blank and calling .name errors out. I know I can do something like ...
getDefaultProps: function() {
return {
player: {
name: null,
team: null
position: null
}
};
}
but it doesn't feel right. I was hoping there might be something similar to how Ruby does .try() where it won't try to call a method on a undefined prop.
The problem is specifically that this.props.player is undefined, if you define an empty object it will prevent the error from occurring. It's not bad practice to stub out the keys you're anticipating, but setting the default value to {} will be enough to prevent it from throwing.
You can create your data from ImmutableJS. Then you can get any part of your data like this:
this.state.getIn(['player', 'name', ...])
or
this.state.get('player')
This will not throw error even player is not defined or other, it will return undefined (or null) I don't remember
The update and updateIn work the same
see the doc here
I'd like to add this vanilla JS solution too - var x = (user || {}).name;
Source

Javascript - Replace callback with function, including parameters

Though Stackexchange Meta forbids me to start with "Hi,", I think there is no substantial harm to being friendly.
Hi,
I use the following piece of code,
while (!success) {
new Magister(chosenSchool, username, password).ready(function(error){
/* Code here using the error variable above */
});
}
but JSLint warnes me that it would be a bad practice to define functions inside a loop.
However, using the following code, doesn't work either.
function checkLogin(error) {
/* Code here using the error variable above */
}
while (!success) {
new Magister(chosenSchool, username, password).ready(checkLogin(error));
}
This results into Uncaught ReferenceError: error is not defined. How can I not redefine a function, but still passing the error as in the original function(error){...}?
I tried various methods, but it won't budge for me.
Thanks in advance!
Just don't call the function:
new Magister(chosenSchool, username, password).ready(checkLogin);
ready expects a function object, so you have to pass chechLogin itself instead of calling it and passing its return value (which is likely undefined).
How can I not redefine a function, but still passing the error as in the original function(error){...} ?
Maybe that's where the confusion lies. You are actually not passing error at all. The argument is passed by the caller, which is ready.
One nice feature of JavaScript is that you can simple replace variables with the literal representation of their value (in most cases).
So if we look at
new Magister(...).ready(checkLogin(error));
and replace checkLogin with it's value (the function) it becomes
new Magister(...).ready(function checkLogin(error){...}(error));
However, that doesn't look like the first version at all! Suddenly a wild (error) appears at the end of our function definition.
Lets go the other way round:
new Magister(...).ready(function(error){...});
// becomes
new Magister(...).ready(function checkError(error){...});
// becomes
function checkError(error) { ... }
new Magister(...).ready(checkError);
Much better.

A weird prototype loading thing with Yabble.js

I have a very odd problem that I have to assume is because of Yabble.js. I have never used Yabble.js before, and the only reason I am now is because it is a dependency of a library I'm using (Gamejs), but I would love to understand why this happens, and whether it is actually Yabble.js's fault, or possibly Gamejs's.
Here's a heavily compressed (and modified for genericness) version of my main.js:
var gamejs = require('gamejs');
...
function Character(/*lots of arguments*/) {
Character.superConstructor.apply(this, arguments);
this.somethingtomakeitaprototypeforthisexample = oneofthearguments;
}
gamejs.utils.objects.extend(Character, gamejs.sprite.Sprite);
Character.prototype.draw = function(display){
display.blit(this.animator.image, this.pos);
}
... /*Skipping most of the file, irrelevant to the problem*/
function main() {
maincharacter = new Character(/* appropriate number and types of arguments */);
... /*skipping the rest*/
}
gamejs.ready(main);
I have done enough debugging to know that it gets into the main function no problem and that the break occurs at the call to Character. Here is the error message (from Chrome's console):
Uncaught TypeError: undefined is not a function
main
_readyResources
I have determined that Character is the undefined function. However, if I define my ready function thusly:
gamejs.ready(function(){
console.log('Character:');
console.log(Character);
main();
});
the full contents of Character, as properly defined, prints out, but I still get the error in main. Thus, I know that Character is defined by the namespace before main is called.
Fun fact though: I do have a workaround. If I change the function prototype for main to:
function main(CharacterClass) {...};
then change the ready function to:
gamejs.ready(function(){ main(Character); });
and change the relevant line in main to:
var character = new CharacterClass(...);
it works fine. But this feels really hackish.
So my question is not how to make it work, since I have that already, but rather why it is a problem and how to make it work like it's supposed to.
Any thoughts?

Getting function through AJAX

I was wondering how I can get a function from an AJAX request, like this:
Let's say I have a file called myfunction.js, that looks like this:
function(bar){
alert(bar);
}
Can I retrieve it via Ajax as a function, like this?
var foo = $.ajax({url:'myfunction.js',async:false}).responseText;
And run it like this?
foo(bar);
The reason I ask is because I know responseText is a string,
so I'm not really sure if JavaScript will understand that it is a function.
Is there a way to convert a string into a function?
In your JS file, give the function a name.
function foo(bar){
alert(bar);
}
Then use $.getScript to load it.
$.getScript('myfunction.js', function(){
foo('test');
});
Absolutely:
foo = eval('(' + foo + ')');
foo(bar);
You could use new Function but in my testing it doesn't work on some versions of IE.
I ended up using new Function instead of eval, eval executes the code as soon as it's parsed, which is not what I was after.
This is what I ended up doing, and it works very nicely in firefox, chrome, and IE 7+ (no errors at all)
function createMyFunction(code){return new Function('params',code)};
var thecode = $.ajax({
url: 'myCode.js',
async: false,
dataType: 'html'
}).responseText
myFunction = createMyFunction(thecode);
I know the createMyFunction is pretty lazy in terms of not being able to define different arguments, but using a single params map works for my templating scenario quite well.
Note the dataType:'html' in the ajax request, if you don't specify a plain text mime type, jQuery will actually recognize that you are getting JS code and try to parse it, which generally ends up throwing a parse error or sometimes "Uncaught TypeError: params is not defined".
With this, I am able to have template files that specify template-specific events, and keep them organized in the same way as the markup and css files for that template.
Thanks for the help everyone, the reason I chose the answer that I did is because the link at the end pointed me in the right direction.
Cheers,
D
One thing to beware.
Chrome and IE don't allow you to eval an anonymous function directly (FF is fine). That is
// Throws Syntax Error in Chrome, Object expected in IE 8
var fun = eval('function(){return 5}'); fun();
A hackaround is to put it in an array, doesn't seem very reliable for the future:
var fun = eval('[function (){return 5}][0]'); fun();
The only safe way would be to make sure your functions are named, since the following works fine in all browsers:
eval('function a(){return 5}]'); a(0);
See Are eval() and new Function() the same thing? for further discussion

Categories

Resources