Thursday Night

Paul Betts’s personal website / blog / what-have-you

A C# 3.5 pattern – the Accept Block pattern

View Comments

A coworker pointed me towards this blog post as a useful trick to make code read cleaner. I’ve been using this trick in C# for quite some time, as it’s a very fundamental pattern in Ruby programming. In my head I call this the “Accept Block” pattern, but I’m fairly certain its just a syntactic version of an existing pattern (the Strategy pattern?). In some sense, it’s like being able to write your own version of the “using” or “lock” statements.

Here’s the old imperative way you might write some code:

void Foo()
{
    SetupTheDatabase();
    bool ShouldExit = SomeFunctionThatNeedsADatabase();
    TeardownTheDatabase();

    if (ShouldExit)
        return;

    DoOtherStuff();
}

And here’s how you’d rewrite it using the pattern:

void WithEnsureDatabaseIsSetup(Action block)
{
    SetupTheDatabase();
    try {
        block()
    } finally {
        TeardownTheDatabase()// Note: Make sure this doesn’t throw!
    }
}

void Foo()
{
    bool ShouldExit;

    WithEnsureDatabaseIsSetup(() => {
        ShouldExit = SomeFunctionThatNeedsADatabase();
        if (ShouldExit)
            return;
    });

    DoOtherStuff();
}

In my opinion, the 2nd version is better to read, and more importantly, allows you to encapsulate the “setup/teardown” pattern – this way, this block of code is consistent, removes copy-paste errors from writing the same thing over and over again, and is easily updated if you want to do additional work when setting up the database.

But there’s a gotcha!

There’s a bug in the above code though that’s quite subtle, and that has bitten me a few times – the syntax () => { } is defining a closure, an anonymous function who can use variables bound inside its lexical environment (to understand the difference, take a look at that ShouldExit variable – even though it’s not a parameter of the function, we were still able to use it). When you call return, in the original example we will exit Foo() – in the new version, we will exit the closure and still execute DoOtherStuff()! Here’s how we should fix it:

void Foo()
{
    bool ShouldExit;

    WithEnsureDatabaseIsSetup(() => {
        ShouldExit = SomeFunctionThatNeedsADatabase();
    });

    if (ShouldExit)
        return;     // Now we’ll return properly

    DoOtherStuff();
}

Ruby doesn’t have this problem

This is a fundamental pattern in Ruby and built into the language and the runtime, so much so that it has special syntax to make it happen. However in Ruby a “block” is a slightly different syntactic structure than a function, so return will do what you expect:

def Foo(an_array)
    an_array.each { |item|  # This is a block with 1 param
        print item
        return if item > 2  # Actually returns from Foo, not from block
    }
end

Written by Paul Betts

January 10th, 2010 at 9:25 pm

Posted in Mono / .NET,Ruby

Yikes! for nerds: how to get the code

View Comments

I ran out of time yesterday, but as promised, here’s how to build and run Yikes!

Quick Start

git clone git://github.com/xpaulbettsx/yikes.git
cd yikes
rake && rake ffmpeg
ruby lib/main.rb -l /path/to/videos -t /path/to/ipod/output -r 1800 -b

Getting the code

By far, the best way to get the code is via Git; this lets you view the entire commit history, as well as send me changes. If you don’t have Git, you can download precompiled source code trees for Linux or Mac OS X 10.5. The Git clone URL via Github is git://github.com/xpaulbettsx/yikes.git

Building (“Huh? Building? On Ruby?”)

(If you downloaded the precompiled version, skip this part!) Even though the application is in Ruby, we need to build ffmpeg and its associated libraries from source, so you need to have the XCode tools installed, and you probably need MacPorts as well. While building this takes forever, it’s fairly easy:

rake && rake ffmpeg

Running the app

Right now, you have to run Yikes! from the command line, but the syntax is pretty easy. Here’s a sample:

cd yikes_public

# The long version
ruby lib/main.rb –library /path/to/videos –target /path/to/ipod/output –rate 1800 –background

# or if you want the short version
ruby lib/main.rb -l /path/to/videos -t /path/to/ipod/output -r 1800 -b

# If you want to run it on the sample files for development, there’s an easier way
rake run

