Keeping it Small and Simple

2008.01.31

Why I keep stressing students to write more code

Filed under: Ruby Programming — Tags: , , , — Lorenzo E. Danielsson @ 21:08

One thing I always tell my students is that if they really want to become good at programming they have to write a lot of code. They shouldn’t just work on projects but also create a separate directory dedicated to little experimental code snippets.

When somebody asks me if “such and such” works, I normally tell them to go and write some code to test it. I usually refuse to answer such questions until I can see some code. Needless to say, many of my students over the years have felt that I’m a royal pain in the ass.

Today I gave one of my Ruby students a little challenge: to extend Ruby’s Array class with methods to rotate the array left and right. The ROL and ROR methods should be familiar to every programmer unless, of course, you fell asleep during assembly language class. In this case we’re not even rotating bits in a byte but elements of an array.

At the end of the day, my student told me that he’ll present his solution tomorrow. I think he’s got it mostly figured out but he’s over-complicating it. This student is at the stage where he has a firm grasp of the basic elements of Ruby. But he needs to learn how to combine the facilities that the language gives him in different ways to produce the results he wants.

I’ve come to realize that this is the most difficult part of learning how to program, and the time when most students risk giving up. I guess it’s a bit similar to learning how to speak a new language. It’s fairly simple to learn the formal grammar of a language and to pick up a basic vocabulary of common, every-day expressions.

But, to combine these building blocks into more interesting sentences is challenging. I often fumble on sentences in Ga where I know all the individual words I need to use, but somehow fail to combine them in a way where I can make myself understood. The solution is simple: I have to force myself to go out and listen to and speak Ga much more. Most importantly, I have to practice the basic constructs of the language until I can use them “without” thinking.

Exactly the same thing goes with writing code. The syntax of the language and other basic elements (the most commonly used classes in Ruby’s core classes) need to be practiced until the student “becomes fluent” in using them.

So I keep on forcing my students to write loads and loads of small, trivial programs. It gets very boring for them from time to time, and I’m sure some of them would love to run me over with a freight train or something like that. But, at end my responsibility is to turn them into programmers, not win popularity contests. And I do feel that that the extra time spent on programming basics pays of for them at a later stage.

If you are a struggling with learning how to program, don’t give up. Give yourself little challenges every day. Don’t tell me you can’t think of any, because their are loads of them around you. They don’t have to be “useful” (whatever that means), and it’s okay to reinvent the wheel over and over again while you are learning.

Back to our rotating array. Anybody who has not only used, but has understood what the following methods do won’t have any problems implementing it.

  • Array#shift
  • Array#<<
  • Array#unshift
  • Array#pop

Of course there are other ways of solving it, but I’m allergic to solutions that are more complex than they need to be. It gives me a bad rash.


 1 #! /usr/bin/ruby
 2
 3 # Rotate an array.
 4
 5 class Array
 6   def rol!(n=1)
 7     n.times { self << self.shift }
 8   end
 9
10   def ror!(n=1)
11     n.times { self.unshift self.pop }
12   end
13 end
14
15 wd = %w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday]
16 puts "Original array:"
17 p wd
18
19 puts "Rotating right 3 times."
20 wd.ror! 3
21 p wd
22
23 puts "Rotating left once."
24 wd.rol!
25 p wd
26     
27 puts "Rotating left nine times (should be like rotating left twice)."
28 wd.rol! 9
29 p wd

Advertisements

2008.01.30

My #1 Ruby wishlist item

Filed under: Ruby Programming — Tags: — Lorenzo E. Danielsson @ 00:35


String#=~ s/PATTERN/REPLACEMENT/egimosx

2008.01.29

Finally got Thunderbird2 to know about Firefox

Filed under: Software — Tags: , — Lorenzo E. Danielsson @ 10:30

I have been using Thunderbird2 as my main MUA of late and must say that I’m beginning to like it a lot. Of course, I can always fall back on mutt if I need to.

One problem I’ve been having is getting Thunderbird to send HTML links that I click on to Firefox. I keep getting an error message about not being able to launch gconfd. Well, a bit of Googling around solved the problem.

  1. Close Thunderbird.
  2. % cd $HOME/.thunderbird/nnnnnnnn.default, where nnnnnnnn is a random sequence of alpha-numeric characters.
  3. % vi prefs.js
  4. Add the following lines to prefs.js:

    user_pref("network.protocol-handler.app.http", "firefox");
    user_pref("network.protocol-handler.app.https", "firefox");
  5. Restart Thunderbird (ALT+R, fbrun pops up, type ‘tb’
  6. )

I find it a bit strange that they didn’t do this by default. They are both Mozilla applications, why is all this required just to get them to work together? Anyways, no need to complain, I’ve solved my problem.

2008.01.28

Intro to hacking on open source: wmymail

Filed under: Open Source — Tags: , , , — Lorenzo E. Danielsson @ 13:34

