--------------040404080407000006030407 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Curt Hibbs wrote: > James Britt wrote: >>Simon Strandgaard wrote: >>>Ruby allows to you enhance the builtin string class with you >> >>own methods, >> >>>which you can invoke "im a string".own_method >>> >>>Thats the sentence I use most. >>>I don't know if there are other languages that allow for this? >> >>JavaScript. >> >>Really. >> >>"JavaScript: It's sweeter than you think." > Yes, JavaScript is underrated. A lot of the things we do with Ruby can be > done with JavaScript (its just not as clean). See attachment. ;) Regards, Florian Gross --------------040404080407000006030407 Content-Type: text/plain; name="ruby.js" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ruby.js" Object.prototype.clone = function(deepClone) { var result = new this.constructor() for (var property in this) { if (deepClone && typeof(this[property]) == 'object') { result[property] = this[property].clone(deepClone) } else { result[property] = this[property] } } return(result) } Object.prototype.extend = function(other) { if (!this.mixins) this.mixins = [] this.mixins.push(other) for (var property in other) if (!this.hasOwnProperty(property)) this[property] = other[property] } Object.prototype.cmp = function(other) { if (this < other) return(-1) if (this > other) return(+1) return(0) } Object.prototype.valuesAt = function() { var obj = this return(arguments.toArray().map(function(index) { return(obj[index]) })) } Object.prototype.toArray = function() { if (!this.length) throw("Can't convert") var result = [] for (var i = 0; i < this.length; i++) result.push(this[i]) return(result) } Object.prototype.hash = function() { return(this.toSource().hash()) } Object.prototype.instanceOf = function(klass) { return(this.constructor == klass) } Object.prototype.isA = Object.prototype.kindOf = function(klass) { if (this.instanceOf(klass)) return(true) if (this["mixins"] != undefined && this.mixins.includes(klass)) return(true) return(false) } Object.prototype.methods = function() { var result = [] for (var property in this) if (typeof(this[property]) == "function") result.push(property) return(result) } Object.prototype.respondTo = function(method) { return(this.methods().includes(method)) } Object.prototype.send = function(method) { var rest = arguments.toArray().last(-1) if (!this.respondTo(method)) throw("undefined method") return(this[method].apply(this, rest)) } Object.prototype.instanceEval = function(code) { if (code.isA(Function)) return(code.apply(this)) else return(eval(code.toString())) } Number.prototype.times = function(block) { for (var i = 0; i < this; i++) block(i) } Number.prototype.upto = function(other, block) { for (var i = this; i <= other; i++) block(i) } Number.prototype.downto = function(other, block) { for (var i = this; i >= other; i--) block(i) } Number.prototype.towards = function(other, block) { var step = this.cmp(other) for (var i = this; i !== other - step; i -= step) block(i) } Number.prototype.succ = function() { return(this + 1) } Number.prototype.pred = function() { return(this - 1) } Number.prototype.chr = function() { return(String.fromCharCode(this)) } enumerable = new Object() enumerable.eachWindow = function(window, block) { if (!window.isA(Range)) window = range(0, window) elements = [], pushed = 0 this.each(function(item, index) { elements.push(item) pushed += 1 if (pushed % window.rend == 0) { start = [0, window.start - window.rend + pushed].max() end = [0, window.rend + pushed].max() block(elements.fetch(xrange(start, end)), index) } }) } enumerable.collect = enumerable.map = function(block) { var result = [] this.each(function(item, index) { result.push(block(item, index)) }) return(result) } enumerable.toArray = enumerable.entries = function() { return(this.map(function(item) { return(item) })) } enumerable.inject = function(firstArg) { var state, block, first = true if (arguments.length == 1) { block = firstArg } else { state = firstArg block = arguments[1] } this.each(function(item, index) { if (first && typeof(state) == "undefined") state = item, first = false else state = block(state, item, index) }) return(state) } enumerable.find = enumerable.detect = function(block) { var result, done this.each(function(item, index) { if (!done && block(item, index)) { result = item done = true } }) return(result) } enumerable.findAll = enumerable.select = function(block) { return(this.inject([], function(result, item, index) { return(block(item, index) ? result.add(item) : result) })) } enumerable.grep = function(obj) { return(this.findAll(function(item) { return(obj.test(item)) })) } enumerable.reject = function(block) { return(this.select(function(item, index) { return(!block(item, index)) })) } enumerable.compact = function() { return(this.select(function(item) { return(typeof(item) != "undefined") })) } enumerable.nitems = function() { return(this.compact().length) } enumerable.sortBy = function(block) { return(this.map(function(item, index) { return([block(item, index), item]) }).sort(function(a, b) { return(a[0].cmp(b[0])) }).map(function(item) { return(item[1]) })) } enumerable.all = function(block) { return(this.findAll(block).length == this.length) } enumerable.any = function(block) { return(typeof(this.find(block)) != "undefined") } enumerable.includes = function(obj) { return(this.any(function(item) { return(item === obj) })) } enumerable.index = function(obj) { var result this.find(function(item, index) { if (obj == item) { result = index return(true) } else { return(false) } }) return(result) } enumerable.uniq = function() { return(this.inject([], function(result, item) { return(result.includes(item) ? result : result.add(item)) })) } enumerable.max = function(block) { if (!block) block = function(a, b) { return(a.cmp(b)) } return(this.sort(block).last()) } enumerable.min = function(block) { if (!block) block = function(a, b) { return(a.cmp(b)) } return(this.sort(block).first()) } enumerable.partition = function(block) { var positives = [], negatives = [] this.each(function(item, index) { if (block(item, index)) positives.push(item) else negatives.push(item) }) return([positives, negatives]) } enumerable.zip = function() { var ary = arguments.toArray() ary.unshift(this) return(ary.transpose()) } enumerable.flatten = function(depth) { if (depth == undefined) depth = -1 if (!depth) return(this) return(this.inject([], function(result, item) { var flatItem = item.respondTo("flatten") ? item.flatten(depth - 1) : [item] return(result.merge(flatItem)) })) } Array.fromObject = function(obj) { if (!obj.length) throw("Can't convert") var result = [] for (var i = 0; i < obj.length; i++) result.push(obj[i]) return(result) } Array.prototype.transpose = function() { var result, length = -1 this.each(function(item, index) { if (length < 0) { /* first element */ length = item.length result = Array.withLength(length, function() { return(new Array(this.length)) }) } else if (length != item.length) { throw("Element sizes differ") } item.each(function(iitem, iindex) { result[iindex][index] = iitem }) }) return(result) } Array.withLength = function(length, fallback) { var result = [null].mul(length) result.fill(fallback) return(result) } Array.prototype.each = function(block) { for (var index = 0; index < this.length; ++index) { var item = this[index] block(item, index) } return(this) } Array.prototype.extend(enumerable) Array.prototype.isEmpty = function() { return(this.length == 0) } Array.prototype.at = Array.prototype.fetch = function(index, length) { if (index.isA(Range)) { var end = index.rend + (index.rend < 0 ? this.length : 0) index = index.start length = end - index + 1 } if (length == undefined) length = 1 if (index < 0) index += this.length var result = this.slice(index, index + length) return(result.length == 1 ? result[0] : result) } Array.prototype.first = function(amount) { if (amount == undefined) amount = 1 return(this.at(xrange(0, amount))) } Array.prototype.last = function(amount) { if (amount == undefined) amount = 1 return(this.at(range(-amount, -1))) } Array.prototype.store = function(index) { var length = 1, obj arguments = arguments.toArray() arguments.shift() if (arguments.length == 2) length = arguments.shift() obj = arguments.shift() if (!obj.isA(Array)) obj = [obj] if (index.isA(Range)) { var end = index.rend + (index.rend < 0 ? this.length : 0) index = index.start length = end - index + 1 } if (index < 0) index += this.length this.replace(this.slice(0, index).merge(obj).merge(this.slice(index + length))) return(this) } Array.prototype.insert = function(index) { var values = arguments.toArray().last(-1) if (index < 0) index += this.length + 1 return(this.store(index, 0, values)) } Array.prototype.update = function(other) { var obj = this other.each(function(item) { obj.push(item) }) return(obj) } Array.prototype.merge = Array.prototype.concat Array.prototype.add = function(item) { return(this.merge([item])) } Array.prototype.clear = function() { var obj = this this.length.times(function(index) { delete obj[index] }) this.length = 0 } Array.prototype.replace = function(obj) { this.clear() this.update(obj) } Array.prototype.mul = function(count) { var result = [] var obj = this count.times(function() { result = result.merge(obj) }) return(result) } Array.prototype.fill = function(value) { var old_length = this.length var obj = this this.clear() var block if (typeof(value) != "function") block = function() { return(value) } else block = value old_length.times(function(i) { obj.push(block(i)) }) } Array.prototype.removeAt = function(targetIndex) { var result = this[targetIndex] var newArray = this.reject(function(item, index) { return(index == targetIndex) }) this.replace(newArray) return(result) } Array.prototype.remove = function(obj) { this.removeAt(this.index(obj)) } Array.prototype.removeIf = function(block) { this.replace(this.reject(block)) } function Range(start, end, excludeEnd) { this.begin = this.start = start this.end = end this.excludeEnd = excludeEnd this.rend = excludeEnd ? end.pred() : end this.length = this.toArray().length } function range(start, end) { return(new Range(start, end)) } function xrange(start, end) { return(new Range(start, end, true)) } Range.prototype.toString = function() { return("" + this.start + (this.excludeEnd ? "..." : "..") + this.end) } Range.prototype.each = function(block) { var index = 0 this.start.towards(this.rend, function(i) {return(block(i, index++))}) } Range.prototype.extend(enumerable) Range.prototype.includes = function(item) { return(this.start.cmp(item) == -1 && this.rend.cmp(item) == +1) } function Hash(defaultBlock) { this.defaultBlock = defaultBlock this.keys = [] this.values = [] this.length = 0 } Hash.fromArray = function(array) { var result = new Hash() array.each(function(item) { var key = item[0], value = item[1] result.store(key, value) }) return(result) } Hash.prototype.at = Hash.prototype.fetch = function(key, block) { var result if (this.hasKey(key)) result = this["item_" + key.hash()] else { if (block) result = block(key) else result = defaultBlock(key) } return(result) } Hash.prototype.store = function(key, value) { this.keys.push(key) this.values.push(value) this.length++ return(this["item_" + key.hash()] = value) } Hash.prototype.toA = function() { return(this.keys.zip(this.values)) } Hash.prototype.isEmpty = function() { return(this.length == 0) } Hash.prototype.has = Hash.prototype.includes = Hash.prototype.hasKey = function(key) { return(hasOwnProperty("item_" + key.hash())) } Hash.prototype.hasValue = function(value) { return(this.values.includes(value)) } Hash.prototype.each = function(block) { this.toA().each(function (pair) { return(block(pair[1], pair[0])) }) } Hash.prototype.extend(enumerable) Hash.prototype.merge = function(other) { other.each(function(value, key) { this.store(key, value) }) } Hash.prototype.remove = function(key) { var valueIndex = this.keys.index(key) var value = this.values[valueIndex] this.keys.remove(key) this.values.removeAt(valueIndex) delete(this["item_" + key.hash()]) this.length-- return([key, value]) } Hash.prototype.removeIf = function(block) { this.each(function(value, key) { if (block(value, key)) this.remove(key) }) } Hash.prototype.shift = function() { return(this.remove(this.keys[0])) } Hash.prototype.clear = function() { var obj = this this.length.times(function() {obj.shift()}) } Hash.prototype.replace = function(obj) { this.clear() this.merge(obj) } Hash.prototype.invert = function() { return(Hash.fromArray(this.map(function(value, key) { return([value, key]) }))) } Hash.prototype.rehash = function() { var result = new Hash(this.defaultBlock) this.each(function(value, key) { result.store(key, value) }) this.replace(result) } function MatchData(matches, str, pos) { this.matches = matches, this.string = str this.begin = this.position = pos this.match = matches[0] this.captures = matches.slice(1) this.end = pos + this.match.length this.length = matches.length this.preMatch = str.substr(0, pos) this.postMatch = str.substr(this.end) } MatchData.prototype.toString = function() { return(this.match) } MatchData.prototype.at = function(index) { return(this.matches.at(index)) } MatchData.prototype.toArray = function() { return(this.matches) } RegExp.prototype.match = function(str) { var matches if (matches = this.exec(str)) { var pos = str.search(this) return(new MatchData(matches, str, pos)) } } String.prototype.clone = function() { return(new String(this)) } String.prototype.each = function(block) { this.split("\n").each(block) } String.prototype.extend(enumerable) String.prototype.toArray = function() { return(this.split("\n")) } String.prototype.towards = function(other, block) { var item = this while (item.cmp(other) <= 0) { block(item) item = item.succ() } } String.prototype.hash = function() { var result = 0 this.split("").each(function(item) { result += item.charCodeAt(0) result += (result << 10) result ^= (result >> 6) }) result += (result << 3) result ^= (result >> 11) result += (result << 15) return(result) } String.prototype.chars = function() { return(this.split("")) } String.prototype.at = String.prototype.fetch = function(index, length) { if (index.isA(Range)) { var end = index.rend + (index.rend < 0 ? this.length : 0) index = index.start length = end - index + 1 } if (length == undefined) length = 1 if (index < 0) index += this.length return(this.substr(index, length)) } String.prototype.store = String.prototype.change = function(index) { var length = 1, obj arguments = arguments.toArray() arguments.shift() if (arguments.length == 2) length = arguments.shift() obj = arguments.shift() if (index.isA(Range)) { var end = index.rend + (index.rend < 0 ? this.length : 0) index = index.start length = end - index + 1 } if (index < 0) index += this.length return(this.substr(0, index) + obj + this.substr(index + length)) } String.prototype.reverse = function() { return(this.split("").reverse().join("")) } String.prototype.scan = function(pattern) { var str = this, result = [], oldPos = -1, match, offset = 0 while (match = pattern.match(str)) { if (match.end == match.begin) throw("Can't have null length matches with scan()") var newMatch = new MatchData(match.matches, match.string, match.position + offset) result.push(newMatch) str = match.postMatch offset += match.toString().length } return(result) } String.prototype.sub = function(what, by, global) { var block = typeof(by) == "function" ? by : function() { return(by) } var matches = this.scan(what), result = this, offset = 0 if (!global && !by.global) matches = matches.slice(0, 1) matches.each (function(match) { var replacement = block(match) offset += replacement.length - match.toString().length result = result.change(match.begin + offset, match.toString().length, replacement) }) return(result) } String.prototype.gsub = function(what, by) { return(this.sub(what, by, true)) } String.prototype.tr = function(from, to) { var map = Hash.fromArray(from.chars().zip(to.chars())) return(this.chars().map(function(chr) { return(map.includes(chr) ? map.fetch(chr) : chr) }).join("")) } String.prototype.mul = function(other) { var result = "", str = this other.times(function() { result += str }) return(result) } String.prototype.isUpcase = function() { return(this == this.upcase()) } String.prototype.isDowncase = function() { return(this == this.downcase()) } String.prototype.isCapitalized = function() { return(this.fetch(0).isUpcase() && this.fetch(range(1, -1)).isDowncase()) } String.prototype.upcase = String.prototype.toUpperCase String.prototype.downcase = String.prototype.toLowerCase String.prototype.capitalize = function() { return(this.fetch(0).upcase() + this.fetch(range(1, -1)).downcase()) } String.prototype.swapcase = function() { return(this.chars().map(function(chr) { if (chr.isUpcase()) return(chr.downcase()) if (chr.isDowncase()) return(chr.upcase()) return(chr) }).join("")) } String.prototype.ord = function() { return(this.charCodeAt(0)) } String.prototype.isEmpty = function() { return(this.length == 0) } String.prototype.succ = function() { if (this.isEmpty()) return(this) /* numerics */ if (/^\d+$/.test(this)) return((Number(this) + 1).toString()) /* just one character */ if (this.length == 1) { /* letters */ if (/[A-Za-z]/.test(this)) { var lastLetter = this.isUpcase() ? 'Z' : 'z' var firstLetter = this.isUpcase() ? 'A' : 'a' return((this == lastLetter) ? firstLetter.mul(2) : (this.ord() + 1).chr()) } else { return(this == (-1).chr() ? 0.0.chr().mul(2) : (this.ord() + 1).chr()) } /* multiple characters */ } else { var result = this for (var index = this.length; index >= 0; index--) { var chr = this.at(index) if (chr.succ().length == 1 || index == 0) return(result.change(index, chr.succ())) else result = result.change(index, chr.succ().at(-1)) } } } String.prototype.ljust = function(length, fill) { if (!fill) fill = " " if (fill.length > 1) throw("TODO: Make fills with length > 1 work.") return(this + fill.mul(length / fill.length - this.length)) } --------------040404080407000006030407--