How To - Gems And .NET

In my last post I showed gems being used for .NET. Now let’s talk about How.  Most of this stuff I’ve learned over the past two days, so if I have a mistake here or you have a better idea, please don’t hesitate to offer a better solution.

The GemSpec

The Gem::Specification reference is your friend.

In order to create a gem, you need to define a gem specification, commonly
called a “gemspec”.

A gemspec consists of several attributes. Some of these are required;
most of them are optional.

From here you learn what is required and what will just get you there.

Setup

1. Create a folder named gems in your top level source directory.

2. In that folder we are going to put our gemspec and version files. This is where we will store the files in source control (and one of them may become autogenerated).

3. We will bring our gems folder to our compiled source folder after we build. Then we can add in the compiled output.

GemSpec for .NET

1. Create a file named project.gemspec. In our example it is roundhouse.gemspec. This is the most important file for this entire process.

First two files

2. Open the gemspec in your favorite notepad editor. Copy the below in and change it for you needs.

version = File.read(File.expand_path("../VERSION",__FILE__)).strip

Gem::Specification.new do |spec|
  spec.platform    = Gem::Platform::RUBY
  spec.name        = 'roundhouse'
  spec.version     = version
  spec.files = Dir['lib/**/*']

  spec.summary     = 'RoundhousE - Professional Database Change and Versioning Management'
  spec.description = 'RoundhousE is a Professional Database Change and Versioning Management tool'
  
  spec.authors           = ['Rob "FerventCoder" Reynolds','Pascal Mestdach','Jochen Jonckheere','Dru Sellers']
  spec.email             = 'chucknorrisframework@googlegroups.com'
  spec.homepage          = 'http://projectroundhouse.org'
  spec.rubyforge_project = 'roundhouse'
end

3. Just about everything with tick marks above you will edit to suit your needs. spec.name and spec.rubyforge_project (and the gemspec file name) should all match and not be an already existing project name on RubyForge.

4. If you are a singular author, instead of spec.authors, replace it with

spec.author = 'somebody'

You can also set up description for multiple lines.

spec.description = <<-EOF
   Rake is a Make-like program implemented in Ruby. Tasks and
   dependencies are specified in standard Ruby syntax.
 EOF

Dependencies On Other Libraries

What we call references. You have a dependency on them existing for your library to run. See this post.

VERSION file

This file is stupid simple. It’s a version number. I believe you can put whatever you want in here. Use the Assembly Version number here and stick with the .NET 4 octets of numbers (like 0.0.0.0) for version.

1. Create a file named VERSION.

2. Open it in your favorite editor and put the version you want here.

VERSION with 0.5.0.242 as contents of file

Libraries

1. Create a folder called lib.

adding in lib folder

2. Copy YOUR compiled DLLs into here. Your references (or dependencies) should not go here. See How To: Gems and .NET - Dependencies.

 Put your dlls in lib folder

Documentation

Create a docs folder. In that folder goes your documentation. This could be release notes, a ReadMe, actual documentation. This area is open. Just make sure you add the docs folder to the specification.

spec.files = Dir['lib/**/*'] + Dir['docs/**/*']

 

Executables

If you want to give someone the ability to run an executable from the command line after installing your application with gems, and you use .NET, this is how you do it.

1. Create a folder named bin as a subdirectory next to the gemspec.

2. Put your executable (and dependencies) into the bin directory.

create a bin directory stand alone executable in bin

3. Create your shim file (it’s named what you would type at the command line). I’ve called mine rh. The one above allows ruby to be able to actually execute the Windows executable. Let’s open it and see what it looks like. This, we learned from an answer to a post on stack overflow.  This shim also goes in source control

result = system(File.dirname(__FILE__) + "/rh.exe " + ARGV.join(' '))
exit 1 unless result

4. Don’t forget that space at the end of your executable name.

5. Open your gemspec. We need to make sure we have spec.executables filled out and our new directory added to our Files.

version = File.read(File.expand_path("../VERSION",__FILE__)).strip

Gem::Specification.new do |spec|
  spec.platform    = Gem::Platform::RUBY
  spec.name        = 'roundhouse'
  spec.version     = version
  spec.files = Dir['lib/**/*'] + Dir['docs/**/*'] + Dir['bin/**/*']
  spec.bindir = 'bin'
  spec.executables << 'rh'

  spec.summary     = 'RoundhousE - Professional Database Change and Versioning Management'
  spec.description = 'RoundhousE is a Professional Database Change and Versioning Management tool'
  
  spec.authors           = ['Rob "FerventCoder" Reynolds','Pascal Mestdach','Jochen Jonckheere','Dru Sellers']
  spec.email             = 'chucknorrisframework@googlegroups.com'
  spec.homepage          = 'http://projectroundhouse.org'
  spec.rubyforge_project = 'roundhouse'
end

Build And Push

You must already have Ruby (1.8.6 or better) and RubyGems installed and/or updated to at least 1.3.7 (gem update –system). You will want to use a RubyInstaller version of Ruby under the Ruby on Windows section.

1. Open a command line and type

gem build project

2. If there are no issues, you should have a gem for upload.

roundhouse-0.5.0.242.gem

roundhouse-0.5.0.242.gem

3. Create an account with RubyGems.org.

4. Ensure your project name isn’t already taken by searching for it. If it is you will need to rename your gemspec file, spec.name, and spec.rubyforge_project to a name that is not taken.

5. Type the following command:

gem push project_someversionnumbers.gem

gem push roundhouse

6. Let it finish. Head out to rubygems.org and look at your shiny, new gem!

 sweet!

7. Test it.

gem install project 

gem uninstall project

 

FollowUp

In my next post, I’ll show you how to make it stupid simple. UppercuT will support this feature natively so all you have to do is have a directory called gems (at the top level of your source) with the gemspec. During the build, it will create the VERSION file and copy your output the the lib folder (custom step for bin folder will be necessary). Then it will execute a step that builds the gem. All for the price of “build”. That’s coming up in the next blog post. In the meantime, feel free to ask any questions you have. Stay tuned…

 

Related Posts

Before you comment about “cluttering” the ruby community, please be sure to read this (we’re with you on this):  http://devlicio.us/blogs/rob_reynolds/archive/2010/07/19/gems-for-net-community-response.aspx

Gems - Package Management for .NET & How To – Gems & .NET - Dependencies (References)

Walkthrough - Create Gems Even Easier With a Conventional Build (UppercuT)!

The Future is Now!


Posted 07-16-2010 10:30 AM by Rob Reynolds

[Advertisement]

Comments

Joshua Flanagan wrote re: How To - Gems And .NET
on 07-16-2010 8:43 AM

Great job - I agree that this is the way to go - no need to re-invent gems.

I think one of the next steps is to have it copy files to your local project. This can also be done with gems by adding a new command to gems, via a plugin. See:

tagaholic.me/.../how-to-write-a-rubygem-command-plugin.html

Rob Reynolds wrote re: How To - Gems And .NET
on 07-16-2010 10:02 AM

