The Irish Penguin Watching Open Source unfold across Ireland

5Mar/115

Bundler installing gems into the wrong directory – mea culpa

So I spent an hour and a half last night unfairly swearing at the spork gem; and blaming it for everything from world hunger to banking crises! This is because somehow when installing spork I had managed to change the location that bundler installs gems into - strangely enough into a directory called ./spork under my project directory. And I figured the blame landed at the door of the spork gem. Here's what happened just so that you don't get caught out.

Once installed, here's how you start up spork: bundle exec spork

But, at some point, here's what I did by accident: bundle install spork

Fool! Fool! Fool! For those of you that aren't familiar with the 'path' argument to bundler, well, what it does is permanently change your path to the value you specify. So for an hour and a half last night, I had ./spork set as my gem directory. Meaning that my furious efforts to correct the problem were in vain - such as clearing out all the gems and reinstalling, grepping for a config file that could be pointing at ./spork in my project and rvm directories.

What I should have done to fix this problem immediately, was to tell bundler to use my standard rvm directory for gems again

bundle install --system

Ta da!

It's pretty confusing that specifying a path argument once off should cause bundler to change it behaviour on a permanent basis but at least I notice that in the docs it says

The path argument to 'bundle install' is deprecated. It will be removed in version 1.1. Please use 'bundle install --path spork' instead.

So I guess I'm not the only one who's hit this confusing behaviour. Long live the --path option!

Sorry spork, I'm a dork...

16Feb/110

Machinist 2 and the undefined method for Sham:Module error

This ain't no Sham marriage! Machinist 2 has done away with the Sham module. But, at time of writing, this isn't immediately obvious from the installation guide. So if you try to horseshoe your Machinist 1 (Sham-based) tests into Machinist 2 then you'll find you get an error like

/home/you/dev/rails/my_project/spec/support/blueprints.rb:5:in `': undefined method `name' for Sham:Module (NoMethodError)

The solution is to use the new serial_number() method technique instead. For more info on what's in Machinist 2 check out the What's new in Machinist 2 page.

A short post but hopefully it helps someone. Mock on!

20Jan/110

Push and pull data between your local MongoDB and Heroku or MongoHQ

Heroku do a great job of providing a free way to host MongoDB. The only slight issue I had was syncing data between my machine and my Heroku apps - in the way I was used to with their Taps plugin which works for Postgres databases. But here's how to do it for MongoDB. Note, I was using it with a Rails 3 and Ruby 1.9.2 app.

Firstly you need to get Pedro Belo's super plugin heroku-mongo-sync . The docs say that the default way to use it is just to do a 'heroku mongo:push' or 'heroku mongo:pull' from inside your app directory on your machine. But this takes the name of your app exactly and assumes that this is the name of your mongo database. Unfortunately, many people like to call their database something else - and even the default is yourappname_development which won't work (it must be 'yourappname' exactly).

A feature allowing you to specify a MONGO_URL shell variable that will let you override this is in the README. Sadly it didn't work for me. But help is at hand - we can just create a new enviroment for syncing and then specify the database we need as the default. Of course you don't have to do this if your database is actually exactly the same as your app already; though the following approach may still serve you well as a workflow

* Pre-requiste, you must have an account setup on MongoHQ for this to work. And see here for how to setup MongoDB on Heroku
* Copy your config/development.rb to config/sync.rb
* Ok, I'm using Mongoid. Here's how I define my db connection to be exactly the same as my app's name in my config/mongoid.yml file

sync:
<<: *defaults
database: yourappname

* Whenver you want to push or pull to Heroku just change the default Rails environment at the top of your config/application.rb file to be 'sync'

require File.expand_path('../boot', __FILE__)

ENV['RAILS_ENV'] = 'sync'

* Now from the command line, you should find 'heroku mongo:push' and 'heroku mongo:pull' work like a dream. Ahoy, me mongols!

22Nov/100

Getting Pyzeemote running on MeeGo

Pyzeemote allows a Zeemote controller to communicate with a running application over D-Bus. We're going to get it running on MeeGo today. All in all, getting this working will involve the following components
- Python drivers for the Zeemote device (provided by Pyzeemote)
- A daemon which listens for Pyzeemote events and shepherds them onto the application over D-Bus (provided by Pyzeemote)
- A test suite which tells you if everything is working correctly (provided by Pyzeemote)
- Bluetooth python bindings (provided by 3rd party library PyBluez)

