Bruce Williams

Summarized using AI

The Next Ruby

Bruce Williams • September 04, 2008 • Earth

In the presentation titled 'The Next Ruby,' Bruce Williams discusses the upcoming Ruby 1.9 version, focusing on its significance and new features. He begins by sharing his history with Ruby, emphasizing the language's evolution from a fun programming tool to a viable career path since 2001. Williams highlights the vibrant Ruby community in Austin, where he resides, and the slow yet steady adoption of Ruby 1.9 in comparison to previous versions.

Key points in the presentation include:
- Ruby 1.9 Overview: Williams identifies Ruby 1.9 as a major evolution from 1.8.x, providing better performance and new features while highlighting its lack of strict backward compatibility.
- New Features and Improvements: The speaker discusses various new syntax and language enhancements in Ruby 1.9, including improved string handling with encoding support, the introduction of the Oniguruma regular expression engine, and changes to enumerables that now return enumerators by default.
- Migration and Risks: He emphasizes the importance of having tests before migrating to Ruby 1.9 since it introduces significant changes that may impact existing codebases. He references the experience of another developer who faced unexpected issues during migration and stresses that properly running tests can help identify these problems early on.
- Community Impact and Libraries: Williams notes that while certain prominent gems, like Rails, are already compatible with Ruby 1.9, many others might not be. He points out the need for community members to ensure gem compatibility with the new version.
- Additional Syntax Changes: The presentation also covers enhancements like proc literals, hash ordering by insertion, and native threading models in Ruby 1.9, making the language more powerful and efficient.

In conclusion, Williams encourages the audience to explore Ruby 1.9 but with caution regarding legacy codebases. He reiterates the importance of maintaining tests and awareness of gem compatibility before fully adopting the new version. Overall, the session serves as an insightful guide for developers looking to transition to Ruby 1.9 successfully.

The Next Ruby
Bruce Williams • September 04, 2008 • Earth

The Next Ruby 960x368 by: Bruce Williams

Help us caption & translate this video!

http://amara.org/v/G1XG/

LoneStarRuby Conf 2008

