Creating a "New" Gem for "Nu" - From 0 to 100 in 24 Hours

Has it really been 24 hours since I jumped on the nu project bandwagon? Sure has. Let’s take a step back first.

Where Have We Been?

For months now (or maybe it’s been years) the .NET community has been talking about some kind of third party dependency package system. The much heralded RubyGems has always been brought up as the model. It was a bold and noble idea. Being able to package up .NET third party assemblies so new projects can hit the ground running.

Rob Reynolds (aka The Fervent Coder) has a great post explaining the hoopla we go through today to try to find a site, download a tools, unzip, reference, lather, rinse, repeat on every single project we do. He goes on to explain there are too many decisions in this process, it’s fragile, hard to manage, etc. Basically being able to pull down all my dependencies that I’m going to use at the start of a project (and add new ones as I go along) by issuing a single command excites the hell out of me.

Getting Ruby with It

I’ve been a long fan of Ruby, getting into it last year as I tried to find a better way to express automated testing via BDD specifications in a natural language and always finding myself turn to Ruby as a language to help with this. Dynamic languages and duck typing is the cat’s meow and I’m glad to see splinters of the DLR getting better and better in the .NET world every day.

There’s been many attempts and even full blown packaging systems built for .NET but nothing has really picked up any traction. Then about 2 weeks ago the “nu” project was born out of the efforts of people like Roby Reynolds and Dru Sellers got down and put something together. Rather than continuing the efforts of trying to build a native .NET “gem” packager, why not just use gems?

RubyGems is a package management system that provides the ability to download a package (or library) and all it’s related dependencies through a simple command. Check out Rob’s post here on some background on Gems and how it relates to .NET.

So they created Nu (which started as ngems but quickly became Nu after the suggestion of “nubular” by Dave Laribee). “Nu” stuck because it was short and sweet (and we’re all about minimalism). It does require Ruby (version 1.8.6 or high or IronRuby) and RubyGems installed but you know, that’s a small price to pay for such a powerful back-end system. I remember I had a discussion with Scott Bellware last year or so about having to “drag in” an entire programming language just to run a tool (at the time, rake) for .NET projects. He made me see the light that it really wasn’t a bad thing (although dragging in Java is a bit of a different feeling, but that’s another post).

Diving In

After getting familiar with what was going on it was time to dive in. Seriously, it’s dead simple.

  1. Install Ruby. I know, you’re going to get all ansy about installing Ruby on your precious .NET development system. Get over it. Download the click-click-done installer from here and stop whining.
  2. Open a command prompt
  3. Make a new directory somewhere for your test project (md c:\projects\nutest)
  4. Change to that directory (cd c:\projects\nutest)
  5. Make sure you have the latest update to gems (gem update --system)
  6. Install nu (gem install nu)
  7. Get a copy of one of the current packages available (nu install nhibernate)
  8. Take a look at your project tree to see nhibernate and all it’s dependencies installed

C:.
├───.nu
└───lib
    ├───castle.core
    │   ├───mono-26
    │   ├───net-20
    │   ├───net-35
    │   └───sl-30
    ├───castle.dynamicproxy2
    │   ├───net-20
    │   ├───net-35
    │   └───sl-30
    ├───log4net
    ├───nhibernate
    │   ├───Required_Bins
    │   └───Required_For_LazyLoading
    │       ├───Castle
    │       ├───LinFu
    │       └───Spring
    └───nlog
        ├───Mono 1.0
        └───Mono 2.0

Did I mention how easy this was? No I can create my project and just add a reference to the assembly I need in my project. Want to add say NUnit and Rhino Mocks to the mix?

C:\projects\nutest>nu install nunit rhino.mocks
Found Gem
Copy From: C:/Ruby/lib/ruby/gems/1.9.1/gems/nunit-2.5.5.10112/lib
Copy To: C:/projects/nutest/lib/nunit
Found Gem
Copy From: C:/Ruby/lib/ruby/gems/1.9.1/gems/rhino.mocks-3.6.0.0/lib
Copy To: C:/projects/nutest/lib/rhino.mocks

