Installing Ruby 1.8.7 on Mac OS X 10.5.3

Yah, this week is all about solving problems. I run into a lot of them, but it gives me something to blog about. But hey, if I can spend 20 minutes writing down a solution to a couple hour problem that I had, then I could save you a few hours too.

Problem

Trying to install Ruby 1.8.7 (or even 1.9) on my Leopard machine produces warning messages on “make” that look like this:

gcc -I. -I../../.ext/include/i686-darwin9.1.0 -I../.././include
-I../.././ext/readline -DRUBY_EXTCONF_H=\"extconf.h\"    -fno-common
-g -O2 -pipe -fno-common   -o readline.o -c readline.c
readline.c: In function 'filename_completion_proc_call':
readline.c:659: error: 'filename_completion_function' undeclared
(first use in this function)
readline.c:659: error: (Each undeclared identifier is reported only once
readline.c:659: error: for each function it appears in.)
readline.c:659: warning: assignment makes pointer from integer without a
cast
readline.c: In function 'username_completion_proc_call':
readline.c:684: error: 'username_completion_function' undeclared
(first use in this function)
readline.c:684: warning: assignment makes pointer from integer without a
cast
make[1]: *** [readline.o] Error 1
make: *** [all] Error 1

Solution

I originally came across this problem right around new years and eventually found a solution thanks to Han Kessels on the Ruby Forums. It involved the following steps:

  1. Download the newest version of readline (version 5.2 at the time of writing) at GNU.org. You may have to apply the following patch. Thanks to Michael Biven for showing a nice simple way to do this from the command line:
    $ curl -O ftp://ftp.gnu.org/gnu/readline/readline-5.2.tar.gz
    $ tar xzvf readline-5.2.tar.gz
    $ cd readline-5.2
    $ curl -O http://ftp.gnu.org/gnu/readline/readline-5.2-patches/readline52-012
    $ patch -p0 < readline52-012
    $ ./configure --prefix=/usr/local
    $ make
    $ sudo make install
    $ cd ..
  2. Now you can download the 1.8.7 version of ruby, and install it but you should point to the version of readline that you just installed (to /usr/local) like so:
    $ curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7.tar.gz
    $ tar xzvf ruby-1.8.7.tar.gz
    $ cd ruby-1.8.7
    $ ./configure --prefix=/usr/local/ruby1.8.7 --with-readline-dir=/usr/local
    $ make
    $ sudo make install
    $ cd /usr/local/ruby1.8.7/bin
    $ ./ruby -v
    ruby 1.8.7 (2008-05-31 patchlevel 0) [i686-darwin9.3.0]

The End Result

If you followed my terminal commands from above you should have a working Ruby 1.8.7 version installed in your “/usr/local/ruby1.8.7/bin”. If you wanted ruby in a different directory then change the “–prefix=/usr/local/ruby1.8.7″ option on ./configure to instead point to the directory you wanted it.

Why put it in its own directory at all? Well, I happen to have multiple version of ruby. By default I have 1.8.6, I have this version of 1.8.7, I even have a 1.9 version I installed a while ago. Its easy to remember where each is if the directory they reside in clearly states the name. This way I can test a script, maybe even run benchmarks, in each version of ruby. However, you might not want to take this extra measure.

A “blog.domain.com” That Works

I seem to have had some really bad luck doing what I thought would be very simple. I finally arrived at a solution that I really don’t feel is optimal, but it works and I’ll monitor it for a while and hope that it continues working. (You’ll know if something ended up changing).

Problem

I own “alpha.com” and I want to create a “blog.alpha.com” that actually pulls pages from “alpha.com/blog/” on the web server but the user should still see “blog.alpha.com” in their browser’s address bar.

How I did it with this WordPress 2.5.1 Blog

Hopefully if you look up at your address bar right now you see blog.bogojoker.com. If not, then this failed and completely ignore me! I ended up having to do three things:

  1. I Setup redirection for a subdomain. I used my hosting company’s Control Panel to create “blog.bogojoker.com” and point it to “http://bogojoker.com/blog/”. Please note this change does not start working immediately. It took a few hours for the redirection to be broadcast over DNS Name Servers. Once it did work I went to the next steps. I wouldn’t recommend going to the next steps until this starts working because I believe they depend on this!
  2. I logged into the WordPress Admin Dashboard. I went to “Settings” and put “http://blog.bogojoker.com” into both the “WordPress address” and “Blog address” fields. This put my browser into an infinite loop which I fixed in the final step.
  3. I FTP’d into my server, went to the “public_html/blog/” directory and commented out these lines from the hidden “.htaccess” file: (Note that adding a “#” to the start of the line comments that line out)
    #RewriteCond %{HTTP_HOST} ^blog.bogojoker.com$ [OR]
    #RewriteCond %{HTTP_HOST} ^www.blog.bogojoker.com$
    #RewriteRule ^(.*)$ http://bogojoker.com/blog/ [R=301,L]

Voila. That is how I did it. I ended up spending far too much time on what I considered “better” solutions that didn’t seem to work. In doing so I found out some things, but I can’t really be sure what I learned anything valuable from it.

Troubleshooting Tricks

If you end up having the same trouble, if you want to experiment on your own, or if you tried something that totally failed hopefully this can help.

At one point during the week everything crashed on me. Not only did the website not redirect properly but the direct paths weren’t working. I chalked it up to me turning the redirection (step 1 above) off. I stumbled upon a temporary solution to fix WordPress in the few hours it would take for that redirection to be reborn through DNS. It involves a little familiarity with mysql or phpMyAdmin and knowing your database schemas.

For those with phpMyAdmin access:

  1. Log into your phpMyAdmin
  2. Select the WordPress’s database. Most servers have username_wp### or the like, this you should recognize pretty easily or can find from your Control Panel
  3. Browse the “wp_options” table
  4. Modify the “siteurl” value to be the “real” path to the blog subdirectory, NOT what you want it to be but where it really is. For example “http://bogojoker.com/blog/” for me.
  5. Now log into your WordPress by manually going to your domains wp-admin page like so: “http://yourDomainHere.com/blog/wp-admin/”
  6. Go to the “settings” tab and change both urls to the url mentioned in step 4.

That should bring your website back up, albeit with the uglier URL structure. For those without phpMyAdmin access the you should have some form of access to your database, be it command line using the “mysql” command or via another graphical interface. Just try to follow the steps above as closely as possible.

I hope this helps you out a little if you want to accomplish the same thing. Even better though, come up with a better solution and let me know. I dreamed of solving this in a couple minutes and ended up spending a little over 3 hours taking a number of approaches. So I figured, what better to do but write about it!

JavaScript Sort an Array of Objects

I ran into an interesting problem today. I had an array of objects that I wanted sorted on a certain property. My obvious thought didn’t work! (Update: I got a comment below from Peter Michaux who points out a nicer solution, it is included here:)

// Array of Objects
var obj_arr = [ { age: 21, name: "Larry" },
                { age: 34, name: "Curly" },
                { age: 10, name: "Moe" } ];

// This doesn't work!
obj_arr.sort( function(a,b) { return a.name < b.name; });

// This does work! (Peter's update, very fast)
obj_arr1.sort(function(a,b) { return a.name < b.name ? -1 :
                                     a.name > b.name ?  1 : 0; });

That kind of frustrated me. Sorting is one of those things I expect to be available in all languages. I don’t want to have to write a sorting algorithm every time I need to sort. So I looked into things, pulled up a Javascript Quicksort Algorithm and manipulated it to support any compare function.

Now that I have the freedom to truly write a compare function that works for objects! I also changed around certain parts of the code I found online to actually extend the Array class and make the extra functions hidden. Take a look at the sample usage:

// Defaults to (a<=b) sorting.  Great for numbers.
var arr = [1234, 2346, 21234, 3456, 32134, 3456, 1234, 2345, 23, 42523, 1234, 345];

// Object Array
var obj_arr = [ { age: 21, name: "Larry" },
                { age: 34, name: "Curly" },
                { age: 10, name: "Moe" } ];

arr.quick_sort();
// => [23, 345, 1234, 1234, 1234, 2345, 2346, 3456, 3456, 21234, 32134, 42523]

obj_arr.quick_sort(function(a,b) { return a.name < b.name });
// => Curly, Larry, Moe

obj_arr.quick_sort(function(a,b) { return a.age < b.age });
// => Moe (10), Larry (21), Curly (34)

For those who want to see the code be glad, its free. I carried the copyright with it but its rather loose. Grab the JavaScript Source Here! Enjoy:

Array.prototype.swap=function(a, b) {
  var tmp=this[a];
  this[a]=this[b];
  this[b]=tmp;
}

Array.prototype.quick_sort = function(compareFunction) {

  function partition(array, compareFunction, begin, end, pivot) {
    var piv = array[pivot];
    array.swap(pivot, end-1);
    var store = begin;
    for (var ix = begin; ix < end-1; ++ix) {
      if ( compareFunction(array[ix], piv) ) {
        array.swap(store, ix);
        ++store;
      }
    }
    array.swap(end-1, store);
    return store;
  }

  function qsort(array, compareFunction, begin, end) {
    if ( end-1 > begin ) {
      var pivot = begin + Math.floor(Math.random() * (end-begin));
      pivot = partition(array, compareFunction, begin, end, pivot);
      qsort(array, compareFunction, begin, pivot);
      qsort(array, compareFunction, pivot+1, end);
    }
  }

  if ( compareFunction == null ) {
    compareFunction = function(a,b) { return a<=b; };
  }
  qsort(this, compareFunction, 0, this.length);

}

Update

Peter Michaux pointed out something very important. The sort() function can be made to work if it returns numeric output (-1,0,1). His approach is far superior. Here was a benchmark I took:

var obj_arr1 = [];
var obj_arr2 = [];
var filler = [ { age: 21, name: "Larry" },
               { age: 34, name: "Curly" },
               { age: 10, name: "Moe" } ];
for (var i=0; i<5000; i++) {
  rand = Math.floor( Math.random() * 3 );
  obj_arr1.push( filler[rand] );
  obj_arr2.push( filler[rand] );
}

var s = new Date();
obj_arr1.sort(function(a,b) { return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; });
var e = new Date();
console.log(e.getTime()-s.getTime()); // => 75 ms

s = new Date();
obj_arr2.quick_sort(function(a,b) { return a.name < b.name });
e = new Date();
console.log(e.getTime()-s.getTime()); //  => 4444 ms

That shows drastic differences for arrays as large as 5000 elements (with not too random data). 75 ms versus 4444 ms (over 4 seconds). Doing the math: (4444/75) => 59.253 times better! Moral of the story, don’t rush into thinking something doesn’t exist!

So if that’s the way to do it, then I want to make it easier on me. My arrays are generally going to be under 100 in size, and at such a size building a function dynamically instead of writing a custom function works just about as well (although if you were using objects, polymorphism and a compare function would be the best way to go). Here is a simple function I can use to more quickly build compare functions in order to ascend sort an array on multiple properties!

function buildCompareFunction(arr) {
  if (arr && arr.length > 0) {
    return function(a,b) {
      var asub, bsub, prop;
      for (var i=0; i<arr.length; i++) {
        prop = arr[i];
        asub = a[prop];
        bsub = b[prop];
        if ( asub < bsub )
          return -1;
        if ( asub > bsub )
          return 1;
      }
      return 0;
    }
  } else {
    return function(a,b) { return a<=b; };
  }
}

Sample usage would be:

var obj_arr = [
  { name: 'Joe',   age: 20 },
  { name: 'Joe',   age: 10 },
  { name: 'Joe',   age: 30 },
  { name: 'Joe',   age: 40 },
  { name: 'Joe',   age: 20 },
  { name: 'Joe',   age: 15 },
  { name: 'Joe',   age: 35 },
  { name: 'Joe',   age: 25 },
  { name: 'Bill',  age: 5 },
  { name: 'Barry', age: 20 },
  { name: 'Paul',  age: 20 },
  { name: 'Peter', age: 1 },
  { name: 'Smith', age: 25 },
  { name: 'Kary',  age: 30 }
];

obj_arr.sort( buildCompareFunction(['name','age']) );

Firebug Feature - Open With Editor

This one was news to me but it just made my day (and not a minute too late)!. I used to have so much trouble copying and pasting code from the Firebug (now Firefox 3 compatible) console. The paste used to have no formatting or indention and sometimes there was line numbers… Well one more problem has been solved. Check this out:

Firebug\'s \

Checking the changelogs in the repository for Firebug shows that it was included in ReleaseNotes_1.1.txt. I can’t believe I missed it!

Now all thats left is copying and pasting from the HTML’s Style textarea on the right. Still, I think this is a nice small step forward.

Brian Amerige - Some Praise to the Developer of Flow

In this blog post I’m going to give praise to Brian Ameriage, the developer of the Flow FTP Program available for Mac OS X Leopard. I’ll quickly go through some of the ways that Brian has impressed me over the short time I have known him over the web.

1Flow

I was involved in the Beta testing of Flow for a few months and as expected I ran into some problems. There was one, rather complicated problem that I decided to send in a bug report regarding. As a developer myself I knew what a good bug report would look like. I started from scratch, listed the steps to produce the bug (100%), etc. To my surprise I got a great personalized response:

Joe,

These issues should all be cleared up in Beta 5 (not yet released.) Keep in mind, though, that the issues you are experiencing are likely related to keychain, however, so it’s worth a shot remove all of your bookmarks, and to open up Keychain Access and remove any bookmarks tagged with “ConnectionKit Password.”

Thanks for the detailed report :-)


Thanks,
Extendmac, LLC.

Not only did he say that it was fixed in the next release, but he gave an indication as to what the problem was, a possible workaround, and appreciation for the report. From that point on I was sold on Flow. I continued to submit bug reports and they were all answered quickly, from a few hours to a few days after submitting them. They were all eventually resolved, and sometimes under extreme conditions. Did anyone ever wonder why there was such a quick jump between Beta 7 and 7.1 (or was it 8)? Turns out Brian stayed up past 2:30 AM hammering out some bug fixes.

2Passion and Dedication

I think Brian’s most recent blog post, Arrogance in Engineering sheds some light on this topic: (my emphasis)

There’s a tremendous difference between an engineer on paper and an honest-to-the-bone engineer. The great kind are tinkerers. They build things in their spare time and are positively eccentric about it.

Passionate developers do the best work because they are always thinking about how they can improve things. Developing, Engineering, etc. its not a 9-5 job… its an ongoing, never-ending, adventure to improve, innovate, and create. For a number of people perfection is not a goal, its the standard. I sensed this quality in the way that Brian handled himself developing Flow, supporting it, collecting critical feedback, and keeping patient by not releasing it before it was ready.

The release of Flow has been a great success. I saw minor improvements made over the last few weeks, and even hours before the launch (I was in email contact late that night) where Brian’s attention to detail, aim for excellence, and dedication really stood out.

3Finally, Composure

Composure is very different then Passion. The combination of the two characteristics is rare, but its something that I saw in Brian. Its especially something that I saw in a number of Brian’s blog articles (some of which I think have been lost). I remember seeing the blog posts and realizing the thought with which he put into his reasoning and his supporting arguments; knowing that what he was saying might not be the idea of the majority. Blogs are often just diaries, outlets for emotion, but those can easily be confused with rants. Either by design or not, Brian’s blog had reason and logic far beyond his years.

Brian who?

To steal a little content from Brian’s website, here is a just a small portion from his Bio:

  1. In that sense, I design how software works. That encompasses engineering the architecture, writing the code, and illustrating the interface, but more importantly, thinking about how people will use it.
  2. It’s not about technology, it’s about what it does. My passion is making tools for people.
  3. I’m 17 years old. (And yes, I’m both embarrassed and depressed by the behavior of most people my age.)

There are Others

People like Brian are not a dime a dozen. I’ll admit he is one of my mini-heros. There are plenty others, who’s names I’ll leave out in the hope that I can contribute an entire article to them as well. But I figured I’d swallow a little of my own medicine. Now I better get back to writing some real programming on this blog before all my readers get confused!

You deserve it, Keep up the great work.
- Joe P

Give Some Appreciation

I have had the idea to write this article for a long time. But this morning I came across Allan Branch’s blog post titled “It isn’t always about you…” containing the following message:

I read many blogs and follow or have followed a number of people on twitter. I think I see a trend in both, rarely does anyone talk about others in a light that takes the spotlight off of themselves. Most people are so worried about their own personal glory and fame they cannot show real praise to anyone but themselves in fear of losing a grasp of their “fame.” They only talk about their thoughts, their ideas, their apps etc. These people aren’t evil, they’re usually great people.

I want to spin this and instead give you ideas about why and maybe even how you should give some appreciation to your “mini-heros.” Don’t worry, this article has an extreme amount of “I” statements, but I (there’s one) really think that this blog post contains my thoughts and I hope you get the chance to read it.

Mini-heros

You should have a list of individuals that you think have passion, present themselves in a model way, are helpful… the list of good characteristics are nearly endless. The essential idea is that they have had some impact on you or possessed some notable quality that impressed you. In some cases, for professions and hobbies you may have a mini-hero that gives you pride in being a part of that activity, hope in its future, and make it even more enjoyable. These people, are the mini-heros.

I think in the end, these role models and mini-heros, lack feedback and recognition and don’t realize how important and influential they really are. More and more frequently I am remembering the names of individuals that make an impact on me, from as important as my career to as nuanced as my hobbies.

Where am I going with this?

I want you to just write out a thank you letter, a blog post, maybe even a donation… offer some appreciation to someone who made an impact on you. If you can’t think of anything now, then just keep your eye out in the future for that small app that really impresses you and maybe the developer was kind enough to help you out.

A Non-Generic “Thank You” Means So Much More

Qualify your thank you with a reference to what the person did that really impressed you. Take the time to reword a “Thank You” to “Thanks for spending the time to look at this. I really appreciate your help.” Point out what it is the person did that was extraordinary or separated them from the norm. Personally, I make sure that I mean every “Thank You” that I say, and I try to say it in such a way that they know I’m thankful. Its a shame that there is such a thing as an empty Thank You, but it does exist. Those two words don’t nearly have the meaning they used to. So if you make them mean something, they will be far more appreciated.