00:00:06.319 Video equipment rental costs paid for by Peep Code Screencasts.
00:00:19.520 Um, okay. My name is Bruce Williams. I'm going to be talking about the next Ruby, which is Ruby 1.9.
00:00:25.119 First of all, to give you a little bit of background on me, that's my name in big red letters at the top.
00:00:32.640 I live here in Austin, Texas.
00:00:39.440 So, seriously.
00:00:44.800 As you can tell, we have a very large and vibrant Ruby community here.
00:00:50.559 With very small voices, the community here is growing at a pretty good rate.
00:00:56.559 It's nice to have all of you here.
00:01:02.079 So, you know, grab somebody from Austin if you're looking for a good restaurant or a good bar. There's plenty of both.
00:01:09.360 I've been a Rubyist since 2001, back when you didn't make any money doing it, and it was just a lot of fun.
00:01:14.880 Now you can make money doing it, and it's still a lot of fun.
00:01:20.479 So that worked out really well. I'm a language tourist.
00:01:27.040 What I mean by that is I'm a Rubyist by trade and it's my tool of choice, but I play with Erlang, Haskell, and whatever makes sense.
00:01:33.920 Ruby has a long lineage, and we owe a lot to many languages.
00:01:40.560 I think we should float around a bit and take a look at other languages as well.
00:01:46.799 If you had to distill my life into a series of URLs, those would probably be it.
00:01:52.799 That's where I blog when I blog, which is probably not as much as I should.
00:01:58.079 You can find me on GitHub there using my name.
00:02:04.320 I work at a company called Five Runs, which is here.
00:02:11.200 We have the Tune Up and the managed products, which you can see to the right.
00:02:17.760 Basically, I just annoy people and talk about what I'm eating for dinner and things like that.
00:02:24.959 My Twitter, I can't claim there's anything useful that comes out of that.
00:02:32.080 So why Ruby 1.9? Why care about Ruby 1.9?
00:02:37.440 How many people here are using 1.8.6 most of the time (MRI)?
00:02:43.920 Okay, keep your hands up. Now, if you're using 1.8.7, keep your hands up.
00:02:51.480 How about 1.9? How about 1.9 in production?
00:02:58.080 Dave, you don't count; you're an early, early adopter.
00:03:05.040 Actually, recently, oh yeah, okay Dave, I guess you do count, but only because you paid.
00:03:12.959 Ruby 1.9 recently did a poll; I don't know if any of you took part in it.
00:03:20.000 They found a pretty good percentage of people—about 10 to 15 percent—last time I looked.
00:03:25.040 Now the poll is gone, so I can't find it, which is perfect for me because I'm speaking about it today.
00:03:31.599 About 10 or 15 percent are using Ruby 1.9 on a regular basis.
00:03:37.840 Thinking back a little bit, Ruby 1.9 reminds me a lot of Ruby 1.7.
00:03:43.840 Back when everybody was using 1.8.6, there was 1.8.7, and people played in the world of 1.7 before 1.8 came out.
00:03:51.200 It's a little bit different now because people have businesses that rely on 1.8.
00:03:56.319 They're a little less willing to go forward willy-nilly and grab stuff because we're very much into robust enterprise software in this community.
00:04:03.840 However, Ruby 1.9 does a lot of good things for us.
00:04:09.280 We get a whole bunch of new syntax and language features.
00:04:14.560 As the next version, it's not strictly backwards compatible with 1.8.
00:04:21.040 There are definitely some issues when you're migrating code, which I'm going to discuss.
00:04:26.240 It definitely has better performance characteristics.
00:04:33.040 And of course, it has more bugs; that's just the way software works.
00:04:39.680 Although, it's probably easier to maintain these days.
00:04:45.199 What I am going to talk about is the new syntax and language features because that's what I really enjoy.
00:04:51.280 I am going to talk about migrating stuff over; I'm not going to talk about performance.
00:04:58.000 That's something that you can find loads of numbers about from the people who are far smarter than me.
00:05:03.040 1.9, as a whole, is much, much faster than MRI 1.8.
00:05:08.560 I'm not going to talk about the bugs that exist besides the ones that have immediately popped up to me.
00:05:14.240 Because I'm not psychic, I don't know where they are.
00:05:20.400 If I were, I would be helping Mats fix them, but that's not the case.
00:05:26.400 So, still on the thread of things I'm not going to talk about: I'm not going to talk about the other implementations of Ruby.
00:05:32.639 Most of which target 1.8, anyway, with the exception of Mac Ruby, which has the benefit of sitting on top of 1.9.
00:05:39.760 I'm going to be talking about YAR, so Yet Another Ruby.
00:05:46.800 Just the plain vanilla Ruby. Not that I'm not excited about those other implementations.
00:05:53.520 So clearly, don't go out and grab 1.9 right now; this is where you would go to grab it.
00:06:00.000 Ruby 1.9 is in Subversion these days. I think 1.8 is a branch as well that you can track.
00:06:06.960 It's a version if you want to get it; it's still changing on a regular basis.
00:06:12.240 Certainly more stable than it used to be.
00:06:15.840 The klaxon I guess was because it used to be very unstable.
00:06:22.080 You can get 1.9 directly from the downloads page or from Subversion, and that's essentially how you build it.
00:06:27.440 Make sure you build it with some type of program suffix or something like that so you don't get confused about what Ruby is on your system.
00:06:35.759 I use 1.9 as mine.
00:06:41.759 A little bit about the standard library: I apologize for this being a little out of date.
00:06:46.800 I've done this version of this talk a couple of times and this one didn't get updated very well.
00:06:52.640 So there may be some stuff here that is different, but in general what you have is RubyGems.
00:06:59.919 They are now part of the standard library. They're built-in Solar, Rake, JSON, Ripper, etc.
00:07:05.919 Some of these may seem a little crazy; you may not know what profiler is, for instance.
00:07:13.120 Secure Random for those of you that are Sran users is for you if you really want random.
00:07:19.840 Here's one for you to look at, and of course the HMAC digests.
00:07:25.120 CSV was replaced by the faster CSV implementation, which I believe we have someone to thank for.
00:07:31.200 That's a vast improvement, and in things that have disappeared, at least the last time I looked, SOAP, Wisdom and Base64 were removed.
00:07:36.800 So for Base64, you're going to take a look at pack and unpack.
00:07:42.800 Now we're going to talk about risk factors: parts of your code that you're going to have a problem converting over to 1.9.
00:07:49.760 Because you're going to do it eventually, and you should at least be looking at it.
00:07:56.480 The first thing I’ll say is that you need tests.
00:08:02.160 If you don't have tests now on your code, first of all, you should have tests on your code.
00:08:10.080 You have to have tests because people at conferences will annoy you to death if you don't.
00:08:16.640 VDD, BDD, BDD; that needs to be said at least three times in every talk.
00:08:22.800 Because it's new and cool and life-changing.
00:08:28.160 Actually, yeah, I like it as a concept, just not as a buzzword.
00:08:34.080 So yeah, write tests! James Edward Gray had a great quote in a Ruby talk thread many months ago.
00:08:40.160 He talked about when he was switching over Faster CSV to 1.9.
00:08:46.639 He talked about the fact that there are a lot of issues you didn't realize that were there.
00:08:53.680 Your tests really helped him find them.
00:08:59.680 That's something I keep coming back to when I've been converting some code over.
00:09:05.760 If I didn't have my tests, it would be a lot harder to find these things.
00:09:10.480 With Ruby, obviously, you're not going to find some bugs unless some branches of code are being executed.
00:09:16.160 So the idea is to get those branches to execute, and tests are the way to do that.
00:09:22.720 This is a really big change in 1.9: text processing.
00:09:28.639 If you're writing parsers, Faster CSV is a good example of this kind of stuff.
00:09:35.039 Regal parsers for instance, and Hpricot and Mongrel, etc., are good examples.
00:09:42.160 You've got the issue now where we have new encoding support.
00:09:48.560 Now when you're using the string sub-method and indexing into a string with a single index, you're going to get a character back.
00:09:55.039 You're not going to get a number back, which is what most of us expected.
00:10:00.480 That’s a thing we’ve brought up for years: yeah, when you index into a string, you get back a number.
00:10:06.000 So that's gone now; we don't have to have that conversation with people.
00:10:13.120 We need to convert over the code that relies on it.
00:10:19.760 Now you can actually manage different encodings for your actual source files.
00:10:25.679 This is kind of cool.
00:10:31.840 Thank you very much. I wonder who that is? I have a wife and two kids, and it's during my talk.
00:10:37.680 That's okay.
00:10:44.000 Okay, where was I? Thank you, dear.
00:10:49.280 Yes, encodings: we have these new encoding conventions, that's kind of an extra feature.
00:10:55.680 You certainly do need to know about string, ord, and various unpack methods.
00:11:02.080 Be familiar with unpack in general, and pack as well. They're very powerful.
00:11:07.680 Now we'll look at some examples of changes in Ruby 1.8 and Ruby 1.9.
00:11:12.800 Generally, in Ruby 1.8 to get what you see in Ruby 1.9, you do something like 0.1 or 0, 1.
00:11:20.000 A major difference there is that it's not backward compatible at all.
00:11:26.000 The recommended approach for instance, for those doing regal parsers is to unpack your string into numbers.
00:11:31.200 You can either convert one way or the other or use character or to pull stuff out.
00:11:38.000 Next, pulling the same kind of stuff out on the left-hand side, I'm only pulling out bytes.
00:11:44.480 So it doesn't really work nicely for me. But on the right-hand side, it actually pulls out the multi-byte character, which is nice.
00:11:50.800 This is obviously using some encoding trickery.
00:11:57.600 Now granted, actually typing this in TextMate with bi-directional text and trying to put an index on the end was a complete nightmare.
00:12:04.160 So I’ve taken the string and then taken the thing next to it and sat it down.
00:12:10.080 It looks like it should. TextMate gets a little confused by bi-directional.
00:12:16.000 For those of you who are dying to type Arabic, your time isn't here yet.
00:12:23.840 You see some unpacked stuff here with actually pulling out the Unicode multi-byte.
00:12:30.000 You know; use ri unpack to see all the crazy options.
00:12:36.000 If you do C-star, you get a bunch of crazy negatives for the Arabic word, so that's not very helpful.
00:12:41.920 Now this is another point: this should only affect you if you're insane.
00:12:48.680 There's this really neat trick, very clever, I always put clever in quotes.
00:12:55.040 Because it’s a synonym for stupid.
00:13:01.760 This kind of stuff, usually a bug, is when someone hasn't realized they're accidentally assigning to a variable that's outside the scope using a block argument.
00:13:08.000 You see some people do crazy things, like assigning an instance variable inside a block.
00:13:15.760 This shouldn't exist in any code you ever show anybody else.
00:13:22.320 And you see the output difference here; the very last loop is going to assign the last yield.
00:13:30.720 The block variable won't take place here; it’s going to shadow it.
00:13:37.120 It'll warn you if you're using Ruby -w, which you should be.
00:13:42.960 So you're going to want to name your variables in your blocks something different.
00:13:48.560 If there's anything here that...
00:13:54.000 So in a solution, just don't do that.
00:14:01.200 We're not going to talk about arrow lambdas just yet.
00:14:07.360 There's a way of declaring a variable as local so that you can use it inside without assigning outside.
00:14:13.680 Just pretend that little arrow is the lambda.
00:14:19.680 Inside of it, you can see you're reassigning d, but on the right side, you aren't because you're declaring it local.
00:14:26.160 But you will still get the shadow warning.
00:14:33.920 This is kind of cool; the principle of least surprises has changed.
00:14:40.960 Hash select now returns hashes, which is nice.
00:14:47.360 You don't get an array of arrays, which I used to just flatten and splat to a hash.
00:14:54.000 So you're creating an array and making a hash, which follows the principle that when you do a select it should return a hash.
00:15:01.200 You probably could remove code to migrate this code since you're generating a hash again.
00:15:08.000 You might be expecting arrays back and doing other things with it, so be careful.
00:15:14.160 You see, if you had a hash called conferences, you could select on it and pull stuff out.
00:15:20.560 Another issue is that the array does matter on select.
00:15:27.120 In the past, with one block argument, it would get both the key and value assigned.
00:15:34.000 Nowadays, it looks out.
00:15:40.000 So Sam Ruby actually originally did this talk at Scotland on Rails in Edinburgh.
00:15:44.640 That's another regional conference across the ocean.
00:15:50.160 I put out a PDF, and people looked at it on Ruby Inside.
00:15:55.680 Sam Ruby recently came out and did another talk; he's much more focused on string encoding.
00:16:02.080 This is a really good point he made: one of the main obstacles for us to decide if 1.9 is cool.
00:16:08.560 Especially in production applications, is the fact that we have all these gems.
00:16:15.680 It’s not like we're Red Hat Enterprise Linux where we have some kind of idea of maintenance status.
00:16:22.160 These gems are just sitting around; they might have 1.8 code that's not compatible.
00:16:28.960 If you get 1.9, install some gems, and some of your dependencies aren't working right, that's a real problem.
00:16:36.880 As a community, we need to do something about that.
00:16:41.680 We need to identify these gems.
00:16:48.560 Certain gems, for instance Rails, run fine on 1.9.
00:16:55.680 The dependencies run fine on 1.9.
00:17:01.760 What 37 Signals is using probably runs fine on 1.9.
00:17:07.680 That's great, but there's a lot of other stuff that you may be using.
00:17:13.920 Maybe you have some crazy list of gems that nobody outside your industry uses.
00:17:19.200 You're going to need to do something about that if you want to continue to use your software with 1.9.
00:17:24.400 So there's no easy solutions there.
00:17:31.760 Now, new features: let's talk a little bit about the mostly syntax changes.
00:17:37.200 Some of the encoding changes I don't want to go too deep into.
00:17:42.560 M17N—obviously, there's a lot.
00:17:48.560 I try not to put a lot of text on the slide, but here it is.
00:17:54.000 The main points here are that strings have encodings nowadays.
00:18:01.200 Your source files can actually have an encoding.
00:18:07.040 You can read things in encodings.
00:18:14.080 That encoding affects a lot of things: regular expressions, various methods on strings.
00:18:21.840 You can't just do .each on strings these days.
00:18:27.520 You have to iterate over characters in each line and each byte.
00:18:33.760 You can examine what the encoding is on the string; you also have different ways of setting what your encoding is.
00:18:40.000 You can use command line stuff from Ruby and also magic comments.
00:18:47.360 If you have the Emacs style comment because you're using X, you can use those.
00:18:54.000 I'm sure there's something for Vim as well.
00:19:01.760 If you're using TextMate, whatever else—there are basic versions that don't give hints.
00:19:08.640 Obviously, I already talked to you a bit about string sub and how to pull stuff out of a string.
00:19:14.000 It supports a lot of different encodings; this was a complete list a few months ago.
00:19:21.120 It might be different nowadays; it's just a lot of stuff here.
00:19:28.720 UTF-8 is obviously the big one for most people that want to do surface languages.
00:19:35.600 Being able to pull stuff out of files and do I/O stuff with different encodings—that is now possible directly.
00:19:42.000 You notice in the second example I'm using an open version of the new hash with a symbol.
00:19:48.560 It reminds you a little bit of keyword arguments, probably, or maybe a little bit of JSON.
00:19:54.240 This is a really, really cool feature.
00:19:59.680 It's one of the features that checks off that enterprise box that people pass around.
00:20:06.080 This is a good thing; it's something people complain about a lot.
00:20:12.000 We don't have support for Unicode, etc., and that’s been a valid concern for years.
00:20:19.360 It's been worked on, and we're going to continue to work on it.
00:20:26.160 This is really cool because if you're a text-processing person like I am, having good regular expressions is really important.
00:20:32.080 One of my main reasons for switching from Python to Ruby years ago was that Ruby's regular expressions were much more natural.
00:20:38.240 But it was missing some really, really cool features from newer regular expression engines.
00:20:45.440 Now, Oniguruma has been integrated into Ruby 1.9.
00:20:51.840 It provides cool things like named grouping, various look-aheads, and look-behinds.
00:20:57.920 It also supports encodings, which is obviously an important feature.
00:21:04.000 There are some differences with enumerables and the enumerators.
00:21:10.320 In Ruby 1.8, you have to require enumerators.
00:21:17.680 In 1.9, all enumerable methods will return an enumerator.
00:21:22.640 You can call next on that enumerator.
00:21:29.360 You can stop complaining about not having hash each with index.
00:21:38.560 This has been a constant complaint for years.
00:21:45.760 Now you have it; you can even add your own crazy things onto an enumerator if you like.
00:21:51.760 However, this does change things like each with index, so you have to be aware.
00:21:58.560 Dot instead of underscore. If you use RSpec, you're going to be confused where to use a dot and an underscore.
00:22:04.000 You'll probably figure it out just fine.
00:22:10.720 In enumerables, there are some other cool things you can do.
00:22:16.400 You’re familiar with symbols of Proc from Rails.
00:22:22.480 That's now in 1.9. Some like it, others don't—that depends on who you ask.
00:22:28.800 There's also something reduce, which is essentially the same as inject.
00:22:35.120 You can pass it either a symbol or a symbol to proc.
00:22:41.840 It flattens things down; you can think of this like dot sum.
00:22:47.680 There's lots of methods on enumerable that make sense to take a look at.
00:22:53.840 Some of which are here: cool things like take and group.
00:22:59.040 Group is now part of Ruby, which is nice.
00:23:05.440 Back in the old days, you only had sort, then got sort by, and now you have min by and max by.
00:23:11.680 You can do count, which I believe is essentially dot size.
00:23:17.760 So there are new features; we got take and drop, a way to quickly grab something out.
00:23:23.040 Hash changes: at least the last time I checked, hashes track their insertion order.
00:23:30.240 You can actually go over a hash in the order things were inserted.
00:23:36.320 This is probably familiar to those using PHP with associative arrays.
00:23:43.680 Now, you can see I'm putting stuff in, taking stuff out, and what you're putting in is staying ordered.
00:23:50.720 Tap is a little thing on an object; if you're familiar with Active Support, this is similar.
00:23:58.000 This is very similar to returning, and some say it's not great for performance.
00:24:04.880 Just be aware it's there, and it's kind of neat.
00:24:10.000 What it's doing is passing itself to that block; you can do stuff with that block.
00:24:15.680 This is kind of cool, especially for things where you're fiddling with an object in a method.
00:24:22.560 Returning that object back means you want the scope to be explicit.
00:24:28.960 This is probably the thing when people think of 1.9; it’s the new proc literal.
00:24:35.040 Forgive me if I use the words proc and lambda interchangeably, as they are interchangeable for me.
00:24:42.320 The main thing here is we actually now have something built into the parser.
00:24:48.640 It's flexible compared to using the goal marker type.
00:24:55.200 You can pass blocks to them; it's great.
00:25:01.520 You can also do things like default arguments, which is nice.
00:25:08.720 Also, you can declare things as local variables, which is experimental.
00:25:16.080 I thought I had another slide, but I guess I don't.
00:25:23.440 So simple changes: we’ve got proc; like I mentioned, there’s less sibling rivalry.
00:25:29.920 You know that Rails created this idea of using symbols for keys in hashes, etc.
00:25:37.440 Stuff coming in from parameters were strings.
00:25:43.920 You check them out; especially when you were indexing, it would all fall over.
00:25:49.760 Now you can actually pretend to be a string in certain ways.
00:25:56.560 I know the idea of symbols being frozen strings was flirted with.
00:26:01.920 That was removed due to performance concerns.
00:26:08.080 But now they pretend to be the same, though you can't use = to check them.
00:26:14.160 That would be a bit too much.
00:26:20.000 But triple equals works, so case statements work.
00:26:26.080 Threads have moved to a native threading model from a user threading model.
00:26:33.440 There are actually three different models if you open up thread.c.
00:26:39.760 You do things like that for some reason, like reading through C code.
00:26:45.680 One is user threads, one is native threads with a giant VM lock, and one with finer grain locks.
00:26:52.000 The one built-in now, I believe, is model 2.
00:26:58.560 I don’t read a lot of C in my leisure time.
00:27:05.760 Also, I’m not a VM guy, so I haven't dug in deep.
00:27:10.640 When 1.9 comes out, hopefully this Christmas, we’ll have all the locks down.
00:27:16.560 This is cool; it's nice to run Ruby, kick off a bunch of threads.
00:27:23.680 Performance should be much better; you can look at Top and see the thread count.
00:27:32.000 This has been another checkbox we needed.
00:27:37.040 Especially for people coming from the Java world, this is something they absolutely needed.
00:27:42.720 It's been something that has kind of hounded us.
00:27:47.680 Fibers are essentially semi-coroutines.
00:27:54.640 You can think of them as lightweight, user-level threads.
00:28:00.320 They're manually scheduled.
00:28:06.000 They're kind of neat, especially for I/O frameworks.
00:28:12.640 But this isn't something I generally do.
00:28:18.280 There are good blog entries to read on fibers.
00:28:25.760 Dave has a really good series of articles on fibers.
00:28:31.680 We're going to go into questions. We have about 15 minutes.
00:28:44.960 So questions?
00:28:50.560 I don’t think I can explain the history behind the tap method.
00:28:56.960 Mats may be willing to talk about that later.
00:29:02.560 The tap method seems to owe a bit of debt to returning.
00:29:07.840 So there seems to be that connection.
00:29:13.440 That reminds me of Smalltalk semicolons for chaining.
00:29:20.960 If you can put that up there, you can chain things onto the same object.
00:29:27.280 I can't say specifically why it's called tap. Maybe tapping into the chain?
00:29:33.040 It also reminded me of jQuery if I can go back but in a less gross manner.
00:29:41.760 I really like jQuery.
00:29:49.040 I can’t tell you the etymology of it, but from a usability perspective it owes a lot to returning.
00:29:55.200 There’s a good subset of people in the Rails community that use returning as a pattern.
00:30:02.480 So, yes?
00:30:09.040 Just give us your personal opinions on the changes that happened to lambda.
00:30:14.960 At first, I really hated it.
00:30:22.880 Partially because I’ve used Ruby long enough, seeing any change can be scary.
00:30:29.760 But I love lambdas; it’s my background.
00:30:36.560 At first, it took me back because it felt like a step away from clarity.
00:30:43.520 But knowing all the new, cool things means that there will be great use cases.
00:30:49.680 I'm hoping the Ruby community self-regulates with all this.
00:30:55.760 We can create a schedule of punishments for horrible lambdas.
00:31:01.960 I have disliked making things as obscure as possible to read.
00:31:07.840 I love elegant code.
00:31:13.920 The utility is also pretty significant.
00:31:20.960 One point I want to stress is that the syntax may feel less clear.
00:31:26.280 So, it’s okay to let it sit for a bit.
00:31:32.000 You can play with it; you might feel more comfortable after a while.
00:31:39.040 Does that kind of answer your question?
00:31:44.640 I think I do have time for two more questions.
00:31:49.440 Okay, so do we have another question?
00:31:57.520 If not, thanks for your time, and thank you Mats for being here.
00:32:03.040 Video equipment rental costs paid for by Peep Code Screencasts.
Explore all talks recorded at LoneStarRuby Conf 2008
+18