Ruby Tidbits: Spork your Cucumber
This is a continuation of last week’s post. Not long after Tim Harper released Spork for RSpec, the Cucumber team announced support for Spork in Cucumber. If this sounds like some kind of dining meme, just let me show you how much of a picnic this is to use.
Since the last blog post, Spork 0.5.7 has been released, so I’ll be using that version here. Cucumber is at version 0.3.11.
First, let’s bootstrap Cucumber
ruby script/generate cucumber
Time to generate some features.
script/generate feature Spoon color:string size:string
We can make our features pass pretty easily for this example.
script/generate rspec_scaffold Spoon color:string size:string
Don’t forget to migrate
rake db:migrate
Now start spork for cucumber
spork cuc
And run the features
rake features
Now we’re not going to see much here since this project is so small, but I did time the run on these.
Without Spork
time rake features
real 0m3.296s
user 0m2.456s
sys 0m0.756s
With Spork:
time rake features
real 0m1.914s
user 0m1.093s
sys 0m0.298s
I would love to see some real world stats on this on somebody’s cucumber suite. If you want help getting this going on your long running suite, let me know and I’ll lend a hand in exchange for getting some timing results.
Ruby Tidbits: Spork
Last week Tim Harper announced Spork, which is billed as a better RSpec DRb server. What does that mean, and why should I care?
RSpec of course is a Behavior Driven Development framework for Ruby. DRb is a distributed object system for Ruby, and it ships with the standard library.
As a Rails code base gets larger, you can start to see app initialization times increase. In production, this isn’t a big problem, since you aren’t frequently starting your app. However, when you are involved in a rapid development/test cycle this can become a nuisance when you start to find yourself waiting for your app to initialize to run your tests.
Spork aims to tackle this problem by only taking that initialization hit once. It starts up the application environment, and then listens over DRb. Then, RSpec can connect to that DRb server and run specs inside that process, skipping the initialization. Furthermore, before running the specs, Spork will fork itself, which is a relatively inexpensive call on POSIX1 systems. Then, when the specs are done running, this process can just go away, and we don’t have to worry about object pollution when running specs again later.
Let’s see just how easy it is to get going with Spork.
My environment for this tidbit includes:
- Mac OS X 10.5.7
- Rails 2.3.2
- RSpec 1.2.6
- The Spork I am installing is version 0.5.6
Install Spork from Ruby gems.
sudo gem install spork
Create (use an existing) Rails project
rails crappy_spoon
Edit config/environments/test.rb. And add the following lines to tell Rails we are using RSpec.
config.gem "rspec", :lib => false
config.gem "rspec-rails", :lib => false
Bootstrap the RSpec environment.
script/generate rspec
I’m going to use scaffolding just to get some specs to try things out with. (Don’t forget to migrate)
script/generate rspec_scaffold Fork
rake db:migrate
I have a little benchmark script that will run a command an number of times and print out the results. Running rake to run these specs 5 times gives:
| user | system | total | real | |
| 0.000000 | 0.000000 | 5.350000 | 6.364407 | |
| 0.000000 | 0.000000 | 5.300000 | 5.648598 | |
| 0.000000 | 0.000000 | 5.320000 | 5.694012 | |
| 0.000000 | 0.000000 | 5.300000 | 5.610330 | |
| 0.000000 | 0.000000 | 5.350000 | 5.824451 | |
| >total: | 0.000000 | 0.000000 | 26.620000 | 29.141798 |
| >avg: | 0.000000 | 0.000000 | 5.324000 | 5.828360 |
So on average on my machine I had to wait 5.8 seconds to run all my specs.
Let’s enable Spork and try it again.
spork --bootstrap
When that’s done, it prints out a message for us.
Done. Edit /Users/redinger/workspaces/rubyrx/crappy_spoon/spec/spec_helper.rb now with your favorite text editor and follow the instructions.
So, let’s go do that. I moved everything into the prefork section for this example. Here’s my final spec_helper.rb:
require 'rubygems'
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.dirname(__FILE__) + "/../config/environment"
require 'spec/autorun'
require 'spec/rails'
Spec::Runner.configure do |config|
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
end
end
Spork.each_run do
end
Then, edit spec.opts to enable drb:
spec.opts --drb
Load up spork
spork
Rerunning the benchmark:
| user | system | total | real | |
| 0.000000 | 0.000000 | 2.220000 | 3.100511 | |
| 0.000000 | 0.000000 | 2.210000 | 3.147859 | |
| 0.000000 | 0.010000 | 2.230000 | 3.057866 | |
| 0.000000 | 0.000000 | 2.190000 | 2.919749 | |
| 0.000000 | 0.000000 | 2.190000 | 2.864102 | |
| >total: | 0.000000 | 0.010000 | 11.040000 | 15.090087 |
| >avg: | 0.000000 | 0.002000 | 2.208000 | 3.018017 |
And we are now down to an average of 3 seconds. Obviously this is with a bare bones app, so we don’t see the real performance savings that we would with a real world app. But, just for the sake of argument, let’s say someone accidentally added a sleep 5 to the init process (simulating an additional 5 second app initialization time).
Rerunning without Spork running (it’s worth pointing out here if you run rspec without having a Spork process running, the specs will just revert to running the old way, printing out a message notifying you there is no server running.):
| user | system | total | real | |
| 0.000000 | 0.000000 | 6.150000 | 18.199735 | |
| 0.000000 | 0.000000 | 5.040000 | 10.131084 | |
| 0.000000 | 0.000000 | 5.040000 | 10.217521 | |
| 0.000000 | 0.000000 | 5.060000 | 10.121561 | |
| 0.000000 | 0.000000 | 5.020000 | 10.150404 | |
| >total: | 0.000000 | 0.000000 | 26.310000 | 58.820305 |
| >avg: | 0.000000 | 0.000000 | 5.262000 | 11.764061 |
That causes the extra time to be seen for each running of the specs. Under spork, which takes an additional 5 seconds to start up the Spork server:
| user | system | total | real | |
| 0.000000 | 0.000000 | 2.090000 | 2.722946 | |
| 0.000000 | 0.000000 | 2.080000 | 2.661724 | |
| 0.000000 | 0.000000 | 2.110000 | 2.731659 | |
| 0.000000 | 0.000000 | 2.080000 | 2.665148 | |
| 0.000000 | 0.010000 | 2.100000 | 2.647866 | |
| >total: | 0.000000 | 0.010000 | 10.460000 | 13.429343 |
| >avg: | 0.000000 | 0.002000 | 2.092000 | 2.685869 |
No extra time. (Technically, less time, but we’ll count that as margin of error.)
One final thing to point out, if you just run spork -d it will run diagnostic mode, which will list which files are being preloaded, and don’t get reloaded each time the specs are run.
Hopefully if you are using RSpec in your Rails project you can see how using spork can immediately benefit you.
1 Right, I said POSIX, so Windows users will need to pursue a different solution for now.
BarCampRDU 2009
Registration has opened for BarCampRdu. It’s free as always, so I’ve registered. And you should too.
See you there!
Default Routes and Rails Engines don't mix
Of course we’ve known for a while to not use default routes in combination with restful routes. However, there is a hidden danger when dealing with Engines. I was doing what should have been a quick experiment with an Engine in Rails 2.3. So, I generated a default app.
rails cereal rails fruits cd cereal script/generate scaffold cornflake
Then I follow the incantation to get my fruits engine into my cereal app. Part of that process involves copying over the routes.rb file. However, by default, that has these unfortunate routes defined already:
map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'
Now, I hit my app at /cornflakes/new, hit the ‘Create’ button, and it posts to … my ‘index’ action?? What’s up with that? Well, it took a while, but then I remembered that default route. I’m assuming that the plugin routes get processed first, and that default route is getting installed before my resourceful route. Meaning, nothing in my app’s routes.rb file is going to get recognized. No corn flakes, no lucky charms, nothing.
Removing the offending lines set the world back to normal. Time to eat.
Passenger, nginx & Leopard development
If you’re wondering if you can still develop on your Mac using Passenger along with the nginx config – the answer is of course you can!
First, follow the installation instructions.
Then you’ll need to edit your /etc/hosts file to tell your host about the virtual domain. (This is only necessary I assume until the fantastic Passenger Preference Pane is updated to work with nginx)
127.0.0.1 localhost my_facebook_killer.local
Finally, update your nginx.conf, which is pretty much the same as the Passenger installation instructions, with one extra line for development.
server {
listen 80;
server_name my_facebook_killer.local;
root /path/to/your/rails/app/public;
passenger_enabled on;
rails_env development; # This line tells passenger to start in development mode.
}
Now restart nginx and you should be able to test your app by hitting http://my_facebook_killer.local in your browser
There, that's better
It seems like just the other day I was bemoaning the fact that in order to run Phusion Passenger, I had to run Apache. Well Happy Birthday to Phusion, today they announced nginx support. No sooner did I read that than I hopped on my server and ripped out Apache for the leaner, sleaker nginx.
Shortly thereafter, I’m up and running again. Fantastic.
Can't find the Phusion Passenger Apache module
Can't find the Phusion Passenger Apache module. Visit http://www.modrails.com for installation instructions.
I started receiving this message after upgrading my Phusion Passenger. And possibly other stuff. Rerunning the passenger setup didn’t work. Then, while looking through my httpd.conf file, I found this line near the top:
LoadModule passenger_module /Library/Ruby/Gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
Which referenced an older version of passenger. Removing that line made things happy again. Of course, I am references the correct version now, down at the bottom of the file.
Getting Things Done With The Hitlist
The HitList is a nice little app that got thrown into the last MacHeist. I’m pretty impressed with it and am currently playing around with implementing some variant of Getting Things Done that will work for me. If you are looking for an app like this and have already passed on Things, I’d highly suggest checking it out.
Switching It Up
Having some free time on my hands today, I decided it was time to switch things up on my blog software. So, as of this evening, here’s how things are looking around here.
- Hosted at Mosso. Because the cloud is where it’s at. I wanted my blog in the clouds, too. And cheaper.
- Served by Phusion Passenger. Because Passenger is fantastic for hosting. I was sad to leave Nginx behind and have to return to Apache. But, Passenger was enticing enough.
- Running Ruby 1.9.1. Because it’s time to leave the 1.8.x branch behind.
- Blogging engine provided by Enki. Because I’m a Ruby developer, and this blog engine really speaks to me.
Granted now I need to spend some time cleaning a few things up. But, overall this migration could not have been any easier.
Debugging Phusion Passenger
Big Chimpin
Freelancing Again
Hoedown in 10 minutes
Couldn’t be there? Watch the video.
Ruby Hoedown '08
This past weekend I attended the Ruby Hoedown in Hunstville, AL. As one of the members of the talk selection committee, I don’t mind saying at all that I thought the line up was fantastic.
I really liked Chris Wanstrath’s anti-keynote. I say anti-keynote, because he basically wrote an essay and then presented it to us without slides. He said later that he was a better writer than speaker; and I’d say it definitely worked. The essay was funny and motivating. I couldn’t do justice trying to summarize it, so make sure to check out the video when it shows up on Confreaks, hopefully next week. (Though not bringing GitHub t-shirts was a fail)
We got a two-for-one talk from Rein’s talk about best practice patterns. The best part was the first talk, which covered such topics as unfactoring: undoing common refactorings for job security. After all if you refactor your code so anybody can understand it, then anybody can maintain it too, so you’re programming yourself out of a job. Bad idea. And if you DRY up your code, you will be able to add new features more quickly. But why would you want to do that if you get paid by the hour?
The lightning talk that really stood out to me was Bryan Liles TATFT version of his testing talk. The slides for the whole thing are up on his site, so it’s worth looking through while waiting for the video.
Another high point was Giles Bowkett’s talk on Archaeopteryx: A Ruby MIDI Generator. I loved the way he just jumped right into the demoing his app for us without giving us any background. So many talks start off slow before getting to the good stuff. He started with it by demoing what Archaeopteryx could do. The title was kind of misleading though, because the talk was really about doing stuff you love, because you love it. Which is why we have this app now.
Of course Friday night was the Hashrocket after-event party. In the RV. In the parking lot at the Marriott. Thanks for doing this guys. The party was definitely worth being exhausted the next day. Best part? The hand-made beer pong table Yes, it actually made it through a game of beer pong.
In other big news, Jeremy McAnally is planning next year’s Ruby Hoedown in Nashville. The plan now is to make the conference free to attenders. Hopefully I’ll see you there!
History meme
Look my first meme!
serenity:~ redinger$ history|awk ‘{a[$2]++} END{for(i in a){printf “%5d\\t%s \\n”,a[i],i}}’|sort -rn|head
147 git
67 rake
22 ga
21 cd
20 ls
16 less
15 serve
15 script/generate
15 curl
14 rm
ga is my alias for git adding and commiting.
Tag Matthew & Ruby Red Rick

