[~/rack/rack-rock-paper-scissors(simple)]$ cat -n rps.rb 1 require 'rack/request' 2 require 'rack/response' 3 4 module RockPaperScissors 5 class App 6 7 def initialize(app = nil) 8 @app = app 9 @content_type = :html 10 @defeat = {'rock' => 'scissors', 'paper' => 'rock', 'scissors' => 'paper'} 11 @throws = @defeat.keys 12 @choose = @throws.map { |x| 13 %Q{ <li><a href="/?choice=#{x}">#{x}</a></li> } 14 }.join("\n") 15 @choose = "<p>\n<ul>\n#{@choose}\n</ul>" 16 end 17 18 def call(env) 19 req = Rack::Request.new(env) 20 21 req.env.keys.sort.each { |x| puts "#{x} => #{req.env[x]}" } 22 23 computer_throw = @throws.sample 24 player_throw = req.GET["choice"] 25 anwser = if !@throws.include?(player_throw) 26 "Choose one of the following:" 27 elsif player_throw == computer_throw 28 "You tied with the computer" 29 elsif computer_throw == @defeat[player_throw] 30 "Nicely done; #{player_throw} beats #{computer_throw}" 31 else 32 "Ouch; #{computer_throw} beats #{player_throw}. Better luck next time!" 33 end 34 35 res = Rack::Response.new 36 res.write <<-"EOS" 37 <html> 38 <title>rps</title> 39 <body> 40 <h1> 41 #{anwser} 42 #{@choose} 43 </h1> 44 </body> 45 </html> 46 EOS 47 res.finish 48 end # call 49 end # App 50 end # RockPaperScissors 51 52 if $0 == __FILE__ 53 require 'rack' 54 require 'rack/showexceptions' 55 Rack::Server.start( 56 :app => Rack::ShowExceptions.new( 57 Rack::Lint.new( 58 RockPaperScissors::App.new)), 59 :Port => 9292, 60 :server => 'thin' 61 ) 62 end
req
pertenece a la clase Rack::Request
. Tiene
un único atributo env
:
(rdb:1) req #<Rack::Request:0x007f8d735b1410 @env={ "SERVER_SOFTWARE"=>"thin 1.5.1 codename Straight Razor", "SERVER_NAME"=>"0.0.0.0", "rack.input"=>#<Rack::Lint::InputWrapper:0x007f8d735776c0 @input=#<StringIO:0x007f8d735426a0>>, "rack.version"=>[1, 0], "rack.errors"=>#<Rack::Lint::ErrorWrapper:0x007f8d73577620 @error=#<IO:<STDERR>> >, "rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false, "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/", "PATH_INFO"=>"/", "REQUEST_URI"=>"/", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"0.0.0.0:9292", "HTTP_CONNECTION"=>"keep-alive", "HTTP_ACCEPT"=>"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36", "HTTP_ACCEPT_ENCODING"=>"gzip,deflate,sdch", "HTTP_ACCEPT_LANGUAGE"=>"es-ES,es;q=0.8", "GATEWAY_INTERFACE"=>"CGI/1.2", "SERVER_PORT"=>"9292", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "rack.url_scheme"=>"http", "SCRIPT_NAME"=>"", "REMOTE_ADDR"=>"127.0.0.1", "async.callback"=>#<Method: Thin::Connection#post_process>, "async.close"=>#<EventMachine::DefaultDeferrable:0x007f8d735603f8>}>Cuando llamamos a
GET
para obtener el valor del parámetro choice
:
player_throw = req.GET["choice"]Si visitamos la página
http://0.0.0.0:9292/
el entorno contiene algo como esto:
rdb:1) p @env {"SERVER_SOFTWARE"=>"thin 1.5.1 codename Straight Razor", ... "QUERY_STRING"=>"", "REQUEST_URI"=>"/" ... }el código de
GET
nos da los datos almacenados en QUERY_STRING
:
def GET if @env["rack.request.query_string"] == query_string @env["rack.request.query_hash"] else @env["rack.request.query_string"] = query_string @env["rack.request.query_hash"] = parse_query(query_string) end end def query_string; @env["QUERY_STRING"].to_s endsi es la primera vez,
@env["rack.request.query_string"]
está a
nil
y se ejecuta el else
inicializando @env["rack.request.query_string"]
y @env["rack.request.query_hash"]
Si por ejemplo visitamos la URL:
http://localhost:9292?choice=rock
entonces env
contendrá:
rdb:1) p env { ... "QUERY_STRING"=>"choice=rock", "REQUEST_URI"=>"/?choice=rock", ... }Familiaricemonos con algunos de los métodos de
Rack::Request
:
(rdb:1) req.GET {"choice"=>"paper"} (rdb:1) req.GET["choice"] "paper" (rdb:1) req.POST {} (rdb:1) req.params {"choice"=>"paper"} (rdb:1) req["choice"] "paper" (rdb:1) req[:choice] "paper" (rdb:1) req.cookies() {} (rdb:1) req.get? true (rdb:1) req.post? false (rdb:1) req.fullpath "/?choice=paper" (rdb:1) req.host "0.0.0.0" (rdb:1) req.host_with_port "0.0.0.0:9292" (rdb:1) req.body #<Rack::Lint::InputWrapper:0x007f8d7369b5d8 @input=#<StringIO:0x007f8d73690318>> (rdb:1) req.cookies() {} (rdb:1) req.get? true (rdb:1) req.post? false (rdb:1) req.fullpath "/?choice=paper" (rdb:1) req.host "0.0.0.0" (rdb:1) req.host_with_port "0.0.0.0:9292" (rdb:1) req.ip "127.0.0.1" (rdb:1) req.params {"choice"=>"paper"} (rdb:1) req.path "/" (rdb:1) req.path_info "/" (rdb:1) req.port 9292 (rdb:1) req.request_method "GET" (rdb:1) req.scheme "http" (rdb:1) req.url "http://0.0.0.0:9292/?choice=paper" (rdb:1) req.user_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36" (rdb:1) req.values_at("choice") ["paper"]
[~/rack/rack-rock-paper-scissors(simple)]$ cat Rakefile desc "run the server" task :default do sh "ruby rps.rb" end desc "run the client with rock" task :rock do sh %q{curl -v 'http://localhost:9292?choice=rock'} end desc "run the client with paper" task :paper do sh %q{curl -v 'http://localhost:9292?choice=paper'} end desc "run the client with scissors" task :scissors do sh %q{curl -v 'http://localhost:9292?choice=scissors'} end
[~/rack/rack-rock-paper-scissors(simple)]$ rake ruby rps.rb >> Thin web server (v1.5.1 codename Straight Razor) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:9292, CTRL+C to stop
[~/rack/rack-rock-paper-scissors(simple)]$ rake rock curl -v 'http://localhost:9292?choice=rock' * About to connect() to localhost port 9292 (#0) * Trying ::1... Connection refused * Trying 127.0.0.1... connected * Connected to localhost (127.0.0.1) port 9292 (#0) > GET /?choice=rock HTTP/1.1 > User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8x zlib/1.2.5 > Host: localhost:9292 > Accept: */* > < HTTP/1.1 200 OK < Content-Length: 332 < Connection: keep-alive < Server: thin 1.5.1 codename Straight Razor < <html> <title>rps</title> <body> <h1> Nicely done; rock beats scissors <p> <ul> <li><a href="/?choice=rock">rock</a></li> <li><a href="/?choice=paper">paper</a></li> <li><a href="/?choice=scissors">scissors</a></li> </ul> </h1> </body> </html> * Connection #0 to host localhost left intact * Closing connection #0
[~/rack/rack-rock-paper-scissors(simple)]$ rake ruby rps.rb >> Thin web server (v1.5.1 codename Straight Razor) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:9292, CTRL+C to stop GATEWAY_INTERFACE => CGI/1.2 HTTP_ACCEPT => */* HTTP_HOST => localhost:9292 HTTP_USER_AGENT => curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8x zlib/1.2.5 HTTP_VERSION => HTTP/1.1 PATH_INFO => / QUERY_STRING => choice=rock REMOTE_ADDR => 127.0.0.1 REQUEST_METHOD => GET REQUEST_PATH => / REQUEST_URI => /?choice=rock SCRIPT_NAME => SERVER_NAME => localhost SERVER_PORT => 9292 SERVER_PROTOCOL => HTTP/1.1 SERVER_SOFTWARE => thin 1.5.1 codename Straight Razor async.callback => #<Method: Thin::Connection#post_process> async.close => #<EventMachine::DefaultDeferrable:0x007ff4e2bf8e78> rack.errors => #<Rack::Lint::ErrorWrapper:0x007ff4e2c04b88> rack.input => #<Rack::Lint::InputWrapper:0x007ff4e2c04c00> rack.multiprocess => false rack.multithread => false rack.run_once => false rack.url_scheme => http rack.version => [1, 0]
Véase la documentación de las siguientes clases: