Camping, a Log

Camping, a Log

Aug 19 2010

Camping 2.1!

Camping 2.1!

        {}
        ||
        ||
  ~~~~~~~~~~~~~~~           <=   _whycake
  ~ Camping 2.1 ~
  ~~~~~~~~~~~~~~~

I’m pleased to announce another release of Camping, the microframework. This time we’ve focused on improving the 1.9 support, adding (builtin) support for more template engines, refreshing the homepage and just general bug fixes.

gem install camping

Also: CodeBugsList.

Let’s have a look:

~> ERB and Haml

Camping now includes support for Tilt which means that you’ll get simple, effortless ERB and Haml support:

module App
  # Path to where you want to store the templates
  set :views, File.dirname(__FILE__) + '/views'
end

module App::Controllers
  class Index
    def get
      render :index
    end
  end
end

Now you just need to add a views/index.haml or views/index.erb and it’ll render that instead of using Markaby. You can still use Markaby of course!

If you want to change any options for either ERB or Haml, you can use #set:

module App
  set :haml, { :escape_html => true }
  set :erb,  { :trim => "%" }
end

~> New homepage

Bluebie has designed an excellent new homepage for Camping:

http://camping.rubyforge.org/

It should have links to pretty much everything you need to know about Camping. As soon as possible we’ll also try to integrate it with the GitHub wiki and make everything more easily editable, so you can add your own links too!

We’ve also started this blog, where we’ll keep you up-to-date on the Camping development and community.

~> _whyday!

It’s the 19th August today, so that means it’s Whyday: http://whyday.org/

Camping 2.1 is our little contribution :-)

I should mention that many of these changes has been available for a *looong* time in the source, but we felt that Whyday was a perfect occasion for finally releasing 2.1.

I’d actually recommend to try out the experimental version if there’s been a while since the latest release. See the installation page in the wiki for information, and subscribe to http://campingrb.tumblr.com/ to get a sneak preview of the latest changes in Camping!

Have fun and enjoy both Whyday and Camping!

— Originally posted to the list, by Judofyr.


One Cool Hack

One Cool Hack

bluebie:

To celebrate #whyday, I designed and deployed a shiny new website for the Camping Microframework—one of Why’s many attempts to teach kids some kind of programming. It has a tent and a tipi. It’s really quite amazing. Everyone’s talking about how unreadable the navigation menu is—which means my work is complete.

What I’m most proud of though is this epic hack! This mightn’t seem like much if you aren’t a typehead or a web developer, but that right there? That’s a webfont. With two colours. Yep. Two of them. Not one. Two. That text is totally dynamic.

Read More

Happy #WhyDay Everyone!


Aug 18 2010

Camping Again

Camping Again

Just in time for #WhyDay, a brand new Camping website. Okay, so that’s a lie. It looks new though! Why, I bet you haven’t even seen any of this here content! Quite spiffy really.

The design was mostly created by @Bluebie, and most of the content by @Judofyr. Camping 2.1 will be out soon too. Oh there’s sure to be some goodies in that. Though really, Camping 2.0 is really quite great! Everyone’s favourite 4k framework is now < 3kb! 150% awesomer, just like that.


Jan 19 2006

Camping is a Microframework

Camping is a Microframework

First, as a mural. For friends here who like to pick at the weave.

 %w[rubygems active_record markaby metaid ostruct].each {|lib| require lib}
 module Camping;C=self;module Models;end;Models::Base=ActiveRecord::Base
 module Helpers;def R c,*args;p=/\(.+?\)/;args.inject(c.urls.detect{|x|x.
 scan(p).size==args.size}.dup){|str,a|str.gsub(p,(a.method(a.class.primary_key
 )[]rescue a).to_s)};end;def / p;File.join(@root,p) end;end;module Controllers
 module Base;include Helpers;attr_accessor :input,:cookies,:headers,:body,
 :status,:root;def method_missing(m,*args,&blk);str=m==:render ? markaview(
 *args,&blk):eval("markaby.#{m}(*args,&blk)");str=markaview(:layout){str
 }rescue nil;r(200,str.to_s);end;def r(s,b,h={});@status=s;@headers.merge!(h)
 @body=b;end;def redirect(c,*args);c=R(c,*args)if c.respond_to?:urls;r(302,'',
 'Location'=>self/c);end;def service(r,e,m,a);@status,@headers,@root=200,{},e[
 'SCRIPT_NAME'];@cookies=C.cookie_parse(e['HTTP_COOKIE']||e['COOKIE']);cook=
 @cookies.marshal_dump.dup;if ("POST"==e['REQUEST_METHOD'])and %r|\Amultipart\
 /form-data.*boundary=\"?([^\";,]+)\"?|n.match(e['CONTENT_TYPE']);return r(500,
 "No multipart/form-data supported.")else;@input=C.qs_parse(e['REQUEST_METHOD'
 ]=="POST"?r.read(e['CONTENT_LENGTH'].to_i):e['QUERY_STRING']);end;@body=
 method(m.downcase).call(*a);@headers["Set-Cookie"]=@cookies.marshal_dump.map{
 |k,v|"#{k}=#{C.escape(v)}; path=/"if v != cook[k]}.compact;self;end;def to_s
 "Status: #{@status}\n#{{'Content-Type'=>'text/html'}.merge(@headers).map{|k,v|
 v.to_a.map{|v2|"#{k}: #{v2}"}}.flatten.join("\n")}\n\n#{@body}";end;def \
 markaby;Class.new(Markaby::Builder){@root=@root;include Views;def tag!(*g,&b)
 [:href,:action].each{|a|(g.last[a]=self./(g.last[a]))rescue 0};super end}.new(
 instance_variables.map{|iv|[iv[1..-1].intern,instance_variable_get(iv)]},{})
 end;def markaview(m,*args,&blk);markaby.instance_eval{Views.instance_method(m
 ).bind(self).call(*args, &blk);self}.to_s;end;end;class R;include Base end
 class NotFound<R;def get(p);r(404,div{h1("#{C} Problem!")+h2("#{p} not found")
 });end end;class ServerError<R;def get(k,m,e);r(500,markaby.div{h1 "#{C} Prob\
 lem!";h2 "#{k}.#{m}";h3 "#{e.class} #{e.message}:";ul{e.backtrace.each{|bt|li(
 bt)}}})end end;class<<self;def R(*urls);Class.new(R){meta_def(:inherited){|c|
 c.meta_def(:urls){urls}}};end;def D(path);constants.each{|c|k=const_get(c)
 return k,$~[1..-1] if (k.urls rescue "/#{c.downcase}").find {|x|path=~/^#{x}\
 \/?$/}};[NotFound,[path]];end end end;class<<self;def escape(s);s.to_s.gsub(
 /([^ a-zA-Z0-9_.-]+)/n){'%'+$1.unpack('H2'*$1.size).join('%').upcase}.tr(' ',
 '+') end;def unescape(s);s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){[$1.
 delete('%')].pack('H*')} end;def qs_parse(qs,d='&;');OpenStruct.new((qs||'').
 split(/[#{d}] */n).inject({}){|hsh,p|k,v=p.split('=',2).map{|v|unescape(v)}
 hsh[k]=v unless v.empty?;hsh}) end;def cookie_parse(s);c=qs_parse(s,';,') end
 def run(r=$stdin,w=$stdout);w<<begin;k,a=Controllers.D "/#{ENV['PATH_INFO']}".
 gsub(%r!/+!,'/');m=ENV['REQUEST_METHOD']||"GET";k.class_eval{include C
 include Controllers::Base;include Models};o=k.new;o.service(r,ENV,m,a);rescue\
 =>e;Controllers::ServerError.new.service(r,ENV,"GET",[k,m,e]);end;end;end
 module Views; include Controllers; include Helpers end;end

  1. gem install camping --source http://code.whytheluckystiff.net/
    • Installs the regular camping.rb.
    • … and dependencies activerecord,markaby and metaid.
  2. For an example, see the blog.

Update:

Update: Field Office Outpost Bravo Bravo reports.

Update: Ranger Douglas has sent word.

Many rangers, myself included, returned from their morning jaunt to find this tiny yarn insignia fastened to their ranger doors without explanation. It seems peaceful, like something Camping would do, but you never know. Radicals often portray future animal executions in the simplest of strokes.

Camping has not had the time or inclination to rate and classify this message, so it is being displayed in its true, unfiltered form.

Update: Reader Justin Heat sent in this awful photo.

He says, “At my aunt’s viewing. Snapped a pic for you with my Treo 650.”

Off-topic. And NOT funny. Let’s start focusing on getting through this day before we talk about this kind of stuff. For crying out loud.

Update: What luck, this month’s Boy’s Life has a feature story for PDFsubscribers only. Very in-depth. An excerpt:

Update: from #camping.

 20:11 <goalie> can camping do e-commerce?
 20:11 <_why> no, use rails
 20:11 <RangerCliff> heh wtf?
 20:13 <goalie> it's just a small store, we only have two products
 20:13 <goalie> root beer lip balm and cream soda lip balm
 20:13 * _why contemplates
 20:14 <goalie> mail-order only
 20:14 <_why> now you're talking!!

Update: 2006 uniforms are in.

Update:

Update: You may now clip the following article from your handbooks, the Camping Phys Ed staff has ejected it from the curriculum!

Update:

If you’ve come to this site looking for the Dog Scouts, or if you’ve never heard of Dog Scouts and would like to sign your dog (or dogs) up for Dog Scouts, please click on the image of the Geocaching 3 Merit Badge for Dogs (to your right, my left) and you will be whisked away to the correct site.

If you are looking for Doggles, they can be foundhere.

Matthew Cartwright from Aberdeen, WA, writes in:

My nine-year-old daughter has been captivated with Camping over the last day or so. We even got her a little tackle box to put all her supplies in. Her excitement really came to a crescendo when she read your story about Ranger Cliff hanging out inIRC. She’s been non-stop Ranger Cliff all morning.

Anyway, she’s now filming a stop-motion film about the wedding of Ranger Cliff, I’m including a still frame I just snapped over her shoulder. Ranger Cliff is the little, rotund, dark fellow.

Great work, Katy! You’ve nailed the Ranger. His balance is abyssmal.

Update: Photos are piling up on Flickr now that everyone’s back from CampingCamp, held last night at Ranger Mayhew’s house in Minneapolis.Jealous.

Alex Chanticlair took the following photo and adds:

Troops 142 and 146 were in attendance. Many a glowstick was had. I know it looks alot like a rave, but believe me, it’s a very safe, very loving environment, sort of like a rave, but with root beer and cream soda lip balms instead of Roofies or Vitamin K. Actually, Roofies are still pretty common at conventions, but usually those people are under the table and don’t pollute the general mood of self-photography.

Update: 100 bytes have been shaved from Camping 1.1. Update through gems or wherever.

Two steps to get Camping working under Lighttpd+FastCGI. At the bottom of your application script (blog.rb):

 if __FILE__ == $0
   require 'fcgi'
   Dir.chdir(File.dirname(__FILE__))
   Camping::Models::Base.establish_connection 
     :adapter => 'sqlite3', :database => 'blog3.db'
   Camping::Models::Base.logger = Logger.new('camping.log')
   FCGI.each do |req|
     ENV.replace req.env
     Camping.run(req.in, req.out)
     req.finish
   end
 end

A suitable lighttpd.conf would look like:

 server.port                 = 3044
 server.bind                 = "127.0.0.1" 
 server.modules              = ( "mod_fastcgi" )
 server.document-root        = "/var/camping/blog/" 
 server.errorlog             = "/var/camping/blog/error.log" 

 #### fastcgi module
 fastcgi.server = ( "/" => ( 
   "localhost" => ( 
     "socket" => "/tmp/camping-blog.socket",
     "bin-path" => "/var/camping/blog/blog.rb",
     "check-local" => "disable",
     "max-procs" => 1 ) ) )

The check-local directive is vital to make sure lighttpd passes all the requests into blog.rb without throwing a 404.

Update:

Update: Reader Bill Atley writes in:

This afternoon I was at my grandfather’s house (I’m his primary caretaker) and midway through a corn feeding, I look over and this little mouse has taken the stage on a bit of carpet over by the television, no idea where he got the little mike, but he started belting away—Walk This Way, Sweet Child of Mine—classic stuff! I swear, it has to be related!

Thanks, Bill. It has to be related.

Hot tip! Give the new symmetrical R is for Routing method a try, it’s in trunk or the 1.1.18 gem on http://code.whytheluckystiff.net/ (still at 3.2k!)

Pave routes with Controllers::R:

 module Camping::Controllers
   class BlogEdit < R '/edit/(\d+)'; end
 edn

Find a Route backwards inside controller and view methods with Helpers::R:

 def Camping::Views.all_posts
   for post in @posts
     a :href => R(BlogEdit, post)
   end
 end

Also works in redirects:

 redirect R(BlogEdit, 2)

One breakage overnight: if a controller and a model are named identically, you’ll need to refer to the model as Models::Blog inside the controller. See the blogging app.

Update: The Florida Friends of Camping want to send out an alert to the vast throngs of bedraggled and disenfranchised coders who don’t fathom Camping, don’t care about it and are hurt that it is even trying to do anything.

Many dogs are out of work and remain unemployed for years on end. Their prospects are weak and many humans lack the patience to help the canine hunt through Craigslist. (The mouse peripheral was specifically designed without paws in mind.) Yet, many of these dogs are our best asset when faced with that initial first stab through Camping. Call us! Our dogs are lined upright now, outside the facility, with their honorary green scarves blowing in the wind, ready to embark on a walking tour of up to 4k. It’s your enjoyment that’s at stake here!

Update: