It’s possible to write Linux desktop apps using ruby! All you need is a distribution running KDE 4.2. I have Kubuntu running on my Macbook.
First off, get the Ruby bindings installed:
apt-get install ruby-kde4Next up, create a project directory for your Plasmoid. You can follow along with ‘Rakete’, which is my attempt at a Twitter client. The only thing Rakete does so far is to load and display an SVG.

you can call your root directory anything you like. In my case, it’s ‘application’ instread of ‘rakete’.
The `contents`directory holds the main files in a number of subdirectories. The most important of these is `code`, which, you guessed it, holds your ruby entry point, `main.rb`. `images` holds the SVG we want to render. You can create SVGs with a number of tools such as Adobe Illustrator or Inkscape (open source).
require 'plasma_applet'module Rakete
class Main < PlasmaScripting::Applet
enddef initialize(parent, args = nil)
super
end
enddef init
@svg = Plasma::Svg.new(self)
@svg.imagePath = 'widgets/rakete'
enddef paintInterface(painter, option, contentsRect)
@svg.resize(size())
@svg.paint(painter, 0, 0)
end`main.rb`should contain a class called `Main`, inside of a module named after your application. There are a number of callbacks you have to implement.
First off, you have ìnit`, which is called when the applet is first loaded. In here, we construct Plasma::Svg, which loads up rakete.svg.
SVGs are read from the svg.imagePath. This is relative to the $KDE_ROOT/apps/desktoptheme/default. KDE_ROOT varies from system to system. In the case of Kubuntu, it is /usr/share/kde4. So specifying an svg image path of
@svg.imagePath = 'widgets/rakete'will mean that the svg is searched for under
/usr/share/kde4/apps/desktoptheme/default/widgets/rakete.svgThis lies outside of your Plasmoid directory structure, so the SVGs you package have to be staged into the widgets directory. Currently I don’t see any way of automating this staging process, so you’ll have to copy the svg from images/ over to the widgets directory. I’ll post more info as soon as I get it.
UPDATE 25.12.08: you can reference images inside of your plasmoid directory structure in your code. it turns out that doing so is very easy. applets have a `package` method, which returns an object representing your plasmoid package. the package object can resolve the canonical filename of your svg like this:
@svg.imagePath = package.file_path("images", "rakete.svg")now you don’t need to worry about staging anything.
Next, create the metadata.desktop file:
[Desktop Entry]
Name=Rakete
Comment=an attempt at a better twitter plasmoid using ruby.
Icon=
Type=Service
ServiceTypes=Plasma/Applet
X-Plasma-API=ruby-scriptX-KDE-PluginInfo-Author=Rany Keddo
X-KDE-PluginInfo-Email=purzelrakete@gmail.com
X-KDE-PluginInfo-Name=rakete
X-KDE-PluginInfo-Version=pre0.1
X-KDE-PluginInfo-Website=http://playtype.net
X-KDE-PluginInfo-Category=
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=MIT
X-KDE-PluginInfo-EnabledByDefault=trueReplace the pertinent field values.
Finally, you’ll want to run this thing. Run the following above the plasma root directory:
plasmapkg --upgrade applicationThis will install the Plasmoid on your system, or update it is already installed. Note that if you plasmoid root directory has a different name to “application”, you’ll need to cahnge the packaging command accordingly.
Finally, open the cashew in the top righthand corner of your desktop and select “Add Widget”. You’ll find your widget in the list.
As it stands, Plasma will sometimes crash when running this Applet. I’ll pass this information on to Richard Dale, the maintainer of the Ruby bindings. Hopefully he will be able to locate problems in the runtime, which is still in Beta1.
Richard was also super helpful in getting this example to run. Thank you Richard :-)
I’ll write more posts as I make progress with the Twitter client. You can find Rakete on Github.
Finally, I got around to installing Linux on my Macbook. I needed KDE 4.2 to try out the ruby bindings for Plasma. Here’s how to get Kubuntu up and running on top of VMWare Fusion on OSX with KDE 4.2.
First all, make sure you have the latest version of Fusion installed. If you don’t have Fusion, you can get a trial license here.
If you own a 1.0 Series version of Fusion, Fusion 2 is a free downloadable upgrade and will work with your existing serial number.
Next up, go and download Kubuntu 8.10 here. The download is not as big as you might think – I pulled it down within 10 minutes.
Once you’ve downloaded the image, start up Fusion and add a new Virtual Image with Apple-N. Click “Continue without Disk”, Now select “use operating system installation disk image file” and choose the Kubuntu Image file you just downloaded.
The Kubuntu installer will now launch. You will be asked if you want to boot off disk. Choose to install Kubuntu instead, then follow the rest of the installation process. Just pick the default options for everything.
Now you’ll have a running version of Kubuntu with KDE 4.1. You might find that the Fonts are too small when you launch programs such as the Terminal. If this is the case, go into the System Settings – Appearance – Fonts, and set “Force fonts DPI” to 96 DPI.
Next up, you can upgrade to KDE 4.2 if you like. As of writing, KDE 4.2 is still in Beta1 and only recommended for Developers. If you are following this along to try the Ruby bindings, or just want to see the most recent interface, then dive in :-)
To get on 4.2, follow these instructions from kde.org:
1.Remove the koffice-data-kde4 package. The current koffice2 packages are incompatible with the KDE 4.2 packages since they try to install icons to the same places.
2. Follow the Kubuntu Repository Guide to enable Recommended Updates and add the following to your ‘Third-Party Software’ tab:
deb http://ppa.launchpad.net/kubuntu-experimental/ubuntu intrepid main3. You can now update any existing KDE 4 installation to the most recent version using the Adept Updater tool in your system tray.
4. Now log out and press Alt + E to restart X. When you log in you will have KDE 4.2 Beta 1.
Enjoy.
i’m currently looking for ruby web work. if you’re looking for an experienced developer or know of a project that is looking for developers, then please do contact me.
my preference is for remote work with onsite visits. send details to rany (at) playtype.net.
If you want to send mail asynchronously in your rails app, but don’t want to bother with using a queue server like Starling, then have a go at this…
First, run this:
./script/plugin install git://github.com/purzelrakete/workling.git
./script/plugin install git://github.com/langalex/workling_mailer.git
./script/plugin install git://github.com/matthewrudy/rudeq.git
rake queue:setup
rake db:migratenow add this to your environment:
Workling::Clients::MemcacheQueueClient.memcache_client_class = RudeQ::Client
Workling::Remote.dispatcher = Workling::Remote::Runners::ClientRunner.newFinally, add this into the body of your mailer classes:
include AsynchMailnow start the workling client:
./script/workling_client startdone!
I did some refactoring this week, and the result is a much improved workling. Adding new work brokers is a snap now. I’ll show you how I added RabbitMQ, so that you can go about adding your own brokers. So without further ado…
RabbitMQ, a quick introduction
A lot of Ruby people have been talking about using RabbitMQ as their Queue of choice. Soundcloud.com are using it, as is new bamboo founder Johnathan Conway, who is using it at his video startup http://www.vzaar.com/. He says:
RabbitMQ – Now this is the matrons knockers when it comes to kick ass, ultra fast and scalable messaging. It simply rocks, with performance off the hook. It’s written in Erlang and supports the AMPQ protocol.
Follow the instructions here to get this beauty installed.
Adding Ampq to Workling
There are two new base classes you can extend to add new brokers. I’ll describe how this is done, but the code i show is already a part of workling. Skip to ‘activating amqp in your application’ to see how this is activated.
Clients
Clients help workling to connect to job brokers. To add an AmqpClient, we need to extend from Workling::Client::Base and implement a couple of methods.
require 'workling/clients/base'
require 'mq'
#
# An Ampq client
#
module Workling
module Clients
class AmqpClient < Workling::Clients::Base
# starts the client.
def connect
@amq = MQ.new
end
# stops the client.
def close
@amq.close
end
# request work
def request(queue, value)
@amq.queue(queue).publish(value)
end
# retrieve work
def retrieve(queue)
@amq.queue(queue)
end
# subscribe to a queue
def subscribe(queue)
@amq.queue(queue).subscribe do |value|
yield value
end
end
end
end
end
Were’s using the eventmachine amqp client for this, you can find it up on github. connect and close do exactly what it says on the tin: connecting to rabbitmq and closing the connection.
request and retrieve are responsible for placing work on rabbitmq. The methods are passed the correct queue, and a value that contains the worker method arguments. If you need control over the queue names, look at the RDoc for Workling::Routing::Base. In our case, there’s no special requirement here.
Finally, we implement a subscribe method. Use this if your broker supports callbacks, as is the case with amqp. This method expects to a block, which we pass into the amqp subscribe method here. The block will be called when a message is available on the queue, and the result is yielded into the block.
Having subscription callbacks is very nice, because this way, we don’t need to keep calling get on the queue to see if something new is waiting.
So now we’re done! That’s all you need to add RabbitMQ to workling. Configure it in your application as descibed below.
Invokers
There’s still potential to improve things though. Workling 0.4.0 introduces the idea of invokers. Invokers grab work off a job broker, using a client (see above). They subclass Workling::Remote::Invokers::Base. Read the RDoc for a description of the methods.
Workling comes with a couple of standard invokers, like the BasicPoller. This invoker simply keeps hitting the broker every n seconds, checking for new work and executing it immediately. The ThreadedInvoker does the same, but spawns a Thread for every Worker class the project defines.
So Amqp: it would be nice if we had an invoker that makes use of the subscription callbacks. Easily done, lets have a look:
require 'eventmachine'
require 'workling/remote/invokers/base'
#
# Subscribes the workers to the correct queues.
#
module Workling
module Remote
module Invokers
class EventmachineSubscriber < Workling::Remote::Invokers::Base
def initialize(routing, client_class)
super
end
#
# Starts EM loop and sets up subscription callbacks for workers.
#
def listen
EM.run do
connect do
routes.each do |queue|
@client.subscribe(queue) do |args|
run(queue, args)
end
end
end
end
end
def stop
EM.stop if EM.reactor_running?
end
end
end
end
end
Invokers have to implement two methods, listen and stop. Listen starts the main listener loop, which is responsible for starting work when it becomes available.
In our case, we need to start an EM loop around listen. This is because the Ruby AMQP library needs to run inside of an eventmachine reactor loop.
Next, inside of listen, we need to iterate through all defined routes. There is a route for each worker method you defined in your application. The routes double as queue names. For this, you can use the helper method routes. Now we attach a callback to each queue. We can use the helper method run, which executes the worker method associated with the queue, passing along any supplied arguments.
That’s it! We now have a more effective Invoker, which we can activate in our application like this…
Configuring your application to use AMQP (with RabbitMQ)
Again, follow the instructions here to get RabbitMQ running on your OSX development machine.
Workling::Remote.invoker = Workling::Remote::Invokers::EventmachineSubscriber
Workling::Remote.dispatcher = Workling::Remote::Runners::ClientRunner.new
Workling::Remote.dispatcher.client = Workling::Clients::AmqpClient.new
enjoy!



