[ Content | Sidebar ]

Archives for programming

**MECHANICAL PIG**

June 20th, 2009

Important news! We have successfully simulated a mechanical pig! This breakthrough has been accomplished by the ingenious combination of the PIG INTERFACE LANGUAGE and the PIG CONTROL LANGUAGE.

Sample program:

PIG DIVISION
  GRUNT
  OINK
  GOTO MUD
  PIGNAP
MUD DIVISION
  ROLL
  ROLL
  ROLL
  GOTO TRUFFLES
  PIGNAP
TRUFFLES DIVISION
  EAT
  EAT
  EAT
  GOTO PIG
  PIGNAP

Sample run:

irb(main):001:0> require 'pig'
=> true
irb(main):002:0> PIG1 = MechanicalPig.new 'pig1.PIG'
00000 **MECHANICAL PIG** PIG BRAIN INITIALISED
00001 **MECHANICAL PIG** PIG ENTERS DIVISION PIG
00002 **MECHANICAL PIG** PIG READY FOR LAUNCH
=> MECHANICAL PIG version 0.14c (Starter Edition)
WARNING!! MECHANICAL PIG ARE PROTECTED BY INTERNATIONAL COPYONWRITE AND MUNITIONS EXPORT LAWS! NO WARRANTY. MALFUNCTIONING OF PIG MAY BE HAZARDOUS TO ONE'S HEALTH. YAHYAHYAHYAHYAH!
irb(main):003:0> PIG1.on
00003 **MECHANICAL PIG** DOES GRUNT 
00004 **MECHANICAL PIG** DOES OINK 
00005 **MECHANICAL PIG** DOES GOTO MUD
00006 **MECHANICAL PIG** PIG ENTERS DIVISION MUD
00007 **MECHANICAL PIG** DOES ROLL 
00008 **MECHANICAL PIG** DOES ROLL 
00009 **MECHANICAL PIG** DOES ROLL 
00010 **MECHANICAL PIG** DOES GOTO TRUFFLES
00011 **MECHANICAL PIG** PIG ENTERS DIVISION TRUFFLES
00012 **MECHANICAL PIG** DOES EAT 
00013 **MECHANICAL PIG** DOES EAT 
00014 **MECHANICAL PIG** DOES EAT 
00015 **MECHANICAL PIG** DOES GOTO PIG
00016 **MECHANICAL PIG** PIG ENTERS DIVISION PIG
00017 **MECHANICAL PIG** DOES GRUNT 
...
01272 **MECHANICAL PIG** DOES EAT 
01273 **MECHANICAL PIG** DOES EAT 
01274 **MECHANICAL PIG** DOES EAT 
01275 **MECHANICAL PIG** PIG IS TIRED
01276 **MECHANICAL PIG** DOES SLEEP

Alas extensive simulations demonstrate that many mechanical pigs may meet an unfortunate end:

00004 **MECHANICAL PIG** DOES OINK 
00005 **MECHANICAL PIG** DOES GOTO MUD
00006 **MECHANICAL PIG** PIG ENTERS DIVISION MUD
00007 **MECHANICAL PIG** DOES ROLL 
00008 **MECHANICAL PIG** DOES ROLL 
00009 **MECHANICAL PIG** DOES ROLL 
00010 **MECHANICAL PIG** DOES GOTO BUTCHER
00011 **MECHANICAL PIG** ABORTED (BACON CORE DUMPED)

Further details available from blodgett.

PowerShell and Git living in harmony

June 6th, 2009

I’m porting some of my programs to Windows at the moment in the hopes of getting access to a bigger market. Turns out that git actually works quite nicely in MS PowerShell. How lovely!

ps2

Ruby Toys

June 18th, 2008

UPDATE 6/4/15: this post was previously a page but was removed when I reorganised the sidebar. Check out the rbib project on GitHub.

This page contains a couple of small Ruby utilities I’ve written.

BibTeX parser

A parser for BibTeX databases. Mostly intended for transforming the entries in some way, such as deleting unneeded keys. But it also works as a general purpose BibTeX interface.

Example: remove all the url fields from a database:

BibTeX::Parser.parse('input.bib').map do |entry|
  entry.reject_fields [:url]
end.save('stripped.bib')

Source code: git clone https://nickg@github.com/nickg/rbib.git

Released under the GPLv3.

Future:

  • Documentation
  • Gem installer

A gettext i18n tutorial

May 23rd, 2008

I’ve recently struggled with GNU gettext for internationalizing some of my programs. This, for the benefit of other people who, like me, can’t be bovered to read the documentation, is the method I’ve used successfully:

I’m assuming you have a standard GNU autoconf/automake setup. If you don’t, there’s a lot of manual work to do. I’ve no idea how to do that: better read the manual instead.

There’s a handy tool gettextize which handles a lot of the monkey work for you. Run it in the top-level project directory:

$ gettextize

This will create a bunch of files (in the m4 and po directories), make a few changes to your configure.ac and Makefile.am (backups are created with a ~ suffix) and also print some instructions. Let’s follow them.

The first thing to do is add AM_GNU_GETTEXT([external]) to configure.ac in order to cause autoconfiguration
to look for an external libintl (apparently).

Next rename po/Makevars.template to po/Makevars and open it up. You’ll probably want to change the COPYRIGHT_HOLDER and MSGID_BUGS_ADDRESS to something relevant. I usually add --keyword=i18n to XGETTEXT_OPTIONS because I think the default _ looks pretty ugly.

Now you need to add every file that contains translatable strings to po/POTFILES.in. You can’t use wildcards or directory names — yuk! Something like this should do the trick:

$ find src -name '*.[ch]pp' > po/POTFILES.in

Now it’s time to regenerate the configure script with the gettext macros:

$ aclocal -I m4
$ autoconf

If you try to run configure now, it will complain about a missing config.sub. Luckily automake can add this for us:

$ automake --add-missing
configure.ac:10: installing `./config.guess'
configure.ac:10: installing `./config.sub'

Now run configure in your build directory. You should see some additional NLS messages.

Next we mark some strings as translatable. Make sure you include libintl.h in every source file with translatable strings. Surround the translatable strings with whatever you passed as a keyword in po/Makevars (_ is default, but I prefer i18n). These macros aren’t defined by default, and they need to be aliases to gettext. I usually make a header file i18n.h like this:

#ifndef INC_18N_H
#define INC_18N_H
 
#include <locale.h>
#include <libintl.h>
 
// Macros which xgettext extracts translatable strings from
#define i18n(s) gettext(s)
 
#endif

Now add i18ns around your translatable strings like this:

puts(i18n("Hello world"));

Before any call to gettext you need to execute the following setup code or it won’t work (assuming you’ve included config.h):

setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);

LOCALEDIR is passed to the compiler from my Makefile.am where I have something like:

localedir = $(datadir)/locale
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@

Now we need to (re-)generate the master package.pot file which contains all the translatable strings (where `package’ is the name of your package). We can do this with make dist in the build directory, but the following command will update the .pot and nothing else:

$ make -C po package.pot-update

Again, substitute `package’ for whatever your package name is. Notice that even if you run this in the build tree it will update the file in the source tree (ewww!!).

Finally, we can actually translate something. In the po directory of the source tree run:

$ msginit -l de_DE -i package.pot

Replace de_DE with whatever locale you wish to translate into. It’ll ask you for your email address and create a new de_DE.po file. Open it up and you’ll see a bunch of lines with msgid and msgstr pairs. The msgid is the English (or whatever language you’re translating from) and the msgstr line is the language you’re translating into. So for our example, we change it to:

msgid "Hello world"
msgstr "Hallo Welt"

It’s .gmo files rather than .po files that get distributed and installed. So how do we generate them? This is the bit that really confused me, and the documentation was not helpful. In the end I looked in the makefile source to see how it works. You need to create a file po/LINGUAS listing the available locales, one per line. Like this:

# List of available locales
de_DE
en_GB

There might be an easier way to do this, however. Now run configure to regenerate your makefiles and run:

$ make dist

The .gmo files for each locale should be generated in the po directory of the source tree.

Now if we install the package with make install the translations should be copied to $PREFIX/share/locale (or whatever your LOCALEDIR was). To test it out you can run your program with a non-default LANG environment variable — it should automagically select the correct set of strings, if a translation exists.

For example, to test our German translation we would set LANG to de_DE.UTF-8. You might have problems if your C library is not set up to support this locale (dpkg-reconfigure locales on Debian).

Finally, whenever you make a change to the translatable strings in your program, run the following to update the .pot file:

$ make -C po package.pot-update

Now in the po directory of the source tree, merge the changes into each translation with the following command:

$ msgmerge -U en_GB.po package.pot

Meta-Ruby for the win!

May 17th, 2008

So… let’s suppose you’re hacking away in Ruby and you mistype a method name:

irb(main):001:0> 5.clas
NoMethodError: undefined method `clas' for 5:Fixnum
        from (irb):1

Obviously I *meant* to type ‘class’, but I got the arity (0) right and the spelling wrong.

I propose an extension to Ruby based on the hypothesis that typos are more common than arity errors: if I call an undefined method with arity A on an object then I probably meant to call *one* of the object’s methods of arity A. Just printing an error message is pretty doof since its certainly not what you wanted to happen. A statistically much better solution is to pick one method of the correct arity at random and execute that — it’s going to be right *some* of the time!

How would we do this in Ruby? After little bit of experimentation I produced this:

class Object
  def method_missing(name, *args)
    choices = self.class.instance_methods.collect do |name|
      self.method name
    end
    right_arity = choices.select do |method|
      method.arity == args.length
    end
    which = right_arity[rand(right_arity.length)]
    which.call(*args)
  end
end

Just include this in your program and *all* Ruby objects will have this amazing feature!!!!

Sample run:

irb(main):017:0> 4.asdsa
nil
irb(main):018:0> 4.asdsa
4
irb(main):019:0> 4.asdsa
Fixnum
irb(main):020:0> 4.asdsa
-5
irb(main):023:0> 4.asdsa(7)
11

:D :D :D