6 ms·
A Full Web Service with HTTP caching in 7 lines
- jonursenbach 18y agoHow about we all stop boasting about how many lines we can write something in, and go back to writing quality software? Who gives a fuck how many lines it is, only thing we should care about is if it's good or not.
- alecst 18y agoUh, novice here, and although I'm sure we all agree that quality of code > lack of lines of code, there's no reason to bash clever programming. Who cares if it's pragmatic -- that's obviously not the motivation.
- rfunduk 18y agoBecause we shouldn't ever have any fun? We shouldn't check out Blake's cool little micro-framework? We shouldn't use our own blogs for things we find interesting?
- m_eiman 18y agoAm I the only one who's tired of these "X in Y lines of code!" things? It's obviously always many more lines of code, just hidden away from view, so meh! Come back when you've actually done some REAL WORK in insanely tight code, not just imported this and that lib.
- aditya 18y agoAgreed, there's nothing here that couldn't have been done 5 years ago with perl and CPAN. But, I think this post is relevant for two big reasons: 1. Sinatra and Rack are amazing lightweight alternatives (especially for web services) compared to the giantness that is Rails. 2. Rack::Cache is seriously awesome (http://tomayko.com/src/rack-cache/ http://tomayko.com/src/rack-cache/) and deserves more attention...
- aaronblohowiak 18y agoRack::Cache is neato for development, but you're better served using Varnish for production -- it acts as a caching reverse proxy to multiple machines, is insanely fast and battle-tested, it can be configured to serve stale content if the backend becomes unreachable, it supports ESI, and more! And yes, Sinatra & Rack are super cool.
- lsb 18y agoI'm using Sinatra et al for my thesis project, for a Master's in Latin, and minimizing the non-interesting bits of infrastructure helps a lot. It's interesting to me for the same reason PHP is interesting: it helped me wrap an HTTP interface over an executable in Ada with its own homegrown database, and (sociologically) it's a social commentary on the bits of plumbing we've agreed upon as useful.
- ph0rque 18y agoThe source code is still 55 characters too many for a tweet.
- rfunduk 18y agoDid you try getting it to fit? Even 'cheating' a bit by renaming the route and make the TTL 1 second I couldn't get it closer than -2 :/ I can get to +1 character left if I just make the route '/:n'! :)
- ph0rque 18y agoI thought about it, but then I remembered you'd get something like the camping microframework: %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
- juliend2 18y agoI love Sinatra. I find it very easy to use. I did a little web service that scraps the usage stats off an ISP page with it and Hpricot. I never had so much fun with Ruby!
- lsb 18y agoJust remember, if you're in Ruby working with strings, you want a local variable, because MRI leaks memory otherwise. See http://groups.google.com/group/god-rb/msg/3f5b13d6d4fa6480 http://groups.google.com/group/god-rb/msg/3f5b13d6d4fa6480