Written by Paul Betts

June 5th, 2008 at 10:27 pm

Posted in Apple,Linux,Ruby,Yikes!

Yikes! It’s your videos on your iPod!

View Comments

For awhile, I’ve been working on a project that is pretty cool, and I’m finally getting near the “first 90% done” software development mark; now I’ve got the 2nd 90% to get it to production-quality, and the 3rd 90% will make it actually good. Here’s the screenshot:


Yes, the UI is rough-draft, I’ve got to go to town on it in CSSEdit

What’s it do?

In its simple mode, Yikes! will take a directory and convert all the movies to iPod/iPhone format (H.264 MPEG-4′s, so compatible with most players), and it will skip files it’s already converted. This isn’t too far off from what you could do with Handbrake and some clever bash scripts.

However, you can also run the program in background mode, and this is where it gets really useful. You give the program a folder of videos, and a place to put the iPod videos, and it will start a web site that you can go to on another computer, where you can see the converted videos, download them, or (and here’s the clever part), add it to iTunes as a video podcast, which will copy all the videos to your iPod automagically.

Where’s the code?

Github! http://github.com/xpaulbettsx/yikes
Update: Changed URL from earlier, merged webif-ramaze into master

Later today once I’m back at home I’ll put up a “how to get/build the code”, as it’s a little tricky. I’m working on official releases for Mac and Linux, and a Windows port is in the future; while I haven’t been coding towards it, I also have made sure to not choose anything that’s completely impossible for Win32.

Thoughts? Ideas? Comments? Want to help?

Since I’m always busy with work, it’s taken me quite a while to get to this point, and I’m definitely open to accepting contributions and making this a real open-source project; so far, I’ve set up Github and a bug tracker (but no mailing list, forums, documentation, etc). If you’re not handy with coding, websites, or art/design, I would even just appreciate suggestions or ideas for cool features. My Email address is paul at paulbetts dot org, let me know!

Written by Paul Betts

June 4th, 2008 at 12:14 pm

Posted in Apple,Linux,Ruby,Yikes!

Getting a backtrace in Ruby

View Comments

Here’s a handy trick I found while trying to practice more of “red-green-refactor”, a method that will dump the stack of every thread without halting the application. Note that this trick uses fork(), so Windows Rubyists are out in the cold (all three of them).

def dump_stacks
    fork do
        ObjectSpace.each_object(Thread) do |th|
            th.raise Exception, "Stack Dump" unless Thread.current == th
        end
        raise Exception, "Stack Dump"
    end
end

This is courtesy of Robert Klemme, via the Ruby Talk mailing list

Written by Paul Betts

December 25th, 2007 at 11:20 pm

Posted in Ruby

A powerful UI programming metaphor from Aaron Hillegass

View Comments

Once upon a time (before Baywatch), there was a man with no name. Knight Industries decided that if this man were given guns and wheels and booster rockets, he would be the perfect crime-fighting tool. First they thought, “Let’s subclass him and override everything we need to add the guns and wheels and booster rockets.” The problem was that to subclass Michael Knight, you would need to know an awful lot about his guts so that you could wire them to guns and booster rockets. So instead, they created a helper object, the Knight Industries 2000 Super Car, or “Kitt”.

Notice how this is different from the RoboCop approach. RoboCop was a man subclassed and extended. The whole RoboCop project involved dozens of surgeons who extended the man’s brain into a fighting machine. This is the approach taken with many object-oriented frameworks.

While approaching the perimeter of an arms dealer compound, Michael Knight would speak to Kitt over his watch-radio. “Kitt”, he would say, “I need to get to the other side of that wall.” Kitt would then blast a big hole in the wall with a rocket. After destroying the wall, Kitt would return control to Michael, who would stroll through the rubble.

– from Cocoa Programming for Mac OS X, by Aaron Hillegass

Even if you don’t care about programming on the Mac, you should take a look because the developers at NeXT were really ahead of their time when they created the Cocoa framework. Objective C is like the “metal” version of Ruby, especially when you look at features in Obj-C like how their vtables are structured and their emphasis on introspection and mixins (called “categories” in Obj-C), and Cocoa takes full advantage of these features to make a really elegant, reusable UI framework.

