C# export for Gaphor

Gaphor is the best free UML tool for X I've seen yet. It's far from finished but at least it produces pretty graphs. I started writing a C# export plugin for it. The first somewhat working version is available. This has been developed with 0.10.4, no guarantees of it working with any other version. No guarantees of it working with that version either, to be exact, but at least it works for me.

Extract it inside Gaphor's source directory, in gaphor/data/plugins.

Article page

Python, Queue, Pygame and the GLib mainloop

The GLib mainloop is what you're probably running in your Python program when you are using PyGTK or GStreamer.

Sometimes you want to integrate other event sources to it. The documentation for this is a bit thin; all I've seen is GLib's page on the main event loop, GSourceFuncs section and test-source.py in pygobject. Here I'm presenting two snippets displaying how to do it with two systems I've needed to work with. No guarantees on their correctness, but they do seem to work. Both are parts of larger modules, so they aren't usable by themselves and aren't really tidied up to look like proper examples. However, they should give you the general idea.

Here's how to do it with Python's Queue:

class QueueSource(gobject.Source):
    def __init__(self, queue):
        gobject.Source.__init__(self)
        self._queue = queue
        self.logger = loghelper.get_logger(self)

    def prepare(self):
        return False

    def check(self):
        return not self._queue.empty()

    def dispatch(self, callback, args):
        self.logger.debug("dispatch called, callback: " + str(callback))
        if callback is not None:
            self.logger.debug("dispatch calling callback: " + str(callback))
            v = callback(self._queue.get(), *args)
            self.logger.debug("dispatch returned " + str(v))
        return True

    def finalize(self):
        self.logger.debug("finalize called")


m = QueueSource(self._queue)
def my_callback(command, *args):
    self.logger.debug("my_callback: args: " + str(command) + ", " + str(args))
    self.logger.debug("my_callback: thread: " + str(threading.currentThread()))
    if command == self.PLAY:
        self._player.play()
    elif command == self.STOP:
        self._player.stop()
    elif command == self.SKIP:
        self._player.skip()

m.set_callback(my_callback, mainloop)
m.attach()

And here's Pygame:

class PygameEventSource(gobject.Source):
    def __init__(self):
        gobject.Source.__init__(self)
        self.logger = loghelper.get_logger(self)

    def prepare(self):
        return False

    def check(self):
        try:
            pygame.event.pump()
            p = pygame.event.peek(
                [KEYUP, KEYDOWN, VIDEOEXPOSE, VIDEORESIZE, NUMEVENTS, QUIT,
                 ACTIVEEVENT, USEREVENT])
            return p
        except Exception, ex:
            self.logger.error("Caught an exception while checking for events",
                              exc_info=True)

    def dispatch(self, callback, args):
        if callback is not None:
            try:
                e = pygame.event.poll()
                v = callback(e, *args)
                return v
            except (KeyboardInterrupt, SystemExit):
                self.logger.warn(
                    "Caught a terminating exception while dispatching to the "
                    "callback, re-raising", exc_info=True)
                pygame.display.quit()
                raise
            except Exception, ex:
                self.logger.error(
                    "Caught an exception while dispatching to the callback",
                    exc_info=True)
        return True

    def finalize(self):
        pass

def my_callback(self, event, *args):
    if event.type == QUIT:
        sys.exit()
    if event.type == KEYDOWN:
        self.logger.debug("my_callback: keydown: event.key: " + str(event.key))
        if event.key in (K_q,):
            sys.exit()
        elif event.key in (K_n, K_SPACE):
            self._player.skip()
        elif event.key in (K_p,):
            if self._player.playing:
                self._player.stop()
            else:
                self._player.play()

    return True


def start_mainloop(self, mainloop):
    self.logger.debug("Starting mainloop")
    if not self._started:
        s = PygameEventSource()
        s.set_callback(self.my_callback, mainloop)
        s.attach()
    return
Article page

One of Those Things You Don't Know If You Should Post in Your Blog Or on TheDailyWTF

From Rails, or more specifically, ActiveSupport's json.rb:

# When +true+, Hash#to_json will omit quoting string or symbol keys
# if the keys are valid JavaScript identifiers.  Note that this is
# technically improper JSON (all object keys must be quoted), so if
# you need strict JSON compliance, set this option to +false+.
mattr_accessor :unquote_hash_key_identifiers
@@unquote_hash_key_identifiers = true
Article page

AudioFormat 0.4 released

After a longish break, released a new AudioFormat when I noticed how aggravating the current version was :-)

The new version, 0.4, allows you to add files to the list of files to convert via a file selector or by dragging. It also should handle and report errors a bit better. And maybe it'll even recognize Vorbis files? Although I suspect it'll get very confused if it encounters something like Ogg Tarkin files. Will have to work on that a bit more.

Enjoy.

Article page

Unit conversion in Java

JUGC is a Java library for unit conversions. It allows you to define a set of units and their relationships (a kilogram is a thousand grams, a tonne is a thousand kilograms, etc), translations for those units (gramma is fi_FI for gram), generate a Java library from those units (well, most of the library won't be generated, but the unit definitions will be) and then deploy that library in a project.

So basically you'll go from unit definitions like this:

    <units>
            <unit>
                    <id>fahrenheit</id>
                    <alias>F</alias>
                    <derive>celsius</derive>
                    <from>9 5 / * 32 +</from>
                    <to>32 - 9 5 / /</to>
            </unit>

            <unit>
                    <id>rankine</id>
                    <alias>R</alias>
                    <derive>fahrenheit</derive>
                    <from>459.67 +</from>
            </unit>
    </units>

to converting units like this:

    ConverterFactory.getConverter("celsius", "rankine").convert(42);

And the translation support is pretty simple, too:

    <units>
            <unit>
                    <id>gram</id>
                    <alias>g</alias>
            </unit>

            <unit>
                    <id>kilogram</id>
                    <alias>kg</alias>
                    <derive>gram</derive>
                    <from>1000 /</from>
            </unit>
    </units>

    <unittrans>
            <locale>fi_FI</locale>

            <translation>
                    <unit>gram</unit>
                    <trans>gramma</trans>
            </translation>

            <translation>
                    <unit>kilogram</unit>
                    <trans>kilogramma</trans>
            </translation>
    </unittrans>

And then in your code:

    ConverterFactory.getConverter("gramma", "kilogramma", "fi_FI").convert(42);

The conversion expressions are in RPN.

I have yet to make a release and it's not totally finished — it should be possible to ask for the conversions to be done with arbitrary precision math, for instance — but I believe it's pretty usable already.

License: BSD sans advertising clause.

Article page

Stamp out the ants

If learning a simple, conceptually mainstream language such as Ruby is too high a price to pay to get away from the madness of Ant and Maven, as it seems to be for some people commenting on Raven, I'm inclined to think you are in the wrong line of work. And Ant and Maven are hardly zero learning curve tools just because the syntax uses XML.

It's possible that Raven (or JRake) isn't the right solution, but the irrational fear evident, for example, in this TheServerSide thread, would be hard to believe if it wasn't just business as usual in the Java world.

Article page