Done. Yeah, really.

Note: If you’re behind a proxy, just set an environmental variable called HTTP_POST to your proxy server and port and Bob’s Yer Uncle.

Autofac Meets Nu

My next challenge was creating a new package. I’m a big fanboy of the IoC container Autofac and found it wasn’t created as a RubyGem yet so I thought I would spend some time before my coffee this morning to package it up and see how easy this all was. And it was. Really.

Head over to Fervent Coder and read up on Robs walkthrough to create a new gem for Nu. It’s basically what I followed (although with Autofac there are no dependencies except the binaries itself).

For Autofac, I downloaded all the releases that are current (version 2.2.4) from the download page here. Autofac comes with 4 main versions: Silverlight 3, Silverlight 4, .NET 3.5, and .NET 4.0. Note that I left out the Autofac contrib release. After taking a look at it, there were all kinds of dependencies in there and I didn’t want to overly complicate things (or my first Gem). Sorry about that.

Once I had the files I extracted them all to a single folder (using their zip names) then did two things: a) rename the folders so it didn’t include the version number and b) bring everything up into the root of that folder. Here’s the structure when I first extracted the files:

C:.
├───Autofac-2.2.4.900-NET35
│   ├───Library
│   └───License
├───Autofac-2.2.4.900-NET40
│   ├───Library
│   └───License
├───Autofac-2.2.4.900-SL3
│   ├───Library
│   └───License
└───Autofac-2.2.4.900-SL4
    ├───Library
    └───License

And here’s the simplified structure after I renamed each folder and moved the contents of Library up to that folder:

C:.
├───NET35
├───NET40
├───SL3
└───SL4

Another note is that I ditched the License directories and contents. Each folder had the various license files for Autofac and a few depencies (like Moq, NUnit, etc.) but Autofac doesn’t actually reference any of these files. It only references itself so I just dropped the extra files. If I’m really peeving anyone off with this, please let me know and I’ll update the gem.

Now that I had all my files in place I was ready to follow Rob’s example to create the gemspec file and VERSION file. Here’s the gemspec file for autofac:

   1: version = File.read(File.expand_path("../VERSION", __FILE__)).strip
   2:  
   3: Gem::Specification.new do |spec|
   4:     spec.platform    = Gem::Platform::RUBY
   5:     spec.name        = 'autofac'
   6:     spec.version     = version
   7:     spec.files = Dir['lib/**/*'] + Dir['docs/**/*']
   8:     spec.summary     = 'Autofac - An addictive .NET IoC container'
   9:     spec.description = 'Autofac is an IoC container for Microsoft .NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity. This is achieved by treating regular .NET classes as components.'
  10:     spec.authors           = ['Nicholas Blumhardt','Rinat Abdulin']
  11:     spec.email             = 'emailme@bilsimser.com'
  12:     spec.homepage          = 'http://code.google.com/p/autofac/'
  13:     spec.rubyforge_project = 'autofac'
  14: end

I just grabbed the info from the website. Note that the spec.authors property should be the name of the authors of the library, not your name (unless of course you’re building a gem for your own project). I’m not sure if the spec.email should be theirs or mine but it didn’t manifest itself on the RubyGems site as such. Again, I can update the package if need be.

I did create a docs directory and dropped the Autofac.chm file (available from the site) into it. As for the VERSION file I just took a look at the properties of the assembly and noticed it was 2.2.4.900 (the website only shows it as 2.2.4) so I put that into the VERSION file.

After everything was done, you’ll need to create an account on RubyGems.org then you can build the project with the command “gem build project.gemspec”. In a minute you get a generated .gem file:

C:\projects\autofac\gems>gem build autofac.gemspec
  Successfully built RubyGem
  Name: autofac
  Version: 2.2.4.900
  File: autofac-2.2.4.900.gem

C:\projects\autofac\gems>dir
Volume in drive C is OSDisk
Volume Serial Number is B6FC-4710

Directory of C:\projects\autofac\gems

