Created
February 25, 2011 13:24
-
-
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__.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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