Written by Paul Betts

September 22nd, 2007 at 1:38 pm

pathedit 0.1 – Change your filesystem using your favorite editor

View Comments

I read on one of the Planets about this idea, but I could never find the post so I reimplemented the idea in Ruby. The idea is, you can use a text editor to do mass file moves/renames/copies/etc. I wrote it to organize my downloaded TV shows, and it works pretty well and hasn’t eaten any of my data yet. Of course, the standard caveats apply.

People who are too lazy to read can now instead watch this window

The utility reads paths from either standard input or passed as parameters. Here’s the output from --help

Usage: pathedit [options] file1 file2 file3…
If no files are given, the paths will be read from standard input

Specific options:
    -a, –action type                Action to perform (one of ‘copy’, ‘move’, ‘symlink’)

Common options:
    -d, –debug                      Run in debug mode (Extra messages)
    -v, –verbose                    Run verbosely
    -h, –help                       Show this message
        –version                    Show version

Caveats for this version

  • Might give you problems on Windows unless you pass paths as parameters – soon to be fixed
  • Can only use GUI editors in Linux, cause that’s the only operating system that handles GUI apps correctly – hopefully I can fix this too

Download it!

Written by Paul Betts

September 21st, 2007 at 12:12 am

Qt4 Ruby and Metaprogramming 0.1 – Wiring up slots automatically

View Comments

In my attempts to learn Qt 4 and QtRuby, it’s pretty obvious that there’s a huge potential for doing Rails-like things, such as declaration by convention. To this end, here’s an example of what you can do with the code I’m writing: this loads a UI file and wires something up to the Open action:

require ‘Qt’

class ActionOpenHandler < Qt::Object
    slots "on_activated()"

    def initialize(main = nil)
        super
        @main = main
    end

    def on_activated
        path = nil
        Qt::FileDialog.new do |fd|
            path = fd.get_open_file_name()
        end
        return unless path

        text = nil; File.open(path, ‘r’) {|f| text = f.read}
        @main.findChild(Qt::TextEdit, "textBrowser").text = text
    end
end

a = Qt::Application.new(ARGV)
QtSuperLoader.new.initialize_and_hook("./main.ui").show
a.exec

Next, I’m seeking to replace the ugly line "@main.findChild(Qt::TextEdit, "textBrowser").text = text" with the more palatable "@main.text_browser.text = text". However, this is a bit more tricky, because findChild creates strongly-typed objects – there may be some trickery to get around it though involving QMetaObject.

Here’s the files, including the code that supports it all: qttest.rb and Translator.ui

Written by Paul Betts

September 8th, 2007 at 10:20 pm

Posted in QT/KDE,Ruby

Extracting a zip file in Ruby

View Comments

I just spent like 2 hours trying to get this damn piece of code to work – trying to extract a zip file to a temporary directory. Most of my problems were because of the lack of documentation in rubyzip, but the end result appears to work. Here it is, obviously you need the abovementioned library from Rubygems.

[‘rubygems’, ‘pathname’, ‘zip/zip’].each {|x| require x}

UUIDchars = ("a".."f").to_a + ("0".."9").to_a
def uuid_seg(len)
  ret = ""
  1.upto(len) { |i| ret < < UUIDchars[rand(UUIDchars.size-1)] }; ret
end

def random_uuid
  "#{uuid_seg(8)}-#{uuid_seg(4)}-#{uuid_seg(4)}-#{uuid_seg(4)}-#{uuid_seg(12)}"
end

def extract_zip_to_tempdir(zip_path)
  temp_root = Pathname.new((ENV[‘TEMP’] || ENV[‘TMP’] || ‘/tmp’))
  raise "Can’t find a temp directory" unless temp_root.exist?

  # Figure out our temp directory
  temp_dir = nil
  while (temp_dir = temp_root.join(random_uuid())).exist?
    nil
  end
  temp_dir.mkpath

  ZipFile.open(zip_path) do |zf|
    zf.each do |e|
      if (m = /^(.*)[\\\/][^\\\/]*$/.match(e.name))
        temp_dir.join(m[1]).mkpath
      end
      zf.extract(e.name, File.join(temp_dir.to_s, e.name))
    end
  end

  temp_dir.to_s
end

Written by Paul Betts

July 29th, 2007 at 3:21 am

Posted in Ruby

Don’t worry, I haven’t forgotten QtRuby on Win32!

View Comments

I was planning on posting the same kind of tutorial for Win32 for using QtRuby, but I’m currently stuck as to how to get it to build. After fighting with random build glitches for three hours or so (making progress, slowly), I’m currently stuck here:

Compiled with:
C:/MinGW/bin/g++.exe   -IC:/Qt/4.3.0/include/QtDBus -IC:/Qt/4.3.0/include/QtTest
 -IC:/Qt/4.3.0/include/QtUiTools -IC:/Qt/4.3.0/include/QtScript -IC:/Qt/4.3.0/in
clude/QtSvg -IC:/Qt/4.3.0/include/QtXml -IC:/Qt/4.3.0/include/QtSql -IC:/Qt/4.3.
0/include/QtOpenGL -IC:/Qt/4.3.0/include/QtNetwork -IC:/Qt/4.3.0/include/QtDesig
ner -IC:/Qt/4.3.0/include/QtDesigner -IC:/Qt/4.3.0/include/QtAssistant -IC:/Qt/4
.3.0/include/Qt3Support -IC:/Qt/4.3.0/include/QtGui -IC:/Qt/4.3.0/include/QtCore
 -IC:\Qt\4.3.0\mkspecs/default -IC:/Qt/4.3.0/include/Qt -IC:/Qt/4.3.0/include  C
:/Qt/4.3.0/lib/libQtCore4.a C:/Qt/4.3.0/lib/libQtNetwork4.a C:/Qt/4.3.0/lib/libQ
tSql4.a C:/Qt/4.3.0/lib/libQtXml4.a C:/Qt/4.3.0/lib/libQtGui4.a C:/Qt/4.3.0/lib/
libQtUiTools.a C:/Qt/4.3.0/lib/libQtSvg4.a C:/Qt/4.3.0/lib/libQtOpenGL4.a C:/Qt/
4.3.0/lib/libQt3Support4.a  -o C:\Users\paulbe\AppData\Local\Temp/3428-qtguess C
:\Users\paulbe\AppData\Local\Temp/3428-qtguess.cpp
Compiler output:
C:\Users\paulbe\AppData\Local\Temp/3428-qtguess.cpp:8:2: warning: no newline at
end of file
C:\Users\paulbe\AppData\Local\Temp/ccMxaaaa.o(.text+0×147):3428-qtguess.cpp:
undefined reference to `_imp___ZN12QApplicationC1ERiPPci
C:\Users\paulbe\AppData\Local\Temp/ccMxaaaa.o(.text+0×154):3428-qtguess.cpp:
undefined reference to `QApplication::~QApplication()’

collect2: ld returned 1 exit status

Thoughts? It looks like I’ve got some sort of compiler mismatch (one library compiled with MSVC and one compiled with MinGW, probably). I have no idea where though, I’m 85% sure that Qt is compiled with MinGW

Update: Alright, the new plan is to compile everything from scratch, and see if I can get some better results.

Update 2: It’s definitely the compiler difference:

> objdump -x C:\Qt\4.3.0\lib\libQtGui4.a

{ Snip! }

SYMBOL TABLE:
[  0](sec  1)(fl 0×00)(ty   0)(scl   3) (nx 0) 0×00000000 .text
[  1](sec  2)(fl 0×00)(ty   0)(scl   3) (nx 0) 0×00000000 .idata$7
[  2](sec  3)(fl 0×00)(ty   0)(scl   3) (nx 0) 0×00000000 .idata$5
[  3](sec  4)(fl 0×00)(ty   0)(scl   3) (nx 0) 0×00000000 .idata$4
[  4](sec  5)(fl 0×00)(ty   0)(scl   3) (nx 0) 0×00000000 .idata$6
[  5](sec  1)(fl 0×00)(ty   0)(scl   2) (nx 0) 0×00000000 __ZN12QApplicationC2ERiPPci
[  6](sec  3)(fl 0×00)(ty   0)(scl   2) (nx 0) 0×00000000 __imp___ZN12QApplicationC2ERiPPci
[  7](sec  0)(fl 0×00)(ty   0)(scl   2) (nx 0) 0×00000000 __head_QtGui4_dll

