30 October 2006
updated 15 February 2009
Exploring TextMate...a Ruby perspective
Marshall Vandegrift has posted an interesting screencast showing off Emacs as a tool for Ruby/Rails development. I enjoyed the screencast, and Emacs certainly has cool features but all I could think whilst watching it was (WARNING: FLAMEBAIT ALERT!)…“urgh, its soooo ugly, how could anybody work with that all day. And TextMate does all of this and in a much nicer way…”.
It got me thinking about how I use TextMate every day and whether I really take full advantage of its built-in commands and snippets for Ruby and Rails development. I wondered how many of the features in the above Emacs screencast were already in TextMate and the answer was…most of them! This inspired write a post about some of my favorite TextMate snippets and hopefully you’ll find out about a few you didn’t know about.
Whether you are a new or seasoned TextMate user, its really worth spending some time to learn some of the more useful snippets in the bundles for the languages that you are using. I’m sure most Ruby and Rails developers are aware of the basics such as do..end completion and the various snippets for creating classes, modules and methods. What follows is an overview of some of the cooler functionality built into the Ruby/Rails bundles that you might not have come across. There is a certain amount of mental overhead in learning these snippets but if you can you will find yourself being even more productive.
If you are running a stock TextMate install, you’ll only have the default set of bundles. There is a wealth of bundles in the Macromates Subversion repository. I won’t repeat the installation instructions here, but I will mention a small tip for managing your bundles.
The Macromates repository has a lot of bundles and the chances are you will only need a small selection of them. Installing all the bundles slows down TextMate’s opening times and adds a lot of noise to the Bundles/Snippets menus. Instead of simply checking out all of the bundles into your /Library/Application Support/TextMate folder, create a folder in a Subversion repository of your own, and check the empty folder out to /Library/Application Support/TextMate. Now, add all the folders in the Macromates repository except the Bundles folder to your repository as an svn:externals entry. Next, create a Bundles folder and check this in. Finally, add all of the Bundles that you want as svn:externals entries in the Bundles folder.
If the above sounds too complicated or time-consuming, you can use my own setup as a starting point.
Note: for the rest of this article, I will put any relevant tab-triggers in square brackets.
The TextMate Ruby bundle has snippets for most of the common declarations that you are likely to use…there are definitions for classes [cla], modules [mod] and methods [def] and other common blocks such as conditional statements [if, ife, elsif], loops [until, while], exception handling [begin] and generic blocks [do].
The class and module snippets, like a lot of newer snippets, use a single tab expansion for multiple snippets, with the different options appearing as a contextual menu. This reduces the overhead of learning lots of obscure triggers and gives you a good overview of what you can do with a particular trigger. The class snippets, for example, have variations for creating standard classes, classes with inheritance, classes with a generated initialize template and more. You can even create a new Test::Unit testcase, complete with the necessary requires, Test::Unit::TestCase inheritance and a default test method with a single trigger [tc].
Finally, there are snippets for many of the common tasks performed when writing a Ruby script, such as entering the shebang line [rb], requiring files [req], generating symbol => value key/value pairs for hashes [:], lambda blocks [lam], and one of my favorites, path-from-here [patfh] which is used for getting the path relative to the current script and generates:
File.join(File.dirname(__FILE__), *%w<strong>[rel path here]</strong>)
h3. Writing classes/modules
In addition to the snippets for defining classes and modules, there are some other goodies too.
If you want to add Enumerable support to your class, you need to include the Enumerable module and define an each method. To do this in Textmate, simply create a new class then inside your class definition, use the Enumerable snippet [Enum]. This will generate something like this for you:
class Foo include Enumerable
In a similar fashion, the Comparable snippet [Comp] will include the Comparable module and create a stub <=> method for you to fill in.
Defining attributes for your class is a breeze – TextMate contains snippets for attr_reader ®, attr_writer [w] and attr_accessor [rw]. You can define class methods just as easily as you define instance methods [defs], alias methods [am] and overwrite method_missing [mm]. Don’t forget the singleton class for helping out with that meta-programming goodness [sin].
Other cool snippets
There are plenty of snippets for all of your favorite iterators including each [ea], each_pair [eap], collect/map [col/map] and everybody’s favorite, inject [inj]. There are too many to mention here – there are snippets for all of the common iterators and block methods defined in Enumerable and other collection classes, as well as snippets for iterating over files.
How often do you fire up IRB just to run a simple snippet of code? I do…but why waste time loading up IRB when you can execute lines of Ruby directly in TextMate? Simply write a line of Ruby code, then run the “Execute line as Ruby” command [Ctrl + Shift + E]. The result of the expression will be inserted directly on the next line.
Finally, some personal favorites. Trying to convert all those string keys to symbols in your Rails app to make things much easier to read? TextMate makes it easy to switch between strings and symbols – simply move the cursor onto the string/symbol you want to switch and hit [Ctrl + :].
Interested to know whats going on under the hood of the library that you’ve required in your script? Put the cursor over the require line, and hit [Cmd + Shift + D]. If TextMate can find the required file, it will open it for you. How cool is that?
A final, Rails-related mention goes to the Rails migration snippets. There are only three commands you need to know: columns, tables and indexes [mcol, mtab, mind]. All of the common migration commands are supported and where possible, the snippets will generate your self.down method for you, whilst you are writing the self.up method! A particularly good example of this is “Drop and Create table” – type in the name of the table you want to drop, hit tab twice and it will populate self.down using the relevant section of your schema.rb. Clever stuff.
Writing your own bundles
Of course, the real power behind TextMate lies not only in its pretty good set of existing bundles, but the ability to write your own. Writing snippets is the easiest of the lot and I really advise you to create your own “personal” bundle to store all of the little snippets tailor-made for you. The next step up is writing commands and here is the killer feature – you can write your commands in whatever language you know best, as long as TextMate can find the interpreter (it uses a shebang line at the top of your command). A lot of the built-in commands are written in Bash, but many of the Ruby commands are written in, unsurprisingly, Ruby. Take a look at some of the built-in commands to give you an idea of what you can do.
Here are some of the bundles that I’ve written that are available for all:* RSpec TextMate Bundle * RESTful Rails – snippets for RESTful Rails development * UJS4Rails Bundle – snippets for the UJS Rails plugin
The last two are still very much under development but the RSpec bundle is pretty comprehensive and covers all of the built-in expectations, as well as the mocking API, Rails integration and spec runners.
Have you got any favorite snippets that you want to share with the world? Let me know. You can use the comments below, although I advise for anything but short snippets that you pastie them and post the link.