--------------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;
 nameuby.js"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenameuby.js"

Object.prototype.clone  unction(deepClone) {
  var result  ew this.constructor()
  for (var property in this) {
    if (deepClone && typeof(this[property]) 'object') {
      result[property]  his[property].clone(deepClone)
    } else {
      result[property]  his[property]
    }
  }
  return(result)
}

Object.prototype.extend  unction(other) {
  if (!this.mixins) this.mixins  ]
  this.mixins.push(other)
  for (var property in other)
    if (!this.hasOwnProperty(property))
      this[property]  ther[property]
}

Object.prototype.cmp  unction(other) {
  if (this < other) return(-1)
  if (this > other) return(+1)
  return(0)
}

Object.prototype.valuesAt  unction() {
  var obj  his
  return(arguments.toArray().map(function(index) {
    return(obj[index])
  }))
}

Object.prototype.toArray  unction() {
  if (!this.length) throw("Can't convert")
  var result  ]
  for (var i  ; i < this.length; i++)
    result.push(this[i])
  return(result)
}

Object.prototype.hash  unction() {
  return(this.toSource().hash())
}

Object.prototype.instanceOf  unction(klass) {
  return(this.constructor klass)
}

Object.prototype.isA  bject.prototype.kindOf  unction(klass) {
  if (this.instanceOf(klass)) return(true)
  if (this["mixins"] ! ndefined && this.mixins.includes(klass))
    return(true)
  return(false)
}

Object.prototype.methods  unction() {
  var result  ]
  for (var property in this)
    if (typeof(this[property]) "function")
      result.push(property)
  return(result)
}

Object.prototype.respondTo  unction(method) {
  return(this.methods().includes(method))
}

Object.prototype.send  unction(method) {
  var rest  rguments.toArray().last(-1)
  if (!this.respondTo(method)) throw("undefined method")
  return(this[method].apply(this, rest))
}

Object.prototype.instanceEval  unction(code) {
  if (code.isA(Function))
    return(code.apply(this))
  else
    return(eval(code.toString()))
}

Number.prototype.times  unction(block) {
  for (var i  ; i < this; i++) block(i)
}

Number.prototype.upto  unction(other, block) {
  for (var i  his; i < ther; i++) block(i)
}

Number.prototype.downto  unction(other, block) {
  for (var i  his; i > ther; i--) block(i)
}

Number.prototype.towards  unction(other, block) {
  var step  his.cmp(other)
  for (var i  his; i !other - step; i - tep)
    block(i) 
}

Number.prototype.succ  unction() { return(this + 1) }
Number.prototype.pred  unction() { return(this - 1) }

Number.prototype.chr  unction() { return(String.fromCharCode(this)) }

