sneaking Ruby through the system
So we’re all glued to the Cheese on Toast saga and we all have our opinions. This can get heated real quickly, but before anyone else says anything, I have to say: muenster cheese. Don’t be wreckless, just go to the deli and have them slice it at a 5.
Again, DO NOT TRY THIS HOME! Go to a skate park late at night when the bowl is empty. Or rent a small storage space or something.
Polly Appleholtz has e-mailed in to remind me that it’s not called “Cheese on Toast,” but rather just “Cheesetoast.” Oh, that’s right!
If you’re running JRuby from trunk, try this:
$ gem install hpricot --source http://code.whytheluckystiff.net Select which gem to install for your platform (java) 1. hpricot 0.5.110 (jruby) 2. hpricot 0.5.110 (mswin32) 3. hpricot 0.5.110 (ruby) > 1 Successfully installed hpricot-0.5.110-jruby Installing ri documentation for hpricot-0.5.110-jruby... Installing RDoc documentation for hpricot-0.5.110-jruby...
But how is this possible given that Hpricot’s parser is written in C?? Because Ragel can generate Java code! Ola goes into it.
With the help and goodwill of the RedCloth mailing list, it has been decided that RedCloth 4 will end up being the polished finished code for SuperRedCloth. There is still a little ways to go, but I think it could happen within February. If, that is, you help goof around with Super.
gem install superredcloth --source http://code.whytheluckystiff.net
And to use it, do:
require 'superredcloth'
p SuperRedCloth.new("h1. The Legend of Zu").to_html
All textile syntax should work. Options like :hard_breaks and :filter_html are still underway.
Bram Cohen: Clearly, digital computers test great. In application however, they have a ton of challenges.
A guy who’s into business trends versus a guy who’s into logic puzzles. Gee, I wonder who is better equipped for this!!
While bunking inside Ragel, I’m starting to see the handiness of its lookahead operator. The bird beak :>, which gives a high priority to the next token in the machine.
In SuperRedCloth, this rule here was a flimsy way of matching a bit of text in parens:
title = ( '(' [^)]+ ')' );
It turns out I was able to cut down the generated grammer by something like fifty K by using this instead:
title = ( '(' chars+ :> ')' ) ;
The beak is great for any rule that’s getting too greedy and concludes with an exact character. Be warned, it may increase the complexity of the machine depending on how ambiguous your other rules are.
If I could offer one other bit of advice: stay away from the question mark, if you can. It seems like anything which uses the empty token can be expensive.
Ach. Prih. Kott! With much, much, much.

