A concise description of Ruby?

B

Brian Candler

So, I wanted to ask all of you, what would your answer be to the question
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.
 
F

Florian Gross

Curt said:
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)
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)
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))
}
 
H

Hal Fulton

Florian said:
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
 
B

Bill Atkins

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.
 
F

Florian Gross

Hal said:
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
 
F

Florian Gross

Jamis said:
[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
 
J

Jos Backus

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'
 
E

Edgardo Hames

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
 
G

gabriele renzi

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 ;)
 
H

Hal Fulton

gabriele said:
python does, and I /think/ smalltalk. And prototype based OO languages
rely on this ;)

I don't know Python, but I really don't think it allows extension of
built-in classes.

Hal
 
C

Curt Hibbs

Edgardo said:
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).

They are both dynamic, typeless, OO languages. If that is what you are
looking for (when you don't know any thing else), then both will quickly
become targets for further investigation.

I would like to think that those without any existing vested interest in
Python would end up choosing Ruby. At least I hope I'm right! :)

Curt
 
J

Jamis Buck

Curt said:
They are both dynamic, typeless, OO languages. If that is what you are
looking for (when you don't know any thing else), then both will quickly
become targets for further investigation.

I would like to think that those without any existing vested interest in
Python would end up choosing Ruby. At least I hope I'm right! :)

I, for one, dislike Python for various reasons. However, both Python and
Ruby exist, and are both successful, because they fit different people's
ways of thinking about the world. Ruby fits my way of thinking. Python
doesn't. For a Python fan, it is doubtless the other way around.

I don't think there is anything wrong with that. I don't think Ruby is
out to displace Python. In fact, I don't think it ever could, just
because there are lots of people for whom Python is a better fit than
Ruby is. That's not blasphemy, just honest talk. ;)

- Jamis
 
E

Edgardo Hames

They are both dynamic, typeless, OO languages. If that is what you are
looking for (when you don't know any thing else), then both will quickly
become targets for further investigation.

Back in February, I was looking for a new OO programming language with
the power of Perl but without all its nasty stuff.

After attending to a Python lecture, reading some documentation about
Ruby and subscribing to the list. I must say that at first I didn't
like Ruby's @'s for object's attributes (a little bit too Perl-ish),
but I decided to try out Ruby anyway and I really love it.

I wondered whether Python came from Perl and Smalltalk and that's the
reason why they are compared (someone even said they are cousins, if
that could ever be).
I would like to think that those without any existing vested interest in
Python would end up choosing Ruby. At least I hope I'm right! :)

I did choose Ruby, so you're at least partially right!

Regards,
Ed
 
J

jim

* Curt Hibbs said:
If nothing else, its a good "ice-breaker", to be followed up with the more
serious response.

What do you mean. I thought that was a serious response....If not serious,
it is definitely truthfull. :)
 
B

bruno modulix

Richard Lyman a écrit :
(top -post corrected)
I tell coworkers - "It's the language that'll let you like programming > again."

Nice try, but already used by pythonistas...
 
B

bruno modulix

Charles Mills a écrit :
Ruby: The powerful and dynamic object-oriented language which "makes
programming fun again".

The first part of that description is taken from and article by Matz and
the second part is taken from an article by Dave Thomas. So, basically
I didn't come up with any of it.

The second part was already used 5 years ago when talking about Python...
 
B

bruno modulix

Mike Clark a écrit :
"Ruby? Oh, you won't like this language. (Slides Pixaxe II out of
view.) It's entirely too fun and productive for most people."
keyboard !-)
 
B

bruno modulix

James Britt a écrit :
(snip)
Although the phrase has been glommed by Python fans, I believe it more
appropriate to say that Ruby is almost like executable pseudo-code[*].
There is very little extraneous syntax to interfere with simply
expressing what you want to do. (snip)
[*] Show of hands: How many people write "__self__" as a routine part
of of their pseudo code?

Err... actually, it's 'self', not '__self__', and since it's pretty
common in OOPLs to have a 'self', 'this' or like keyword to refer to the
current instance in methods, I don't see where's the problem. Now, how
many people would write @attr instead of this.attr or self.attr in their
pseudocode ?-)

Bruno
 
P

Phil Tomson

You're looking for a ruby "elevator speech"!

Ruby is an elegant language in which it's easy and natural to express
solutions. It's simple enough that a beginner can start using it
immediately, yet powerful enough to deal with sophisticated needs. It's
so fun that the Puritans would have banned it had they known about it.

The Puritans often get a bad wrap, but that would lead to another long
thread...

Actually, if you want to get people to rally behind Ruby you should change
your sentence to:
It's so fun and powerful that John Ashcroft is planning to ban it.

Then you'd get lots of folks interested and 'Save Ruby' websites would
spring up all over the web ;-)

Phil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top