I’ve been writing a web application in Ruby recently, in order to glue together a couple of fairly complicated systems into something approaching a sane workflow.
You might think I’d use Rails. Once upon a time I thought I’d write applications in Rails too. I bought the book, wrote some toy apps, and set it aside until I next needed it.
I’m not a big fan of frameworks anyway. “Why I Hate Frameworks” discusses part of the reason—they tend to result in too much abstraction. They also tend to result in lots of indirect external dependencies; your platform choices, for example, can end up being made for you. And then there’s the opinionated way they tend to dictate your other choices. To me, a framework is a library with delusions of grandeur; it’s like hiring a plumber because you need the sink fixed, and having him lecture you about how you should landscape your front yard.
That’s not to say that there isn’t a place for frameworks. Sometimes you are doing something that’s very complicated but standardized, like building a GUI application. Sometimes you’re a beginner, and you want someone to tell you what to do and how to do it. But mostly, frameworks annoy me.
There are a few exceptions, though. One is the framework I’ve been using for my trivial web application. It’s called Sinatra, and is not much more than a thin layer of syntactic sugar sprinkled on top of HTTP.
I don’t need widgets or a sophisticated templating system, as the look and feel has been supplied to me by the corporate web design team. I don’t even need a database, because my application just needs to pull data from one system and push/pull it with another, via REST APIs. The Ruby rest-client Gem makes that easy; it basically does for REST calls what Sinatra does for HTTP servers. So Sinatra gets the job done. Rails is a faster way to get CRUD apps started, but if you have a problem that isn’t CRUD, I’d suggest checking out Sinatra.
Ruby tends to lend itself to these kinds of domain-specific languages. For instance, here’s a function which implements locking using a temporary lock file and the POSIX flock call, to ensure exclusive access between multiple processes:
LOCK_FILE='/tmp/lockfile.tmp'
def exclusively
File.open(LOCK_FILE, File::CREAT|File::RDWR, 0644) do |file|
file.flock(File::LOCK_EX)
yield
file.flock(File::LOCK_UN)
end
end
You can then put a lock around some access to a resource like this:
puts "Entering exclusivity zone..."
exclusively do
puts "I'm in!"
sleep 20 # simulate access to slow resource
puts "Exiting exclusivity zone..."
end
For more elaborate lock file requirements, there’s the lockfile gem.
This is handy, as it means you can distribute both the utility and the documentation in a single file, and symlink the script into the appropriate man page.
You can also, of course, look for the standard --help command line option, and make your utility call man with its own source file as argument to provide the help.
Note that if your utility makes extensive use of command line options, you’ll probably want to use GetoptLong.
As a Unix guy, the IBM Lotus Domino server log has always annoyed me. Since Domino is cross-platform, and Windows doesn’t have a syslog, Domino keeps its logs in a Domino database. While that makes some sense, it leads to colossal overheads; the log.nsf database is often 95% unused space. By switching my 90 days of logs to compressed syslog files, I was able to reclaim gigabytes of space.
In addition, because syslog files are just text, you can grep them, and use all kinds of open source tools to analyze them. You can use rsyslog to concentrate logs from multiple servers into a single set of logs. You can set up tasks to page you about problems. And so on.
So, I started with Daniel Nashed’s excellent rc_domino scripts, and crudely hacked them to make them pump the Domino console logs into a custom Ruby program which parses them and sends to them to syslog. You can get the code from GitHub via those links; I’ve been running it for several months now without any crashes or noticeable bugs.
Note that you still end up with events in log.nsf with this solution, but you can set it to a much shorter retention time. Hopefully at some point rc_domino will get cleaner support for console log processing. Ideally Domino would get official syslog support, but I won’t be holding my breath for that.
Recently on the ruby-core mailing list, someone asked why Ruby doesn’t have multi-line comments. I did a few searches, and didn’t find much discussion of the evils of multi-line comments. I thought it was common knowledge that they were a bad thing and a historical mistake made by Kernighan and Ritchie, but apparently not. So, here’s my opinion on the matter.
Superficially, multi-line comments seem like a handy thing to have, especially if you often comment out blocks of code temporarily during development. However, as soon as you allow multi-line comments, you need to decide what to do about nested multi-line comments–that is, what should happen when the ‘start comment’ sequence occurs inside a comment.
Option 1 is to allow it and make it not special. This is bad because it makes it very easy to end up with a run-away comment:
/* set variables
param = 0
/* set maximum size */
maxs = 100
Here ‘param’ ends up unset. This kind of bug can be really hard to locate.
Option 2 is to allow the start-comment sequence within a comment, and make comment pairs stack, so you need as many end-comment sequences as start-comment sequences. This at least makes errors like the above cause a compile-time failure, but it still makes them a pain to locate; you end up having to use something like vim’s ‘%’ command to play match-the-comment-delimiters until you spot which pair is mismatched. That’s no fun, especially once your comments contain pages of documentation. Ask a Java programmer…
Option 3 is to disallow nested comments, in which case multi-line comments can’t be used to comment out blocks of code which contain multi-line comments. That makes them pretty useless for temporary disabling of code; it would also cripple their use in rdoc.
Single-line comments have none of the above problems. You always know the comment will end when the next line starts. You can always comment out a block of code, no matter how many comments or comments-within-comments it contains. You never get runaway comments, and you never have to match up comment delimiters. The only downside to single-line comments is that it’s harder to comment out and un-comment-out multiple lines. That’s easily solved by using any good text editor.
All of which is why C++ introduced single-line comments, and C99 added them to regular C.
So in short, multi-line comments have no significant advantages, make parsing harder, and make errors more likely. I think Matz was entirely right not to put them in Ruby. As a rule, the only place I use multi-line comments is for JavaDoc, and that’s only because I have to.
Suppose you want to install a DB2 server, and connect to it from some client software. If you browse the IBM DB2 Software pages, you’ll soon find that there’s a bewildering array of products with confusingly similar names. For example, IBM Data Server Client and IBM Data Server Runtime Client are two different things.
Fortunately, help is at hand. Paul Zikopoulos has written several articles for IBM developerWorks describing the differences between the different DB2 client and server options.
For example, on the server side, I work in an environment where requirements are constantly changing. Online table reorganization is a big plus for me, as it means I shouldn’t ever have to take applications down in order to modify data structures. That points me at DB2 Workgroup as my most lightweight server option. On the client side, I use Java and Ruby, and don’t care at all about .NET or Visual Studio, so I only need the IBM Data Server Runtime Client, which includes a prebuild Ruby Gem (for Ruby 1.8.x only, sadly) and the Java Type IV JDBC driver db2jcc4.jar.
If you want Ruby 1.9 support, you need the larger Data Server Client so you can compile a newer version of the Gem from source. You also need to do a custom install, and check “Base application development tools” under “Application development tools”, or else you’ll find that Gem building fails when it can’t find sqlcli1.h.