Camping 2.0 - minature rails for stay-at-home moms

require “uri”;require “rack”;class Object;def meta_def
m,&b;(class<<self;self
end).send:define_method,m,&b end end;module
Camping;C=self;S=IO.read(FILE
)rescue nil;P=“

Cam\ping
Problem!

%s

”;U=Rack::Utils;Apps=[]
class H<Hash;def method_missing
m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
to_s]:super end;undef id,type if ??==63;end;module Helpers;def R
c,*g;p,h=
/(.+?)/,g.grep(Hash);g-=h;raise"bad route"unless
u=c.urls.find{|x|break x if
x.scan(p).size==g.size&&/^#{x}/?$/=~(x=g.inject(x){|x,a|x.sub
p,U.escape((a[
a.class.primary_key]rescue a))})};h.any?? u+“?”+U.build_query(h[0]):u
end;def
/ p;p[0]==?/?@root + p : p end;def URL c=‘/’,*a;c=R(c, a) if
c.respond_to?(
:urls);c=self/c;[email protected][/.{8,}?(?=/)/]+c if c[0]==?/;URI c end
end
module
Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
:headers,:body;def render v,a,&b;mab(/^/!~v.to_s){send(v,*a,&b)}
end;def
mab l=nil,&b;m=Mab.new({},self);s=m.capture(&b);s=m.capture{layout{s}}
if l &&
m.respond_to?(:layout);s end;def r s,b,h={};b,h=h,b if
Hash===b;@status=s;
@headers.merge!(h);@body=b;end;def redirect *a;r
302,‘’,‘Location’=>URL(*a).
to_s;end;def r404 p;P%“#{p} not found"end;def r500 k,m,e;raise e;end;def
r501 m
P%”#{m.upcase} not implemented"end;def
to_a;@env[‘rack.session’]=@state;r=Rack::
Response.new(@body,@status,@headers);@cookies.each{|k,v|next if
@old_cookies[
k]==v;v={:value=>v,:path=>self/“/”} if
String===v;r.set_cookie(k,v)};r.to_a;end
def initialize(env,m)
r=@request=Rack::Request.new(@env=env);@root,@input,
@cookies,@state,@headers,@status,@method=r.script_name.sub(//$/,‘’),n(r.params
),H[@old_cookies = r.cookies],H[r.session],{},m=~/r(\d+)/?$1.to_i: 200,m
end;def
n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=n(v);m}: h end;def service
*a;r=catch(
:halt){send(@method,*a)};@body||=r;self;end;end;module
Controllers;@r=[];class<<
self;def r;@r end;def R
u;r=@r;Class.new{meta_def(:urls){u};meta_def(:inherited
){|x|r<<x}}end;def D p,m;p='/'if
!p||!p[0];r.map{|k|k.urls.map{|x|return(k.
instance_method(m)rescue nil)?[k,m,
$~[1…-1]]:[I,‘r501’,m]if
p=~/^#{x}/?$/}}
[I,‘r404’,p] end;N=H.new{|
,x|x.downcase}.merge!
“N”=>‘(\d+)’,“X”=>‘([^/]+)’,
“Index”=>‘’;def M;def
M;end;constants.map{|c|k=const_get(c);k.send:include,C,
Base,Helpers,Models;@r=[k]+r if r-[k]==r;k.meta_def(:urls){ [
"/#{c.scan(
/.[^A-Z]
/).map(&N.method(:[]))
‘/’}“]}if !k.respond_to?:urls}end
end;I=R()
end;X=Controllers;class<<self;def goes
m;Apps<<eval(S.gsub(/Camping/,m.to_s),
TOPLEVEL_BINDING) end;def call
e;X.M;p=e[‘PATH_INFO’]=U.unescape(e[‘PATH_INFO’])
k,m,*a=X.D
p,e[‘REQUEST_METHOD’].downcase;k.new(e,m).service(*a).to_a;rescue
r500(:I,k,m,$!,:env=>e).to_a;end;def method_missing
m,c,*a;X.M;h=Hash===a[-1]?
a.pop:
{};e=H[Rack::MockRequest.env_for(‘’,h.delete(:env)||{})];k=X.const_get(c
).new(e,m.to_s);h.each{|i,v|k.send”#{i}=",v};k.service(a);end;def
use
a,&b;m=a.
shift.new(method(:call),*a,&b);meta_def(:call){|e|m.call(e)}end
end;module Views
include X,Helpers end;module Models;autoload:Base,
‘camping/ar’;end;autoload:Mab,‘camping/mab’;C end


Wow. After 199 commits, 11875 lines of diff and 1284 days, it’s an honor
to
present a new, freshly baked version of the microframework; now built
upon
Rack and weighing only 3072 tiny bytes. (That’s exactly 3k!)

gem install camping

Home: http://whywentcamping.com/ (currently only redirects to the docs)
Docs: http://camping.rubyforge.org/
Code/wiki/bugs: GitHub - camping/camping: the 5k pocket full-of-gags web microframework
Mailing list: http://rubyforge.org/mailman/listinfo/camping-list

~> Wait a second, you’re not _why!

Well, no. He went camping, so we decided to commandeer and steer this
ship
back on course. I’m merely a scoutmaster; it’s the community who’s in
charge.
Want to have an impact on Camping? Just join the mailing list, and your
voice
will be heard.

~> What’s new?

Let’s start with Rack.

Every Camping app is now a Rack app. This is your config.ru:

require 'blog'
run Blog

If your app requires a middleware, you can inject it inside your app:

module Blog
  use Rack::MethodOverride
end

Sessions are now simply a wrapper around env[‘rack.session’], so it’s
easy as
pie to use Other::SessionBackends.

Ironicly, the methods Rack stole from Camping are no longer in Camping,
since
it’s shorter to simply call those in Rack :slight_smile:

Next up: The book - http://camping.rubyforge.org/book.html

Not really a book, but it should get you started with Camping pretty
quick. It’s
far from complete, but in the end you should know plenty about both
Camping,
Rack, HTTP and other frameworks. Web development is a huge field in Ruby
and can
be a little confusing for newcomers. This book should give you a gentle
introduction together with pointers to where you could go for more.

This book isn’t written yet. Let me repeat that: This book isn’t
written yet. Nothing is set in stone. These are basically just some of
mine
ideas - what I wish was there some years ago. But I’m neither the author
nor
the reader, so I want YOU to tell me how it really should be. It’s
open-source
after all.

Being open-source means you are free to do whatever you want. Does that
sentence suck? That paragraph is badly phrased? That chapter doesn’t
belong
there? Rewrite it! Reorganize the whole book! Just make sure to tell the
rest
why it’s better.

Being open-source ALSO means you sometimes have to give up your perfect
chapter. Realize it wasn’t as good as you thought. It’s tough, but
that’s how
it’s going to be.

Okay, now: Simpler routes

The most used line is Camping apps has to be:

class Index < R '/'

So _why commited and now you can write:

class Index  # matches /
class Posts  # matches /posts
class PostX  # matches /post/([^/]+)
class UserN  # matches /user/(\d+)

~> Interesting. Is 1.5 still supported? What should I do to upgrade my
app?

No more development will be done for 1.5, so we recommend that you
upgrade
your app to 2.0. Rack::Adapter::Camping will be removed in the next
release of
Rack, so if you’re using it you should absolutely switch to Camping 2.0.

Plese read
http://camping.rubyforge.org/book/51_upgrading.html#from-15-to-20
for upgrade notes and if you still have any problems, please let us know
and
we’ll update it.

~> What will we see 2.1?

That’s up to you! What would you like to see? You don’t necessarily have
to
implement it yourself, just tell the rest on the mailing list and maybe
someone else helps out.

Sean Busbey is trying to make migrations suck less, and I want to make
it even
more Rackified. And we’ll all be smashing bugs.

~> Help, I’m stuck! Where should I go?

The mailing list: http://rubyforge.org/mailman/listinfo/camping-list

You can also try #camping on irc.freenode.net:
http://java.freenode.net/?channel=camping

// Magnus H.

Magnus H. wrote:

Wow. After 199 commits, 11875 lines of diff and 1284 days, it’s an honor
to
present a new, freshly baked version of the microframework; now built
upon
Rack and weighing only 3072 tiny bytes. (That’s exactly 3k!)

gem install camping

Sweet!
His spirit goes on. Grats to the team!

Magnus H. wrote:

require “uri”;require “rack”;class Object;def meta_def m,&b;(class<<self;self

With this post, you have single-handedly restored the ruby-talk
signal-to-noise ratio to 2002 levels.

On Apr 9, 2010, at 09:51 , Joel VanderWerf wrote:

Magnus H. wrote:

require “uri”;require “rack”;class Object;def meta_def m,&b;(class<<self;self

With this post, you have single-handedly restored the ruby-talk signal-to-noise ratio to 2002 levels.

Those were the days, weren’t they?

Now I want to pay Magnus to pit-fight thunk and take care of our 2010
problem.