[~/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 end
si 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: