Skip to content

Instantly share code, notes, and snippets.

@gunn
Created February 25, 2011 13:24
Show Gist options
  • Save gunn/843772 to your computer and use it in GitHub Desktop.
Save gunn/843772 to your computer and use it in GitHub Desktop.
It turns out javascript is actually pretty flexible. If only we had __noSuchProperty__.
$rubyMode = false
// Lets us define a named method on any object either as a getter
// or a traditional function. Getters are fun because they look more like ruby.
Object.prototype.defineMethod = function(name, method){
if ($rubyMode) this.__defineGetter__(name, method);
else this[name] = method;
}
// Enable (5).times with argument |number|
Number.prototype.times = function(callback){
for (var i=0; i < this; i++) {
callback(i);
};
}
// Enable [].each with argument |item|.
Array.prototype.each = function (callback) {
var array = this;
this.length.times(function(i){
callback(array[i]);
});
return this;
}
// Enable [].map with argument |item|.
Array.prototype.map = function (callback) {
var array = this;
this.length.times(function(i){
array[i] = callback(array[i]);
});
return this;
}
// Uses the previously defined each to
// enable {}.each with arguments |key, value|.
Object.prototype.each = function(callback) {
var names = Object.getOwnPropertyNames(this);
var self = this;
names.each(function (name) {
callback(name, self[name]);
});
}
// Set up all date methods. Each value builds on the last.
// 3.5.minutes, (1).day, 22.0.years etc.
var milliseconds = 1000;
var time_values = { second:1, minute: 60, hour: 60, day: 24, week:7, fortnight:2, month:2.17406071, year:12 }
time_values.each(function(name, value){
var ms = milliseconds *= value;
var meth = function () { return this*ms; };
Number.prototype.defineMethod(name, meth);
Number.prototype.defineMethod(name+"s", meth);
});
// Define ago and fromNow methods on time.
// 6.0.hours.ago, (9).months.fromNow etc.
Number.prototype.defineMethod("ago", function(){
return new Date(new Date()-this);
})
Number.prototype.defineMethod("fromNow", function(){
return new Date(new Date().valueOf()+this);
});
// And the result:
if ($rubyMode) (2.0.years+1.0.month+10.5.days).ago
else 14.3.hours().fromNow();
describe("Number", function() {
describe("#times", function() {
it("should not call callback if number < 1", function() {
var functionless = { func: function() {} };
spyOn(functionless, 'func');
(0).times(functionless.func);
(-1).times(functionless.func);
expect(functionless.func).not.toHaveBeenCalled();
});
it("should count from 0 to one less than it's number", function() {
var string = "";
(9).times(function(n) {
string += n;
});
expect(string).toBe("012345678");
});
});
});
describe("Array", function() {
describe("#each", function() {
it("should iterate over each item in the array, and call a provided closure with it", function() {
var string = "";
["2+", "2", "=5"].each(function(item){
string += item
});
expect(string).toEqual("2+2=5");
});
});
describe("#map", function() {
it("set the value of each element to the output of a callback called with the original value", function() {
var squares = [1, 2, 3, 4].map(function(n){
return n*n;
});
expect(squares).toEqual([1, 4, 9, 16]);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment