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.
- 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.
- Open a command prompt
- Make a new directory somewhere for your test project (md c:\projects\nutest)
- Change to that directory (cd c:\projects\nutest)
- Make sure you have the latest update to gems (gem update --system)
- Install nu (gem install nu)
- Get a copy of one of the current packages available (nu install nhibernate)
- 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!