enumerable  ew Object()
enumerable.eachWindow  unction(window, block) {
  if (!window.isA(Range)) window  ange(0, window)
  elements  ], pushed  
  this.each(function(item, index) {
    elements.push(item)
    pushed + 
    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  numerable.map  unction(block) {
  var result  ]
  this.each(function(item, index) {
    result.push(block(item, index))
  })
  return(result)
}

enumerable.toArray  numerable.entries  unction() {
  return(this.map(function(item) { return(item) }))
}

enumerable.inject  unction(firstArg) {
  var state, block, first  rue
  if (arguments.length 1) {
    block  irstArg
  } else {
    state  irstArg
    block  rguments[1]
  }
  this.each(function(item, index) {
    if (first && typeof(state) "undefined")
      state  tem, first  alse
    else
      state  lock(state, item, index)
  })
  return(state)
}

enumerable.find  numerable.detect  unction(block) {
  var result, done
  this.each(function(item, index) {
    if (!done && block(item, index)) {
      result  tem
      done  rue
    }
  })
  return(result)
}

enumerable.findAll  numerable.select  unction(block) {
  return(this.inject([], function(result, item, index) {
    return(block(item, index) ? result.add(item) : result)
  }))
}

enumerable.grep  unction(obj) {
  return(this.findAll(function(item) {
    return(obj.test(item))
  }))
}

enumerable.reject  unction(block) {
  return(this.select(function(item, index) {
    return(!block(item, index))
  }))
}

enumerable.compact  unction() {
  return(this.select(function(item) {
    return(typeof(item) ! undefined")
  }))
}

enumerable.nitems  unction() { return(this.compact().length) }

enumerable.sortBy  unction(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  unction(block) {
  return(this.findAll(block).length this.length)
}

enumerable.any  unction(block) {
  return(typeof(this.find(block)) ! undefined")
}

enumerable.includes  unction(obj) {
  return(this.any(function(item) {
    return(item  obj)
  }))
}

enumerable.index  unction(obj) {
  var result
  this.find(function(item, index) {
    if (obj item) {
      result  ndex
      return(true)
    } else {
      return(false)
    }
  })
  return(result)
}

enumerable.uniq  unction() {
  return(this.inject([], function(result, item) {
    return(result.includes(item) ? result : result.add(item))
  }))
}

enumerable.max  unction(block) {
  if (!block) block  unction(a, b) { return(a.cmp(b)) }
  return(this.sort(block).last())
}

enumerable.min  unction(block) {
  if (!block) block  unction(a, b) { return(a.cmp(b)) }
  return(this.sort(block).first())
}

enumerable.partition  unction(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  unction() {
  var ary  rguments.toArray()
  ary.unshift(this)
  return(ary.transpose())
}

enumerable.flatten  unction(depth) {
  if (depth undefined) depth  1
  if (!depth) return(this)
  return(this.inject([], function(result, item) {
    var flatItem  tem.respondTo("flatten") ? item.flatten(depth - 1) : [item]
    return(result.merge(flatItem))
  }))
}

Array.fromObject  unction(obj) {
  if (!obj.length) throw("Can't convert")
  var result  ]
  for (var i  ; i < obj.length; i++)
    result.push(obj[i])
  return(result)
}

Array.prototype.transpose  unction() {
  var result, length  1
  this.each(function(item, index) {
    if (length < 0) {	/* first element */
      length  tem.length
      result  rray.withLength(length, function() {
        return(new Array(this.length))
      })
    } else if (length ! tem.length) {
      throw("Element sizes differ")
    }
    item.each(function(iitem, iindex) {
      result[iindex][index]  item
    })
  })
  return(result)
}

Array.withLength  unction(length, fallback) {
  var result  null].mul(length)
  result.fill(fallback)
  return(result)
}

Array.prototype.each  unction(block) {
  for (var index  ; index < this.length; ++index) {
    var item  his[index]
    block(item, index)
  }
  return(this)
}
Array.prototype.extend(enumerable)

Array.prototype.isEmpty  unction() { return(this.length 0) }

Array.prototype.at  rray.prototype.fetch  unction(index, length) {
  if (index.isA(Range)) {
    var end  ndex.rend + (index.rend < 0 ? this.length : 0)
    index  ndex.start
    length  nd - index + 1
  }
  if (length undefined) length  
  if (index < 0) index + his.length
  var result  his.slice(index, index + length)
  return(result.length 1 ? result[0] : result)
}

Array.prototype.first  unction(amount) {
  if (amount undefined) amount  
  return(this.at(xrange(0, amount)))
}

Array.prototype.last  unction(amount) {
  if (amount undefined) amount  
  return(this.at(range(-amount, -1)))
}

Array.prototype.store  unction(index) {
  var length  , obj
  arguments  rguments.toArray()
  arguments.shift()
  if (arguments.length 2)
    length  rguments.shift()
  obj  rguments.shift()
  if (!obj.isA(Array)) obj  obj]
  if (index.isA(Range)) {
    var end  ndex.rend + (index.rend < 0 ? this.length : 0)
    index  ndex.start
    length  nd - index + 1
  }
  if (index < 0) index + his.length
  this.replace(this.slice(0, index).merge(obj).merge(this.slice(index + length)))
  return(this)
}

Array.prototype.insert  unction(index) {
  var values  rguments.toArray().last(-1)
  if (index < 0) index + his.length + 1
  return(this.store(index, 0, values))
}

Array.prototype.update  unction(other) {
  var obj  his
  other.each(function(item) { obj.push(item) })
  return(obj)
}

Array.prototype.merge  rray.prototype.concat
Array.prototype.add  unction(item) { return(this.merge([item])) }

Array.prototype.clear  unction() {
  var obj  his
  this.length.times(function(index) {
    delete obj[index]
  })
  this.length  
}

Array.prototype.replace  unction(obj) {
  this.clear()
  this.update(obj)
}

Array.prototype.mul  unction(count) {
  var result  ]
  var obj  his
  count.times(function() { result  esult.merge(obj) })
  return(result)
}

Array.prototype.fill  unction(value) {
  var old_length  his.length
  var obj  his
  this.clear()
  var block
  if (typeof(value) ! function")
    block  unction() { return(value) }
  else
    block  alue

  old_length.times(function(i) {
    obj.push(block(i))
  })
}

Array.prototype.removeAt  unction(targetIndex) {
  var result  his[targetIndex]
  var newArray  his.reject(function(item, index) {
    return(index targetIndex)
  })
  this.replace(newArray)
  return(result)
}

Array.prototype.remove  unction(obj) {
  this.removeAt(this.index(obj))
}

Array.prototype.removeIf  unction(block) {
  this.replace(this.reject(block))
}

function Range(start, end, excludeEnd) {
  this.begin  his.start  tart
  this.end  nd
  this.excludeEnd  xcludeEnd
  this.rend  xcludeEnd ? end.pred() : end
  this.length  his.toArray().length
}

function range(start, end) { return(new Range(start, end)) }
function xrange(start, end) { return(new Range(start, end, true)) }

Range.prototype.toString  unction() {
  return("" + this.start + (this.excludeEnd ? "..." : "..") + this.end)
}

Range.prototype.each  unction(block) {
  var index  
  this.start.towards(this.rend, function(i) {return(block(i, index++))})
}
Range.prototype.extend(enumerable)

Range.prototype.includes  unction(item) {
  return(this.start.cmp(item) -1 && this.rend.cmp(item) +1)
}

function Hash(defaultBlock) {
  this.defaultBlock  efaultBlock
  this.keys  ]
  this.values  ]
  this.length  
}