Keep in mind blubbering flattery or worship is not what I’m asking. People appreciate praise more from their peers and equals or from people who are “above” them (I’m thinking bosses, managers, etc.). I’ll leave with the following article by Neil Patel that I feel carries some truth on How to Build Influential Relationships. If you read that article I want you to keep in mine that its not always necessary to build “influential” relationships; a simple letter of praise, with good reason, is always appreciated.

Dot Files For Your Shell and Even Ruby

I have come across a number of programmers who don’t know what dotfiles are. Thats a shame. Every programmer should know common dotfiles and actively seek to add aliases, functions, and other tidbits to increase their productivity and make the shell more usable. I recently went on a binge and updated a few of my dotfiles. I’ll share some useful tricks that I found on not only my ~/.bashrc file but also ~/.irbrc for my ruby IRB prompt!

I won’t show off my entire ~/.bashrc file, only because it is rather long. I just want to get across some of the usefulness of such a file:

# -----------
#   General
# -----------
alias ..='cd ..'
alias ll='ls -lh'
alias la='ls -la'
alias ps='ps -ax'
alias du='du -hc'
alias cd..='cd ..'
alias more='less'
alias mkdir='mkdir -p'
alias today='date +"%A, %B %d, %Y"'
alias yest='date -v-1d +"%A %B %d, %Y"'
alias recent='ls -lAt | head'
alias ebashrc='mate ~/.bashrc'
alias mbashrc='mate ~/.bashrc'
alias sbashrc='source ~/.bashrc'
alias htdocs='cd /Applications/MAMP/htdocs/'
alias mampmysql='/Applications/MAMP/Library/bin/mysql -u XXXXX -p'
alias desktoptopia='open /Users/joe/Library/Application\ Support/Desktoptopia/.Backgrounds/'
alias ql='qlmanage -p "$@" >& /dev/null' # Quick Look alias

# -------------
#   Shortcuts
# -------------
alias c="clear"
alias m="mate"

# --------
#   SSHs
# --------
alias rit="ssh holly.cs.rit.edu -l XXXXX"
alias vega="ssh vega.it.rit.edu -l XXXXX"

# -------
#   Git
# -------
alias ga='git add'
alias gs='git status'
alias gd='git diff'
alias github="open \`git config -l | grep 'remote.origin.url' | sed -En 's/remote.origin.url=git(@|:\/\/)github.com(:|\/)(.+)\/(.+).git/https:\/\/github.com\/\3\/\4/p'\`"

# --------
#   Ruby
# --------
alias irb='irb -r irb/completion -rubygems'

# ---------------
#   Environment
# ---------------
export PATH="$PATH:/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin"
export PATH="$HOME/bin/:$PATH"
export HISTSIZE=10000
export HISTFILESIZE=10000
export PAGER=less
export CLICOLOR=1
export EDITOR="/usr/bin/mate -w"

Hopefully this wasn’t too overwhelming. But lets take a look at some of these. There are a bunch of aliases at the top which simply replace the older version? It just makes sense that when you do a ps you really want `ps -ax`. Likewise a few others there are printing disk usage with human readable output.

Nothing completely interesting however everything is extremely useful. I’m cutting my keystrokes in half and getting better output. I have a bunch of more exciting tricks in the rest of my ~/.bashrc. Its not just reserved for aliases and EXPORTS, take this function for example:

# cd directly to a dir and list contents
cdl() {
  if [ "$1" ]
  then builtin cd "$1" && ll
  else builtin cd && ll
  fi
}

Cd to a directory and list the directory. I even reference my ll alias up above to list long. You can take a peek at my entire .bashrc file on dotfiles.org. Lets move on to something you may not have known about. Let me walk you through parts of a nice ~/.irbrc file, which you might want for yourself:

# Load and Start Wirble, a gem to beautify irb
require 'wirble'
Wirble.init
Wirble.colorize

Probably one of the most popular inclusions in a .irbrc file. Wirble is a Ruby gem built for improving the irb interactive ruby console. That means you may also have to ‘require “rubygems”‘ in order for this to work. Take a look at the gem documentation for Wirble to find out more of its capabilities. But that also means you can include a number of other useful rubygems. For instance, what_methods, map_by_method, hpricot, yaml, the list goes on and on. Instead I’m going to point out some other neat additions you can add to your .irbrc!

# Awesome benchmarking function
# Source: http://ozmm.org/posts/time_in_irb.html
def time(times=1