@Joshua: Let me ping Dru on that. They are looking at doing exactly that for Nu (#nuproj).

NotMyself wrote re: How To - Gems And .NET
on 07-16-2010 12:51 PM

Now that is pretty damn hot.

Chris Patterson wrote re: How To - Gems And .NET
on 07-16-2010 2:55 PM

KickAss (tm)

Yeah, they are reworking nu in ruby now, and are likely going to add the nu commands to gem somehow based on that link. But getting the .csproj and other files tweaked to add the dependencies and stuff is going to really complete this out.

Super stoked man, this is finally starting to come together!

Victor Costan wrote re: How To - Gems And .NET
on 07-19-2010 8:49 PM

Rubygems is an awesome way to do cross-platform package management. Kudos for  discovering that and sharing the knowledge outside the Ruby community! Unfortunately, as a Ruby programmer, I have some issues with what you're doing.

spec.platform = Gem::Platform::RUBY is not cool for what you're doing. You're putting together binary gems, and Gem::Platform::RUBY is for platform-independent gems. Given that you're using .net, you probably want Gem::Platform::Win32

Also, since your binaries aren't targeted to a Ruby ecosystem, it would be nice if you wouldn't pollute the rubygems namespace. You should get the .net community together and run your own server off the open-source Gemcutter codebase. I don't want to see your code when looking for libraries that I can use in my Ruby projects.

Last, you probably want to distribute your own build of Rubygems that has your gem repository hardcoded in it. Or, even better, you could write a patch for Rubygems that makes it programming language-aware, so we can all live happily off the same package management platform.

Rob Reynolds wrote re: How To - Gems And .NET
on 07-19-2010 10:01 PM

@Victor: Yep - we are way ahead of you already -  devlicio.us/.../gems-for-net-community-response.aspx

The other part about the platform is a valid argument and trust me, I would rather specify something like 'mswin32'. In fact I tried, but the version number doesn't carry forward if the version number is nonstandard. I need to get with Nick to figure out if this is a RubyGems.org thing, a gemcutter thing, or a gems thing.

And last, again man - great minds think alike. We are way ahead of you there as well.

But I got to tell you - the word pollute has such a negative connotation to it and actually probably detracts away from the awesome Ruby people I have met already. It even detracts from your well thought out comments as well. I prefer the term share a space.

Like I said, we've already been talking to Nick about exactly everything you have brought up.

And keep in mind you are going to start seeing more devs that are both ruby and .net. And code bases that are both. I'm already starting to dive into some ruby and put it into my .net code base, so the lines of what is ruby and what is .net is going to blur.

Victor Costan wrote re: How To - Gems And .NET
on 07-20-2010 12:18 AM

@Rob: I'm sorry if I gave off the wrong vibe by saying 'pollute'. People around me use that near 'namespace' so it seemed like the idiomatic verb to use.

I think we should all share this wonderful technology that is Rubygems. It's awesome to say 'gem install x', and have the right piece of code downloaded, compiled, and installed in the appropriate place, no matter whether you're on Windows, OSX or Linux.

On the other hand, I think there needs to be some separation, because (1) .net code and Ruby code isn't interoperable (yet, afaik) and (2) we use different naming conventions.

(1) If I need to interface with youtube, I'll do a gem search for 'youtube', pull up the documentation, and be done. I wouldn't be very happy if 'youtube' was, instead, a bunch of DLLs that I can't use. Conversely, a .net programmer would have a bad start in today's Ruby namespace... most of the time, their search results would be ruby code, not .net code.

(2) .net has deep nested namespaces. System::Windows::Forms::Button or System::Threading::Thread would be eyesores in Ruby. .net has assemblies. Ruby has this convention that you name your gem 'gem_name', you put your code in 'lib/gem_name.rb', and you use the GemName namespace, and then require 'gemname' just works. Ruby libraries tend to have flatter namespaces. When we see deep namespaces, we think "this looks like Python" or "this was ported from Java".

For these reasons, I think we should have different namespaces for our packages, even if we share the same distribution infrastructure.

You mentioned mixing ruby and .net code together. I think the right way of doing that would be to extend RubyGems to be able to compile .cs files into Ruby extensions, just like it does with .c files. Provided that you have a Ruby interface to the code, then that is indeed a Ruby gem, and it should live in the Ruby namespace.

At the same time, I don't think .net programmers should be forced to write Ruby interfaces to use the awesomeness in Rubygems. So I think we should have separate global namespaces for Ruby and .net, and whatever other VMs want to join in on the fun. I know Headius was playing with converting JVM jars into gems, to get the same convenience. Perhaps he also has a good idea of how to go about it.

I hope this makes more sense than my last post.

Rob Reynolds wrote re: How To - Gems And .NET
on 07-20-2010 9:42 AM

@Victor: What do you think of the naming convention .net? As in masstransit.net versus masstransit. The gem without the ".net" is a ruby gem and the one with is a .net gem.

And this is for real already. There is really a masstransit ruby gem that is being built by the same folks that built masstransit (the .net version). They are going to conflict on their own name and we started thinking .net would serve the purpose of separating the .net world from the ruby world.

And then you would know immediately if you were looking at a ruby gem or a .net gem just by the name of the gem.

Thoughts?

Rob Reynolds - The Fervent Coder wrote The Future of .NET Open Source Software Delivery
on 07-26-2010 4:15 PM

Imagine we are awhile into the future. How do you get open source releases down to your project so that

Rob Reynolds - The Fervent Coder wrote The Future of .NET Open Source Software Delivery
on 07-26-2010 4:18 PM

Imagine we are awhile into the future. How do you get open source releases down to your project so that

Rob Reynolds - The Fervent Coder wrote The Future of .NET Open Source Software Delivery
on 07-26-2010 4:21 PM

Imagine we are awhile into the future. How do you get open source releases down to your project so that

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)