Module: Rackful::Resource

Includes:
Rack::Utils
Included in:
EPIC::Resource, HTTPStatus
Defined in:
gems/rackful-0.1.1/lib/rackful_resource.rb,
gems/rackful-0.1.1.orig/lib/rackful_resource.rb

Overview

Mixin for resources served by Server.

Server helps you implement Rackful resource objects quickly in a couple of ways. Classes that include this module may implement a method `content_types` for content negotiation. This method must return a Hash of `media-type => quality` pairs.

See Also:

Since:

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

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:

See Also:

Since:

  • 0.0.1



# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 239

- (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:

Since:

  • 0.0.1



# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 263

- (Rackful::Path) path

The path of this resource.

Returns:

See Also:

  • #initialize

Since:

  • 0.0.1



198
199
200
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 198

def path
  @path
end

Class Method Details

+ (void) included(base)

Since:

  • 0.0.1



26
27
28
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 26

def self.included(base)
  base.extend ClassMethods
end

Instance Method Details

- (void) default_headers

Adds `ETag:` and `Last-Modified:` response headers.

Since:

  • 0.0.1



436
437
438
439
440
441
442
443
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 436

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

An optional header hash.

Returns:

  • (Hash, nil)

    an optional header hash.



# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 280

- 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_`.

Examples:

Handling `PATCH` requests

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

Raises:

Since:

  • 0.0.1



# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 176

- (Boolean) empty?

Does this resource exists?

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

Returns:

  • (Boolean)

    The default implementation returns `false`.

Since:

  • 0.0.1



228
229
230
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 228

def empty?
  false
end

- http_DELETE(request, response)

This method returns an undefined value.

Wrapper around #do_GET

Raises:

Since:

  • 0.0.1



382
383
384
385
386
387
388
389
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 382

def http_DELETE request, response
  raise HTTP404NotFound if self.empty?
  raise HTTP405MethodNotAllowed unless self.respond_to?( :destroy )
  response.status = status_code( :no_content )
  if headers = self.destroy( request, response )
    response.headers.merge! headers
  end
end

- http_GET(request, response)

This method returns an undefined value.

Raises:

Since:

  • 0.0.1



359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 359

def http_GET request, response
  raise HTTP404NotFound if self.empty?
  # May throw HTTP406NotAcceptable:
  content_type = self.class.best_content_type( request.accept )
  response['Content-Type'] = content_type
  response.status = status_code( :ok )
  response.headers.merge! self.default_headers
  # May throw HTTP405MethodNotAllowed:
  serializer = self.serializer( content_type )
  if serializer.respond_to? :headers
    response.headers.merge!( serializer.headers )
  end
  response.body = serializer
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)

Since:

  • 0.0.1



341
342
343
344
345
346
347
348
349
350
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 341

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_method(request, response)

This method returns an undefined value.

Wrapper around #do_PUT

Raises:

  • (HTTPStatus)

    `405 Method Not Allowed` if the resource doesn’t implement the `PUT` method.

Since:

  • 0.0.1



417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 417

def http_method request, response
  method = request.request_method.to_sym
  if ! self.respond_to?( :do_#{method}" )
    raise HTTP405MethodNotAllowed, self.http_methods
  end
  if  ( request.content_length ||
        'chunked' == request.env['HTTP_TRANSFER_ENCODING'] ) and
      ! self.class.media_types[method] ||
      ! self.class.media_types[method].include?( request.media_type )
    raise HTTP415UnsupportedMediaType, self.class.media_types[method]
  end
  self.send( :do_#{method}", request, response )
end

- (Array<Symbol>) http_methods

List of all HTTP/1.1 methods implemented by this resource.

This works by inspecting all the #do_METHOD methods this object implements.

Returns:

  • (Array<Symbol>)

Since:

  • 0.0.1



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 293

def http_methods
  r = []
  if self.empty?
    self.class.all_media_types
  else
    r.merge! [ :OPTIONS, :HEAD, :GET ]
    r << :DELETE if self.respond_to?( :destroy )
  end
  self.public_instance_methods.each do
    |instance_method|
    if /\Ado_([A-Z])+\z/ === instance_method
      r << $1.to_sym
    end
  end
  r
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:

Since:

  • 0.0.1



324
325
326
327
328
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 324

def http_OPTIONS request, response
  raise HTTP404NotFound if self.empty?
  response.status = status_code :no_content
  response.header['Allow'] = self.http_methods.join ', '
end

- http_PUT(request, response)

This method returns an undefined value.

Raises:

Since:

  • 0.0.1



398
399
400
401
402
403
404
405
406
407
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 398

def http_PUT request, response
  raise HTTP405MethodNotAllowed unless self.respond_to? :do_PUT
  unless self.class.media_types[:PUT] &&
         self.class.media_types[:PUT].include?( request.media_type )
    raise HTTP415UnsupportedMediaType, self.class.media_types[:PUT]
  end
  response.status = status_code( self.empty? ? :created : :no_content )
  self.do_PUT( request, response )
  response.headers.merge! self.default_headers
end

- (Boolean) requested?

Returns:

  • (Boolean)

Since:

  • 0.0.1



213
214
215
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 213

def requested?
  self.path.slashify == Request.current.path.slashify
end

- (Serializer) serializer(content_type)

Returns:

Since:

  • 0.0.1



163
164
165
166
167
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 163

def serializer content_type
  @rackful_resource_serializers ||= {}
  @rackful_resource_serializers[content_type] ||=
    self.class.all_serializers[content_type][0].new( self, content_type )
end

- (void) title

Since:

  • 0.0.1



206
207
208
209
210
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 206

def title
  ( '/' == self.path ) ?
    Request.current.host :
    File.basename(self.path).to_path.unescape
end

- (void) to_rackful

Since:

  • 0.0.1



233
234
235
# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 233

def to_rackful
  self
end

- (#to_json, #each_pair) to_struct

Returns:

  • (#to_json, #each_pair)


# File 'gems/rackful-0.1.1/lib/rackful_resource.rb', line 171