The compiler’s looking for __imp___ZN12QApplicationC1ERiPPci, but the precompiled library has C2. I don’t understand why Qt’s distributing a busted library – this would break even their samples in straight C++ – it’s possible that Mingw updated behind their back though.

Written by Paul Betts

July 22nd, 2007 at 8:32 pm

Posted in Microsoft,QT/KDE,Ruby

Cross-platform UI with Qt4 and Ruby – Mac/Linux HOWTO

View Comments

Today I’ve spent the day working on figuring out how to make UIs using Ruby and Qt4. If you haven’t heard of it, Qt4 is an awesome UI framework written in C++. Since C++ is way too much work, some great KDE devs wrote a bindings generator for Qt4 called qt4-qtruby. While this package is fairly “linuxy”, it’s pretty easy to build it on Mac OS X too, making it possible to write GUI programs for OS X without having to delve into RubyCocoa which has too much hackiness (in my opinion), or even worse, Objective C. Furthermore, your code that you write on OS X will look great on Windows and Linux too!

Starting from scratch

First, install Ruby. If you’re using Linux, you’ll probably use the package manager to install Ruby and the Ruby development libraries! (Ubuntu will run sudo apt-get install ruby irb ruby-dev) OS X Tiger ships with Ruby by default, but you’ll want to install an updated version, via the Ruby one-click installer, then disable the old Ruby by using the following command:

## Only do this on Mac! Linux doesn’t need this nonsense ##
touch ~/.bashrc && echo ‘export PATH="/usr/local/bin:$PATH"’ >> ~/.bashrc
sudo mv /usr/lib/libruby.1.dylib /usr/lib/_libruby.1.dylib

Installing Qt4 and QtRuby

First, install Qt4 by using your package manager on Linux (in Ubuntu, use the -kdecopy packages, they are more up to date), or by downloading the DMG from the Qt/Mac Open Source Edition Download page. You’ll also need MacPorts (and by proxy, the XCode tools). Also, download the Qt4 Ruby bindings source code from Rubyforge and save it to the Desktop.

Here’s the cool thing about QtRuby, and the advantage of building it from source: the build framework for QtRuby scans through whatever version of Qt you have installed, and dynamically builds the bindings. This means, there’s no waiting for new Qt features to be available in Ruby, it’s always up-to-date! Which is quite handy, because it seems like every minor version of Qt has new cool stuff.

Next, we have to do a bit of hackery – unfortunately, there’s no easy way to install QtRuby but it’s not so hard. Here’s what you’ll run:

cd ~/Desktop
sudo port install cmake   ## CMake is a cool build system
tar -xzvf qt4-qtruby-1.4.9.tgz && cd ./qt4-qtruby-1.4.9
cmake .
make && sudo make install

Try it out!

Once you’ve got it built, try this sample code to see some of the new features in Qt 4.3 – this code will run a natively-styled wizard in Windows, Mac, and Linux without any changes! Unfortunately, this code isn’t very elegant or Ruby-like, but it’s a base that someone could write a really elegant UI framework over like RoR.

require ‘Qt’
a = Qt::Application.new(ARGV)

def create_intro_page
        page = Qt::WizardPage.new do |p|
                p.title = "Introduction"
        end

        label = Qt::Label.new("This is a wizard!")
        label.word_wrap = true
        layout = Qt::VBoxLayout.new do |v|
                v.add_widget(label)
        end
        page.layout = layout
        page
end

wiz = Qt::Wizard.new do |x|
        x.add_page(create_intro_page())
        x.set_window_title("Test Wizard")
        x.show
end

a.exec


On Mac OS X

On Linux

In summary:

  1. Install a Ruby that doesn’t suck, and hack your environment so it works right
  2. Install Qt and MacPorts
  3. Build QtRuby and install it
  4. Make UIs for all 3 platforms without hating your life

Written by Paul Betts

July 22nd, 2007 at 6:03 pm