PRE-REQUISITES

The MeeGo machine these steps were carried out on was a Leveno IdeaPad, which had the MeeGo core repository disabled and the MeeGo test and devel repos enabled - as outlined at our earlier guide Installing Ruby and Rubygems on MeeGo. You may need to do this as well, as these repositories are likely the source of some of the libraries used in this guide. Furthermore you will need to install packages for building python bluezy bindings

sudo zypper install gcc make python-devel bluez-libs-devel

PYZEEMOTE INSTALLATION STEPS

* Create a directory pyzee in your home directory

mkdir pyzee

* Download pyzeemote source on Google Code using svn
* If you don't have svn you can just use the Browse functionality of Google Code and download (the raw version) of the following files manually:

pyzeemote-test.py, zeemote_listener.py, README

* Whether you use svn or Browse simply ensure that you have the above 3 files at the top level of your pyzee directory

* Download bluezy python bindings (PyBluez-0.18.tar.gz) which will work on MeeGo from PyBluez on Google Code
* Move the PyBluez-0.18.tar.gz to the top level of your pyzee directory
* Change directory to the pyzee directory

cd ~/pyzee

* Extract the PyBluez-0.18 contents

tar -zxvf PyBluez-0.18.tar.gz

* Change directory to the PyBluez-0.18 directory

cd PyBluez-0.18

* Build the python bluetooth bindings by running

python setup.py build

* Change directory back up one level so that you're inside the top level of the pyzee directory

cd ..

* Create a symlink to the freshly built bluetooth python bindings, so that they'll be found when we run pyzeemote

ln -s PyBluez-0.18/build/lib.linux-i686-2.6/bluetooth