Now with these little pulps and these more splatters. And, more recently:
a[text()="Click Me!"] and h3[text()*="space"] and the like.The gem is undergoing a brief mirroring dungeon quest on Rubyforge, but can meanwhilst be slurped from the still:
gem install hpricot --source http://code.whytheluckystiff.net/
And, tarball too: hpricot-0.5.tgz.
I have a sneaking suspicion that a 0.5.1 will be needed. But I’m at peace with that!! Thankyou for letting this sticky stuff drip down your chin, fine people.
I’m sick of RedCloth being my most nauseating library!! All those treacherous regexps…
$ svn co http://code.whytheluckystiff.net/svn/redcloth/branches/superredcloth $ cd superredcloth $ rake
You’ll need the latest ragel installed. This will be ten times faster.
What’s up with this job posting which demands a Gemini, Leo, Libra, Sagittarius or Aquarius?
The most ambitious Ruby on Rails project calls for a Rail’s guru to lead team as Co-founder
This is a wonderful entrepreneurial position for the humanitarian keen on facilitating emotional fulfilment for humanity.
*Birthday must fall between;
January 20 and February 18
May 21 and June 20
July 23 and August 22
Sept. 23 and Oct. 22
November 23 and December 21
Is this a phenomenon common to Germany? I’m sorry, the stars just aren’t aligned for you to code for us today. (Seen on onslaught.)
I had previously been using rb_iterate and a call to Proc.new to build a block in C. But that takes two function calls while the undocumented rb_proc_new is just one.
require 'rubygems'
require 'inline'
module Kernel
inline do |ext|
ext.prefix %{
static VALUE sum(VALUE args)
{
return rb_funcall(rb_ary_entry(args, 0), rb_intern("+"), 1,
rb_ary_entry(args, 1));
return Qnil;
}
}
ext.c %{
VALUE sum_block()
{
return rb_proc_new(sum, 0);
}
}
end
end
p sum_block[13, 2]
p (0..20).inject(0, &sum_block)
Most of the time rb_iterate is what you need. But, you know, in case you actually want a Proc object.
Kevin Clark: This might be the longest post with the least substance I’ve read in a long time. Why would you use this space to tout your history? How did you get post access on the O’Reilly Ruby Blog?
Let the blogging contests begin!!
Today, the International Kayak Consortium celebrates Camping (a Microframework)’s 1st birthday. They have honored the paragraph of code by awarding it the Annual First Place in Birthdaying Special Day Award and So Brave.
The commissioner of kayaking LeBrock Mitchell gave an acceptance speech on behalf of Camping at this morning’s banquet. His sentiments were brief, but stirring:
I have written two speeches for today, a long one and a short one. However, the pages for both got wet inside my kayak. Yes, I tried blow-drying them. But as I held that that cylinder of hot air, I realize that I couldn’t say anything as brief as Camping itself.
And he held up a printout of Camping from trunk and he wept exactly 4k of tears. We, in fact, measured with a graduated cylinder.
Here is Camping today.
%w[active_support markaby tempfile uri].map{|l|require l}
module Camping;Apps=[];C=self;S=IO.read(__FILE__).sub(/S=I.+$/,'')
P="Cam\ping Problem!";module Helpers;def R(c,*g);p,h=/\(.+?\)/,g.grep(Hash)
(g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|s.sub p,C.
escape((a[a.class.primary_key]rescue a))}+(h.any?? "?"+h[0].map{|x|x.map{|z|C.
escape z}*"="}*"&": "")end;def URL c='/',*a;c=R(c,*a)if c.respond_to?:urls
c=self/c;c="//"+@env.HTTP_HOST+c if c[/^\//];URI(c)end;def/p;p[/^\//]?@root+p :
p end;def errors_for o;ul.errors{o.errors.each_full{|x|li x}}if o.errors.any?end
end;module Base;include Helpers;attr_accessor:input,:cookies,:env,:headers,:body,
:status,:root;def method_missing*a,&b;a.shift if a[0]==:render;m=Mab.new {},self
s=m.capture{send(*a,&b)};s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.
respond_to?:layout;s end;def r s,b,h={};@status=s;@headers.merge!h;@body=b end
def redirect*a;r 302,'','Location'=>URL(*a)end;Z="\r\n";def to_a;[@status,@body,
@headers]end;def initialize r,e,m;e=H[e.to_hash];@status,@method,@env,@headers,
@root=200,m.downcase,e,{'Content-Type'=>"text/html"},e.SCRIPT_NAME.sub(/\/$/,'')
@k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r;if%r|\Amultipart/form-.*boun\
dary=\"?([^\";,]+)|n.match e.CONTENT_TYPE;b=/(?:\r?\n|\A)#{Regexp::quote("--#$1"
)}(?:--)?\r$/;until@in.eof?;fh=H[];for l in@in;case l;when Z;break
when/^Content-D.+?: form-data;/;fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten]
when/^Content-Type: (.+?)(\r$|\Z)/m;fh[:type]=$1;end;end;fn=fh[:name];o=if
fh[:filename];o=fh[:tempfile]=Tempfile.new(:C);o.binmode;else;fh=""end;while l=@in.
read(16384);if l=~b;o<<$`.chomp;@in.seek(-$'.size,IO::SEEK_CUR);break;end;o<<l
end;C.qsp(fn,'&;',fh,q) if fn;fh[:tempfile].rewind if fh.is_a?H;end;elsif@method==
"post";q.u C.qsp(@in.read)end;@cookies,@input=@k.dup,q.dup end;def service*a
@body=send(@method,*a)if respond_to?@method;@headers["Set-Cookie"]=@cookies.map{
|k,v|"#{k}=#{C.escape(v)}; path=#{self/'/'}"if v!=@k[k]}-[nil];self end;def to_s
a=[];@headers.map{|k,v|[*v].map{|x|a<<"#{k}: #{x}"}};"Status: #{@status}#{Z+a*Z+
Z*2+@body}"end;end;X=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 M;def M
end;constants.map{|c|k=const_get(c);k.send:include,C,Base,Models;r[0,0]=k if
!r.include?k;k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls}end;def
D p;r.map{|k|k.urls.map{|x|return k,$~[1..-1]if p=~/^#{x}\/?$/}};[NotFound,[p]]end
end;class NotFound<R();def get p;r(404,Mab.new{h1 P;h2 p+" not found"})end end
class ServerError<R();def get k,m,e;r(500,Mab.new{h1 P;h2"#{k}.#{m}";h3"#{e.class
} #{e.message}:";ul{e.backtrace.each{|bt|li(bt)}}}.to_s)end end;self;end;class<<
self;def goes m;eval S.gsub(/Camping/,m.to_s).gsub("A\pps=[]","Cam\ping::Apps<<\
self"),TOPLEVEL_BINDING;end;def escape s;s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.
unpack('H2'*$&.size)*'%').upcase}.tr(' ','+')end;def un s;s.tr('+',' ').gsub(
/%([\da-f]{2})/in){[$1].pack('H*')}end;def qsp q,d='&;',y=nil,z=H[];m=proc{|_,o,n|o.u(
n,&m)rescue([*o]<<n)};q.to_s.split(/[#{d}] */n).inject((b,z=z,H[])[0]){|h,p|k,v=un(p).
split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end;def
kp s;c=qsp(s,';,')end;def run r=$stdin,e=ENV;X.M;k,a=X.D un("/#{e[
'PATH_INFO']}".gsub(/\/+/,'/'));k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.
service *a;rescue Object=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
def method_missing m,c,*a;X.M;k=X.const_get(c).new(StringIO.new,H['HTTP_HOST',
'','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s);H.new(a.pop).each{|e,f|k.send(
"#{e}=",f)}if Hash===a[-1];k.service *a;end;end;module Views;include X,Helpers
end;module Models;autoload:Base,'camping/db';def Y;self;end;end;class Mab<
Markaby::Builder;include Views;def tag!*g,&b;h=g[-1];[:href,:action,:src].map{
|a|(h[a]=self/h[a])rescue 0};super end end;H=HashWithIndifferentAccess;class H
def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(
NoMethodError,"#{m}")end;alias_method:u,:regular_update;end end
More recently:
Update: If all of you can get out your copy of the Camping core team’s group picture, Indian Chief Skittles McQueeny has just sent me the following legend:

Update from Air Force Staff Sargeant Guds Mandragon:

We try to keep a lid on it, but some pilot folklore has infiltrated our ranks. The tale goes that if you eject from your plane on Camping’s birthday that you will be visited in the night by a red fairy who will grant you a free batch of caramel apples, answering to any quantity you provide. In some permutations of the rumor, she grants an infinite quantity. Four aircraft have been ditched, two have struck earth, one crushing a cereal factory. I am told Grape Nuts. Please dispell this rumor forthrighly.
Hmm, interesing stuff. Thanks, Guds!
Update: 
Update: The latest Camping trunk lets you add a query string to your routes by adding a Hash argument.
>> a "version 2", :href => R(Show, page.title, :version => 2) => "<a href='/wiki/title?version=2'>version 2</a>"
Chad Fowler: I was thinking we could deploy this on rubygems.org and maybe open up the source for a few collaborators.
RE: Gemtacular.com. Added to hoodwink.d, if you want to comment on gems. Also related and interesting: Dr. Nic and Erik Kastner offer Gem metastuff in JSON.
Matz is warming up to the term eigenclass, the People’s slang for (class << self; self; end). From [ruby-talk:231992]:
In my mindset, two candidates have survived. singleton_class (or singletonclass), which can easily be confused with a class in the singleton design pattern. And eigenclass, which is unfamiliar for most people.
Does anyone know if Perl 6 folks still use it?
Want to move from Instiki to Junebug? I exported my Instiki as a zip of .textile pages and wrote instiki2junebug.rb to import my pages. Give it the Junebug username to assign the pages to and a path to the unzipped directory of files.
junebug wiki cd wiki ruby instiki2junebug.rb _why ~/instiki-dump
So, in what ways have you guys extended Hpricot? I really enjoy this collection of accessories to Hpricot by Christoffer Sawicki, who also wrote the Hpricot-based HTML-to-feed library called Feedalizer.
He has one script that does gsub! on all text nodes in the document. Another script is for generating tables of contents from the headers on an HTML page. I imagine that would go great with Markdown and Textile. (See also: del.icio.us/tag/hpricot.)