Today I’m going to start a new series on the cool stuff behind Camping. There’s a lot to cover, but I will try to keep each part short and concise so you can jump right in without reading the previously parts.
It should also be noted that I will only cover 2.0. So you better grab your own copy from GitHub:
git clone git://github.com/why/camping.git
I’m starting with what every Camping app starts with:
Before 1.2, you didn’t use Camping.goes at all. You simply used the Camping module for all your apps:
require 'camping' module Camping::Controllers class Index < R '/' def get "Hello World!" end end end
It worked great in the beginning, but if you tried to load several apps in one process they started overwriting each other; fighting for survival.
Camping.goes was the solution.
Let’s take a look at this method:
module Camping S = IO.read(__FILE__) rescue nil def self.goes(m) eval S.gsub(/Camping/,m.to_s), TOPLEVEL_BINDING end end
First of all we’re saving the content of camping.rb in Camping::S, and we don’t really care if we encounters any errors.
Next up, #goes replaces every occurrence of “Camping” with
Then we simply evaluate this string as it was in the top of our program, not inside the Camping module (hence TOPLEVEL_BINDING).
The result: A module which is an exact copy of Camping.
The real magic
The real magic is that the four-oh-four page still shows Camping Problem! Didn’t we just replaced every occurrence of “Camping?” Why didn’t this also get replaced?
module Camping P = "<h1>Cam\ping Problem!</h1><h2>%s</h2>" end
See? When Ruby reads this code it will include the backslash and won’t be replaced. But when Ruby evaluates it, it will simply return “Camping”, since “\p” isn’t a special character:
>> "Cam\ping" => "Camping"
Due to this nasty use of
eval, not everything would work as we expect it to do:
require 'camping' def Camping.rules! "Let's go shopping" end Camping.goes :Shopping Shopping.rules! # => it hits Camping#method_missing
Camping doesn’t copy the object, so it doesn’t matter what you do with it. Instead you have to modify Camping::S
require 'camping' Camping::S << <<EOF def Camping.rules! "Let's go shopping" end EOF Camping.goes :Shopping Shopping.rules! # => "Let's go shopping"
Oh, and one more thing
For those of you who haven’t subscribed to the mailing list, I think you should know this:
Magnus Holm: Come on, you lazy interrogative! Are your shoes too heavy? :-(
Why the Lucky Stiff: Bzzt! (Drawing on backup camping power grids…) Very sorry to be bad about this. Yeah, lots of Shoes stuff going on this week as we’re shooting for a July 31st release and there many bothersome bugs to smash.
You’ve all done a lot of fanastic work and I say we keep working a bit longer. I just merged zimbatm’s week-old patches and I think it would be great if we could get more campers to mess with judofyr’s gems, as I think camping 2.0 will inspire some breakages.
Augusttime would be better for me, but let’s talk about what you guys want to do.