One of the benefits of open source is that you can modify an existing application to work the way you want it or to fix a bug. Yet, many people don’t do this but rather just accept that their application doesn’t behave “right”. If you look at the Linux community, it used to be very different, before the name “Linux” became a marketing managers wet dream. Linux users were programmers (not in the slimy sense of business types in suit and tie who earn $$$ by writing commercial garbage software, but in the real sense of somebody who writes code to fix things) at the same time and modified tools to suit themselves.

I will use a very simple example to show you that this doesn’t have to be hard at all. I’m going to modify a dockapp called wmymail. Now this example is very trivial, but the principles are the same even with larger programs. Since it is so trivial, there should be no problem following along even if you don’t have much programming experience. You’ll be amazed at just how simple this is.

Some of you will already know that there are dockapps that check your gmail account. But I wanted to use wmymail.

You might not be a dockapp user. Maybe you don’t use a window manager like fluxbox, WindowMaker or blackbox. That’s okay. You can still follow along here, even if you don’t intend to use wmymail. Hopefully you will learn something along the way.

Just to remind you, I am nobody in particular. It’s likely that you haven’t heard of me before. I have spent the last 20 or so years being a really lousy programmer, but keep doing it because I love it. If I am able to do this, then so can you. Now let’s get started.

Background

Last night I just couldn’t resist the temptation to get wmymail working in my fluxbox slit. This is a little mail checker that notifies you when you have new mail. By default it checks you mail spool, but with the help of a command-line option and fetchmail, it can check the status of an IMAP account as well.

Getting and compiling the source

I started off by downloading wmymail-0.3, which is the latest version I could find. I extracted it with tar zxf ~/dl/wmymail-0.3.tar.gz. I compiled, which went find, apart from a few warnings. Compiling is very simple. There is a Makefile in the project directory. To compile you just type ‘make’.

You will need to make sure you have a few things. You need gcc to compile, but that comes by default on Linux. You also need to have libdockapp installed. If you are on a brain-dead distro that separates a package into tiny sub-atomic particles, you will also need libdockapp-dev. Make sure you check the names. On my Debian system, the packages are libdockapp2 and libdockapp-dev. There may be some other dependencies. This is a good time to learn how to read your make/gcc output and use it to figure out what is wrong.

Problems with wmymail

I launched wmymail with the following (in fbrun):

% wmymail -F -i

Before that I had set up ~/.fetchmailrc to connect to my gmail account. The file looks as follows (the names have been changed to protect the innocent).


poll imap.gmail.com
proto IMAP
user 'your.user.name@gmail.com'
pass 'your super secret password'
ssl

In a split second wmymail was up and running. But something was not right. It didn’t appear to check my gmail account at all. Moreover, it pooed temp files into my home directory. The normally go away, as long as wmymail dies naturally, but I cannot stand when application put files into my home directory.

I had two problems, that needed to be fixed.

  1. Write temporary files into a directory designated for them
  2. Figure out why the heck wmymail claims I have 0/0 emails.

Stop polluting my $HOME!

I opened up the file wmymail.c in vim and did a search for “tmp”. The very first hit came on line 285 and looks like this:

char tmpfile[20] = "wmymail.XXXXXX";

As you can see, problem one is solved already. All we have to do is prepend the path to the string. Eh.. you may also want to count characters and size the array up just a little. Your generic, re-usable solution would probably involve checking if the user has set $TMPDIR, checking if the directory exists and all those things. At this stage I just needed it to work for me (always solve one problem at a time), so I simply did:

char tmpfile[40] = "/home/lorenzod/tmp/wmymail.XXXXXX";

See how simple that was. You’ve made your first little modification, and your brain could be left in standby while you did it. That is exactly what I mean. These things are not as difficult as you may think.

Why is it not updating my mail status?

When you launch wmymail with fbrun you won’t be able to see any output, which makes it hard to debug. So kill mymail and start it from rxvt instead. Doing this quickly revealed:

% ./wmymail -F -i 5
wmymail: error when using system() to run fetchmail -c: No child processes

Okay, I had no clue what caused this but now we have some form of a lead. I went back to vim, found the checkfetchmail() function, looking for an error message that looked similar to what I had just got. Lines 305-308 looked interesting

if (system(syscmd) < 0) {
perror("wmymail: error when using system() to run fetchmail -c");
return;
}

The variable syscmd just holds the command-line to be executed. So something is prevent the dockapp from proceeding beyond this point. What could that be? To find out we can do like this: declare an integer called ret in the variable decleration secion of the checkfetchmail() function and add the following:

ret = system(syscmd);
printf("%d\n", ret);
if (ret < 0) {
perror("wmymail: error when using system() to run fetchmail -c");
return;
}

Note that I like to outdent temporary code that I add for testing purposes. If we compile and run again, we get:

