Module: Sinatra::RestHelpers

Defined in:
lib/sinatra/rest_helpers.rb

Overview

Include it with:

class App < Sinatra::Base
  helpers Sinatra::RestHelpers
end

Constant Summary collapse

INFINITY =
1/0.0

Instance Method Summary collapse

Instance Method Details

#compute_etag(*args) ⇒ Object

:nodoc:

Raises:

  • (ArgumentError)


65
66
67
68
# File 'lib/sinatra/rest_helpers.rb', line 65

def compute_etag(*args)  # :nodoc:
  raise ArgumentError, "You must provide at least one parameter for the ETag computation" if args.empty?
  Digest::SHA1.hexdigest(args.join("."))
end

#parse_input_data!(parser_selector, options = {:limit => 10*1024}) ⇒ Object

parser_selector must respond to :select(content_type) and return a parser object with a :load method.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/sinatra/rest_helpers.rb', line 50

def parse_input_data!(parser_selector, options = {:limit => 10*1024})
  case (mime_type = request.env['CONTENT_TYPE'])
  when nil
    halt 400, "You must provide a Content-Type HTTP header."
  when /application\/x-www-form-urlencoded/i
    request.env['rack.request.form_hash']
  else
    input_data = request.env['rack.input'].read
    halt 400, "Input data size must not be empty and must not exceed #{options[:limit]} bytes." if (options[:limit] && input_data.length > options[:limit]) || input_data.length == 0
    parser_selector.select(mime_type).load(input_data)
  end
rescue StandardError => e
  halt 400, "#{e.class.name}: #{e.message}"
end

#provides(*formats) ⇒ Object

e.g.:

get '/x/y/z' do
  provides "application/json", :xml, :zip, "text/html;level=5"
end


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/sinatra/rest_helpers.rb', line 17

def provides *formats
  generate_type_hash = Proc.new{ |header| 
    type, *params = header.split(/;\s*/)
    Hash[*params.map{|p| p.split(/\s*=\s*/)}.flatten].merge("type" => type)
  }
  supported_formats = formats.map do |f| 
    # selects the correct mime type if a symbol is given
    f.is_a?(Symbol) ? ::Rack::Mime::MIME_TYPES[".#{f.to_s}"] : f
  end.compact.map do |f|
    generate_type_hash.call(f)
  end
  # request.accept is an Array
  accepted_formats = request.accept.map do |f| 
    generate_type_hash.call(f)
  end
  selected_format = supported_formats.detect{ |supported_format| 
    !accepted_formats.detect{ |accepted_format| 
      Regexp.new(Regexp.escape(accepted_format["type"]).gsub("\\*", ".*?"), Regexp::IGNORECASE) =~ supported_format["type"] &&
        (accepted_format["level"] || INFINITY).to_f >= (supported_format["level"] || 0).to_f
    }.nil?
  }      
  if selected_format.nil?
    halt 406, supported_formats.map{|f| 
      output = f["type"]
      output.concat(";level=#{f["level"]}") if f.has_key?("level")
      output
    }.join(",")
  else
    response.headers['Content-Type'] = "#{selected_format["type"]}#{selected_format["level"].nil? ? "" : ";level=#{selected_format["level"]}"}"
  end
end