(Sat Feb 10, 2007) [/Ruby] #
Just for fun, here are the RubyGems I currently have installed:
actionmailer (1.3.2)
actionpack (1.13.2)
actionwebservice (1.2.2)
activerecord (1.15.2)
activesupport (1.4.1)
aws-s3 (0.3.0)
builder (2.0.0)
capistrano (1.4.0)
cgi_multipart_eof_fix (1.0.0)
cheat (1.2.1)
daemons (1.0.3)
fastthread (0.4)
flexmock (0.4.5)
gem_plugin (0.2.1)
gruff (0.2.8)
hoe (1.1.7, 1.1.4)
hpricot (0.5)
mime-types (1.15)
mocha (0.4.0)
mongrel (0.3.13.2)
mongrel_cluster (0.2.0)
net-sftp (1.1.0)
net-ssh (1.0.10)
piston (1.3.0)
rails (1.2.2)
rake (0.7.1)
rb-appscript (0.3.0)
rcov (0.7.0.1)
RedCloth (3.0.4)
rmagick (1.14.1)
ruby-prof (0.4.1)
rubyforge (0.4.0, 0.3.1)
rubygems-update (0.9.2, 0.9.1)
safariwatir (0.2.2)
sources (0.0.1)
test-spec (0.3.0)
xml-simple (1.0.10)
This list may be interesting to look back on, say, 2 years from now.
(Don't count on it.) Who knows which gems will stand the test of time,
and if so, what versions we'll be using by then.
Which RubyGems are you sporting?
(Thu Feb 01, 2007) [/Ruby] #
Every once in a while you run across a library that makes your day. Everything just works as you'd
expect and you can focus on getting something done quickly. Today, for example, I needed to share a
relatively large file with a significant number of people. Linking it up on our host just didn't
make sense. Added to which, just last week Marcel Molina Jr. had given a talk at The Rails Edge about his new AWS::S3 library. Coincidence? No, opportunity!
Getting started was so doggone easy that I just had to share...
1. Sign Up
Signing up is free, then you pay as you go. It's currently $0.20 per gigabyte of data transferred
and $0.15 per gigabyte stored each month.
Using your existing Amazon account, simply create an Amazon Web
Services (AWS) account. Then just activate the S3 Web
Service. You'll receive an email that includes a link for fetching two keys: an access key id
and a secret access key. You need these to make requests against the S3 service.
2. Download the AWS::S3 Library
gem install aws-s3
3. Play Around
Before you start shuttling bits around from inside an application, I recommend playing around with
the API a bit. It's fun, and made easier with an interactive shell called s3sh that comes with the AWS::S3 library. It's your irb for Amazon S3.
$ s3sh
The first thing you'll need to do is make a connection to your S3 account:
AWS::S3::Base.establish_connection!(
:access_key_id => 'your access key id goes here',
:secret_access_key => 'your secret key goes here'
)
Then create a unique container, called a bucket, for your objects:
Bucket.create('intergalactic')
The bucket also serves as the global namespace for your objects. Here's where the magic happens. Add an object to your bucket:
AWS::S3::S3Object.store('flight_manual.pdf',
open('/path/to/local/flight_manual.pdf'),
'intergalatic',
:access => :public_read)
Once the object has been stored in the big hard-drive in the sky, you can access it at http://s3.amazonaws.com/intergalactic/flight_manual.pdf.
That's really all there is to it! It's a convenient service fronted by an elegant Ruby library that
adds up to a whole lot of fun and productivity. The API supports a boatload more options and
operations, and it's extremely well designed. Having polished off the task in a couple minutes, I
found the short and sweet documentation to be just what
I needed for diving deeper.
4. Integrate
For my one-off task today, using s3sh was super convenient. But at some point you'll
probably want to manage buckets and objects from within a larger program, such as a Rails
application. That's pretty easy given the AWS::S3 Ruby library. But just to get you started, I'll
leave you with this handy s3.rb file for storing an object in one fell swoop:
#!/usr/bin/env ruby
require 'rubygems'
require 'aws/s3'
AWS::S3::Base.establish_connection!(
:access_key_id => ENV['AMAZON_ACCESS_KEY_ID'],
:secret_access_key => ENV['AMAZON_SECRET_ACCESS_KEY']
)
file = ARGV.first
bucket = "intergalactic"
AWS::S3::S3Object.store(File.basename(file),
open(file),
bucket,
:access => :public_read)
puts AWS::S3::S3Object.url_for(File.basename(file), bucket)[/[^?]+/]
To store the same object we did in the previous step, you'd type:
s3.rb /path/to/local/flight_manual.pdf
When all the bits have been safely tucked away, the public URL is printed. Share your objects at
will, but remember that the meter's running.
5. Enjoy
Thanks Marcel!
(Wed Jan 17, 2007) [/Ruby] #
It's great to see a flurry of activity around RubyCocoa: the bridge for writing Cocoa apps using Ruby. Word on the street is that it'll ship with
Leopard...
(Tue Oct 24, 2006) [/Ruby] #
At RubyConf this weekend, Laurent Sansonetti from Apple gave a talk
and demonstration of RubyOSA. It's a bridge that
connects Ruby to the AppleEvent infrastructure. Translated, that means
you can do in Ruby what before you could only do in the insufferable
language called AppleScript.
RubyOSA is still under heavy development, so watch your head. The
official release is rumored to be out Any Day Now (TM). Until then,
here's a quick way to start playing:
1. Install libxml and its Ruby bindings:
sudo port install libxml
sudo gem install libxml-ruby
2. Checkout and build RubyOSA:
svn co svn://rubyforge.org/var/svn/rubyosa/trunk rubyosa
cd rubyosa/
ruby extconf.rb
make
ln -s src/lib/rbosa.rb rbosa.rb
3. Fire it up in irb:
irb -r osa.bundle -r rbosa.rb
4. Start controlling applications, such as iTunes:
>> require 'rbosa'
=> false
>> itunes = OSA.app_with_name('iTunes')
>> track = itunes.current_track
>> p track.name
=> "Blue Dress"
>> track.rating = 20
=> 20
>> itunes.next_track
=> nil
>> itunes.previous_track
=> nil
>> itunes.sound_volume = 50
=> 50
>> itunes.pause
=> nil
>> itunes.play
=> nil
>> itunes.current_playlist.tracks.size
=> 2110
>> itunes.public_methods(false).size
=> 68
Or iChat:
>> ichat = OSA.app('ichat')
>> ichat.status_message = "Live from RubyOSA"
=> "Live from RubyOSA"
>> windows = ichat.windows.to_a
>> windows.first.name
=> "Chat with Marcel Molina"
>> ichat.public_methods(false).size
=> 20
Taking that a step further, you can hold yourself accountable with
Rake
Shame. Let your friends motivate you!
In theory, you can use Ruby to control any application that has a scriptable
definition. We're still poking and prodding on the boundaries. For
example, OSA.app('finder') works, but it's uncharted
territory. And yet the way forward looks a lot clearer than it used
to.
Major props to Marcel for helping me get started. :-)
Have fun!
(Mon Oct 23, 2006) [/Ruby] #
Herewith, a sparse collection of completely out of context and
unattributed quotes I overheard at RubyConf this weekend. Names aren't
attached either because I didn't know the person's name or I felt the
accuracy of the quote was sketchy. Corrections and additions welcome.
"They're flipping one of the ladies rooms into a mens room for us"
"We decided Ruby wasn't niche enough (queue Erlang movie)"
"I'm not Matz"
"Rubinius has evil built in"
"I hope your minds are sufficiently blown"
"It's ugly, we'll fix it"
"First come, first served, but not right now"
"No cussing; that's so 2005"
"Can you write that code, please?"
"But seriously, who doesn't have this book? (holds up AWDWR book)"
"How many people here understand Unicode (hands go up) to a
fairly deep level? (hands go down)"
"YARV will find you a new girl friend"
"We have room for the next 3 alien races in the Unicode plane"
"As with most Java APIs, things aren't necessarily built for comfort"
(Fri Apr 08, 2005) [/Ruby] #
I had no idea this test-driven learning approach would resonate with
so many folks. Thanks for your kind words and encouragement!
What Happens Next?
I'm sorry to have made you wait so long for the second installment of
this series. To be honest, I was waiting to get some input from you,
dear reader, about how best to proceed. Although I've been using this
technique to learn new languages and APIs for several years now, I've
just started thinking about how to share it with others. You see, I
don't want this to turn into another Ruby language reference. You
probably already have Programming
Ruby pressed against your bosom.
Since posting the first
test, many of you have suggested great ideas about what you'd like
to see covered in future tests. I'm delighted to hear that you're not
expecting a language reference, and I won't need to hire a ghost
writer. Instead, I'll be using this space to explore how to use the
learning test technique to supplement other resources. That is, I'll
show you how I wrote learning tests to internalize the core concepts I
learned in the Ruby book. Things like classes, blocks, exceptions,
modules, and threads. As well, please do keep the comments coming.
Your input will influence how this plays out, and I'll be picking up
the pace now that I know you're on the edge of your seat to learn more
Ruby. So welcome aboard!
Pulled Up By Your Bootstraps
So you've installed Ruby and learned enough about the Test::Unit
module to bootstrap some learning. It may not feel like much, but
given this simple (and safe) testing environment, you can learn useful
things about Ruby without having to learn much more about Test::Unit
just yet.
Hopefully you felt motivated to write a few more tests to explore how
String works---it has over 75 standard methods just waiting
to serve you. You don't need a main() method or a debugger
to try them out. Just a simple assert_equal will do, and you
already know how that works. Do you need to write a test for each
method right away? Certainly not. Instead, I wait until I learn
about a new method, then I write a learning test in order to learn how
the method really works.
Trying What You Read
So how does this technique work in practice? Last time we were
focused on just feeling our way around writing tests and getting them
to pass. We didn't exactly discuss how this changes the way you read
the Ruby book.
Say, for example, you're reading through Chapter 2 of Programming
Ruby, and Dave starts explaining how to send messages to objects.
Then he shows you some code.
"Rick".index("c") --> 2
To the left of the arrow you see the Ruby expression. The resulting
value of the expression is to the right of the arrow. To really learn
how to program, I have to program alongside the book. Learning tests
give me a way to incrementally try out and, well, test what
I've learned. So when you see that format in the book, think of it as
an assertion and write a test.
def test_index
assert_equal(2, "Rick".index('c'))
end
Notice that the test method is named test_index. The
test prefix is required by Test::Unit. The _ is the
Ruby convention for separating words in method names. Finally,
index describes what the test is testing.
I like to keep my test methods nice and short. They test just one
thing, and I describe what they test using an expressive method name.
That way, if I forget how the index method works, I can
easily find an example in my learning test repository. In this case,
a search would find the use of index in the assertion,
regardless of the method name. But as you write more learning tests,
expressive test method names become invaluable. I often find that if
I'm unable to find a test quickly, it means the method name needs to
be changed. So expect the names to get refined over time.
Coloring Outside the Lines
OK, so the learning test passes. Not surprisingly, the index
method returns the index of the first occurrence of the given
character. It's at this point in my reading that I'm generally not
satisfied. I want to do a bit of exploration, and perhaps even try to
break something. The learning test environment allows me to answer
questions where the book doesn't.
What happens if the given character isn't in the string, for example?
Knowing very little about the language at this point, you can make a
guess and ask Ruby for the real answer.
def test_index_character_not_found
assert_equal(-1, "Rick".index('t'))
end
(That test doesn't pass, by the way. Go ahead and run it to find out what the
actual answer is.)
This is active reading. While you're reading, pay attention to things
that pique your curiosity. If you keep reading, you risk losing that
moment when your brain really wants to learn by doing. Writing a
learning test gives you a way to immediately apply the material and,
perhaps more importantly, seek answers to questions the material
raises for you.
Your Next Mission
Use ri to find out what methods the Fixnum class responds to.
Then create a test case in a file called number_test.rb and write a few
tests. A Fixnum represents an integer value within a certain range.
Here's a learning test demonstrating how to create one:
def test_create_fixnum
f = 123
assert_equal(Fixnum, f.class)
end
Notice the use of the class method to test the class of the object
referenced by the f variable. If you create a number outside the
range of a Fixnum, what is the class of the variable f?
Everything in Ruby is an object. Yes, even numbers. Try sending some messages
to numbers. Here's a starter test:
def test_abs
assert_equal(1, -1.abs)
end
What other tests can you think of for numbers? Chapter 5, Standard Types, of
Programming Ruby
shows example uses of numbers and the reference library in the back documents
all of the methods. As you read about numbers in the
book, what questions do you have? Answer the questions by writing learning
tests. I'm holding back writing a bunch of
assert_equal tests here because that won't help you learn.
But next time we'll dig into how to write learning tests for
facets of Ruby that require more than a simple assertion of an
expression's value.
(Fri Mar 18, 2005) [/Ruby] #
I truly have no idea where this is going or if it will scale. But
I've been meaning to try it, and I'll let you judge whether it's worth
it. Here's what I do know: It doesn't cost you anything to come along
for the ride.
How I Learned Ruby
A couple years back I flipped open the first edition of Dave and
Andy's wonderful book Programming
Ruby. A few pages in I'm introduced to my first Ruby code. It
looks somewhat foreign... maybe it's just my strained eyes. Ah, it's
so clean and elegant! I want to try it. Oh, but will I have the time
and opportunity to keep learning Ruby? Just when I'm at the tipping
point, Dave beckons me closer: "Go ahead, run the code and you'll
see the following output." Those words are intoxicating to a
programmer, and so I proceeded to write my first Ruby program.
But it was at that very moment when I asked Ruby a question and it
responded with the answer that I learned more than Ruby. I knew right
then that I didn't want to run the example just once. No, I wanted to
preserve the example and ultimately build a Ruby knowledge base that I
could draw from later. That meant the examples had to be executable
and check their own results. That sounded familiar. I needed to
write tests.
There was just one problem: I didn't yet know enough about Ruby to
write a test. Oh, I could print stuff to the screen, but that sort of
manual inspection breaks down quickly. Using JUnit had taught me the
value of writing automated tests that put the computer in charge of
remembering what outcome is expected. Thankfully, when you install
Ruby you automatically get the Test::Unit
unit testing module. And so I had to learn enough about Test::Unit to
learn Ruby itself. The result, years later, is the following:
[~/work/code/ruby/learn] $ ruby all_learning_tests.rb
ruby all_learning_tests.rb
Loaded suite all_learning_tests
Started
.......................... (a lot more dots)
Finished in 1.467719 seconds.
215 tests, 452 assertions, 0 failures, 0 errors
That's pretty much everything I know about Ruby, give or take. It's a
living repository of knowledge; the test suite grows each time I learn
something new. Promptly after installing a new version of Ruby, I run
the test suite. I do that not necessarily because I think the tests
will find a bug, but rather to get a heads-up when something has
changed and I need to reset my expectations. It's also a good way to
identify when something has been deprecated.
But the real value of writing these tests was less about testing, and
more about learning. Through trial and error they taught me how Ruby
and its rich set of libraries really work. Not surprisingly, typing
in code and running it makes you remember. Indeed, writing learning
tests is a fun way to poke and prod any new language or API.
And with every test you write you're investing in an executable
knowledge base.
So You Want To Learn Ruby?
Perhaps you've been meaning to learn Ruby for fun or profit, but you
just don't know where to start. I'd like to help by trying a bit of
an experiment. No, I'm not going to send you a copy of my Ruby
learning tests. The learning comes through doing.
Rather, I'll start by showing you how I wrote my first Ruby
learning test. Then, over the coming weeks and months, I'll spoonfeed
you more tests as a starting point for exploring new facets of Ruby.
(Submissions are appreciated, too.) Of course, if I get
the sense that nobody's listening, I'll stop.
After we get the fundamentals down, I won't try to explain in depth
what the Ruby code in each test does. If the test is written well,
you won't need an explanation. And frankly, you really do need a copy
of Programming
Ruby for a definitive guide and tutorial to Ruby. (Disclaimer: I
don't get royalties from sales of the book, but it's quite excellent
and it saves me typing here.) When I introduce a major new topic,
I'll try to call out page numbers from that book. Then you can go to
those pages, read up on how and why something works, and codify your
understanding with learning tests.
One caution before we go any further: Ruby has spoiled many
programmers.
Write a Learning Test
Starting is always the difficult part, so let's get right to it.
Download and install Ruby using the one-click
Windows installer, tarball,
or any other option.
Now we get to write our first learning test. Strings are always fun
and easy pickings, plus they usually have a lot of interesting methods
to play with. So change to a directory where your learning tests will
live (mine's called learn) and create a file called
string_test.rb that contains the following Ruby code:
require 'test/unit'
class StringTest < Test::Unit::TestCase
def test_length
s = "Hello, World!"
assert_equal(13, s.length)
end
end
You just wrote your first Ruby class! The require statement
at the top of the file loads the Test::Unit module: Ruby's
built-in unit testing framework. The next line declares a class
called StringTest. The < symbol on the class
declaration line means that StringTest is a subclass of
Test::Unit::TestCase. Classes that are test cases must
extend Test::Unit::TestCase to enjoy the set of
computer-checked assertion methods that we'll use later.
The StringTest class has one method: test_length.
Test methods take no parameters and they must be named with a
"test" prefix so that Test::Unit knows that they're tests we
want to run. After defining the method, we create a variable called
s that references an object of class String. We
don't have to declare the type of the variable because Ruby figures
out its type based on what the variable can do. (More on this
exciting topic later.) We then call the assert_equal method
(inherited from TestCase) with two parameters. What we're
saying here is we expect the length of the string s to be 13.
Then the method definition ends with the end keyword, as does
the class definition.
Now, let's run the test.
> ruby string_test.rb
Loaded suite string_test
Started
.
Finished in 0.0051 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
OK, so we can count! Let's kick it up a notch. Double-quoted strings
can also contain any Ruby expression of the form
#{expression}. So let's add another test.
def test_expression_substitution
assert_equal("", "#{'Hello! ' * 3}")
end
Hmm, that's not going to pass. We're asserting that the result of the
expression passed as the second parameter will equal an empty string.
We may not be sure what the expression will do, but we're pretty sure
it will evaluate to a non-empty string. So why use "" as the
expected value?
Sometimes when we're trying to learn something new, we just don't know
the answer. We might have a guess, but if we trust the source then we
can do one better: we can ask. By leaving the expected outcome empty,
we're asking Ruby to tell us what the answer is when we run the test.
> ruby string_test.rb
Loaded suite string_test
Started
F.
Finished in 0.093141 seconds.
1) Failure:
test_expression_substitution(StringTest) [string_test.rb:13]:
<""> expected but was
<"Hello! Hello! Hello! ">.
2 tests, 2 assertions, 1 failures, 0 errors
Ah, so that's how it works! Thanks, Ruby! It's pretty much what we
expected: Print the phrase "Hello!" three times. Now we
plug that answer in, happy to have learned something new.
def test_expression_substitution
assert_equal("Hello! Hello! Hello! ", "#{'Hello! ' * 3}")
end
With the answer recorded, we can re-run just that test method.
> ruby string_test.rb --name test_expression_substitution
Loaded suite string_test
Started
.
Finished in 0.005031 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Wait just a doggone minute! What did we just do? We ran a test,
knowing it would fail, and then we picked out the answer from the
error and plugged it into the test so that it now passes. You
wouldn't dare try this with code you were really testing!
We have no idea if Ruby did what it should have done: we just know
what it did. That is, we used the language as a tool to explore
itself. In the same way that a test is better than a specification,
the language is better than a description of the language. The test
is definitivewhen we ask Ruby what the answer to 'Hello! ' *
3 is, we're going to the horse's mouth. It doesn't matter what
the documentation says; what we're testing is what actually happens.
And that's learning. So the test is both a learning test and a
regression test.
Now It's Your Turn
We've barely scratched the surface of what the Ruby String
class can do. See pages 61 and 606 of the book for a full listing of
all the methods and explanations for each. You can also get a list of
all the messages that String responds to by typing:
> ri String
Indeed, there's a lot to learn, but these first tests give you a
framework to explore the many wonders of strings. Better yet, you
have a safe learning environment and a language that makes it easy to
write and run tests. So go ahead, write a few more string tests, then
run them and Ruby will tell you the answers. Give gsub and
squeeze a poke. It's just a start, but it may be more Ruby
code than you've written before. Next time we'll look at another facet
of Ruby through the eyes of learning tests.
(Thu Oct 09, 2003) [/Ruby] #
I just upgraded from Ruby 1.6.7 (ships with Mac OS X) to Ruby 1.8.0. Upgrading
software in general can be a risky game, but in this case I was actually looking
forward to it. Indeed, I wanted something to break.
When I first started looking into Ruby, I decided that I wanted to learn it by
writing tests. That is, I wanted to explore the language and its libraries by
poking and prodding it with chunks of example client code. But instead of using
the equivalent of a main method containing example code, I wanted the examples
to check their own results. In other words, I'd use tests to ask Ruby a
question, learn from its response, then codify the answer in a test assertion.
Then when I wanted to refresh my memory of a particular usage of Ruby, I'd refer
back to the test. So over time I've grown a fairly comprehensive suite of
learning tests -- things I know to be true about Ruby.
Flash-forward to today just after I'd upgraded to Ruby 1.8.0. What's the next
step? Pull the test trigger:
[enoch:~/projects/ruby/learn] > ruby AllTests.rb
Loaded suite AllTests
Started
..............................................................................FF...........................
Finished in 0.667704 seconds.
1) Failure!!!
testObjectSpace(ReflectionTest) [./ReflectionTest.rb:12]:
<45> expected but was
<34>
2) Failure!!!
testRangeIntrospection(ReflectionTest) [./ReflectionTest.rb:21]:
<["extend", "equal?"]> expected but was
<["to_a", "instance_eval"]>
107 tests, 243 assertions, 2 failures, 0 errors
Interesting. Two tests failed. 105 tests passed. What gives?
Here's the first test that fails, with the failed assertion highlighted:
def testObjectSpace
a = 102.7
b = 95.1
living = Array.new
ObjectSpace.each_object(Numeric) { |x| living.push(x) }
assert_equal(45, living.length)
assert(living.include?(a))
assert(living.include?(b))
end
I'm learning introspection (reflection) here. The omniscient
ObjectSpace class knows about all living objects. I'm asking it to
traverse its universe of objects of type
Numeric and then
I rack 'em up on a stack. Then, for a reason I can't quite recall now, I assert
that 45
Numeric objects are alive. Finally I assert that two
numbers I created are among the land of the living.
So why is the first assertion failing? Well, apparently in Ruby 1.8.0 there are
only 34 Numeric objects alive at the point this test is run. It's
an implementation detail really. In hindsight, I probably could have just
tested that my two numbers are alive. Testing for 45 objects is a
triviality.
Here's the second test that fails, again with the failed assertion highlighted:
def testRangeIntrospection
range = 1..10
methods = range.methods
assert_equal(68, methods.length)
assert_equal(["extend", "equal?"], methods[1..2])
assert(range.respond_to?("equal?"))
assert(!range.respond_to?("hasKey"))
end
I'm still learning introspection here. This time I create a
Range object, assert that it has 68 methods at
my disposal, test the name of the methods at the index 1 and 2, and then
demonstrate how to use
respond_to? to see if the object will
respond to selected method invocations. It worked in Ruby 1.6.7. Seems that in
Ruby 1.8.0 the returned method names have been reordered. Does it matter?
Probably not. Again, the first two assertions are trivialities that test
implementation details. I can't remember why I wrote those assertions now. The
last two assertions are probably sufficient, but I was in a learning mode
at the time.
So should I just clean up these tests to be version independent? Doing so would
mean removing the trivialities -- making the tests more generic. More to the
point, do I care that version 1.8.0 has a few less Numeric
instances and might be using a different data structure to hold method names?
Well, I probably shouldn't care because I don't want to become dependent on
these sort of implementation details. But I think the tests are trying to tell
me something. I just don't get it (yet). And if I remove the assertions I
might miss it later.
So for now I'm just going to update the assertions -- trivialities and all -- to pass for Ruby 1.8.0, then
see what happens the next time I upgrade. After all, running the tests is free.
In the meantime, 105 passing tests tells me that my expectations about Ruby
still hold true despite the upgrade. That is, while there may be new things in
version 1.8.0 that I've yet to learn, upgrading hasn't invalidated what I
already know. These learning tests have payed back once again, this time by
giving me a lot of confidence going forward.
(Fri Oct 04, 2002) [/Ruby] #
I dig Java. Besides being the language that rescued me from five long years coding in C++, Java has paid the bills over the last six years. I remember keying in my first Java program, ironically from the pages of a Microsoft Press book a colleague loaned me. Since then the number of Java APIs has grown to staggering proportions. It seems you can do just about anything in Java these days, and I continue to have good success with it, especially building enterprise apps.
But I don't want to be a one-trick pony. After attending a conference session
by Pragmatic Dave earlier this year, I started to try my hand at Ruby.
Now when I program in my sleep (all programmers do that, right?), I see Ruby code.
Ruby is a top shelf object-oriented language that started in Japan, but has created a groundswell in the U.S. over the last couple years. It's a dynamically-typed language, with types bound to objects rather than classes. An object's type is determined by which messages (methods for us Java/C++ hacks) the object responds to. Yes, I know what they taught you about the goodness of strongly-typed languages: Write code with lots of syntactic sugar and let the compiler sort it out. Trouble is, we mere mortals have to read and write the code.
The beauty of Ruby is its simplicity and consistency. With Ruby, I find myself writing code to get the job done rather than to appease the compiler. Using test-driven development gives me all the confidence I need that the code is reliable. Will Ruby supplant Java? Nah. But there are many general purpose programs and utilities that could be written quite effectively in Ruby. In my limited experience, programming in Ruby is just good, clean fun!
If you want to learn Ruby, I recommend that you run, don't walk, to your nearest bookstore for a copy of Programming Ruby. I promise that looking into Ruby will give you a different perspective on whatever language you're currently using. You'll be sharpening the saw.