% ./wmymail -F -i 5
-1
wmymail: error when using system() to run fetchmail -c: No child processes

So the fetchmail process is returning -1 and wmymail is saying that a return less than 0 indicates an error. The reason for that is available in the system man page (look for the section RETURN VALUE). So we’ve read the section, blindly accepted everything that we read, but we still feel that we want to try something. Looking at the temp file (something like ~/tmp/wmymail.DALuun) we see that fetchmail seems to have run fine, at least if it looks something like this:

% cat ~/tmp/wmymail.DALuun
4243 messages (4236 seen) for some_user@gmail.com at imap.gmail.com.

This lead me comment out the part where we check for the return statement.

ret = system(syscmd);
printf("%d\n", ret);
/*
if (ret < 0) {
perror("wmymail: error when using system() to run fetchmail -c");
return;
}
*/

Compile and run again. Now it should work. So we’ve solved our two problems and haven’t even broken a sweat yet. Now since you are a good program (or at least, aspiring to be one) and not a useless waste product of society like myself, you will add a small comment that you need to look into *why* the commented out code wasn’t working. Take that as an exercise for yourself.

But wait..

If you have a lot of mail you will notice that the largest number of mails that wmymail can handle is 999. This means your total mails will constantly say 999, and if you’re lazy like me, your unread mails will also read 999. 😉

This is simple to fix. We will let wmymail display four-digit numbers. First of all look into the xpm directory. You will find a file called main.xpm. If you cat this file you will see that it would parse as a C file. Yes, XPM (X pixamp) is a graphics format made in heaven. It works well with revision control, diff and all the other every-day tools. XPM files can also be open in Gimp, which is what we will do now.

I suck at Gimp, but was still able to do the following without any difficulty. If you are on the artistic side, you can take the opportunity to improve the look. Below you can see the original image and modified one. (Note: I had to convert this to PNG because stupid WordPress can’t handle the *standard* image format.)

mainorig.png mainnew.png
Original XPM Modified XPM

As you can see I’ve added an image to the end of the left digit box and one at the beginning of the right input box. We still have a small gap between the two boxes as well. Now, we just have to figure out how to code this as well. Actually, before you do that compile and run. That way you will better see why you need to modify the code. In general, you should always make a single atomic change, compile, run and test before moving on. Trust me, it will make you life much simpler.

By looking around a bit we realize that numMessages and numUnread look like interesting variables. More digging leads us to the function updatePixmap() (line 400 +/- a few lines depending on how you formatted the previous edits. Find the block that looks like this:

if (numMessages > 998) {
putnumber(999, outPixmap, numbersPixmap, 40, 49);
} else {
putnumber(numMessages, outPixmap, numbersPixmap, 40, 49);
}

And change 998 to 9998 and 999 to 9999. Do the same in the next block (the one relating to unread mails). If you compile and run you will realize that this doesn’t do much to improve the situation. It rather makes it worse. But don’t abandon all hope quite yet.

In the blocks that we just modified, did you notice how there are calls to a function called putnumber()? That just gives me a gut feeling that we might find something interesting there. That function is the one following the one we are currently positioned in so you can just jump down a little and you will find it.

The very first statement of the function putnumber() gives us much information. Three integers are declared: digit1, digit2 and digit3. I bet adding a digit4 would be a step in the right direction!

But, we are not done quite yet. Right underneath we initialize the digit variables. Modify this to look like this:

digit1 = number / 1000;
digit2 = (number % 1000) / 100;
digit3 = (number % 100) / 10;
digit4 = number % 10;

Before you move on, make sure you understand why this works. Take a few numbers, for instance 6481, 5077, 4000, 231 and 4 and work through them. In each case what values will digit1, digit2, digit3 and digit4 hold?

We’re almost done now. Just one last thing. We need to update the next block of code to look as follows:

if (digit1) XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit1 * 5, 0, 5, 9, destx, desty);

if (digit2 || digit1) XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit2 * 5, 0, 5, 9, destx + 6, desty);

if (digit3 || digit2 || digit1)
XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit3 * 5, 0, 5, 9, destx + 12, desty);

XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit4 * 5, 0, 5, 9, destx + 18, desty);

Again, make sure you understand why the code looks as it does (make sure you have the man pages for Xlib installed). Notice that we’ve added one XCopyArea for digit4. Each digit takes up 6 pixels, so we have to add a multiplier value to destx for each consecutive digit.

Okay, so we are done, right? Good. Compile and run and… oh!!! Now what is wrong?? Why is the total number of messages miss-aligned? If you think about it for 2 seconds it’s obvious. When we edited the XPM we added a digit to the end of the number of unread messages, but the beginning of the total mails box. In other words we need to shift the position where the total number of mails get printed to the left. We already know that the width of a digit is six pixels, but if we didn’t we could open the file in Gimp again, move the mouse over the left-most part of the first digit and read off the coordinates. Simple!

