From df22480a10063d3735374a394154658e72780c35 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 11 Dec 2009 16:18:41 -0600 Subject: rack.logger specification --- lib/rack/lint.rb | 39 ++++++++++++++++++++++++++++++++++----- lib/rack/request.rb | 7 ++++--- test/spec_rack_lint.rb | 31 ++++++++++++++++++------------- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/lib/rack/lint.rb b/lib/rack/lint.rb index a1fcc3c6..493982ac 100644 --- a/lib/rack/lint.rb +++ b/lib/rack/lint.rb @@ -148,6 +148,35 @@ module Rack } end + ## rack.logger:: A common object interface for logging messages. + ## The object must implement: + if logger = env['rack.logger'] + ## info(message, &block) + assert("logger #{logger.inspect} must respond to info") { + logger.respond_to?(:info) + } + + ## debug(message, &block) + assert("logger #{logger.inspect} must respond to debug") { + logger.respond_to?(:debug) + } + + ## warn(message, &block) + assert("logger #{logger.inspect} must respond to warn") { + logger.respond_to?(:warn) + } + + ## error(message, &block) + assert("logger #{logger.inspect} must respond to error") { + logger.respond_to?(:error) + } + + ## fatal(message, &block) + assert("logger #{logger.inspect} must respond to fatal") { + logger.respond_to?(:fatal) + } + end + ## The server or the application can store their own data in the ## environment, too. The keys must contain at least one dot, ## and should be prefixed uniquely. The prefix rack. @@ -243,7 +272,7 @@ module Rack assert("rack.input #{input} is not opened in binary mode") { input.binmode? } if input.respond_to?(:binmode?) - + ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. [:gets, :each, :read, :rewind].each { |method| assert("rack.input #{input} does not respond to ##{method}") { @@ -300,9 +329,9 @@ module Rack args[1].kind_of?(String) } end - + v = @input.read(*args) - + assert("rack.input#read didn't return nil or a String") { v.nil? or v.kind_of? String } @@ -311,7 +340,7 @@ module Rack !v.nil? } end - + v end @@ -325,7 +354,7 @@ module Rack yield line } end - + ## * +rewind+ must be called without arguments. It rewinds the input ## stream back to the beginning. It must not raise Errno::ESPIPE: ## that is, it may not be a pipe or a socket. Therefore, handler diff --git a/lib/rack/request.rb b/lib/rack/request.rb index 248ce18d..d5070257 100644 --- a/lib/rack/request.rb +++ b/lib/rack/request.rb @@ -32,6 +32,7 @@ module Rack def content_type; @env['CONTENT_TYPE'] end def session; @env['rack.session'] ||= {} end def session_options; @env['rack.session.options'] ||= {} end + def logger; @env['rack.logger'] end # The media type (type/subtype) portion of the CONTENT_TYPE header # without any media type parameters. e.g., when CONTENT_TYPE is @@ -92,7 +93,7 @@ module Rack PARSEABLE_DATA_MEDIA_TYPES = [ 'multipart/related', 'multipart/mixed' - ] + ] # Determine whether the request body contains form-data by checking # the request media_type against registered form-data media-types: @@ -216,11 +217,11 @@ module Rack url end - + def path script_name + path_info end - + def fullpath query_string.empty? ? path : "#{path}?#{query_string}" end diff --git a/test/spec_rack_lint.rb b/test/spec_rack_lint.rb index 9c5d5031..bbf75c17 100644 --- a/test/spec_rack_lint.rb +++ b/test/spec_rack_lint.rb @@ -71,6 +71,11 @@ context "Rack::Lint" do }.should.raise(Rack::Lint::LintError). message.should.equal("session [] must respond to store and []=") + lambda { + Rack::Lint.new(nil).call(env("rack.logger" => [])) + }.should.raise(Rack::Lint::LintError). + message.should.equal("logger [] must respond to info") + lambda { Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP?")) }.should.raise(Rack::Lint::LintError). @@ -110,7 +115,7 @@ context "Rack::Lint" do Rack::Lint.new(nil).call(env("rack.input" => "")) }.should.raise(Rack::Lint::LintError). message.should.match(/does not respond to #gets/) - + lambda { input = Object.new def input.binmode? @@ -119,7 +124,7 @@ context "Rack::Lint" do Rack::Lint.new(nil).call(env("rack.input" => input)) }.should.raise(Rack::Lint::LintError). message.should.match(/is not opened in binary mode/) - + lambda { input = Object.new def input.external_encoding @@ -347,25 +352,25 @@ context "Rack::Lint" do yield 23 yield 42 end - + def rewind raise Errno::ESPIPE, "Errno::ESPIPE" end end - + eof_weirdio = Object.new class << eof_weirdio def gets nil end - + def read(*args) nil end - + def each end - + def rewind end end @@ -452,7 +457,7 @@ context "Rack::Lint" do }.should.raise(Rack::Lint::LintError). message.should.match(/body was given for HEAD/) end - + specify "passes valid read calls" do hello_str = "hello world" hello_str.force_encoding("ASCII-8BIT") if hello_str.respond_to? :force_encoding @@ -462,35 +467,35 @@ context "Rack::Lint" do [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(0) [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(1) [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(nil) [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(nil, '') [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(1, '') -- cgit v1.2.3-24-ge0c7