I wrote some ruby code today

I’ve been using ditz for a few months now. It’s a bugtracking system like trac or bugzilla except that it doesn’t run in a centralized server. Instead, it lives as a bunch of text files inside your SCM.

Ditz is written in ruby, and it uses yaml files to store all the issues (tickets) and groupings of issues. Ditz allows issues to be grouped into releases.

$ ditz releases
0.6 (unreleased)
0.4 (released 2008-07-27)
0.5 (released 2008-08-20)

I wrote an extension that would show all the issues attached to a particular release, like this:

$ ditz help ri
Show issues for a particular release.
Usage: ditz ri

$ ditz ri
Error: command 'ri' requires a release

$ ditz ri bogus
Error: no release with name bogus

$ ditz ri 0.6
x ditz-61: Use text editor for multiline input where possible.
x ditz-72: add model object post-creation validation
x ditz-71: 'ditz add' shouldn't ask for comments
x ditz-76: allow configuration of whether the editor is used or not
x ditz-69: Store issues in .ditz directory by default
_ ditz-42: support tiny issue identifiers (like #34) in the single-component case
x sheila-1: check for a "git push" having updated the issue db, and reload if so
.... lots more issues snipped for brevity.

Thanks to all the really neat plumbing already built into ditz, my patch was trivial to write:

operation :ri, "Show issues for a particular release", :release do
def ri project, config, opts, release
puts todo_list_for(release.issues_from(project))

Ruby is a pretty neat language and people do neat stuff with symbols. In that code above, the operation method takes the symbol :ri and effectively decorates my ri method with the help text. I’m really impressed by how ditz took the fact that my ri method takes a :release symbol as a parameter, and because of that, it knew how to search in the list of releases and then give me the relevant release.

I learned some neat stuff at clepy last night

Brian Beck showed how to use metaclasses and descriptors to make DSLs with python.

I do this kind of this kind of thing every so often in my code:

def f(x):
class C(object):
y = x
return C

That function takes a parameter and makes and returns a class based on that parameter. Whoop-di-do. I was surprised to learn that you can’t do this:

class C(object):
x = 99
class D(object):
y = x + 1

I gotta explore this some more until it makes sense.

Here’s another neat trick: It isn’t possible to add two classes together:

>>> class C(object):
... pass
>>> C + C
Traceback (most recent call last):
File "", line 1, in
TypeError: unsupported operand type(s) for +: 'type' and 'type'

But if you want to support this, the solution would be to define an __add__ method on the metaclass:

>>> type(C)

>>> class MC(type):
... def __add__(self, other):
... print 'Adding!'
... return 99
>>> class C(object):
... __metaclass__ = MC
>>> C + C

Wacky, right? More realistically, I could build a new class by taking attributes of both classes together. In other words, if class C has a class attribute x, and class D has a class attribute y, then we can use a metaclass to add C and D together to get a new class E, that has both x and y as class attributes.

In this example, C has a class attribute x and D has a class attribute y. When I add the two classes, I get a new class with both of those class attributes.

>>> C.x, D.y
(99, 98)
>>> E = C + D
>>> E.x, E.y
(99, 98)

Here’s the metaclass that allows this sort of nonsense:

class MC(type):

def __add__(self, other):

class E(self):

for k,v in other.__dict__.items():
if k not in ('__dict__', ):
setattr(E, k, v)

return E

Anybody want to meet up on Wednesday night before PyWorks?

speaker button I’m doing a talk at PyWorks, and I’m getting into town Wednesday afternoon.

Anybody want to get dinner or meet up that evening? We can talk about Python or theorize about these things.

Anyhow, the slides for my talk are here. I’m going to update them before the talk with more detail on class decorators vs metaclasses. I welcome feedback.