* Fire up the pyzeemote daemon (you shouldn't see any output) using

python zeemote_listener.py

You shouldn't see any output if things went correctly. If you get the following then there is a problem with the bluetooth python bindings built in the last steps
---------------------------------------------------
Traceback (most recent call last):
File "zeemote_listener.py", line 39, in <module>
from bluetooth import *
ImportError: No module named bluetooth
---------------------------------------------------
You'll have to figure out why this is. Perhaps the symlink wasn't created correctly or it was created in the wrong place?

* Run the pyzeemote test suite

python pyzeemote-test.py

* You should see it say
Trying to find a Zeemote device...
* Try to click some buttons on your zeemote device. If successful, you should see output at the command line as you do so. Congrats, it's working!

20Nov/100

Installing Ruby on Rails on MeeGo with SQLite

This post will go through installing Ruby on Rails 2.3.2 on MeeGo - though it should likely work for any version of Rails, including Rails 3 (though the actual Rails commands at the end of this guide will be a little different). Firstly go through the Installing Ruby and Rubygems on MeeGo guide to get at least Ruby 1.8.7 on your system and then carry out the following steps.

PRE-REQUISITES

* The above guide requires you to disable the core repository and then enable the devel and testing repositories. I found that when following the below steps, I would get an error trying to install sqlite3 gem itself - saying that the sqlite3.h header could not be found. I had to run the following commands first

# Update all packages on the system

sudo zypper update

# Then the chrome browser would not work saying

[declan@declan-desktop grr]$ chromium-browser
/usr/lib/chromium-browser/chromium-browser: error while loading shared libraries: libicuuc.so.42: cannot open shared object file: No such file or directory

# To fix this, I had to update chromium-browser separately

sudo zypper update chromium

Ok, so onto the actual install steps for Rails and SQLite3...

RAILS INSTALLATION

#Install ruby and sqlite development headers (as we'll be using sqlite as our backend)

sudo zypper install ruby-devel

sudo zypper install sqlite-devel

# Install tools for building C-based gems

sudo zypper install make # Not 100% sure that make is needed

sudo zypper install gcc

# Install sqlite3 gem for ruby

sudo zypper install sqlite3-ruby

# Install Rails

sudo gem install rails -v 2.3.2

# Create a new Rails application
rails grr

# Create a thing (ok, more correctly called a resource) in Rails

cd grr

./script/generate Animal name:string

# Create the database

rake db:migrate

# Fire up the Rails web server

./script/server

# And then browse to your site in the web browser - http://localhost:3000/animals

Hurrah! Everything works! (At least I hope it did!). Happy Rails development!

29Oct/100

Supressing hrefs in image hyperlinks when deleting resources using jquery

This week we're trying to delete a resource using jquery within a Rails 2.3 app. First thing to note when using Rails is that if you set :method => :delete like below you will get a whole bunch of obtrusive prototype library javascript injected into the hyperlinks onclick() event. This can clash with your jquery code so you can't use :method => :delete alongside jquery. And it doesn't make any sense to do it this way. The number one reason that someone (err... yes, me!) will get into this mess is that they've been using the image_tag and link_to helper's and just forgotten that all this extra prototype code will be generated. So this is not so good for what we want...

<%= link_to image_tag('/images/delete.png', :title => 'Delete the thing', :class => 'clearPrintQueueOnClick'), '/things/3', :method => :delete %>

But this is better...

<%= link_to image_tag('/images/delete.png', :title => 'Delete the thing', :class => 'deleteThingOnClick'), '/please_enable_javascript.html' %>

Note: That we have jquery code set up against anything that has the class deleteThingOnClick.

Ok, if the user's browser does not have javascript enabled it will take them to the please_enable_javascript.html which you can drop in your public html. If you want to support non-javascript browsers you can create a page with a form for doing delete requests - an example is shown in this blog entry by Andy Gaskell.

With those pitfalls out of the way, all that remains to do to supress the href is to add event.preventDefault(); to the start of your deleteThingOnClick handler

$("a").click(function(event) {
event.preventDefault();
// rest of your deletion code goes here..
}

That's it really! Exit stage left...

8Oct/100

How to localize model names in ActiveRecord associations via config locales with Ruby on Rails

Argghhh!!! I went bananas for a little while getting my head around this. What are we trying to achieve? Well, say let's we have a model called Consultant which has a many-to-many relationship with Company though a Contract association. The Contract model is basically sitting on topic of a simple join in the database which has consultant_id and and company_id fields.

class Consultant < ActiveRecord::Base
  has_many :contracts
  has_many :companies, :through => :contracts

  accepts_nested_attributes_for :contracts
end

class Company < ActiveRecord::Base
  has_many :contracts
  has_many :consultants :through => :contracts
end

class Contract < ActiveRecord::Base
  belongs_to :consultant
  belongs_to :company

  validates_uniqueness_of :consultant_id, :scope => :company_id,
    :message => "cannot have a contract with the same company more than once"

end

We have a New Consultant page which allows us to associate existing Companies with a Consultant by adding/removing Contracts. A Consultant cannot have a contract with a Company more than once, hence we need a validate_uniqueness_of validation on the Contract association.

But hey, business is booming! We end up needing to reuse the code base for another Rails project. The new project is in the construction domain but it has been decided that the database schema and domain model should remain unchanged. However we are told that as far as the user is concerned they should never see the term Consultant, rather they should see the term Builder. Enter translations!

Though you're not going to put your shoddy Spanish to the test and you failed French before you left school, translations are a handy way to work around this problem. Simply translate the word Consultant into Builder via the config/locales/en.yml file in your Rails project. At the same time we'll also change

  • The validation error header that is present when the user submits an invalid record
  • The displayed version of the consultant_name to be Builder Name
  • The displayed version of the consultant model name to be Builder when arising from errors on the Contract association. The way to do this is not immediately obvious - you have to translate the foreign key field (consultant_id) to Builder for the association

Here's the complete config/locales/en.yml file. Note: Whitespace and indentation is very important.

en:
  activerecord:
    errors:
      messages:
      template:
        header:
          one: "This Builder has just one error but still you gotta fix it..."
          other: "This Builder has lots of errors, get your act together..."
    attributes:
      consultant:
        consultant_name: Builder Name # Handles the work of translating this attribute
      contract:
        consultant_id: Builder # NNB: This the big one! Notice how must translate the foreign key field to Builder for the association!!!
    models:
      consultant: Builder # This causes the consultant model to be referred to as Builder on the UI

So there you have it. The foreign key is the key, so to speak!

The best guide I encountered on translation was this one by Ian Hecker on Translating ActiveRecord which is a great way to get started. There is also a somewhat overwhelming guide to translations at Rails Internationalization (I18n) API but is comprehensive nonetheless. Also, do look at the en-GB.yml example at Sven Fuchs Locale Examples on GitHub.com which is where I first saw how you can define you locale file as an .rb file or yaml as above. Finally, I came across this entry on how to remove Rails Validation Message Prefixes which I didn't try but I just mention here in case I need it in future.

3Oct/100

Getting readline to work with Ruby Version Manager (RVM) on Linux Mint KDE

I couldn't get readline to be picked up using the 'rvm package install readline' command. So instead I had to install the readline development headers as a Debian package

sudo aptitude install libreadline6-dev

And then tell rvm about the /usr directory when installing ruby

(Note: I had run 'rvm package install zlib' and 'rvm package install openssl' before running this next command)

rvm install 1.8.7 -C --with-zlib-dir=$HOME/.rvm/usr --with-openssl-dir=$HOME/.rvm/usr --with-readline-dir=/usr

This solution should also work for Ubuntu.

22Sep/100

Beginning Optimization in MySQL

The first place to start be to run your query using EXPLAIN in order to see what MySQL execution plan. Simply put EXPLAIN in front of your SELECT statement and check the output. Initially, you might think that its output doesn't give hard figures and as a result is pretty awkward to understand. But you'll soon see that it really helps you understand your queries and how they interact with things like indexes. The first page of this article by Ian Gilfillan is a great explanation of explain (bit of a mouthful that!).

The other good starting point is to known how does MySQL do joins? Well, the short answer is the single-sweep multi-join method and if you didn't know that then check out this post by Mike Papageorge.

Cache rich, time poor...

Of course, as you use EXPLAIN you'll try different things in your query and re-run queries to see the difference in performance. You'll want to some hard figures. Each time you run a MySQL query from the MySQL command line, or MySQL Query Browser, it will give you a query execution time. Unfortunately, the second time you run a query the execution time will be drastically shorter - because the results from the previous execution will be in MySQL's Query Cache. The only reliable way I've found to minimise the effect of the cache is to restart the MySQL server after every query (eg. /etc/init.d/mysql restart). It won't give you the exact same metric as, for example, after a reboot of your machine but it's a good line in the sand nonetheless.

Ok, a quick checklist...

The thing is someone else has always done the hard work for you on topics like this. A great place to start is with this checklist by Sevn Welzel. Here's my favourite from that checklist, which I'm listing here more as a memo-to-self than anything else.

Note: That MySQL 5.0 introduced a lot of changes so certain optimizations pre-5.0, such as converting OR statements to UNIONs are no longer needed.

  • Derived tables (subqueries in the FROM clause) can be useful for retrieving BLOBs without sorting them. (Self-join can speed up a query if 1st part finds the IDs and uses then to fetch the rest)
  • Avoid using IN(…) when selecting on indexed fields
  • InnoDB ALWAYS keeps the primary key as part of each index, so do not make the primary key very large
  • This list of Easy MySQL Performance Tweaks
  • Sven also lists a bundle of tips by Alexander Skakunov at AjaxLine the most useful one for me being the way the MySQL Query Optimizer can use the leftmost index prefix - this mean you can define index on several columns so that left part of that index can be used a separate one so that you need less indices (though remember that your index will be bigger overall and hence not a fast to search as a smaller index)

Handpicking Indexes

A big part of optimizing in MySQL is experimenting with different indexes on your database but you don't want to have to keep adding and removing them - as this can take a long time on big tables. Consider using IGNORE INDEX(some_index) if you'd like to see how your query would perform in the absence of an index or FORCE INDEX(some_index) if you'd like make sure MySQL to use's a particular index. By looking a the output of EXPLAIN you can see which indexes are being used. Sometimes, if you know your data well, you can outsmart the MySQL query optimizer. Though be careful when doing so as if the shape of your data changes your optimization might work against you. More details at MySQL Manual Index-hints.

Top optimization picks from the MySQL Documentation

The MySQL docs really are great at explaining a lot of this stuff and the optimization sections are well worth a read. Here I've just selected the bits that were the most useful as I worked through this area and expanded on them in one or two cases.

  • From MySQL SELECT Documentation
    • STRAIGHT_JOIN forces the optimizer to join the tables in the order in which they are listed in the FROM clause.
    • The Irish Penguin says: "This can be really really handy. For example, if you have a GROUP BY clause that references a column in a large table in a query featuring some JOINS, you probably will want to the table containing this column to be the first hit in the query - even if it produces a much higher number of rows examined figure in the EXPLAIN output. My understanding is that the way MySQL decides on its query plan is to put the table that is likely to yield the fewest rows first. But this can be at loggerheads with GROUP BY clauses. It does a similar behaviour when choosing indexes as this MySQL Performance Blog article states"
  • From MySQL INDEX and MULTIPLE-COLUMN INDEX
    • If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to find rows. For example, if you have a three-column index on (col1, col2, col3), you have indexed search capabilities on (col1), (col1, col2), and (col1, col2, col3).
    • If a multiple-column index exists on col1 and col2, the appropriate rows can be fetched directly. If separate single-column indexes exist on col1 and col2, the optimizer will attempt to use the Index Merge optimization (see Section 7.3.1.4, “Index Merge Optimization”), or attempt to find the most restrictive index by deciding which index finds fewer rows and using that index to fetch the rows.
    • If a range scan is possible on some key, the optimizer will not consider using Index Merge Union or Index Merge Sort-Union algorithms
  • Consider running OPTIMIZE TABLE if you have deleted a large part of a table or if you have made many changes to a table with variable-length rows
  • From MySQL Optimizer Issues
    • Use ANALYZE TABLE tbl_name to update the key distributions for the scanned table. See ANALYZE TABLE Syntax
  • From InnoDB restrictions and InnoDB turning
    • An InnoDB table cannot contain more than 1000 columns
    • SHOW TABLE STATUS does not give accurate statistics on InnoDB tables, except for the physical size reserved by the table. The row count is only a rough estimate used in SQL optimization
    • Cascaded foreign key actions to not activate triggers
    • InnoDB does not store an index cardinality value in its tables. Instead, InnoDB computes a cardinality for a table the first time it accesses it after startup. With a large number of tables, this might take significant time. It is the initial table open operation that is important, so to “warm up” a table for later use, access it immediately after startup by issuing a statement such as SELECT 1 FROM tbl_name LIMIT 1.
  • Relating to the Group By Optimization
    • Usually a GROUP BY clause causes a scan of the whole table and the creation of a new temporary table where all rows from each group are consecutive. This temporary table is then used to establish groups and apply aggregate functions. MySQL can sometimes use indexes that avoid temporary table creation if the query is written in a certain way -  all GROUP BY columns must reference attributes from the same index. Also the index must stores its keys in order (for example, this is a BTREE index and not a HASH index). See this InformIT article for the difference between BTEE and HASH indexes and more information
    • Very importantly, make sure that the column(s) involved in the GROUP BY clause are from the lead table in your query. If MySQL's Optimizer is choosing a different table as the lead table try using STRAIGHT_JOIN to force MySQL to first hit the table containing the columns that appear in the GROUP BY when executing the query. Why doesn't MySQL always do this by default? MySQL's Query Optimizer prefers to using indexes for restriction (WHERE clause) rather than sorting (GROUP BY or ORDER BY) that's why you sometimes need to give it this hint
  • Relating to the Limit Optimization
    • The LIMIT clause can speed up things even when applied after an ORDER BY clause. MySQL does not always need to finish the sorting before it can apply the limit. In some cases, you can think of LIMIT as a buffer that MySQL fills up as it sorts the results - MySQL stops as soon as the buffer is filled. For example, if you use LIMIT 10 with ORDER BY, MySQL ends the sorting as soon as it has found the first 10 rows of the sorted result, rather than sorting the entire result. Here's some caveats
      • Avoid using a HAVING clause as this will prevent the optimizations
      • You really want the ordering to use an index. Otherwise if a filesort must be done, all rows that match the query without the LIMIT clause must be selected, and most or all of them must be sorted, before it can be ascertained that the first 10 rows have been found

Some other random musings

And as if that wasn't enough, there'll be a few more updates to this article at a later date. Coffee permitting!

Tagged as: , No Comments
10Aug/101

Ruby Bindings for Qt: Building QtRuby on MeeGo and creating an RPM

MeeGo is great. What could make it even better? More Ruby :-) So what better way to achieve this than by getting the Ruby bindings for Qt up and running on MeeGo. So here's a Work In Progress guide...

Pre-requisites
Get the MeeGo SDK running on your machine under Xephyr http://wiki.meego.com/MeeGo_SDK_with_Xephyr
I'll assume that you can successfully run the meego-sdk-chroot command and are now at a MeeGo console. Here's what we need to do to build QtRuby...

The Guide
Install cmake:
zypper in cmake

Pull down the kdebindings source code from svn:
svn checkout -N svn://anonsvn.kde.org/home/kde/trunk
cd trunk
svn up -N KDE
cd KDE
svn up kdelibs kdebindings
# The above should be all you need to do but if you have problems then maybe try reading http://en.opensuse.org/openSUSE:KDE_developers_guide

Copy the kdebindings/qtruby directory to your meego home directory in the <meego_sdk_directory>, the latter will be something like /home/yourusername/meego-sdk-0524/home/meego/ depending on where you installed the MeeGo SDK earlier.

Copy the file kdebindings/CMakeLists.txt.qtruby to /home/meego/qtruby/CMakeLists.txt (yes, this will overwrite the old file. This is ok, we don't want to build all of kdebindings, just qtruby)

cd <meego_sdk_directory>/home/meego/qtruby

Edit the new CMakeLists.txt, underneath the line "include (MacroOptionalFindPackage)" add the lines:
include (MacroOptionalAddBindings)
include (MacroLogFeature)
include (CheckCXXSourceCompiles)

Also, just before the line "add_subdirectory(smoke)" add the ine:
add_subdirectory(generator)

Finally, if you want to be able to build an RPM (or any other package type supported by the CPack tool), add the following line as the very last line in the CMakeLists.txt file:
include(CPack)

Ok now we need to create a cmake/modules directory
mkdir -p qtruby/cmake/modules

cd qtruby

As the CMakeLists.txt file says in the commented section, we need to copy some files we need from the KDE related directories (this is because we are building QtRuby standalone instead of as part of the all-encompasing kdebindings module). Note, you need to change the location of kdelibs in the next command to wherever you pulled down the subversion directory

cp kdelibs/cmake/modules/FindQt4.cmake ./cmake/modules/
cp kdelibs/cmake/modules/FindRUBY.cmake ./cmake/modules/
cp kdelibs/cmake/modules/MacroOptionalFindPackage.cmake ./cmake/modules/
cp kdelibs/cmake/modules/MacroPushRequiredVars.cmake ./cmake/modules/

Additionally you will need to copy the following files

cp kdelibs/cmake/modules/Qt4Macros.cmake ./cmake/modules/
cp kdelibs/cmake/modules/Qt4ConfigDependentSettings.cmake ./cmake/modules/
cp kdelibs/cmake/modules/HandleImportedTargetsInCMakeRequiredLibraries.cmake ./cmake/modules/
cp kdelibs/cmake/modules/MacroLogFeature.cmake ./cmake/modules/
cp kdelibs/cmake/modules/CheckCXXSourceCompiles.cmake ./cmake/modules/

And also copy these from kdebindings

cp kdebindings/cmake/modules/MacroOptionalAddBindings.cmake ./cmake/modules/
cp -r kdebindings/ruby .
cp -r kdebindings/smoke .
cp -r kdebindings/generator .

Now we are going to create a qtruby_build directory so that we can do an out-of-source build of qtruby. If you don't know what an out-of-source build is, don't worry!
cd ..
mkdir qtruby_build
cd qtruby_build

Create a file called cmake_qtruby. Copy and paste the long commented cmake command in CMakeLists.txt to this file (you can exclude the make and make install commands)

At the end of the last line of this command add a backslash (so that you can continue the command on the next line) and then add the line:
../qtruby

Then change the cmake command options
-DRUBY_EXECUTABLE=/usr/bin/ruby
-DRUBY_INCLUDE_PATH=/usr/lib/ruby/1.8/i386-linux/

At the end of this step the file should look something like

cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DRUBY_EXECUTABLE=/usr/bin/ruby \
-DRUBY_INCLUDE_PATH=/usr/lib/ruby/1.8/i386-linux/ \
-Wno-dev \
-DENABLE_SMOKE=on \
-DENABLE_QTRUBY=on \
-DENABLE_QTWEBKIT_SMOKE=off \
-DENABLE_QTSCRIPT_SMOKE=off \
-DENABLE_QTUITOOLS_SMOKE=off \
-DENABLE_QTTEST_SMOKE=off \
-DENABLE_PHONON_SMOKE=off \
-DENABLE_QSCI_SMOKE=off \
-DENABLE_QWT_SMOKE=off \
-DENABLE_KDE_SMOKE=off \
-DENABLE_KDEVPLATFORM_SMOKE=off \
-DENABLE_KHTML_SMOKE=off \
-DENABLE_KTEXTEDITOR_SMOKE=off \
-DENABLE_SOLID_SMOKE=off \
-DENABLE_PLASMA_SMOKE=off \
-DENABLE_QTWEBKIT_RUBY=off \
-DENABLE_QTUITOOLS_RUBY=off \
-DENABLE_QTSCRIPT=off \
-DENABLE_QTTEST=off \
-DENABLE_PHONON_RUBY=off \
-DENABLE_QSCINTILLA_RUBY=off \
-DENABLE_QWT_RUBY=off \
-DENABLE_SOPRANO_RUBY=off \
-DENABLE_KDEVPLATFORM_RUBY=off \
-DENABLE_KORUNDUM_RUBY=off \
-DENABLE_KHTML_RUBY=off \
-DENABLE_KTEXTEDITOR_RUBY=off \
-DENABLE_SOLID_RUBY=off \
-DENABLE_KROSSRUBY=off \
-DENABLE_PLASMA_RUBY=off \
-DENABLE_QIMAGEBLITZ_SMOKE=off \
../qtruby

Make this command executable and run it
chmod u+x cmake_qtruby
./cmake_qtruby

This should go off prepare your qtruby_build directory for compiling. Once it is finished, you should be able to install by any one of the following methods

RPM-based Install
You will need to have added the include(CPack) to the CMakeLists.txt file as outlined earlier before running cmake. You also now need to install the following:
zypper install rpm-build
zypper install meego-rpm-config # Maybe you dont need this but I installed it anyway

Now all you need to do is run 'make package' and then 'cpack -G RPM' to build the RPM. You will find that the generated RPM install is called kdebindings-0.1.1-Linux.rpm. That's because we were originally pulled all our qtruby code out of the kdebindings codebase - you can customize the package name, version and much much more by passing parameters to the cpack command when generating the rpm. You can check what values were used to build the package by viewing the CPackSourceConfig.cmake file. As I was just building this rpm for personal use, I didn't bother changing any package details. Tut! Tut! Anyway, once you have an rpm you are happy with, simply install the QtRuby bindings on your system via:
rpm -i <your_generated_rpm_name>

Note: If you want to see the RPM spec file generated, have a look at _CPack_Packages/Linux/RPM/SPECS/kdebindings.spec

Deb-based Install (and other package types)
This is pretty much identical to the RPM-based Install. The difference is to use 'cpack -G DEB' instead of 'cpack -G RPM'

Source-based Install
All need to do 'make' and 'make install' to get the QtRuby bindings installed onto your system. Not quite as easy to undo as an package based installation though!

Testing that everything works
I only tested the RPM package installation method. I found that when running the rbqtapi command I got the following error

/usr/lib/ruby/site_ruby/1.8/i386-linux/qtruby4.so: libsmokeqtcore.so.3: cannot open shared object file: No such file or directory - /usr/lib/ruby/site_ruby/1.8/i386-linux/qtruby4.so (LoadError)
from /usr/lib/ruby/site_ruby/1.8/Qt4.rb:5
from /usr/local/bin/rbqtapi:6:in `require'
from /usr/local/bin/rbqtapi:6

This was because some of the qtruby libraries installed into /usr/local/lib which my MeeGo system does not check for libraries by default. I changed this by adding the file /etc/ld.so.conf.d/qtruby-i386.conf which simply contained the line:
/usr/local/lib
And then running the ldconfig command. Then the rbqtapi command worked happily!

This guide still needs some polish. We'll get to that eventually, but hopefully it may be of some use in getting the Ruby and Qt playing real nice together on MeeGo!