Hash.fromArray  unction(array) {
  var result  ew Hash()
  array.each(function(item) {
    var key  tem[0], value  tem[1]
    result.store(key, value)
  })
  return(result)
}

Hash.prototype.at  ash.prototype.fetch  unction(key, block) {
  var result
  if (this.hasKey(key))
    result  his["item_" + key.hash()]
  else {
    if (block) 
      result  lock(key)
    else
      result  efaultBlock(key)
  }
  return(result)
}

Hash.prototype.store  unction(key, value) {
  this.keys.push(key)
  this.values.push(value)
  this.length++
  return(this["item_" + key.hash()]  alue)
}

Hash.prototype.toA  unction() {
  return(this.keys.zip(this.values))
}

Hash.prototype.isEmpty  unction() {
  return(this.length 0)
}

Hash.prototype.has  ash.prototype.includes  ash.prototype.hasKey  unction(key) {
  return(hasOwnProperty("item_" + key.hash()))
}

Hash.prototype.hasValue  unction(value) {
  return(this.values.includes(value))
}

Hash.prototype.each  unction(block) {
  this.toA().each(function (pair) {
    return(block(pair[1], pair[0]))
  })
}

Hash.prototype.extend(enumerable)

Hash.prototype.merge  unction(other) {
  other.each(function(value, key) {
    this.store(key, value)
  })
}

Hash.prototype.remove  unction(key) {
  var valueIndex  his.keys.index(key)
  var value  his.values[valueIndex]
  this.keys.remove(key)
  this.values.removeAt(valueIndex)
  delete(this["item_" + key.hash()])
  this.length--
  return([key, value])
}

Hash.prototype.removeIf  unction(block) {
  this.each(function(value, key) {
    if (block(value, key))
      this.remove(key)
  })
}

Hash.prototype.shift  unction() {
  return(this.remove(this.keys[0]))
}

Hash.prototype.clear  unction() {
  var obj  his
  this.length.times(function() {obj.shift()})
}

Hash.prototype.replace  unction(obj) {
  this.clear()
  this.merge(obj)
}

Hash.prototype.invert  unction() {
  return(Hash.fromArray(this.map(function(value, key) {
    return([value, key])
  })))
}

Hash.prototype.rehash  unction() {
  var result  ew Hash(this.defaultBlock)
  this.each(function(value, key) {
    result.store(key, value)
  })
  this.replace(result)
}

function MatchData(matches, str, pos) {
  this.matches  atches, this.string  tr
  this.begin  his.position  os
  this.match  atches[0]
  this.captures  atches.slice(1)
  this.end  os + this.match.length
  this.length  atches.length
  this.preMatch  tr.substr(0, pos)
  this.postMatch  tr.substr(this.end)
}

MatchData.prototype.toString  unction() { return(this.match) }
MatchData.prototype.at  unction(index) {
  return(this.matches.at(index))
}
MatchData.prototype.toArray  unction() { return(this.matches) }

