Git for Rubyforge accounts

Posted by Dr Nic on April 08, 2008

rubyforge has git - account creation

First there was CVS, then came SVN to RubyForge. Actually, I’m guessing that CVS was the sole SCM initially, and SVN was added later. I just can’t imagine them starting RubyForge from scratch and explicitly saying “yeah we’ll offer CVS because …”. I don’t know how that sentence would have finished. It must have been added first. There is no valid “because …”.

But now, with each RubyForge project there is a Git repository. This is great for two very good reasons:

  1. the end is nigh for empty or unmaintained SVN repositories
  2. less centralised decentralised development

GitHub + Gitorious are the go-to-guys for somewhere to hang your proverbial hat: somewhere you push your local git repository to so other people can access it.

Yet when I’m investigate someone’s new RubyGem or other project, the first place I look for its source is RubyForge. I assume the project name is the same as the gem name, and goto http://rubyforge.org/projects/pastiepacker for example.

rubyforge scm link

Then I click on the SCM tab. Normally this gives SVN instructions. In this modern era, many projects SVN repos can now be blank or unmaintained with Git repos being preferred by many.

So, the reason to push your git repository to RubyForge’s new git system is to make life easier for me. I mean, I don’t know who else clicks on the SCM link, but I do.

While this is all well and great for new projects - you can select “git” instead of “svn” as per the first image above - but I’m not yet sure how to migrate old projects [follow support ticket].

The other reason is to actually help your distributed repository be distributed. Push it to github. Push it to gitorious. And now you can push it to rubyforge. Sweet.

Adding another remote repository

Since your default remote repository is probably called “origin”, you may wonder how such a naming schema could ever expand to multiple remote repositories? Might I suggest “rubyforge” as the name of the rubyforge repository?

git remote add rubyforge gitosis@rubyforge.org:pastiepacker.git
git push rubyforge master
git push origin master

If you do this for all your projects, perhaps a bash script is in order:

function gpall() {
  git push rubyforge master
  git push origin master
}

One project equals one repository, but multiple packages

Using a Rubyforge project’s git repository might be problematic where you release multiple packages/rubygems (codeforpeople, seattlerb, mongrel, drnicutilities, etc). Here I’d prefer one repository per package, rather than one repository for the whole “project”.

Perhaps you could push the master branch from your local repository for each package into different branches of the rubyforge git repository. Thoughts?

Can’t push to your rubyforge git repo?

From the FAQ:

RubyForge Git repositories are managed via gitosis; gitosis does authentication via public keys. This means that in order to push to a RubyForge Git repository you’ll need to upload a public key to your account - see notes on that here.

Generally, Git support is something we’ve just introduced, so feedback about it on the forums would be quite welcome.

What is Pastie Packer?

I can’t tell you. Its a secret.

The explicit Ruby metaclass you know you always wanted

Posted by Dr Nic on April 03, 2008

When you define a “static” or “class” method on a Ruby class, it actually stores the method on that class’s metaclass/singleton class/eigenclass.

_why’s metaid gem gives you a metaclass method to explicit access this object:

require 'metaid'
class Person
  def self.oldest
    # find oldest person
  end
end
Person.methods.grep(/oldest/) # => ['oldest']
Person.metaclass.instance_methods.grep(/oldest/) # => ['oldest']

So now here’s a new, fun way to access the metaclass of a class, look for a constant suffixed with ‘Metaclass’. For the Person class, look for PersonMetaclass. Yep, we can have explicit metaclass constants. Or try PersonClass or PersonEigen or PersonEigenclass. No one can agree on what they are called, so I made them all work.

$ gem install magic_metaclass
$ irb

In irb try:

require 'rubygems'
require 'magic_metaclass'
class Person; end
Person
# => Person
PersonMetaclass
# => #<Class:Person>
PersonClass
# => #<Class:Person>
PersonEigenclass
# => #<Class:Person>
PersonEigen
# => #<Class:Person>

Neat.

Finally, the example from above:

class Person
  def self.oldest
    # find oldest person
  end