Go back to the updatePixmap() function. More specifically, find the block that (now) starts if (numMessages > 9998) { and change the fourth parameter in each of the putnumber() calls to read 34 instead of 40. You should make a total of two changes.

Now recompile, run and Vittoria!!! You have done it. Good on you. A triple shot of Vodka is a good idea at this stage, especially if you have a grumpy boss looking over your shoulder.

Wasn’t that just so much fun? From now on, any time the behavior of some software application annoys you, download the source and start playing around with it. Er.. you might not want to start with openoffice.org. There are loads and loads of little applications that you can play around with, just to get your feet wet.

Conclusion

So is that it? Is it really that simple? Well, of course, larger projects are more complex. If you want to start hacking on device drivers you have to have (or build up) a solid understanding of the hardware and the kernel. But, you start off by solving simple things in small projects and gradually work your way up. Many of the people you admire started off doing things like this.

Of course, “professional” programmers don’t work like this. They hate programming, only learned it to earn money. They spend the whole day drinking coffee and having sex in corporate toilets. They earn hundreds of $ a day doing so.

2008.01.27

An evening with Window Maker

Filed under: X Windows — Tags: , , , — Lorenzo E. Danielsson @ 23:11

Many, many years ago, WindowMaker was my favorite window manager. For some obscure reason that I cannot remember, I began using blackbox more and more, then moved on to fluxbox. I had a few tours of KDE and Gnome, but eventually came back to fluxbox.

I was doing a few random searches with aptitude this evening a stumbled upon WindowMaker again and just couldn’t resist the temptation to play around with it again. So I aptitude installed it, edited ~/.xinitrc and fired it up with a startx.

The initial nostalgia shock was almost too much. Here was a window manager that I had stared at almost 24/7 for at least 2-3 years. I grabbed the Extras tarball so that I could get it to exactly the way I used to have it running.

For a while I was contemplating going back to WindowMaker. Sadly, I don’t think that will happen. Over the years I’ve just grown too accustomed to fluxbox (which is another great window manager, btw). I’ve handcrafted my fluxbox menu and I’ve built up keybindings for all the things I need. I launch rxvt with ALT+T, irssi with ALT+i etc. In short, I hardly ever have to grab for the mouse. Setting all that up in WindowMaker again feels like too much work.

But it sure was fun. And WindowMaker feels so snappy, it’s amazing. Fluxbox feels old and slow by comparison. If you have some real old hardware with limited RAM and a video card from a previous era, give Window Maker a try. It will not disapoint you. And using WindowMaker for a while did inspire me to make a few changes to my fluxbox set-up.

First of all, my favorite WindowManager theme was Night, which comes on the Extras tarball. I especially liked the wallpaper because it is dark and simple. It also has a calming effect on me. I also decided to get a few dockapps again. Seems the dockapps warehouse is gone, but there are some other sites. Also Debian packages some of them. I was able to get some of the ones I used to run in the WindowMaker dock.

Screenshot follows:

Fluxbox 2008.01.27

Fluxbox with a few dockapps. Style is mussel. One rxvt window, busy scrotting this screenshot. Here’s a closer look at the slit:

Fluxbox 2008.01.27: The Slit

The following dockapps are running here, all available in Debian:

  • wmmoonclock: shows the moon phase
  • wmcalclock: date and time
  • wmnd: monitors network interfaces
  • wmtop: top three processes
  • wmfire: shows CPU load

I would have liked to have wmscope there as well. It does exist in Debian, but when I launched it, CPU usage show right up. Also, it didn’t really seem to work right. A little bit of quick research revealed that it doesn’t seem to work with ALSA, only OSS, which of course was *the* sound system for Linux back in those days.

I also used to have a dockapp for mail notification (I think it was wmymail or something like that). Now that I’m on a bunch of mailing lists and recieving new mails almost constantly I’m not sure if a biff for the slit makes all that much sense.

Well, it was fun and my “new” fluxbox look will serve as a reminder of WindowMaker, the totally great window manager that I wish I had the patience to get used to again..

Another Ruby implementation: XRuby

Filed under: Ruby Programming — Tags: , , , , — Lorenzo E. Danielsson @ 21:21

In #rubinius on Freenode today, I heard of another Ruby implementation called xruby. It compiles ruby files to Java class files that can be run in the JVM. I just downloaded xruby-0.3.2, which appears to be the latest release at least as this time of writing.

It’s cool that there is a lot of interest in Ruby and so many different implementations coming up. At this point in time I think it’s a good idea that there are several different implementations. I also think it’s cool if at least some of them take the opportunity to experiment a little bit, without straying away too far from the core Ruby language of course. Several implementations gives us the ability to compare and contrast ideas, to see what works well and what doesn’t.

What I wouldn’t want is that each implementation over time adding its own extensions to the point where we end up with 100,000 incompatible Ruby implementations. I don’t want Ruby to become fragmented to point where we have Ruby, Ruby++, Ruby#, RubyLite and RubyDuby. Wouldn’t you also hate to have to sit and add a section in your READMEs about which Rubies are supported or to go to download some Ruby program just to be confronted with 1000 different packages for different rubies?

I understand the good folks over at the Rubinius have added a few extensions. A few methods here and there that have been added to core Ruby classes. If these extensions prove useful they should obviously go into all Ruby implementations. I don’t have anything against Rubinius at all (on the contrary, I’m very excited about it). But I’d be reluctant to use a feature that is only available in Rubinius, at least if it is going to remain a Rubinius-specific extension.

JRuby obviously has its own set of extensions which are required in order to interact with the Java class libraries and to be a good citizen of the JVM community. JRuby manages to be a good citizen of the Ruby community as well.

And now there’s XRuby. That was a lie. It’s been around for quite some time, just that I hadn’t heard of it before today. I’ve managed to build it while I’m writing this post. I compiled one of the samples. It seems to compile and JARify the ruby sources. I haven’t been able to figure out how to run the compiled program yet (complaining about not finding RubyProgram.class), but I haven’t tried all that hard yet.

Of course, I hear there is a Ruby implementation for Mono as well. But an aptitude search doesn’t turn up anything interesting. It could be that it’s not in Debian yet. It could also be that it’s got a weird name that has nothing to do with Ruby. I don’t really have much experience with Mono.

What I think is important is that the various communities work closely together so that all the good stuff finds its way back and becomes an official (whatever *that* means) part of Ruby eventually. I guess in the end MRI is the One Ruby to rule them all, so if a feature makes it there it is likely to get adapted by the others. I hope MRI doesn’t turn the others into mindless zombie (read: nazgul) processes that only know how to obey their master.. 😉

Enough already! I’m a programmer not a damn philosopher.

2008.01.26

ScrapBook, a Firefox extension

Filed under: Software — Tags: , , — Lorenzo E. Danielsson @ 20:50

ScrapBook is a Firefox extension that allows you to save web pages. This is really cool, especially if you happen to be somebody that does not always have on-line access. ScrapBook also works well with the Firefox 3.0 betas.

Actually ScrapBook does alot more than just save web pages. But already there it is useful for me. While I am on-line, I usually don’t have time to read all the pages that I find. So I need to store them locally. Later when I get home (where I’m not connected) I can read the documents that ScrapBook has saved for me. ScrapBook also allows me to categorize those pages into “folders”.

Opera, which is a wonderful browser, as well as Konqueror have the ability so save pages as “web archives” which contains not only the page itself, but also the CSS and images that are linked from the page. ScrapBook also gives me a sidebar that I can use to organize and browse through my saved pages.

I use ScrapBook for another thing as well. Very often I find pages that I may need access to for a limited period of time, say a few days or weeks. I don’t really like bookmarking such pages because I tend to bookmark sites, not individual pages. Also I don’t like messing up my bookmarks (I’ve spent a lot of time organizing and re-organizing them). I used to have a bookmark category called ‘tmp’ where I stored temporary bookmarks. I’ve done away with that since I discovered ScrapBook.

You can do a host of other things with ScrapBook as well. For instance, you have highlighters that you can use to mark important text. You can also add annotations to pages. I find the ability to add inline annotations quite useful from time to time, when I want to remind myself of something I need to get more information about.

If you don’t have Internet access 24/7 I would definitely recommend ScrapBook. But even if you do, I think this is an extension that you might want to try out.

2008.01.25

What is so great about Eclipse?

Filed under: Programming tools — Tags: , , , , , — Lorenzo E. Danielsson @ 18:25

Before I start, this on not meant to incite any religious wars. These are simply my own opinions. I’ve also just gone through 20 disturbing minutes with Eclipse and am not in a good mood. In an hour or so I’ll be calmed down again, and I can safely deny any knowledge of ever having written this. 😉

The simple way to program

I have been using vim+zsh+(perl,python,ruby) as my IDE for about as long as I can remember. It’s efficient and easy to use. Moreover, you get good control, as in you decide how everything should work. The more skills you have with your tools, the better the IDE works for you.

You get full plug-in support for any revision control system you want to use. All you have to do is type the commands in a shell, be it hg commit, bzr status or, if you are so inclined, svn whatever. No worrying about whether such-and-such tool that you are used to works with whatever IDE. They all work, period.

Also, my preferred IDE does not require X Windows. If you have really old hardware, or if you are a sucker for user interfaces that make sense you can use vim+zsh+ppr without having to startx. It is fully functional over SSH sessions.

Did I mention “integrated documentation”? Use man and info. If you have html documentation, standard plug-ins like elinks, lynx and w3m are all designed to handle that. For file management, zsh normally does the job, but if you have special needs in that department, mc (midnight commander) will serve you well.

The not-so-simple way to program

Just because everybody keeps raving about them, I also try out various graphical, all-in-one designed-just-like-a-monster IDEs once in a while. I must say I’m fairly happy with Netbeans apart from the fact that it is slow and consumes far too much memory. Apart from that, Netbeans feels fairly clean and well thought-out. If i were forced to program in Java, Netbeans might actually make the experience slightly less painful.

But of course, all the people you would care to listen to will tell you that Netbeans sucks. Instead you are supposed to love Eclipse. I have never actually been able to spend more than 30-40 minutes with Eclipse without feeling hopelessly stupid, old and out-of-touch with reality.

Now, I don’t mind if people love Eclipse, that is great for them. If it helps them to be productive, cool! And I do understand and appreciate the fact that Gnome folks will have serial orgasms over Eclipse simply because it uses SWT, which, if I’ve understood it well, is just a JNI wrapper for Gtk, which Gnome folks have been brain-washed into believing is *the standard*. I *cough, cough* prefer Athena and (Mo|Less)tif myself. But, hey, live and let live. Maybe if I had 200+ Gb of core memory I would love Gtk too.

What it cannot stand is when somebody, who is a happy Eclipse user, goes to say that vi is “too complicated”. Anybody who thinks vi is difficult to use but Eclipse is not deserves to be pushed head-first into quick-sand. Eclipse *is* rocket science. It even makes monstrosities such as Emacs seem simple.

I can fire up Netbeans and pretty much start using it immediately. If I need a plug-in, it is very simple to grab it. And Netbeans plug-ins have descriptive names. If I want mercurial support, I just get the mercurial plug-in.

Eclipse isn’t even an IDE. It’s some for of meta-IDE. You cannot do anything with it without the right plug-ins. And these tend to have such wonderful names as VE, WTF, GFYA, STFU etc. How the hell am I supposed to know what the hell VE is? Look it up you say? Okay, that’s minus one on the list of items that makes Eclipse superior to vi. You have to learn vi and you have to learn Eclipse.

If you want to do JEE development on Eclipse of have to install the POOFT plug-in, which is an implementation of the PIFFY meta-plugin, which in turns requires the ESAD meta-meta plug-in. The ESAD plug-in, in turn, requires the FLUNKY meta-meta-meta-plug-in. Unfortunately, it won’t install because it also depends on about 400 other plug-ins, one of which is the INFERNO plug-in, which doesn’t exist in a version compatible with the version of Eclipse you are using.

What about the others?

I refuse to comment on Anjuta or MonoDevelop because they are Gnome-related. If you criticize anything related to Gnome you will end up on a terrorist-list somewhere. I refuse to comment on KDevelop because if I say anything negative about it I will be accused of being part of a Gnome conspiracy to destroy *the* successor to CDE.

I haven’t tried ProjectCenter in an awfully long time, so I really cannot comment on it. Maybe I should set up GNUStep again one of these days and see how it’s coming along.

Conclusion

😦

Simple wallpaper tool in Ruby

Filed under: Ruby Programming — Tags: , , , , — Lorenzo E. Danielsson @ 15:39

Ben is constantly on the look-out for small applications that he can write in order to practice his Ruby skills. This morning he told me he wants to write a “wallpaper switcher” (or whatever you call those things). It seemed like an interesting little program, so I hastily put this together.


 1 #! /usr/bin/ruby
 2
 3 # A wallpaper tool.
 4
 5 require optparse
 6
 7 def parsedir(path)
 8   a = []
 9
10   Dir.new(path).each do |file|
11     next if file =~ /^\./
12   
13     fp = "#{path}/#{file}"
14     File.directory?(fp) ? a.concat(parsedir(fp)) : a << fp
15   end
16   a
17 end
18
19 options = {
20   :dir => nil,
21   :file => nil,
22   :interval => 60,
23   :random => false,
24   :use => wmsetbg
25 }
26
27 begin
28   OptionParser.new do |opts|
29     opts.banner = "usage: #{$0} [options]"
30
31     opts.on("-d", "–directory=DIR", String, "scan directory") do |dir|
32       options[:dir] = dir
33     end
34
35     opts.on("-f", "–file=FILE", String, "read wallpapers from file") do |file|
36       options[:file] = file
37     end
38
39     opts.on("-i", "–interval=I", Integer, "set the interval") do |interval|
40       options[:interval] = interval
41     end
42
43     opts.on("-r", "–[no-]random", "randomize the order") do |r|
44       options[:random] = r
45     end
46
47     opts.on("-u", "–use=APP", String, "set the utility to use") do |use|
48       options[:use] = use
49     end
50   end.parse!
51 rescue OptionParser::InvalidOption => err
52   $stderr.print err.to_s + "\n"
53   exit
54 rescue OptionParser::MissingArgument => err
55   $stderr.print err.to_s + "\n"
56   exit
57 end
58
59 wp = []
60 wp.concat(IO.readlines(options[:file])) unless options[:file].nil?
61 wp.concat(parsedir(options[:dir])) unless options[:dir].nil?
62 wp.collect! { |image| image.chomp }.delete_if { |image| !File.exists? image }
63 abort "No wallpapers in list." if wp.empty?
64
65 %w[TERM INT].each do |sig|
66   trap(sig) {
67     puts "Are you crazy?? What are you doing to me?"
68     exit
69   }
70 end
71
72 loop do
73   (options[:random] ? wp.sort_by { rand } : wp).each { |image|
74     `#{options[:use]} #{image} > /dev/null 2>&1`
75     sleep options[:interval]
76   }
77 end

Improving it

Several ideas come to mind:

  • Add standard options like –help
  • Handle errors.
  • Make sure all the files added to the wp array actually are images.
  • Add an option to make the program run through the wallpapers once only (or a certain number of times.
  • Currently all the images get scaled by default (using wmsetbg). Add options for centering, tiling etc. images.
  • I’m calling a utility called wmsetbg, which comes with Window Maker. Instead of doing this, you could set the “paint” an image on the root window yourself. Look into Ruby/Xlib, Imlib2-ruby or any other library that you know of that will allow you access to the root window.
  • I’m sure you can think of lots more.

If you really wanted to take this little exercise a bit further you could create a custom format for the wallpapers file. For example, it could look like this

path/to/wallpaper:options

Where options would be something like scale, center, tile, etc. You could take it way too far and create an XML file with all kinds of options, such as display such-and-such image only during a specific time of the day, or on a specific day or interval of days. This way you could have special images for special occasions, such as Yule, Easter and so on. If you do decide to implement this, you may also want to consider a visit to your shrink. You are going waaay overboard and need help. Urgently.

Does it work with JRuby?

I’m glad you asked. Short answer: yes. Long answer: Hell, yeah! 😉

Does it work with Ruby 1.9?

Yes it does. Notice that there are some things you could do to ruby1.9-ify it. For instance, you could initialize the options array as follows:


options = {
  dir: nil,
  file: nil,
  interval: 60,
  random: false,
  use: wmsetbg
}

Does it work with Rubinius?

Yes, of course it does! 🙂

I did discover one small annoyance. Hitting CTRL+C will display the “Are you..” message alright, but the program will keep running. Not sure why, but I’ll look into that.

2008.01.24

Scrambling words in Ruby

Filed under: Ruby Programming — Tags: , , , — Lorenzo E. Danielsson @ 22:50

Somebody needed a program that takes an input string and scrambles the letters in each of the words. Capitalization and punctuation should be intact. I don’t normally solve people’s exercises for them, but I did decide to write something of my own. I get severe allergic attacks from typing too much, so instead of Java, I chose Ruby as an implementation language.

Scramble a string

The first part of the problem is to scramble a string. The following seems to work fairly well, and should be easy to understand:


1 def scramble(str)
2   s = str.split(//).sort_by { rand }.join()
3   s =~ /[A-Z]/ && s =~ /[a-z]/ ? s.capitalize : s
4 end
5
6 puts scramble("Hello world")

The first line in the method does exactly what you would think it does: splits a string into an array of characters, “sorts” them randomly (whatever that means), and joins the characters back into a string.

The second line maybe deserves a comment. I use a very naive (not to mention stupid) way of deciding whether or not to capitalize the string. If I can find both upper-case and lower-case letters then I capitalize, otherwise I don’t. It works well enough for normal English, but if you pass some camelCased strings then it probably won’t do what you expect. Then again, that wasn’t in my friends specification..

One thing before we continue. Scrambling looks like an interesting candidate for the String class, don’t you think? Okay, let’s fix that right away!


1 class String
2   def scramble
3     s = self.split(//).sort_by { rand }.join()
4     s =~ /[A-Z]/ && s =~ /[a-z]/ ? s.capitalize : s
5   end
6 end
7
8 puts "Hello world".scramble

Now, that looks so much better, wouldn’t you agree? Now we can go on and figure out how to scramble individual words instead of strings.

Scrambling words

Just as a reminder: punctuation characters are supposed to be left in place. So, if I have a string like Hello, world! then the comma and the exclamation mark (or the bang, if you have been using UNIX for too long) need to be left in place.

So the procedure will be to split the string on white-space. That way we get an array of words, possibly with punctuation characters attached. We then break out the actual word and scramble it. The following would do just that:


 1 def scramble_words
 2   ret = []
 3   self.split(/\s+/).each { |nws|
 4     nws.scan(/^(\W*)(\w*)(\W*)$/) { |pre, word, post|
 5       ret << pre + word.scramble + post
 6     }
 7   }
 8
 9   ret.join " "
10 end
11

Of course, this method should be added to the String class as well. You can find the full code below. The first thing we do is split on one or more white-spaces. Since I join the array of words at the end of the method separated by a single string this means that you lose multiple consecutive white-spaces in the string. This may be a problem. The good news is that it is trivial to fix. Can you figure it out? Good, I knew you would.

Once I have split out the “words”, I use String#scan to separate any punctuation characters from the word itself. You may wonder why I use ^(\W*)(\w*)(\W*)$/ as the regex. It would appear to be better to use ^(\W*)(\w+)(\W*)$/. Well, the fact is that you could end up having one or more lone punctuation characters, which means the match would fail with a \w+.

Now we are ready to put it all together.

The scramble-words program

The String class, extended with the scramble and scramble_words methods follows. There is also a little loop there that lets the user enter strings, which get passed to scramble_words.


 1 #! /usr/bin/ruby
 2
 3 # Scramble words.
 4
 5 class String
 6   def scramble
 7     s = self.split(//).sort_by { rand }.join()
 8     s =~ /[A-Z]/ && s =~ /[a-z]/ ? s.capitalize : s
 9   end
10
11   def scramble_words
12     ret = []
13     self.split(/\s+/).each { |nws|
14       nws.scan(/^(\W*)(\w*)(\W*)$/) { |pre, word, post|
15         ret << pre + word.scramble + post
16       }
17     }
18
19     ret.join " "
20   end
21 end
22
23 loop do
24   print "Enter something: "
25   str = gets.chomp
26   exit if str.empty?
27   puts str.scramble_words
28 end

Okay. So how does this fare?


% ruby scramble.rb
Enter something: "Hello, world!", said the C programmer.
"Hello, dlorw!", adis the C mreorrgapm.

First test worked okay. Let’s try something else.


Enter something: Hey! Hey! My, my, Rock'n'roll will never die!
Hey! Eyh! My, my, llwi nvree die!

Uh-oh! Seems we lost something. If you think about it, it’s obvious why. I don’t really expect my friend would be parsing words like Rock’n’roll, but words with an apostrophe are likely: I’m, I’ll, let’s, he’s, don’t and so on. Considering the frequency of this character you could fix this by changing the regex in line 14 to look like this:


/^(\W*)([\w|’]*)(\W*)$/

That fixes words with an apostrophe, but for some reason capitalization on such words gets screwed. I haven’t looked into it yet. Feel free to fix it as an exercise. If you’ve solved that and need more, figure out how scrambling of words containing apostrophe should behave. Should the position of the apostrophe be maintained? If so, the program currently does not behave well. So go on and fix it! 😉

If we disregard a few warts here and there the program does mostly what it’s supposed to. Or at least it appears so. I cannot say I have given it any extensive amount of testing.

But wait! We’re being a bit rude by only testing it on ruby 1.8. Let’s try it out on a few other implementations of Ruby (the language).

Does it work with ruby 1.9?

Ruby 1.9 works fine, but the program goes to gets without displaying the prompt. I’m not sure why, but I’ve seen it before. The fix is simple. You just need to flush stdout as shown below.


loop do
  print "Enter something: "
  $stdout.flush
  str = gets.chomp
  exit if str.empty?
  puts str.scramble_words
end

Does it work with JRuby?

What a silly question. Of course it does. What did you expect? 😉

Does it work with Rubinius?

Well, we won’t know unless we try it, will we?


% rbx scramble.rb
Enter something: An exception has occurred:
undefined local variable or method `gets' for main (NameError)

Backtrace:
Object#gets (method_missing_cv) at kernel/core/object.rb:117
main.__script__ at ./scramble.rb:26
CompiledMethod#as_script at kernel/bootstrap/primitives.rb:35
Compile.single_load at kernel/core/compile.rb:204
Compile.unified_load {} at kernel/core/compile.rb:124
Array#each at kernel/core/array.rb:557
Compile.unified_load at kernel/core/compile.rb:107
Kernel(Object)#load at kernel/core/compile.rb:329
main.__script__ at kernel/loader.rb:171

Obviously not. Nothing we can do here. Go home, folks. No, but wait! Those error messages are actually there for our benefit, so why not read them? This looks interesting: undefined local variable or method `gets' for main (NameError). If Rubinius doesn’t know of Kernel.gets, what would happen if we were a little more precise?


loop do
  print "Enter something: "
  str = $stdin.gets.chomp
  exit if str.empty?
  puts str.scramble_words
end


% rbx scramble.rb
Enter something: "Hello, world!", said the C programmer.
"Llhoe, lwrod!", said teh C arpmergmor.

Sweet!


% rbx -v
rubinius 0.8.0 (ruby 1.8.6 compatible) (r) (01/23/2008) [i686-pc-linux-gnu]

Conclusion

I need coffee.


Update 2008.01.27: with Rubinius checked out and compiled this morning, $stdin.gets is no longer necessary. I guess Kernel.gets is working now.

Older Posts »

Create a free website or blog at WordPress.com.