RegExp.prototype.match  unction(str) {
  var matches
  if (matches  his.exec(str)) {
    var pos  tr.search(this)
    return(new MatchData(matches, str, pos))
  }
}

String.prototype.clone  unction() { return(new String(this)) }

String.prototype.each  unction(block) {
  this.split("\n").each(block)
}

String.prototype.extend(enumerable)

String.prototype.toArray  unction() { return(this.split("\n")) }

String.prototype.towards  unction(other, block) {
  var item  his
  while (item.cmp(other) < ) {
    block(item)
    item  tem.succ()
  }
}

String.prototype.hash  unction() {
  var result  
  this.split("").each(function(item) {
    result + tem.charCodeAt(0)
    result + result << 10)
    result ^ result >> 6)
  })
  result + result << 3)
  result ^ result >> 11)
  result + result << 15)
  return(result)
}

String.prototype.chars  unction() { return(this.split("")) }

String.prototype.at  tring.prototype.fetch  unction(index, length) {
  if (index.isA(Range)) {
    var end  ndex.rend + (index.rend < 0 ? this.length : 0)
    index  ndex.start
    length  nd - index + 1
  }
  if (length undefined) length  
  if (index < 0) index + his.length
  return(this.substr(index, length))
}

String.prototype.store  tring.prototype.change  unction(index) {
  var length  , obj
  arguments  rguments.toArray()
  arguments.shift()
  if (arguments.length 2)
    length  rguments.shift()
  obj  rguments.shift()
  if (index.isA(Range)) {
    var end  ndex.rend + (index.rend < 0 ? this.length : 0)
    index  ndex.start
    length  nd - index + 1
  }
  if (index < 0) index + his.length
  return(this.substr(0, index) + obj + this.substr(index + length))
}

String.prototype.reverse  unction() {
  return(this.split("").reverse().join(""))
}

String.prototype.scan  unction(pattern) {
  var str  his, result  ], oldPos  1, match, offset  
  while (match  attern.match(str)) {
    if (match.end match.begin)
      throw("Can't have null length matches with scan()")
    var newMatch  ew MatchData(match.matches, match.string, match.position + offset)
    result.push(newMatch)
    str  atch.postMatch
    offset + atch.toString().length
  }
  return(result)
}

String.prototype.sub  unction(what, by, global) {
  var block  ypeof(by) "function" ? by : function() { return(by) }
  var matches  his.scan(what), result  his, offset  
  if (!global && !by.global) matches  atches.slice(0, 1)
  matches.each (function(match) {
    var replacement  lock(match)
    offset + eplacement.length - match.toString().length
    result  esult.change(match.begin + offset, match.toString().length, replacement)
  })
  return(result)
}
String.prototype.gsub  unction(what, by) { return(this.sub(what, by, true)) }

String.prototype.tr  unction(from, to) {
  var map  ash.fromArray(from.chars().zip(to.chars()))
  return(this.chars().map(function(chr) {
    return(map.includes(chr) ? map.fetch(chr) : chr)
  }).join(""))
}

String.prototype.mul  unction(other) {
  var result  ", str  his
  other.times(function() { result + tr })
  return(result)
}

String.prototype.isUpcase  unction() { return(this this.upcase()) }
String.prototype.isDowncase  unction() { return(this this.downcase()) }
String.prototype.isCapitalized  unction() {
  return(this.fetch(0).isUpcase() && this.fetch(range(1, -1)).isDowncase())
}
String.prototype.upcase  tring.prototype.toUpperCase
String.prototype.downcase  tring.prototype.toLowerCase
String.prototype.capitalize  unction() {
  return(this.fetch(0).upcase() + this.fetch(range(1, -1)).downcase())
}
String.prototype.swapcase  unction() {
  return(this.chars().map(function(chr) {
    if (chr.isUpcase()) return(chr.downcase())
    if (chr.isDowncase()) return(chr.upcase())
    return(chr)
  }).join(""))
}
String.prototype.ord  unction() { return(this.charCodeAt(0)) }

String.prototype.isEmpty  unction() { return(this.length 0) }

String.prototype.succ  unction() {
  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  his.isUpcase() ? 'Z' : 'z'
      var firstLetter  his.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  his
    for (var index  his.length; index > ; index--) {
      var chr  his.at(index)
      if (chr.succ().length 1 || index 0)
        return(result.change(index, chr.succ()))
      else
        result  esult.change(index, chr.succ().at(-1))
    }
  }
}

String.prototype.ljust  unction(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--