end
PersonMetaclass.instance_methods.grep(/oldest/) # => ['oldest']

I wrote this gem with no known use cases. If you find any, let me know.

Writing C extensions in RubyGems using newgem generators (plus a free TextMate bundle)

Posted by Dr Nic on April 01, 2008

Already know C extensions in RubyGems? Cool - then just run the following cmds and see what can be generated for you; plus check out the TextMate bundle at the bottom.

sudo gem install newgem
newgem pickaxe
cd pickaxe
script/generate extconf my_test
rake test

For everyone else…

Its 15000km from Brisbane AU to Prague CZ where Euruko2008 - the European Ruby Conf - was held. I came ready to talk, to met lots of cool multi-lingual Rubyists, and to learn. Ooh, I learnt something alright.

Tim Becker was introducing Native C Extensions for Ruby, and fortunately he said “now, everyone, follow along with this example”. I’d never done native C extensions, but I’d received lots of requests from RubyGem developers on how to do it. I had no idea.

So I was typing in everything Tim told me to type in. When Tim changed slides too quickly, I may have yelled at him to slow down. Perhaps I was the only one doing his tutorial out of 300 people, but I didn’t care. This was gold.

After he finished his session, I dragged him off into the corridor with Jonas Pfenniger (zimbatm), and the three of us mapped out a generic layout for how native C extensions work within RubyGems. I didn’t know any of this, but Tim and Jonas did, and we probably looked silly sitting at a small table in the middle of the narrow corridor.

But at the end, we had a working RubyGem with native C extensions that were built: when the tests were executed via rake, and when the gem was installed. The next day I figured out how to get the C extension built via autotest.

Thanks to Tim and Jonas I was able to then write a extconf generator for RubyGems so that its super-super easy to get started writing native C extensions within RubyGems.

Tutorial

This tutorial is for *nix, as I’m still investigating win32 extensions, and jruby + .net/ironruby extensions. So when I figure that out - hopefully with the help of other people currently at RubyFools conferences, I’ll get back to you.

The code comes from the Pickaxe book - p264, and we’ll insert it into a new RubyGem using newgem (version 0.20.1+):

sudo gem install newgem
newgem pickaxe
cd pickaxe
script/generate extconf my_test

Create a test for a class MyTest that doesn’t exist yet:

# test/test_my_test_extn.rb
require "test/unit"
require 'pickaxe'

class TestMyTestExtn < Test::Unit::TestCase
  def test_working
    t = MyTest.new
    assert_equal(Object, MyTest.superclass)
    assert_equal(MyTest, t.class)
    t.add(1)
    t.add(2)
    assert_equal([1,2], t.instance_eval("@arr"))
  end
end

Run rake to build the C extension and run the tests. You can also run autottest and it will automatically build the C extension before running the tests.

To create the MyTest class, using the code from p262 of the Pickaxe book:

#include "ruby.h"
static int id_push;

static VALUE t_init(VALUE self)
{
  VALUE arr;
  arr = rb_ary_new();
  rb_iv_set(self, "@arr", arr);
  return self;
}

static VALUE t_add(VALUE self, VALUE obj)
{
  VALUE arr;
  arr = rb_iv_get(self, "@arr");
  rb_funcall(arr, id_push, 1, obj);
  return arr;
}

VALUE cTest;
void Init_my_test() {
  cTest = rb_define_class("MyTest", rb_cObject);
  rb_define_method(cTest, "initialize", t_init, 0);
  rb_define_method(cTest, "add", t_add, 1);
  id_push = rb_intern("push");
}

To lib/pickaxe.rb:

require "my_test.so"
# or require 'my_test' if its unique

The last line will import the generated shared library. If the RubyGem is tested or installed on Windows, then the .dll file will be automatically loaded instead. The “.so” notation is merely a placeholder to explicitly specify the shared C-extension, rather than any Ruby library of the same name.

Now run tests (rake), the C extension will be rebuilt and the tests will pass.

Build and install RubyGem

rake manifest:refresh
rake install_gem
irb -rubygems -rpickaxe
> a = MyTest.new
> a.add 3

You have successfully created a C-extension within RubyGems, using TDD.

TextMate bundle for Ruby C extensions

I’ve started a TextMate bundle to give syntax highlighting + some simple snippets for developing the C files for Ruby extensions.

To install:

cd ~/Library/Application Support/TextMate/Bundles
git clone git://github.com/drnic/ruby-c-extensions-tmbundle.git "Ruby C Extensions.tmbundle"

or 

wget http://github.com/drnic/ruby-c-extensions-tmbundle/tarball/master
tar xfv drnic-ruby-c-extensions-tmbundle-master.tar.gz
mv drnic-ruby-c-extensions-tmbundle-master "Ruby C Extensions.tmbundle"

Then restart TextMate or “Reload Bundles”.

You can clone/fork the source via http://github.com/drnic/ruby-c-extensions-tmbundle/tree/master

Training: Get Started Fast with Ruby on Rails

Posted by Dr Nic on March 25, 2008

You probably know a dozen people in Brisbane, or Sydney, or Melbourne or somewhere in between who need to learn Rails. That’s sad, because the 2-day course I’m running on the 19-20th of April only has 7 places remaining. So 12-7=5 of your friends will hate you; but 7 of them will love you and that’s more than 50%.

So they can get uber-edumacated on the Ways of Rails, send them course website or indirectly via the Dr Nic Academy website.

The early bird price ends on 31st of March, so please buy your tickets early. The course is in Brisbane, so if you’re flying in from out of town and need help arranging accomodation etc, ping me.

Read “Wrath of a Mad God” and get closure on Raymond E Feist

Posted by Dr Nic on March 23, 2008

I just finished reading a book.

If you’ve read Magician, by Raymond E Feist, and any of the sequels then you need to read Wrath of a Mad God which has just come out. I know as well as you do that Ray’s work hasn’t been fantastic over the last decade or so. In fact, I stopped reading his books altogether. This is noteworthy since he was the only novelist for whom I used buy each and every book he wrote, in hard cover so I could have the entire collection site nicely on my shelf. I even saw him speak in public once.

Then his books became soft like a wet tissue, and I stopped giving him my money. But I just read his latest book over Easter, and now you must read it too.

Similarly if the Catholic church releases the 3rd volume of their “Bible: The Testaments” trilogy, you’d probably grab a copy just to see how the story ends, even if you didn’t really follow the first 2 books.

With “Wrath of a Mad God,” Raymond E Feist has rewarded each any every loyal reader of his multitude of books with a final “this is how it ends” book. I’m prepared to believe that this is Ray’s final book. He might write more because his publisher gives him money to do it, but really this book ties together 20+ books about the fabulous characters from Midkemia. More importantly, this book answers questions.

Who is Nakor?

Who was Macros?

The downside of this book is that its the 3rd book of a trilogy. Over the last few weeks I bought + read them all, so I can’t say whether you can just read this latest one on its own and get full value.

Also, I’m not saying this is the best book you’ll ever read.

But, if you’re like me - yearning for the majestic wars, battles between armies from different planets, interfering Gods, and the superhumans at the center of it all, then its worth taking the final journey: read all three books (starting with Flight of the Night Hawks and Into a Dark Realm).

Need a final excuse to read these books and return to the bosom of all the wonders of Feist’s earlier works?

When I saw Feist speak in public a decade ago, I distinctly remember one thing. He said the problem with having a superhuman like Pug or Tomas is that you constantly need to distract them throughout the whole book so that the other characters have something to do. So Pug hasn’t really done any amazingly jaw dropping since he said “Tremble and despair for I am Power!” in the first book. I think this last book contains another jaw dropping moment worth the price of admission. Unfortunately he is on his own when he does it, so there is no snappy one-line quote to go with it. This is just an example of my final excuse for you to read these books and thus have closure of Raymond E Feist’s world of Midkemia:

The last book is all about Pug. A happy place to finish, just as it was a happy place to start.