I’ve finally gotten tired of this Wordpress Blog and moved to a new one based on Octopress. The new site is temporarily hosted at http://spadgos.github.com. Eventually, it’ll also get moved over to spadgos.com and we can kiss this horrid red-and-black theme goodbye.
Sublime Text & JSDocs
Recently, I’ve had one of those events in my professional life. They happen (for me) even less frequently than changing jobs. Yes, I have changed my preferred text editor. gasp!
I’ve moved from Komodo, which is a very competent and extensible (with Javascript!) editor, to the new kid on the block, Sublime Text 2. Sublime is a product still in beta, but I can recommend it as being definitely stable enough for every day use.
I’ll apologise up front if the following sounds too gushing or like an advertising pitch. I have no commercial interest in the product whatsoever, I actually just really like it and want others to try it out.
When starting with Sublime, the first thing you’ll notice is how amazingly fast it is. I am still amazed at how quickly it starts and continues to be, even on my little old netbook. The second thing is that you’ll see that Sublime is a text editor made by programmers for programmers. The default colour scheme is a very pleasing and eye-friendly pastels on dark grey, the interface is absolutely no-nonsense: no toolbars; no buttons for new file, save, cut, copy or paste; just one menu bar, an (albeit slightly gimmicky IMO) “minimap” of the file, and your code. All commands are available from a “command palette” which is opened via a key binding. Similarly, opening project files or searching for functions is done with another palette. These palettes, apart from being super-quick, also provide fuzzy text matching. For example, to make the selected text upper case, I just select the text, then press Ctrl+Shift+P, and type “chup”, which will find “CHange text to UPper case”, or if I want to open “lib/test/PolygonTest.js”, Ctrl+Shift+O and “l/t/p” or “PolTe” or whatever narrows it down enough with the minimum amount of typing. Everything is possible without even touching your mouse.
Probably the most surprising thing is the configuration settings. Every programmer worth his salt will fiddle and adjust settings to get the work environment Just Right, and usually this means poring through dialog after dialog of checkboxes and pull-downs. In Sublime, all the configuration (yes, ALL) is done via JSON text files. This is shocking at first, but amazingly liberating once you start to use it. As a programmer, every day you build complex data-structures capable of modelling anything by combining numbers and strings into nested arrays and maps — why couldn’t you configure a text editor in the same way? Settings are applied instantly upon save, meaning you can test out each of the settings very easily and get it just how you like it. Even key bindings are handled this way. Every interaction you have, from moving the cursor, to basic copy/paste/save actions, even to what happens when you click a mouse button is configurable. Even better though is that you can bind the same key combo to several actions and then affix conditions (referred to as “context” in the config) to that setting. For example, the “enter” key can add a new line in regular text, but you can also add another binding which makes it prepend commenting characters (//) if the current context is a comment. Triple-click might normally select a line, but if it’s on a function definition it could select the entire function body for you. After all this tweaking, you can commit your plain-text settings to version control for portability between your workstations, which is very handy!
One other feature I’ve not seen in any other editor is multiple selections. Komodo and other editors (VI, Emacs…) have “block editing” where you can make rectangular selections and edits across rows and columns. This is particularly useful for modifying blocks of repetitive code which happen to align vertically. Sublime takes that a step further by allowing for multiple selections. It is surprisingly useful for reformatting code, and as a replacement for Find-and-Replace. Just select (let’s say) the variable you want to rename, and hit Ctrl+D. The next occurrence of that word will get selected. Repeat as often as you like, the just start typing and you’ll be typing in multiple discrete locations. This feature alone has reduced the amount of macros and regexes I use to clean up text drastically. You’ll wonder how you lived without it, seriously.
The last thing I want to mention is the fledgling, but fast-growing developer community around Sublime. As a tool for programmers, its been designed to be extended with plugins, written in Python. What’s even better is that there’s a package repository plugin called Package Control, written by Will Bond, that completely streamlines the plugin installation and upgrade process integrated directly into the editor. Plugins are hosted on Github or Bitbucket and you can pull the upgrades as their published. After installing that package (which you can do just by pasting a command into the integrated python shell..!), all the available packages are shown in a command palette, and are installed without even requiring a restart. Since the code for the plugins is on Github, it’s really easy to fork it and send in pull requests if you find a bug, too. I highly recommend it!
And there’s just enough time for a quick little shout-out for one of my own plugins. If you’re writing Javascript with Sublime, you should totally install the JSDocs plugin. You can install it with the aforementioned Package Control plugin, or there’s instructions on the Github page. This plugin makes writing Javadoc-style comments a breeze by adding context-sensitive autocompletes, comment-aware linebreaking, and it even inspects your code to prefill @param and @return tags in a docblock. The readme file has much more information and many examples. If you run into any problems, leave me a note in the issue tracker and I’ll get right onto it!
Converting arguments into an array
I've been working on the previously-mentioned Myrtle project, as well as its unit-testing sister project, Tyrtle (which will get further plugs soon...), and I kind of stumbled across this interesting little thing.
In javascript, there's a "magic" variable made available inside every function, called arguments. It appears to be an array at first glance, but it isn't. Observe:
var arr = ['x', 'y']; // a real array, for comparison
typeof arguments; // "object"
typeof arr; // "object"
arguments.length; // 2
arr.length; // 2
arguments[0]; // "x"
arr[0]; // "x"
typeof arguments.join; // "undefined" !!!
typeof arr.join; // "function"
Object.prototype.toString.call(arguments);
// "[object Arguments]" !!!
Object.prototype.toString.call(arr);
// "[object Array]"
}
f('x', 'y');
It is actually a special type of object called Arguments, and it's documented well on the Mozilla Developer Network. Essentially, it is just an enumerable object in that it has a .length property and other properties in the slots 0...length - 1, but it doesn't have Array as its prototype, and hence, it doesn't have any of the array functions on it.
Obviously, in most cases where you want to actually do something useful with the arguments object, you actually want to have an array, rather than this strange object. Converting it to an array is usually done like so (as is recommended in the MDN article linked above):
This works. If you really wanted to be pedantic about it, you could say that it isn't actually safe, in case some code overwrites Array.prototype.slice, but I digress. In any case, it's a lot of typing and can be very confusing to newbies.
Now, in the interests of openness, I originally wrote this post to talk about this amazing new technique I discovered: [].concat(arguments). I wrote benchmarks and everything. It was shorter and performed about 4x better on Firefox. Then I actually used it in my code and discovered that it doesn't even work. So, there you go. I thought I'd keep the bulk of this article and instead compare some other methods which actually do work...
I wrote some functions which convert their arguments to an array and then return it. The first two both use slice, but I wanted to see if there was a difference between creating an array literal or using the prototype (there isn't).
return Array.prototype.slice.apply(arguments);
}
function arrayLiteralSlice() {
return [].slice.apply(arguments);
}
function splice() {
return [].splice.call(arguments, 0);
}
function push() {
var x = [];
x.push.apply(x, arguments);
return x;
}
function unshift() {
var x = [];
x.unshift.apply(x, arguments);
return x;
}
The results were interesting. I tested by calling each of the above functions with 1000 arguments.
| Browser | Slice | Splice | Push | Unshift |
|---|---|---|---|---|
| Firefox 6.0.2 | 4044 | 3549 | 10068 | 9846 |
| Chrome 13 | 37814 | 2701 | 38180 | 40952 |
Yes, some of these numbers are bizarre, but they're not typos. Push/unshift is 250% faster than slice on Firefox, and only about 10% faster on Chrome. Yes, splice is 94% slower than any other method on Chrome -- even slower than Firefox in this test. Unshift out-performs Push on Chrome by about 8%, too.
Of course, the real benefit of [].slice.apply(arguments) is that it's a one-liner. In real life usage, at best, the push/unshift technique requires 2 lines, but could be extracted to an external function. Of course, adding another function call is not free, so I did another benchmark.
var x = [];
x.push.apply(x, args);
return x;
}
function pushWithFnCall () {
return convertWithPush(arguments);
}
// and the same for unshift
In Chrome, the extra function call led to a ~33% slow down. It did not seem to affect Firefox's performance at all, however.
In summary:
- If you want a simple one liner, go with: var args = [].slice.apply(arguments)
- If you want better performance, use: var args = []; args.push.apply(args, arguments)
- Never use splice
Please do run the tests yourself here: http://jsperf.com/converting-arguments-to-an-array and here for version 2 which has the additional benchmarks. Let me know if I've forgotten a different method, or if I've stuffed up my tests somehow.
Introducing Myrtle: A Javascript Mocking Framework
This is just a short post to mention a little project I just put together. I call it Myrtle (which I guess is some sort of play on words on the Mock Turtle), but in any case, it is a Javascript Mocking Framework!
The project code is available on Github, or you can just grab Myrtle.js if you like.
So anyway, let's look at what it does. Let's say you're writing some tests for your code, and you want to check that a particular function is called. For example, you might have a Validator class which should be called when a form input is changed. Here's the signature of a basic validation class:
/**
* @param {DOMElement} a HTML Input element
* @param {String} a value to validate
* @return {Boolean} If the value was valid.
*/
validate : function (input, inputValue) {
// code here
}
};
The first step is to spy on the validate method:
Spying on a method modifies it so that metadata about that method is stored with each call to it, without changing the actual functionality. You can access this metadata through the API object returned by Myrtle.spy.
$(myInputElement).val('a changed value').trigger('change');
// let's check that validate was called
info.callCount(); // 1
// and let's see what it returned
info.lastReturn(); // true
// and let's check what the parameters passed to it were
info.lastArgs(); // [myInputElement, "a changed value"]
What's important to remember here is that the validate method is still executed as if nothing ever happened. Myrtle wouldn't be a good spy otherwise...
Other times you want to actually stop functions from running. For example, in a test environment, you might want to suppress error messages which you're triggering on purpose, or to stop AJAX functions from executing. In these cases, you can stub out a function.
This replaces the displayError method with a function which does nothing. Care should be taken in these cases that other code isn't expecting a return value from functions which you stub out completely.
You can also replace a function using stub. This is useful if you want to simulate a method, but not actually execute it - for example, when an AJAX method is called, you can put together a fake response.
callback({isSuccess : true});
});
You'll see there that the first parameter passed to the stub function is the original method. This is useful in cases where you may want to only stub it out based on some criteria, or to modify arguments or return values of the original method.
Notifications,
'displayError',
function (origFn, message) {
if (message !== 'My expected error') {
origFn(message);
}
}
);
The last feature currently in Myrtle is some basic speed profiling. If you want to find out how fast your function is executed, or if it runs slower given some input, you can turn on profiling and find out.
calc.factorial(3);
calc.factorial(8);
calc.factorial(12);
info.getAverageTime(); // a number, like 12 (ms)
info.getQuickest(); // { args : [3], ret : 6, time: 1 }
info.getSlowest(); // { args: [12], ret: 479001600, time: 20 }
Those are the three main features of Myrtle (so far). However, the nice thing about them is that they can all be combined in any way. You can spy on and stub out a method, or spy and profile. Stubbing and profiling probably isn't so useful though, since you'd only be measuring the speed of performing your replacement method.
There are a few ways to combine the options, and it's important to know that each of the Myrtle functions returns the exact same API object per function. To demonstrate:
var info2 = Myrtle.stub(Obj, 'foo'); // turn on stubbing
info1 === info2; // true
There's also the Myrtle function itself which can be used:
spy : true,
stub : function () {
// my replacement
},
profile : true
});
Of course, the last thing to cover is an important one: tidying up. Chances are that you don't want to stub out your methods for all the tests, and you want to restore them to how they were before at some point. Myrtle makes this super easy.
info.release();
// and even if you don't, remember that
// Myrtle will give you it easily.
Myrtle(Obj, 'foo').release();
// and if you're really lazy, just clean them all up!
Myrtle.releaseAll();
// if you're not sure if you've left
// some hanging about, just check!
Myrtle.size();
So, like I said, the code is on Github. Go have look and let me know what you think!
Image radio buttons
I came across this Stack Overflow question today about replacing radio buttons with images, however the answers there didn't sit quite right with me. They were completely reliant on javascript, which was fine according to the OP, but I feel that javascript enhancements like this, especially when they deal with things which require user input, should be just that: enhancements and not the entire solution itself.
Progressive enhancement is a fairly well known concept. Start with a valid, semantic and, most importantly, usable page and then add the niceties to it with javascript. If javascript isn't available or something breaks, then you don't have the niceties but you still have a usable page. Like I said, this is especially important for user input. Nothing is more frustrating than not being able to use a form because some half-wit developer thought they'd do something clever with javascript... or so my users tell me, anyway.
So, getting back to the radio buttons. We should set up some requirements.
- Instead of radio buttons, we'd like to see an icon which has two states: on and off.
- The icon behaves exactly like a radio button:
- Clicking on it or its label activates it.
- Clicking on a different button in the group deactivates it.
- Accessible via the keyboard or mouse
- With javascript turned off, it should still work
- Minimal extra markup required.
- Cross browser
The styles, including the icon images will be handled via CSS, so each radio button will need a class to identify which icon to use. We'll also need a class to identify which radio buttons should be replaced with images. This leaves our HTML fairly standard:
<input type="radio" name="sex" value="male"
class="image_radio male_icon" id="male_radio" />
<label for="male_radio">Male</label>
<input type="radio" name="sex" value="female"
class="image_radio female_icon" checked="checked" />
I've not given the second radio button an ID or label, just to demonstrate that both are optional. I'm not much of a fan of the overuse of ID attributes...
Almost all the styling is done via CSS, of course:
label.image_radio {
width: 16px; /* the same size as our icons */
height: 16px;
display: inline-block;
}
label.image_radio input.image_radio {
margin-left: -9999px;
/* this effectively hides the radio button
without removing it from the document flow */
}
/* define the icons for each radio */
label.male { background-image: url(male_off.png); }
label.male.active { background-image: url(male_on.png); }
label.female { background-image: url(female_off.png); }
label.female.active { background-image: url(female_on.png); }
So, if you were to take a look at this in your browser, you'd see a completely unstyled page with standard radio buttons. Excellent. Without the javascript, we haven't broken anything. Now, let's enhance.
Before I jump into the jQuery, I'll just get on my soapbox for a quick second to note that if it weren't for IE, the following code would be a single statement (kinda). If you click on a label associated with an input, IE doesn't pass the click event on to the input so we have to manually add those labels into our result set before applying the click event.
// get all the image radio buttons
var $radios = $('input.image_radio')
.each(function() {
var $t = $(this);
// wrap each in a label, copying over all the classes
$t.wrap(
$("<label></label>", {
className: $t.attr('className')
})
.toggleClass('active', $t.is(':checked'))
);
})
// $clickTarget will be the elements to apply
// the click event handler to
, $clickTarget = $radios
;
if ($.browser.msie) {
// get the parent labels
$clickTarget = $radios.parent();
// now find all the labels which are for this element
$radios.each(function() {
if (this.id) {
$clickTarget = $clickTarget
.add('label[for="' + this.id + '"]');
}
});
}
$clickTarget
.click(function() {
var $t = $(this),
$label = $t.closest('label')
;
if (!$label.is(".active")) {
$('label.active:has(:radio[name="' + ($t.is(":radio") ? $t : $t.find(":radio")).attr('name') + '"])')
.removeClass('active')
;
$label.addClass('active');
}
})
;
});
And that's all there is to it. There's probably still quite a bit more work you could put into it (for example, though it's still completely accessible via the keyboard, there's no visual indication that a particular button has focus), but it provides nice progressive enhancement for your radio buttons. With some very small tweaks, the same code could also apply to checkboxes too!
Javascript default values
Just a small post here to share a bit of benchmarking I just did. In Javascript, the boolean operators (|| and &&) behave a little differently to how many people expect. In PHP, the result of using || or && is always a boolean:
$x = "hello" || false; // bool(true)
$x = false || 0; // bool(false)
Javascript, on the other hand, returns the first determining value in the statement.
var x = "hello" || false; // string("hello")
var x = false || 0; // int(0)
var x = 0 || "hello"; // string("hello")
var x = 5 && 2; // int(2)
var x = 5 && ""; // string("")
var x = NaN && 6; // NaN
That is, when using ||, the result will be the first truthy value or the last value.
When using &&, the result will be the first falsey value or the last value.
"Truthy" and "falsey" here obviously means a value which, when cast to a boolean, is true or false, respectively. Falsey values are 0, -0, false, null, undefined, and NaN. Truthy values are everything else (including "0", empty arrays and empty objects).
Knowing this gives us the opportunity to use a handy little shortcut for setting some default values for variables.
a = a || "default a";
alert(a);
}
foo(); // "default a"
foo(false); // "default a"
foo("my message"); // "my message"
The other important thing to know about the boolean operators is that they will short-circuit the processing once enough information is known to determine the output. That is, when using &&, if the first parameter is falsey, then it doesn't matter at all what the second parameter is, since the output will always be false(y), so it skips evaluating that parameter. Similarly with ||, if the first parameter is truthy, then we can stop right there. This allows us to write a slightly more efficient default-value routine.
a || (a = "default a");
alert(a);
}
// this produces the same output as above
If the first parameter is truthy, then it stops right there and never actually evaluates the second parameter which would assign a value to a. This is a bit more efficient than the first example, since there is only ever an assignment when it is required. How slight is this gain? Over 1,000,000 loops, running the first method took ~1640ms compared to ~1400ms for the second, so it's not going to make even a vaguely noticeable difference, but it doesn't hurt to do things the best way, right?
Ubuntu, nooooo!
Starting with version 10.10, coming out in October this year, Ubuntu will be using base 10 units, taking its lead from Apple's move last year which I didn't much like. At least Ubuntu will give users an option to switch back, something Apple is yet to do. (Options? On a mac? ha!)
The great rep recalc of 2010
The Stack Overflow team recently announced that they were changing the question upvotes to only give 5 points instead of 10.
Though I've got plenty more reputation than I could possibly need (that is, I have full user-moderator rights), this has affected my score. A lot. Like -4250. Bummer. I ask a lot of questions and I think doing so is a really good thing, so I'm a little disappointed to see it go this way in discouraging new questions. Good questions already only attracted a fraction of the number of votes which good answers receive, so I guess I don't see it as fixing anything which was broken in the first place.
As you'd imagine, it stirred up a bit of malcontent in the comments thread (though, this happens with any change):
This constant changing and making it all retroactive to all previous votes cast is crap. When people signed up you told them the rules and awarded points based on those rules.
I understand that things change and need to be changed in order to keep possible issues and problems in check. However rolling back people’s points is a jerk move and one you seem to have no issue doing.
I feel bad for the people [who have lost much rep], but we all get the added bonus of *having our questions answered* when we ask them. I think this change just shifts the focus of asking a question away from gaining reputation and towards getting an answer. Just as it should be.
I can understand the need of the changes *now*, but why punish those who helped bootstrap the system by providing lots of questions in the beginning?
Well, that’s demotivating. I’m pretty close to 10K, and this rule-change/recalc will drop me back to 8.7K.
Not much incentive to keep running on the rat machine, is it?
I feel this guy's pain. Though it's obviously not the main reason I or anyone else would visit the site, trying to achieve a "high score" is one key feature, and knowing that it could be arbitrarily taken away from you just like that is quite demotivating. Though how can you argue when the site owner says this:
I think it’s healthy for everyone to realize that rep is kind of an arbitrary concept, and think about what it means to them, to anyone else, and why.
Overall, it seems as though not many are actually too concerned about the change in rep, but there's quite a lot of people who are very annoyed at the fact that it is being applied retroactively. There was a bit of a discussion/speculation about the notion that this was technically the only way to do it, which is rubbish. Yes, you don't want to have to keep a history of rules and the dates they changed, since that would grow unwieldy and awkward very quickly. Here's a smarter way to do it: get the Community User to double every single vote, then halve the score to +5. Done.
For a website built on community contribution, I'm just saddened to see how little they actually listened to their users. Perhaps only the voices of the top users were heard? The ones with nothing to lose anyway.
A suggestion for Ford
Breaking with the theme of this blog, but this has been irritating me for some time now.
The "Voice Control" ad for the Ford Mondeo.
If you're going to make an ad touting a new feature such as voice control, it'd probably be a good idea to not highlight how buggy your software is.
jQuery 1.4 released
Despite the risk of joining in the echo chamber that I'm sure will start up very soon, I just wanted to write a little observation.
jQuery 1.4 has been released. Kinda.
It's a little baffling to me, considering the first release candidate was only announced one day ago, yet the dedicated jQuery 1.4 website proudly states "jQuery 1.4 has been released!", but alas, there is no link. The nightly build still reads "1.4a2-pre", so I guess it's up to me.
It's a tad overdue. The roadmap slated it for a November 2009 release, and it's been promised for a while now, but it's here now anyway. I was looking at a jQuery cheat sheet which contains the new functions introduced in 1.4, and two of them jumped out at me: nextUntil() and prevUntil. They seem to be very similar to something I've seen before. Kinda. Maybe I'm just seeing things.
Recent Entries
- Time to upgrade
- Sublime Text & JSDocs
- Converting arguments into an array
- Introducing Myrtle: A Javascript Mocking Framework
- Image radio buttons
- Javascript default values
- Ubuntu, nooooo!
- The great rep recalc of 2010
- A suggestion for Ford
- jQuery 1.4 released
Recent Comments
- Damo in Image radio buttons
- alex in The great rep recalc of 2010
- Fisher in Anyone have any questions?
- fake in Anyone have any questions?
- alex in Anyone have any questions?
- Fisher in Common Mistakes Part 0: 83.333% of …
- alex in Common Mistakes Part 0: 83.333% of …
- Fisher in Perhaps the most epic Stack Overflo…
- alex in Perhaps the most epic Stack Overflo…
- alex in jQuery is not optimised how you'd t…
Categories
Archives
- November 2011
- September 2011
- August 2011
- June 2010
- May 2010
- March 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- June 2009
- May 2009
- April 2009
- March 2009
- January 2009
- December 2008
- September 2008
- July 2008
- June 2008
- April 2008
- March 2008
- December 2007
- November 2007
- September 2007
- August 2007
- July 2007
- May 2007
- April 2007
- March 2007
Pages
Blogroll
- Chris Dot Spadgos
- Fisher Dot Spadgos
- Furious Steals - Highly destructive UT2004 racing mod
- Marshmallow Duel - The 1996 cult classic and delicious fan remakes
- NB Dot Spadgos
- Pospi Dot Spadgos