Skip to content

Instantly share code, notes, and snippets.

@cowboy
Created July 1, 2010 17:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cowboy/460275 to your computer and use it in GitHub Desktop.
Save cowboy/460275 to your computer and use it in GitHub Desktop.
Test jQuery version WIP UNTESTED
/*!
* jQuery isVersion - v0.1 - 07/02/2010
* http://benalman.com/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($){
'$:nomunge'; // Used by YUI compressor.
var re = /^([!<>=]+)?\s*((\d+(?:\.\d+)*)(pre)?)$/i,
cur = get_num( $.fn.jquery || '' );
// Return true if all version criteria are met. Comparison operator defaults
// to == if omitted. Valid comparisons are == != < <= > >=.
//
// ie. $.isVersion( '1.3.2' ) or $.isVersion( '>= 1.4', '!= 1.4.1' )
//
$.isVersion = function() {
var result;
// Iterate over all function arguments, allowing any number of tests.
$.each( arguments, function(i,v){
var matches = v.match( re );
// If the regexp matched, then evaluate the comparison, setting `result`
// to that value, and returing it (so that a `false` value will break
// out of the each loop).
return matches && ( result = (new Function(
'return ' + cur + ( matches[1] || '==' ) + get_num( matches[2] )
))() );
});
return result;
};
// Get number that can be used for comparison. Converts a string like
// "1.2.3.4" into the number 1020304 (and "1.2.3.4pre" into the number
// 1020303.9) for easy numeric comparisons.
function get_num( str ) {
var matches = str.match( re ),
num = 0;
if ( matches ) {
$.each( matches[3].split('.'), function(i,v){
num += Math.pow( 0.01, i ) * v * 1000000;
});
num -= matches[4] ? 0.1 : 0;
}
return num;
};
})(jQuery);
@rkatic
Copy link

rkatic commented Jul 2, 2010

eval is banned by many teams (including jQuery team). You could easily replace it with new Function('a', 'b', code)(a, b).

Why not simply $.each( arguments, ... )

@cowboy
Copy link
Author

cowboy commented Jul 2, 2010

Thanks for the suggestions!

@rkatic
Copy link

rkatic commented Jul 2, 2010

new Function(code)() is evaluated in the global object (window). You have to use the new Function('a', 'b', code)(a, b) form.

@cowboy
Copy link
Author

cowboy commented Jul 2, 2010

rkatic, what are the negative implications of doing it the way I've done it?

@rkatic
Copy link

rkatic commented Jul 2, 2010

Ah, yes, you putted all in the code. My error.

Also, instead of:

    if ( matches ) {
      result = result && ...;
    }

you could:

    if ( matches ) {
      return ( result = ... ); 
    }

so on the first fail it will stop wit evaluating other versions...

@cowboy
Copy link
Author

cowboy commented Jul 2, 2010

You know, rkatic, I originally intended to do that but completely forgot to add it in there.. so, thanks! I've updated my code.

@cowboy
Copy link
Author

cowboy commented Jul 2, 2010

It might be a good idea, for size considerations, for me to just use your method for version comparisons, since there aren't any versions of jQuery that have a double-digit part, and that my code, while "cool," just adds bloat.

@rkatic
Copy link

rkatic commented Jul 2, 2010

Which one (there are 3 versions). Specially the second one is not too much shorter, but feel free to use any you like.

@jdalton
Copy link

jdalton commented Jul 10, 2010

@rkatic: The whole eval is evil thing is kinda dumb.

Environments that don't allow eval() usually won't allow function compilation or script injection either.

For example see Adobe AIR or Google Caja.

Ban all or ban none :P

@rkatic
Copy link

rkatic commented Jul 10, 2010

Environments that don't allow eval() usually won't allow function compilation or script injection either.

Not exactly. eval is not only something more dangerous, but also mekes advanced js compressors less advanced.

@jdalton
Copy link

jdalton commented Jul 10, 2010

@rkatic:

Not exactly. eval is not only something more dangerous, but also mekes advanced js compressors less advanced.

That's incorrect, eval has some limitations such as using the same ThisBinding, LexicalEnvironment, and VariableEnvironment as the calling execution context. There are also further restrictions placed on eval in ES5's strict mode.

On the other hand, script injection has no such restrictions and executes code in the global context. It also happens to be readily available in jQuery via its jQuery.globalEval() method.

Furthermore, large use of eval, the Function constructor, or script injection will minify less because they all use strings.

@cowboy
Copy link
Author

cowboy commented Jul 10, 2010

And of course, because I'm building the string by concatenating vars, they can be minified. And gzipping will handle the return in there, etc.. And I'm not particularly worried about script injection because the regexp won't lett anything invalid pass through.

This is roughly how I originally did the comparison (pre-gist), but since it looked really gross, I switched to eval.

if ( matches ) {

  var cmp = matches[1],
    num = get_num( matches[2] );

  return ( result = 
      cmp === '==' ? cur == num
    : cmp === '!=' ? cur != num
    : cmp === '<'  ? cur < num
    : cmp === '<=' ? cur <= num
    : cmp === '>=' ? cur >= num
    : cmp === '>'  ? cur > num
    : false
  );

}

@rkatic
Copy link

rkatic commented Jul 10, 2010

That's incorrect, eval has some limitations such as using the same ThisBinding, LexicalEnvironment, and VariableEnvironment as the calling execution context. There are also further restrictions placed on eval in ES5's strict mode.

ES5 tries to fix eval but ES3 is still the reality.

Furthermore, large use of eval, the Function constructor, or script injection will minify less because they all use strings.

I was not pointing on the problem of minifing strings, but on the incapacity to compress names declared in all parent scopes of the one with the eval. Function, in other hand, has not this issue because it evaluates script globally.

@jdalton
Copy link

jdalton commented Jul 10, 2010

ES5 tries to fix eval but ES3 is still the reality.

Sure but at least there are more restrictions coming soon (Firefox 4).
The same can't be said for script injection.

I was not pointing on the problem of minifing strings, but on the incapacity to compress names declared in all parent scopes of the one with the eval.

True, but it comes down to how you use it. The same could be said for the Function constructor if your code accesses pseudo private properties/methods on a global object (those prefixed with an underscore _) because some minifiers will shrink them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment