Well, it turns out that you do indeed need more than one if you want to do IntelliSense: if you have an error in your Ruby code or are typing happily away, then your Ruby file won’t parse and unless you have a copy of the symbol table, you don’t get any IntelliSense. An object lesson in why it’s a good idea to engage the brain before engaging the keyboard.
After unscrambling all the global variables (sorry, static variables), the next problem was how to copy a symbol table. It’s not that easy in .NET and it turns out that the only reasonable way of doing it is to use ‘serialization’. With serialization, you write all the data out as a binary stream to some sort of backing store, then read it back in again – ‘deserialize’ it. Unfortunately, this is slow – my first attempt took 3 seconds to cycle a symbol table of 2500 symbols. Put it another way, that’s about 1ms per symbol or, on my PC, about 3 million instructions per symbol!
After a good bit of tweaking, I got this down to half a second – ok, but not brilliant. This doesn’t affect the speed at which the drop-down ‘code completion’ list appears, incidentally – that’s pretty near instantaneous. It just affects the speed of the analysis that goes on silently ‘behind the scenes’ and, for my own satisfaction, I want that to be done as quickly and efficiently as possible.
I’m somewhat surprised that the .NET designers at Microsoft have not come up with a decent way of simply deep copying an object. The parsing itself seems to run at around 1ms per line of Ruby code. I’m pretty sure I can improve greatly on that later on.
Anyway, here’s a picture of what you get from doing self. in a class X which has included a module N.
I’ve turned off all of the methods you get as default from the mixing in of the Kernel module with Object. There are about 60 methods in there and with them all on, you can’t easily see which ones you want. Currently, I’m experimenting with various ways of managing this list.
Here’s another picture of Ruby IntelliSense showing inheritance of a class Y from X. Module M is now mixed in and you can also see an accessor definition, name.
Finally (just to show I’m not faking it!), here’s a picture of an ‘IntelliSensed’ Array object.
In general, the Steel IntelliSense system figures out what the class of an expression is and then displays all the available methods, including singletons, inherited classes, included modules and those added via extend. And it does it all without calling Ruby. Obviously, it can’t deal with all Ruby’s dynamic behaviour, but it does seem to be good at handling most - if not all - of the things that are useful as you type or edit a Ruby program.
I’m going to be doing a good bit more testing over the next week and then if it stills looks ok, it’s over to Huw and the beta test team he’s assembling.
PS: I decided to take time out today to get Smart Indenting to work – I decided that I couldn’t live any longer without it. Pretty cool too – it’s now getting to be like working in C#, except that it’s Ruby. Strange feeling!