jeremy burks
merb_annotate_models
I like the handiness of Dave Thomas’ Rails plugin annotate_models. I’ve been doing some Merb development so I decided to do a quick port of the plugin.
It can be found over at GitHub.
stack: A Ruby Build Tool For .Net Development
This is an introduction to an internal .Net build tool written in Ruby. Although it’s not Open Source I thought some would be interested in hearing about it.
The idea of writing a .Net build tool in Ruby comes up from time-to-time. Most recently, that I’ve seen, Jeremy Miller briefly mentioned the idea. Now that I finally got around to setting up a weblog I thought I would share my experiences in writing such a tool.
Some History
My employer started the transition to .Net about 1.5 - 2 years ago. There were a lot of discussion about whether or not to use Team System. It was a discussion similar to the one Roy Osherove and Ayende had. In the end it was decided not to use Team System.
A downside to that decision is the number of pieces involved. Some of the different pieces that had to be managed include Subversion, NUnit, MSBuild, NCover, log4net, iBatis, internal frameworks and libraries. Everything needed to be managed as one cohesive unit. Beyond encapsulating the various development tools, there was the desire to enforce things like solution and directory layouts, namespacing, project names, unit tests, continuous integration, etc…
Stack was developed to solve the above problems.
Why Ruby?
So, why Ruby? Ruby is an excellent language for gluing things together. Stack had to bring in many disparate tools together so it was a good fit. In addition, .Net was just being introduced so there were no legacy NAnt or MsBuild scripts to contend with. There was no interest in going down that road if it could be avoided. Lastly, my feeling is, the more exposure .Net developers have to Ruby the better (or more generally, exposure to different languages is a good thing). Being introduced to Ruby through using Stack is a delicate way to do that.
Some Details
- Stack is a gem that is distributed via an internal gem server.
- All dependencies are packaged with stack. That includes all required SDK tools. You should be able to build a Stack based solution anywhere where the .Net Framework and Stack is installed.
- Stack is used to generate new solutions. There are several defined solution templates like lib, forms and shell to name a few. For every VS.Net project generated a corresponding .Test project is generated. The one exception is the View project, if there is one.
- It’s easy to retro fit Stack around an existing solution.
- Stack has the concept of version freezing. There tends to be a lot of smallish solutions that become feature complete pretty quickly and then sit untouched for one or more years. To ensure the tests and the rest of the build continue to work, each solution is frozen to a specific version of stack. The solution must be explicitly upgraded to a newer version of Stack. As a result, Stack’s toolset can be upgraded without worrying about breaking builds when a new version of Stack is released. To illustrate the point a little bit, the build server has about 5 different versions of stack installed, all being used by solutions in various stages of development.
- Stack initializes it’s environment by parsing a solution file to discover all the projects. Test projects are selected by matching a pattern, the default is project names ending in Test. Parsing the solution and project files allows stack to provide a basic set of tasks out of the box.
- Stack has an import task that creates a new Subversion repository, sets appropriate commit permissions (everything is anonymous read by default), imports the solution and does an inplace checkout. During the import process Stack also creates a new product, via a web service, on a Project Management type web app (written in Rails).
- Build output is written to both STDOUT and a HTML report when build tasks (compile, test, coverage, etc..) are run locally.
- Stack has a cruise task for easy integration with CriuseControl.rb. If stack detects that its being run as a CruiseControl.rb build it redirects output to the appropriate location.
In Summary
That is stack in a nutshell. It’s used on a daily basis to manage 100+ Visual Studio solutions and counting.
DRY up ActiveRecord specs a bit
These days I use RSpec exclusively. Well, there are those few remaining crufty test/unit tests hanging around but I digress. When writing specs for ActiveRecord models there is a particular pattern I follow. I tend not to use fixtures unless their required. Typically I just new up a model with the required data. If the model needs to exist on the database I use create instead.
With RSpec, examples tend to get broken up into several describe blocks. As a result I almost always create a helper module that gets included into the describe blocks.
Assuming a Post model, post_spec.rb might start out looking like the following:
require File.dirname(__FILE__) + '/../spec_helper.rb' module PostSpecHelpers def default_attributes { :title => 'Ninjas Kick Ass', :body => 'Ninjas are dangerous, watch out!' } end end describe Post do include PostSpecHelpers end describe Post, 'validating' do include PostSpecHelpers it "should require a title" do post = Post.create default_attributes.merge(:title => nil) post.should have(1).error_on(:title) end end
There is not a whole lot to DRY there. The common pattern shown is to create the object while overriding one or more attribute defaults. The tediousness of the code is pretty minor but it starts to grow old. Another thing that bothers me is RSpec knows a model is being spec’d. That seems like useful information that should be taken advantage of.
Normally I would just deal with the above. You usually want to tread carefully when abstracting things out of specs.
I did end up coming up with something. What put me over the edge was the need to create and new up models in shared specs.
For example, what if there is a Post and a WikiPage that both have a title and body? You could do inheritance but I tend not to like that. You never know how the two models will diverge. Instead I usually create a module with the shared code. I’ll then write specs that are shared by both taking advantage of it_should_behave_like.
The result of what I ended up with is very simple. Just a couple of helper methods to create (and new up) models while taking advantage of the fact that RSpec knows modles are being spec’d.
Here is the example above rewritten:
it "should require a title" do create_with(:title => nil).should have(1).error_on(:title) end
Here is what I have in spec_helper.rb:
module ModelExtensions def new_model(overrides = {}) self.class.described_type.new(respond_to?(:default_attributes) ? default_attributes.merge(overrides) : overrides) end alias new_with new_model def create_model(overrides = {}) self.class.described_type.create(respond_to?(:default_attributes) ? default_attributes.merge(overrides) : overrides) end alias create_with create_model end Spec::Runner.configure do |config| # only include for Model examples config.include(ModelExtensions, :type => :model) end
In the past I’ve used several more extensions, especially when it comes to specing controllers (controllers and their specs drive me nuts with there repetitive patterns). I often go back and forth. It’s a battle between DRYness and obscuring the specs. Based on experienced its almost always (just plain always?) best to err on the side of maximum readability at the expense of DRYness. Although I don’t think the above example is too bad, sometimes I just can’t help myself.
Firefox Extensions
I’m in the process of setting up a new computer and I’m trying to remember all the Firefox extensions that I use. This list is mostly for myself, so that I don’t have to think so much the next time around.
I only use these at work where it’s Windows. Brief, I use for intranet feeds otherwise I use Google Reader.
deploying a gem using capistrano
This is something I wrote to push gems to an internal gem server. It is a simple Capistrano recipe. Here is the Capfile. You can easily move the GemDeployer module into a separate file if you want to reuse it.
module GemDeployer def deploy(gem_path_glob) gem = Dir[gem_path_glob].first unless gem raise "failed to find gem using #{gem_path_glob}" end # the gem must be read in binary mode, its a # windows thing File.open(gem, 'rb') do |f| put f.read, "/var/www/html/gems/gems/#{File.basename(gem)}" end run 'gem generate_index -d /var/www/html/gems' # use this for rubygems < 0.9.4 # run 'index_gem_repository.rb -d /var/www/html/gems' end end Capistrano.plugin :gem_deployer, GemDeployer role :app, '[SET HOSTNAME HERE]' namespace :deploy do task :default do gem_deployer.deploy File.dirname(__FILE__) + "/pkg/name-of-your-gem-*.*.*.gem" end end
hello world and all of that
The start of this weblog completes the first item on my nebulous list of 2008 New Years resolutions. I’ve been a lurker of the interwebs for many years. I’m a programmer going on 7 years. I read a lot of weblogs (148 feeds and counting, yeah, probably too many) and I always follow what the cool kids are doing. This year I have decided to take on a more participatory role. It’s time to start using all that hosting space that I have.
You may be wondering whether or not you should care about this weblog. I’ll be discussing Ruby, open source, some .Net stuff since that’s a lot of what my day job is, web development, internet technologies like XMPP and other things related to software development such as source control and agile. Lastly, I’ll occasionally throw in some things that interest me outside of technology like running and movies. If you’re interested you can read more about me.
I’m not much of a writer or grammarian (despite the efforts of my AP English teacher) so please forgive me in advance. The grammarati can correct me in comments if they like, maybe I’ll learn a thing or two.
