Class: Rackful::Resource Abstract

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rackful/resource.rb

Overview

This class is abstract.

Realizations must implement…

TODO:

better documentation

Abstract superclass for resources served by Server.

See Also:

Direct Known Subclasses

HTTPStatus::Resource

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Resource) initialize(uri)

Returns a new instance of Resource



122
123
124
125
# File 'lib/rackful/resource.rb', line 122

def initialize( uri )
  @uri = uri.kind_of?( URI::Generic ) ? uri.dup : URI(uri.to_s).normalize
  #self.uri = uri
end

Instance Attribute Details

- (String) get_etag (readonly)

This method is abstract.

The ETag of this resource.

If your classes implement this method, then an ETag: response header is generated automatically when appropriate. This allows clients to perform conditional requests, by sending an If-Match: or If-None-Match: request header. These conditions are then asserted for you automatically.

Make sure your entity tag is a properly formatted string. In ABNF:

entity-tag    = [ "W/" ] quoted-string
quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
qdtext        = <any TEXT except <">>
quoted-pair   = "\" CHAR

Returns:

  • (String)

See Also:



# File 'lib/rackful/resource.rb', line 216

- (Array<(Time, Boolean)>) get_last_modified (readonly)

This method is abstract.

Last modification of this resource.

If your classes implement this method, then a Last-Modified: response header is generated automatically when appropriate. This allows clients to perform conditional requests, by sending an If-Modified-Since: or If-Unmodified-Since: request header. These conditions are then asserted for you automatically.

Returns:

  • (Array<(Time, Boolean)>)

    The timestamp, and a flag indicating if the timestamp is a strong validator.

See Also:



# File 'lib/rackful/resource.rb', line 239

- (URI) uri (readonly)

The canonical path of this resource.

Returns:



187
188
189
# File 'lib/rackful/resource.rb', line 187

def uri
  @uri
end

Class Method Details

+ (self) add_parser(parser, method = :PUT)

Meta-programmer method.

Examples:

Have your resource accept XHTML in PUT requests

class MyResource
  include Rackful::Resource
  add_parser Rackful::Parser::XHTML, :PUT
end

Parameters:

  • parser (Class)

    an implementation (ie. subclass) of Parser

  • method (#to_sym) (defaults to: :PUT)

    For example: :PUT or :POST

Returns:

  • (self)


47
48
49
50
51
52
53
# File 'lib/rackful/resource.rb', line 47

def add_parser parser, method = :PUT
  method = method.to_sym
  self.parsers[method] ||= []
  self.parsers[method] << parser
  self.parsers[method].uniq!
  self
end

+ (self) add_serializer(serializer, quality = 1.0)

Meta-programmer method.

Examples:

Have your resource rendered in XML and JSON

class MyResource
  add_serializer MyResource2XML
  add_serializer MyResource2JSON, 0.5
end

Parameters:

  • serializer (Serializer)
  • quality (Float) (defaults to: 1.0)

Returns:

  • (self)


25
26
27
28
29
30
31
32
33
34
35
# File 'lib/rackful/resource.rb', line 25

def add_serializer serializer, quality = 1.0
  quality = quality.to_f
  quality = 1.0 if quality > 1.0
  quality = 0.0 if quality < 0.0
  s = [serializer, quality]
  serializer::CONTENT_TYPES.each {
  |content_type|
    self.serializers[content_type.to_s] = s
  }
  self
end

Instance Method Details

- (void) default_headers

Adds ETag: and Last-Modified: response headers.



397
398
399
400
401
402
403
404
# File 'lib/rackful/resource.rb', line 397

def default_headers
  r = {}
  r['ETag'] = self.get_etag     \
if self.respond_to?( :get_etag )
  r['Last-Modified'] = self.get_last_modified[0].httpdate     \
if self.respond_to?( :get_last_modified )
  r
end

- (Hash?) destroy

Returns an optional header hash.

Returns:

  • (Hash, nil)

    an optional header hash.



# File 'lib/rackful/resource.rb', line 255

- do_METHOD(Request, Rack::Response)

This method is abstract.

This method returns an undefined value.

HTTP/1.1 method handler.

To handle certain HTTP/1.1 request methods, resources must implement methods called do_<HTTP_METHOD>.

Examples:

Handling PATCH requests

def do_PATCH request, response
  response['Content-Type'] = 'text/plain'
  response.body = [ 'Hello world!' ]
end

Raises:



# File 'lib/rackful/resource.rb', line 167

- (Boolean) empty?

Does this resource exist?

For example, a client can PUT to a URL that doesn't refer to a resource yet. In that case, your resource registry can produce an empty resource to handle the PUT request. HEAD and GET requests will still yield 404 Not Found.

Returns:

  • (Boolean)

    The default implementation returns false.



205
206
207
# File 'lib/rackful/resource.rb', line 205

def empty?
  false
end

- (self) http_HEAD(request, response)

Handles a HEAD request.

This default handler for HEAD requests calls #http_GET, and then strips off the response body.

Feel free to override this method at will.

Returns:

  • (self)


314
315
316
317
318
319
320
321
322
323
# File 'lib/rackful/resource.rb', line 314

def http_HEAD request, response
  self.http_GET request, response
  response['Content-Length'] =
    response.body.reduce(0) do
      |memo, s| memo + bytesize(s)
    end.to_s
  # Is this really necessary? Doesn't Rack automatically strip the response
  # body for HEAD requests?
  response.body = []
end

- http_OPTIONS(request, response)

This method returns an undefined value.

Handles an OPTIONS request.

As a courtesy, this module implements a default handler for OPTIONS requests. It creates an Allow: header, listing all implemented HTTP/1.1 methods for this resource. By default, an HTTP/1.1 204 No Content is returned (without an entity body).

Feel free to override this method at will.

Raises:



299
300
301
302
# File 'lib/rackful/resource.rb', line 299

def http_OPTIONS request, response
  response.status = Rack::Utils.status_code :no_content
  response.header['Allow'] = self.http_methods.join ', '
end

- (Parser?) parser(request)

The best media type for the response body, given the current HTTP request.

Parameters:

Returns:

  • (Parser, nil)

    a Parser, or nil if the request entity is empty

Raises:



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rackful/resource.rb', line 146

def parser request
  unless request.content_length ||
         'chunked' == request.env['HTTP_TRANSFER_ENCODING']
    raise HTTP411LengthRequired
  end
  request_media_type = request.media_type.to_s
  supported_media_types = []
  all_parsers = self.class.all_parsers[ request.request_method.to_sym ] || []
  all_parsers.each do |p|
    p::MEDIA_TYPES.each do |parser_media_type|
      if File.fnmatch( parser_media_type, request_media_type )
        return p.new( request, self )
      end
      supported_media_types << parser_media_type
    end
  end
  raise( HTTP415UnsupportedMediaType, supported_media_types.uniq )
end

- (Serializer) serializer(request, content_type = nil)

Parameters:

  • request (Request)
  • content_type (String, nil) (defaults to: nil)

    If omitted, you get the best serializer available, which may not be acceptable by the client.

Returns:



134
135
136
137
# File 'lib/rackful/resource.rb', line 134

def serializer request, content_type = nil
  content_type ||= request.best_content_type( self, false )
  self.class.all_serializers[content_type][0].new( request, self, content_type )
end

- (void) title



190
191
192
# File 'lib/rackful/resource.rb', line 190

def title
  self.uri.segments.last || self.class.to_s
end

- (void) to_rackful

TODO:

documentation



210
211
212
# File 'lib/rackful/resource.rb', line 210

def to_rackful
  self
end