07/30/2010  09:43 AM    <DIR>          .
07/30/2010  09:43 AM    <DIR>          ..
07/30/2010  09:43 AM         1,053,184 autofac-2.2.4.900.gem
07/30/2010  07:03 AM               801 autofac.gemspec
07/30/2010  06:49 AM    <DIR>          docs
07/30/2010  06:51 AM    <DIR>          lib
07/30/2010  06:48 AM                 9 VERSION

Once the .gem file was built I pushed it up to RubyGems (“gem push autofac-2.2.4.900.gem”) and it was done. I headed over to the autofac page on RubyGems.org and everything was golden. Version number correct, author names corect, etc.

One thing I did to polish it off was to click on the Edit link once your gem is produced and put in links to Source Code, Documentation, Wiki, Mailing list (autofac didn’t have one), and bug tracker. It’s just a simple step that you can’t set in the .gemspec file (or can you?) but gives people some links if they’re interested in looking for more info about the original library.

Roll Your Own

Like I said, this was easy. 24 hours ago I was looking at Nu; 12 hours ago I installed Ruby, created an account on RubyGems; 2 hours ago I downloaded Autofac, built my first gem, and uploaded it. There’s no reason why you can’t do the same.

Setting up your project is a breeze and it only takes 10 minutes at most to get it packaged and uploaded. Having to deal with dependencies automatically is a little more involved so check out Rob’s post here on dealing with that. It’s still neither rocket science or brain surgery (or rocket surgery) so anyone can do it and it helps the Nu community in these early days to get some momentum.

What are you Waiting for?

Drop by the nu-net Google group, join in the discussion, and get started using Nu!

And remember… Nice package!

10 Comments

  • Awesome post man!

    Couple of follow ups -
    1) The email address I use in the spec is as close as I can find to how you get support. I usually try to put the discussion group email address (like a google groups email address).
    2) Finding the version, always a good idea to use Reflector. It's the closest thing you are going to get to finding the version that the .NET framework tells you that you need for a missing reference. That's the version that should be used. It's not always the same as the file version or informational/product version either. Just depends on the library and what the authors decided to do. :D

    Like I said, awesome post! Very detailed and shows how easy it really is. And Awesome first gem w/autofac!

  • Nice instructional post, Bil! Way to spread the word!

  • Nice work. You can't have metadata like the links offered on rubygems.org in the gemspec...yet. We've talked about making that happen since the gemspec should be your only interface to the site. Glad to see another dev community getting on the instant deployment/packaging train. It's about time :)

  • Excellent stuff. I can't stand the bootstrapping time wasted in .net projects!

  • I wish I understood more of this so that I could say 'great article' and mean it really. But I don't understand it and I still think it's a great article.

    M.

  • Just a note. Followed your instructions and nLog wasn't installed as part of the nHibernate gem install, not sure why my install differed from what you said.

  • thanks for pointing us to this utility, i do have a question though.

    I installed ruby (i put it under c:\program files\ruby191 )
    mkdir c:\project\nutestproject
    cd c:\project\nutestproject
    gem install nu
    gem install nhibernate
    gem install rhino.mocks
    gem install nunit
    gem install autofac

    this has copied the nhibernate, castle.core and dyn.proxy dll's into c:\project\nutestproject\lib but rhino.mock, nunit and autofac dll's aren't there.
    But i do find them under C:\Program Files\Ruby191\lib\ruby\gems\1.9.1\gems\autofac-2.2.4.900\lib\NET35

    Any idea why they're not copied to the project lib-folder?

  • Ok, i found out what i missed.... instead of
    gem install nunit

    i should've done
    nu install autofac

  • If the gem hasn't been installed yet (using "gem install gemname") you usually can just do "nu install gemname". It will delegate to gem and download it first, then copy it to the local lib folder. This doesn't always work but I use this first to skip the extra step.

  • This is a wonderfully useful article - thanks! Sorry for sounding old fashioned but I would keep the License directories intact. There's always someone that wants to understand something's provenance and it sounds like the easiest way to do that is to maintain the licenses in place. My two cents. cheers, stephe

Comments have been disabled for this content.