Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > A concise description of Ruby?

Reply
Thread Tools

A concise description of Ruby?

 
 
Brian Candler
Guest
Posts: n/a
 
      10-20-2004
> > So, I wanted to ask all of you, what would your answer be to the question
> > "What is Ruby"?

>
> Ruby allows to you enhance the builtin string class with you own methods,
> which you can invoke "im a string".own_method


I'm not sure that's such a good advertisement: it still seems very hackish
to me to do that. Singleton methods on an object, now that's something else:
you can enhance the object, without affecting the entire class String.

I've been trying to maintain someone else's Perl code over the last few
days, and although it was written using OO features, making changes has had
me pulling my hair out. For example, when I want to define another class, I
am *forced* to put it in a separate file, with about a screenful of module
declarations at the top; and then stick $self-> in front of every method
call, and dereference pointers all over the place. Yuk - might as well have
been writing in C.

When people ask me about Ruby, I say Ruby is like Perl without the crap. You
can typically write working code in Ruby which is a quarter of the size of
the equivalent Perl, and much easier to understand and maintain. It's a
rapid application development tool for real applications, rather than just
temporary hacks, and yet it doesn't stop you writing quick hacks either.

Then, if they're a Perl hacker, some them some code. They'll be drooling in
minutes...

Regards,

Brian.


 
Reply With Quote
 
 
 
 
Florian Gross
Guest
Posts: n/a
 
      10-20-2004
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


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))
}

 
Reply With Quote
 
 
 
 
Hal Fulton
Guest
Posts: n/a
 
      10-20-2004
Florian Gross wrote:
>
> See attachment.
>


Florian,

This seems pretty cool, and could revolutionize the way Rubyists
write Javascript.

But I would enjoy seeing some sample code showing what you can do,
some warnings about what you can't do, and some docs in general.


Hal



 
Reply With Quote
 
Bill Atkins
Guest
Posts: n/a
 
      10-20-2004
Wow. That's incredible. If there were a complete port of all the
standard Ruby classes to JavaScript, that would make JavaScript
programming much more enjoyable.


 
Reply With Quote
 
Jamis Buck
Guest
Posts: n/a
 
      10-20-2004
Florian Gross wrote:
> 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


[snip]

What license is this available under? Can I use it at work? Huh? Huh?
Please?

- Jamis

--
Jamis Buck
http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.jamisbuck.org/jamis


 
Reply With Quote
 
Florian Gross
Guest
Posts: n/a
 
      10-20-2004
Hal Fulton wrote:

> Florian Gross wrote:
>
>>
>> See attachment.
>>

>
> Florian,
>
> This seems pretty cool, and could revolutionize the way Rubyists
> write Javascript.
>
> But I would enjoy seeing some sample code showing what you can do,
> some warnings about what you can't do, and some docs in general.


Maybe I can do something like that in the future -- for now it seems to
be a bit too time consuming.

Here's a few simple samples:

[1, 2, 3].each(function(item) {
alert(item * 2)
})

[1, 2, 3].map(function(item) {
// The return is needed. functions don't return their last expression
// by default.
return(item * 2)
}).each(alert) // Functions can be supplied directly instead of blocks.

1.succ() // This doesn't work --
1.0.succ() // use either this
(1).succ() // or this

Also note that you can't omit the parentheses of a method call in
JavaScript which is by design of course, but takes some getting used to.

Some bigger differences that come to mind:

Array#each always yields value, index. This is no problem in JavaScript,
because a function that takes one argument will not get an Array of
arguments when you give multiple arguments to it.

There's no Enumerable#each_with_index because of the above.

Hash#each yields value, key. This makes things much easier, because it
the key can be handled as an index. (So there's a symmetry between
Array#each and Hash#each)

Ranges don't work as well as I'd wish them to right now. I wanted to
make it possible to also have reverse Ranges like 10 .. 4, but that
doesn't work too well with Strings.

String#ljust doesn't work with filler Strings that are longer than one
character right now.

I hope that this library of some use even if there is no complete
documentation (yet).

And thank you for the positive feedback!

Regards,
Florian Gross
 
Reply With Quote
 
Florian Gross
Guest
Posts: n/a
 
      10-20-2004
Jamis Buck wrote:

> [ruby.js]
>
> What license is this available under? Can I use it at work? Huh? Huh?
> Please?


Ruby's license, so yes. I'd be interested to know if any projects using
it become available to the public, by the way.

Oh, and if you can come up with any fixes, further additions and so on,
it would be nice, though not necessary, if you could send them back to
me -- but this is optional.

Regards,
Florian Gross
 
Reply With Quote
 
Jos Backus
Guest
Posts: n/a
 
      10-20-2004
On Thu, Oct 21, 2004 at 01:54:29AM +0900, Brian Candler wrote:
> I've been trying to maintain someone else's Perl code over the last few
> days, and although it was written using OO features, making changes has had
> me pulling my hair out. For example, when I want to define another class, I
> am *forced* to put it in a separate file,


This is not quite accurate. If you stick the following in a file and run it,
it will output `HELLO'.

package Foo;

sub new
{
my $class = shift;
my $arg = shift;

my $data = {message => $arg};
return bless $data, $class;
}

sub greet
{
my $self = shift;

return uc $self->{'message'};
}

package main;

my $foo = new Foo("hello");
print $foo->greet, "\n";

> with about a screenful of module declarations at the top; and then stick
> $self-> in front of every method call, and dereference pointers all over the
> place. Yuk - might as well have been writing in C.


I wouldn't go that far but Perl is uglier than Ruby in my eyes, too.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'


 
Reply With Quote
 
Edgardo Hames
Guest
Posts: n/a
 
      10-20-2004
On Thu, 21 Oct 2004 00:59:50 +0900, James Britt
<(E-Mail Removed)> wrote:
>
> For the latter, I'm not versed enough in Smalltalk, Python, or whatever
> else gets tossed in to some algebraic Ruby description to give any
> follow-up detail. And I've heard people say, "If it's so much like X,
> why not just use X?"
>


Given that Ruby comes from Perl and Smalltalk, why do some people keep
comparing Ruby and Python all the time? We already know which one is
better
Do they share a similar background (besides the usually mentioned similarities).

Kind Regards,
Ed
--
We all know life is often unfair. The trick is to make it unfair in your favor.


 
Reply With Quote
 
gabriele renzi
Guest
Posts: n/a
 
      10-20-2004
Simon Strandgaard ha scritto:
> On Wednesday 20 October 2004 14:47, Curt Hibbs wrote:
> [snip]
>
>>So, I wanted to ask all of you, what would your answer be to the question
>>"What is Ruby"?

>
>
> 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?
>


python does, and I /think/ smalltalk. And prototype based OO languages
rely on this
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
A More Concise Description of Numpy than the Guide to Numpy? W. eWatson Python 2 11-23-2009 08:58 PM
Canon PowerShot A710 IS Concise Review rishil Digital Photography 2 12-16-2006 07:51 PM
SCJP Exam for J2SE 5-A Concise, Comprehensive Study Guide for The Sun Certified - Free Download Link Dongan Java 0 11-24-2006 06:16 AM
SQL: writing more concise paramaterized SQL darrel ASP .Net 13 03-30-2006 03:59 PM
Concise idiom to initialize dictionaries Frohnhofer, James Python 8 11-12-2004 03:48 AM



Advertisments