sinatra-rest-addons 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 1.0.0
@@ -6,11 +6,103 @@ module Sinatra
6
6
  # class App < Sinatra::Base
7
7
  # helpers Sinatra::REST::Helpers
8
8
  # end
9
- module Helpers
9
+ module Helpers
10
+
11
+ INFINITY = 1/0.0
12
+
10
13
  def compute_etag(*args)
11
14
  raise ArgumentError, "You must provide at least one parameter for the ETag computation" if args.empty?
12
15
  Digest::SHA1.hexdigest(args.join("."))
13
16
  end
17
+
18
+ # e.g.
19
+ # get '/' do
20
+ # provides :xml, "text/html;level=5"
21
+ # "Hello"
22
+ # end
23
+ # will accept requests having an Accept header containing at least one of the following value:
24
+ # * application/xml
25
+ # * application/*
26
+ # * text/html
27
+ # * text/html;level=5
28
+ # * text/html;level=6
29
+ def provides(*formats)
30
+ generate_type_hash = Proc.new{ |header|
31
+ type, *params = header.split(/;\s*/)
32
+ Hash[*params.map{|p| p.split(/\s*=\s*/)}.flatten].merge("type" => type)
33
+ }
34
+ supported_formats = formats.map do |f|
35
+ # selects the correct mime type if a symbol is given
36
+ f.is_a?(Symbol) ? ::Rack::Mime::MIME_TYPES[".#{f.to_s}"] : f
37
+ end.compact.map do |f|
38
+ generate_type_hash.call(f)
39
+ end
40
+ # request.accept is an Array
41
+ accepted_formats = request.accept.map do |f|
42
+ generate_type_hash.call(f)
43
+ end
44
+ selected_format = nil
45
+ accepted_formats.each{ |accepted_format|
46
+ selected_format = supported_formats.detect{ |supported_format|
47
+ Regexp.new(Regexp.escape(accepted_format["type"]).gsub("\\*", ".*?"), Regexp::IGNORECASE) =~ supported_format["type"] &&
48
+ (accepted_format["level"] || INFINITY).to_f >= (supported_format["level"] || 0).to_f
49
+ }
50
+ break unless selected_format.nil?
51
+ }
52
+ if selected_format.nil?
53
+ content_type :txt
54
+ halt 406, supported_formats.map{|f|
55
+ output = f["type"]
56
+ output.concat(";level=#{f["level"]}") if f.has_key?("level")
57
+ output
58
+ }.join(",")
59
+ else
60
+ response.headers['Content-Type'] = "#{selected_format["type"]}#{selected_format["level"].nil? ? "" : ";level=#{selected_format["level"]}"}"
61
+ end
62
+ end # def provides
63
+
64
+
65
+ # Automatically decode the input data (coming from a POST or PUT request) based on the request's content-type.
66
+ # You must pass a Proc that will return the parser object to use to decode the payload.
67
+ # The parser object must respond to a <tt>parse</tt> method.
68
+ # You may also pass a hash of options:
69
+ # * <tt>:size_range</tt>: byte range specifying the minimum and maximum length (in bytes) of the payload [default=(1..1024**3)]
70
+ #
71
+ # e.g.
72
+ # post '/resource' do
73
+ # data = decode lambda{|content_type| if content_type =~ /^application\/.*json$/i then JSON}, :size_range => (1..2*1024**3)
74
+ # end
75
+ #
76
+ # The processing of the request will be halted in the following cases:
77
+ # * 400 if the payload is not within the specified size range.
78
+ # * 400 if the payload cannot be correctly parsed.
79
+ # * 415 if the payload's content type is not supported (i.e. the given Proc returns nil)
80
+ #
81
+ def decode(proc, config = {})
82
+ raise ArgumentError, "You must pass an object that responds to #call" unless proc.respond_to?(:call)
83
+ size_range = config.delete(:size_range) || (1..(1024**3))
84
+ case (mime_type = request.env['CONTENT_TYPE'])
85
+ when /^application\/x-www-form-urlencoded/i
86
+ request.env['sinatra.decoded_input'] = request.env['rack.request.form_hash']
87
+ else
88
+ content = ""
89
+ request.env['rack.input'].each do |block|
90
+ content.concat(block)
91
+ break if content.length > size_range.end
92
+ end
93
+ if not size_range.include?(content.length)
94
+ halt 400, "Input data size must be between #{size_range.begin} and #{size_range.end} bytes."
95
+ elsif parser = proc.call(mime_type)
96
+ begin
97
+ parser.parse(content)
98
+ rescue StandardError => e
99
+ halt 400, "#{e.class.name}: #{e.message}"
100
+ end
101
+ else
102
+ halt 415, "Format #{mime_type} not supported"
103
+ end
104
+ end
105
+ end # def decode
14
106
  end # module Helpers
15
107
  end # module REST
16
108
  end # module Sinatra
@@ -11,51 +11,6 @@ module Sinatra
11
11
 
12
12
  # Allow the definition of OPTIONS routes
13
13
  def options(path, opts={}, &bk); route 'OPTIONS', path, opts, &bk end
14
-
15
- # e.g.
16
- # get '/', :provides => [:xml, "text/html;level=5"] { "hello" }
17
- # will accept requests with Accept header =
18
- # * application/xml
19
- # * application/*
20
- # * text/html
21
- # * text/html;level=5
22
- # * text/html;level=6
23
- def provides(*formats)
24
- generate_type_hash = Proc.new{ |header|
25
- type, *params = header.split(/;\s*/)
26
- Hash[*params.map{|p| p.split(/\s*=\s*/)}.flatten].merge("type" => type)
27
- }
28
- condition {
29
- supported_formats = formats.map do |f|
30
- # selects the correct mime type if a symbol is given
31
- f.is_a?(Symbol) ? ::Rack::Mime::MIME_TYPES[".#{f.to_s}"] : f
32
- end.compact.map do |f|
33
- generate_type_hash.call(f)
34
- end
35
- # request.accept is an Array
36
- accepted_formats = request.accept.map do |f|
37
- generate_type_hash.call(f)
38
- end
39
- selected_format = nil
40
- accepted_formats.each{ |accepted_format|
41
- selected_format = supported_formats.detect{ |supported_format|
42
- Regexp.new(Regexp.escape(accepted_format["type"]).gsub("\\*", ".*?"), Regexp::IGNORECASE) =~ supported_format["type"] &&
43
- (accepted_format["level"] || INFINITY).to_f >= (supported_format["level"] || 0).to_f
44
- }
45
- break unless selected_format.nil?
46
- }
47
- if selected_format.nil?
48
- content_type :txt
49
- halt 406, supported_formats.map{|f|
50
- output = f["type"]
51
- output.concat(";level=#{f["level"]}") if f.has_key?("level")
52
- output
53
- }.join(",")
54
- else
55
- response.headers['Content-Type'] = "#{selected_format["type"]}#{selected_format["level"].nil? ? "" : ";level=#{selected_format["level"]}"}"
56
- end
57
- }
58
- end # def provides
59
14
 
60
15
  # Allow access to the route based on the result of the given proc, whose argument is a <tt>credentials</tt> object.
61
16
  # You MUST declare a helper function named <tt>credentials</tt> that will return an object (of your choice) containing the client's credentials,
@@ -76,46 +31,6 @@ module Sinatra
76
31
  end
77
32
  }
78
33
  end # def allow
79
-
80
- # Automatically decode the input data (coming from a POST or PUT request) based on the request's content-type.
81
- # First argument must be a parsing procedure that will be used to parse the input data according to its content type.
82
- # The decoded input will be available in request.env['sinatra.decoded_input']
83
- # e.g.
84
- # post '/',
85
- # :decode => Proc.new{ |content_type, content|
86
- # content_type =~ /^application\/.*json$/i ? JSON.parse(content) : throw(:halt, [400, "Don't know how to parse '#{content_type}' content."])
87
- # } do
88
- # "#{request.env['sinatra.decoded_input']}"
89
- # end
90
- def decode(*args)
91
- args = [args] unless args.kind_of? Array
92
- parsing_proc = args.shift
93
- raise ArgumentError, "You must provide a proc to parse the input data" unless parsing_proc.kind_of?(Proc)
94
- size_range = args.shift || (1..(1024**3))
95
- condition {
96
- begin
97
- case (mime_type = request.env['CONTENT_TYPE'])
98
- when /^application\/x-www-form-urlencoded/i
99
- request.env['sinatra.decoded_input'] = request.env['rack.request.form_hash']
100
- else
101
- content = ""
102
- request.env['rack.input'].each do |block|
103
- content.concat(block)
104
- break if content.length > size_range.end
105
- end
106
- if not size_range.include?(content.length)
107
- content_type :txt
108
- halt 400, "Input data size must be between #{size_range.begin} and #{size_range.end} bytes."
109
- else
110
- request.env['sinatra.decoded_input'] = parsing_proc.call(mime_type, content)
111
- end
112
- end
113
- rescue StandardError => e
114
- content_type :txt
115
- halt 400, "#{e.class.name}: #{e.message}"
116
- end
117
- }
118
- end # def decode
119
34
 
120
35
  end # module Routes
121
36
  end # module REST
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{sinatra-rest-addons}
8
- s.version = "0.1.4"
8
+ s.version = "1.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Cyril Rohr"]
12
- s.date = %q{2009-11-23}
12
+ s.date = %q{2010-01-07}
13
13
  s.description = %q{A set of helpers and extensions for sinatra apps that expose REST resources.}
14
14
  s.email = %q{cyril.rohr@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  "lib/sinatra/rest/routes.rb",
27
27
  "sinatra-rest-addons.gemspec",
28
28
  "test/helper.rb",
29
+ "test/test_helpers.rb",
29
30
  "test/test_routes.rb"
30
31
  ]
31
32
  s.homepage = %q{http://github.com/crohr/sinatra-rest-addons}
@@ -35,6 +36,7 @@ Gem::Specification.new do |s|
35
36
  s.summary = %q{A set of helpers and extensions for sinatra apps that expose REST resources.}
36
37
  s.test_files = [
37
38
  "test/helper.rb",
39
+ "test/test_helpers.rb",
38
40
  "test/test_routes.rb"
39
41
  ]
40
42
 
@@ -0,0 +1,182 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'json'
3
+
4
+ class HelpersTest < Test::Unit::TestCase
5
+
6
+ context "helper :provides" do
7
+
8
+ test "should return 406 and the list of supported types, if the server does not support the types accepted by the client [simple matching]" do
9
+ mock_app {
10
+ helpers Sinatra::REST::Helpers
11
+ get '/' do
12
+ provides "application/xml", "application/vnd.x.y.z+xml"
13
+ request.env['HTTP_ACCEPT']
14
+ end
15
+ }
16
+ get '/', {}, { 'HTTP_ACCEPT' => 'application/json' }
17
+ assert_equal 406, last_response.status
18
+ assert_equal 'application/xml,application/vnd.x.y.z+xml', last_response.body
19
+ assert_equal 'text/plain', last_response.headers['Content-Type']
20
+ end
21
+ test "should return 406 if the accepted type has a level lower than what is supported" do
22
+ mock_app {
23
+ helpers Sinatra::REST::Helpers
24
+ get '/' do
25
+ provides "application/xml;level=5"
26
+ request.env['HTTP_ACCEPT']
27
+ end
28
+ }
29
+ get '/', {}, { 'HTTP_ACCEPT' => 'application/xml;level=4' }
30
+ assert_equal 406, last_response.status
31
+ assert_equal 'application/xml;level=5', last_response.body
32
+ assert_equal 'text/plain', last_response.headers['Content-Type']
33
+ end
34
+ test "should return the first matching type if the accepted type contains a *" do
35
+ mock_app {
36
+ helpers Sinatra::REST::Helpers
37
+ get '/' do
38
+ provides "application/xml", "application/vnd.x.y.z+xml"
39
+ request.env['HTTP_ACCEPT']
40
+ end
41
+ }
42
+ get '/', {}, { 'HTTP_ACCEPT' => 'application/*' }
43
+ assert_equal 200, last_response.status
44
+ assert_equal 'application/*', last_response.body
45
+ assert_equal 'application/xml', last_response.headers['Content-Type']
46
+ end
47
+ test "should respect the order in which the accepted formats are declared when looking for the format to select" do
48
+ mock_app {
49
+ helpers Sinatra::REST::Helpers
50
+ get '/' do
51
+ provides "application/json", "application/xml", "application/vnd.x.y.z+xml"
52
+ request.env['HTTP_ACCEPT']
53
+ end
54
+ }
55
+ get '/', {}, { 'HTTP_ACCEPT' => 'application/xml, */*' }
56
+ assert_equal 200, last_response.status
57
+ assert_equal 'application/xml, */*', last_response.body
58
+ assert_equal 'application/xml', last_response.headers['Content-Type']
59
+ end
60
+ test "should be successful if the accepted type does not require a specific level" do
61
+ mock_app {
62
+ helpers Sinatra::REST::Helpers
63
+ get '/' do
64
+ provides "application/xml;level=5"
65
+ request.env['HTTP_ACCEPT']
66
+ end
67
+ }
68
+ get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
69
+ assert last_response.ok?
70
+ assert_equal 'application/xml', last_response.body
71
+ assert_equal 'application/xml;level=5', last_response.headers['Content-Type']
72
+ end
73
+ test "should be successful if the accepted type level is greater than what is supported" do
74
+ mock_app {
75
+ helpers Sinatra::REST::Helpers
76
+ get '/' do
77
+ provides "application/xml;level=5"
78
+ request.env['HTTP_ACCEPT']
79
+ end
80
+ }
81
+ get '/', {}, { 'HTTP_ACCEPT' => 'application/xml;level=6' }
82
+ assert last_response.ok?
83
+ assert_equal 'application/xml;level=6', last_response.body
84
+ assert_equal 'application/xml;level=5', last_response.headers['Content-Type']
85
+ end
86
+ end
87
+
88
+ context "helper :decode" do
89
+ setup do
90
+ PARSING_PROC = Proc.new{|content_type| content_type =~ /^application\/.*json$/i ? JSON : nil} unless defined?(PARSING_PROC)
91
+ end
92
+ test "should return 400 if the input content is empty" do
93
+ mock_app {
94
+ helpers Sinatra::REST::Helpers
95
+ post '/' do
96
+ data = decode PARSING_PROC
97
+ end
98
+ error 400 do
99
+ content_type :txt
100
+ "#{response.body.to_s}"
101
+ end
102
+ }
103
+ post '/', "", {'CONTENT_TYPE' => "application/json"}
104
+ assert_equal 400, last_response.status
105
+ assert_equal 'Input data size must be between 1 and 1073741824 bytes.', last_response.body
106
+ assert_equal 'text/plain', last_response.headers['Content-Type']
107
+ end
108
+ test "should return 400 if the input content is too large" do
109
+ mock_app {
110
+ helpers Sinatra::REST::Helpers
111
+ post '/' do
112
+ decode PARSING_PROC, :size_range => 2...30
113
+ end
114
+ }
115
+ post '/', '{"key1": ["value1", "value2"]}', {'CONTENT_TYPE' => "application/json"}
116
+ assert_equal 400, last_response.status
117
+ assert_equal 'Input data size must be between 2 and 30 bytes.', last_response.body
118
+ end
119
+ test "should return 400 if the input content can be parsed but is malformed" do
120
+ mock_app {
121
+ helpers Sinatra::REST::Helpers
122
+ post '/'do
123
+ decode PARSING_PROC, :size_range => 2...30
124
+ end
125
+ }
126
+ post '/', '{"key1": ["value1", "value2"]', {'CONTENT_TYPE' => "application/json"}
127
+ assert_equal 400, last_response.status
128
+ assert_equal "JSON::ParserError: 618: unexpected token at '{\"key1\": [\"value1\", \"value2\"]'", last_response.body
129
+ end
130
+ test "should return 415 if the parsing proc does not return a parser" do
131
+ mock_app {
132
+ helpers Sinatra::REST::Helpers
133
+ post '/' do
134
+ decode PARSING_PROC
135
+ end
136
+ }
137
+ post '/', '<item></item>', {'CONTENT_TYPE' => "application/xml"}
138
+ assert_equal 415, last_response.status
139
+ assert_equal "Format application/xml not supported", last_response.body
140
+ end
141
+ test "should correctly parse the input content if a parser can be found for the specified content type, and the decoded input must be returned" do
142
+ input = {"key1" => ["value1", "value2"]}
143
+ mock_app {
144
+ helpers Sinatra::REST::Helpers
145
+ post '/' do
146
+ data = decode PARSING_PROC, :size_range => 2...30
147
+ content_type 'application/json'
148
+ JSON.dump data
149
+ end
150
+ }
151
+ post '/', JSON.dump(input), {'CONTENT_TYPE' => "application/json"}
152
+ assert_equal 200, last_response.status
153
+ assert_equal JSON.dump(input), last_response.body
154
+ assert_equal 'application/json', last_response.headers['Content-Type']
155
+ end
156
+ test "should set the decoded input to the params hash already decoded by Sinatra, if the request's content type is application/x-www-form-urlencoded" do
157
+ input = {"key1" => ["value1", "value2"]}
158
+ mock_app {
159
+ helpers Sinatra::REST::Helpers
160
+ post '/' do
161
+ data = decode PARSING_PROC, :size_range => 2...30
162
+ content_type 'application/json'
163
+ JSON.dump data
164
+ end
165
+ }
166
+ post '/', input
167
+ assert_equal 200, last_response.status
168
+ assert_equal JSON.dump(input), last_response.body
169
+ assert_equal 'application/json', last_response.headers['Content-Type']
170
+ end
171
+ test "should raise an error if the first argument is not a proc" do
172
+ mock_app {
173
+ helpers Sinatra::REST::Helpers
174
+ post '/' do
175
+ decode :whatever
176
+ end
177
+ }
178
+ assert_raise(ArgumentError){ post '/' }
179
+ end
180
+ end
181
+
182
+ end
@@ -19,200 +19,6 @@ class RoutesTest < Test::Unit::TestCase
19
19
  assert_equal 'remove me', response.body
20
20
  end
21
21
 
22
- context "route option :provides" do
23
-
24
- test "should return 406 and the list of supported types, if the server does not support the types accepted by the client [simple matching]" do
25
- mock_app {
26
- register Sinatra::REST::Routes
27
- get '/', :provides => ["application/xml", "application/vnd.x.y.z+xml"] do
28
- request.env['HTTP_ACCEPT']
29
- end
30
- }
31
- get '/', {}, { 'HTTP_ACCEPT' => 'application/json' }
32
- assert_equal 406, last_response.status
33
- assert_equal 'application/xml,application/vnd.x.y.z+xml', last_response.body
34
- assert_equal 'text/plain', last_response.headers['Content-Type']
35
- end
36
- test "should return 406 if the accepted type has a level lower than what is supported" do
37
- mock_app {
38
- register Sinatra::REST::Routes
39
- get '/', :provides => ["application/xml;level=5"] do
40
- request.env['HTTP_ACCEPT']
41
- end
42
- }
43
- get '/', {}, { 'HTTP_ACCEPT' => 'application/xml;level=4' }
44
- assert_equal 406, last_response.status
45
- assert_equal 'application/xml;level=5', last_response.body
46
- assert_equal 'text/plain', last_response.headers['Content-Type']
47
- end
48
- test "should return the first matching type if the accepted type contains a *" do
49
- mock_app {
50
- register Sinatra::REST::Routes
51
- get '/', :provides => ["application/xml", "application/vnd.x.y.z+xml"] do
52
- request.env['HTTP_ACCEPT']
53
- end
54
- }
55
- get '/', {}, { 'HTTP_ACCEPT' => 'application/*' }
56
- assert_equal 200, last_response.status
57
- assert_equal 'application/*', last_response.body
58
- assert_equal 'application/xml', last_response.headers['Content-Type']
59
- end
60
- test "should respect the order in which the accepted formats are declared when looking for the format to select" do
61
- mock_app {
62
- register Sinatra::REST::Routes
63
- get '/', :provides => ["application/json", "application/xml", "application/vnd.x.y.z+xml"] do
64
- request.env['HTTP_ACCEPT']
65
- end
66
- }
67
- get '/', {}, { 'HTTP_ACCEPT' => 'application/xml, */*' }
68
- assert_equal 200, last_response.status
69
- assert_equal 'application/xml, */*', last_response.body
70
- assert_equal 'application/xml', last_response.headers['Content-Type']
71
- end
72
- test "should be successful if the accepted type does not require a specific level" do
73
- mock_app {
74
- register Sinatra::REST::Routes
75
- get '/', :provides => ["application/xml;level=5"] do
76
- request.env['HTTP_ACCEPT']
77
- end
78
- }
79
- get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
80
- assert last_response.ok?
81
- assert_equal 'application/xml', last_response.body
82
- assert_equal 'application/xml;level=5', last_response.headers['Content-Type']
83
- end
84
- test "should be successful if the accepted type level is greater than what is supported" do
85
- mock_app {
86
- register Sinatra::REST::Routes
87
- get '/', :provides => ["application/xml;level=5"] do
88
- request.env['HTTP_ACCEPT']
89
- end
90
- }
91
- get '/', {}, { 'HTTP_ACCEPT' => 'application/xml;level=6' }
92
- assert last_response.ok?
93
- assert_equal 'application/xml;level=6', last_response.body
94
- assert_equal 'application/xml;level=5', last_response.headers['Content-Type']
95
- end
96
- end
97
-
98
- context "route option :decode" do
99
- setup do
100
- PARSING_PROC = Proc.new{|content_type, content| content_type =~ /^application\/.*json$/i ? JSON.parse(content) : throw(:halt, [400, "Cannot parse"])} unless defined? PARSING_PROC
101
- end
102
- test "should return 400 if the input content is empty" do
103
- mock_app {
104
- register Sinatra::REST::Routes
105
- post '/', :decode => PARSING_PROC do
106
- request.env['sinatra.decoded_input'].inspect
107
- end
108
- }
109
- post '/', "", {'CONTENT_TYPE' => "application/json"}
110
- assert_equal 400, last_response.status
111
- assert_equal 'Input data size must be between 1 and 1073741824 bytes.', last_response.body
112
- assert_equal 'text/plain', last_response.headers['Content-Type']
113
- end
114
- test "should return 400 if the input content is too large" do
115
- mock_app {
116
- register Sinatra::REST::Routes
117
- post '/', :decode => [PARSING_PROC, 2...30] do
118
- request.env['sinatra.decoded_input'].inspect
119
- end
120
- }
121
- post '/', '{"key1": ["value1", "value2"]}', {'CONTENT_TYPE' => "application/json"}
122
- assert_equal 400, last_response.status
123
- assert_equal 'Input data size must be between 2 and 30 bytes.', last_response.body
124
- assert_equal 'text/plain', last_response.headers['Content-Type']
125
- end
126
- test "should return 400 if the input content can be parsed but is malformed" do
127
- mock_app {
128
- register Sinatra::REST::Routes
129
- post '/', :decode => [PARSING_PROC, 2..30] do
130
- request.env['sinatra.decoded_input'].inspect
131
- end
132
- }
133
- post '/', '{"key1": ["value1", "value2"]', {'CONTENT_TYPE' => "application/json"}
134
- assert_equal 400, last_response.status
135
- assert_equal "JSON::ParserError: 618: unexpected token at '{\"key1\": [\"value1\", \"value2\"]'", last_response.body
136
- assert_equal 'text/plain', last_response.headers['Content-Type']
137
- end
138
- test "should allow the parsing proc to throw an exception if needed (e.g. no parser can be found for the requested content type)" do
139
- mock_app {
140
- register Sinatra::REST::Routes
141
- post '/', :decode => [PARSING_PROC, 2..30] do
142
- request.env['sinatra.decoded_input'].inspect
143
- end
144
- }
145
- post '/', '<item></item>', {'CONTENT_TYPE' => "application/xml"}
146
- assert_equal 400, last_response.status
147
- assert_equal "Cannot parse", last_response.body
148
- assert_equal 'text/html', last_response.headers['Content-Type']
149
- end
150
- test "should correctly parse the input content if a parser can be found for the specified content type, and the decoded input must be made available in env['sinatra.decoded_input']" do
151
- input = {"key1" => ["value1", "value2"]}
152
- mock_app {
153
- register Sinatra::REST::Routes
154
- post '/', :decode => [PARSING_PROC, 2...30] do
155
- content_type 'application/json'
156
- JSON.dump request.env['sinatra.decoded_input']
157
- end
158
- }
159
- post '/', JSON.dump(input), {'CONTENT_TYPE' => "application/json"}
160
- assert_equal 200, last_response.status
161
- assert_equal JSON.dump(input), last_response.body
162
- assert_equal 'application/json', last_response.headers['Content-Type']
163
- end
164
- test "should work" do
165
- input = "{\"walltime\":3600,\"resources\":\"/nodes=1\",\"at\":1258552306,\"on_launch\":{\"in\":\"/home/crohr\",\"do\":\"id\"}}"
166
- mock_app {
167
- register Sinatra::REST::Routes
168
- post '/', :decode => [PARSING_PROC, 2...3000] do
169
- content_type 'application/json'
170
- JSON.dump request.env['sinatra.decoded_input']
171
- end
172
- }
173
- post '/', input, {'CONTENT_TYPE' => "application/json"}
174
- p last_response.body
175
- assert_equal 200, last_response.status
176
- assert_equal JSON.parse(input), JSON.parse(last_response.body)
177
- assert_equal 'application/json', last_response.headers['Content-Type']
178
- end
179
- test "should set the decoded input to the params hash already decoded by Sinatra, if the request's content type is application/x-www-form-urlencoded" do
180
- input = {"key1" => ["value1", "value2"]}
181
- mock_app {
182
- register Sinatra::REST::Routes
183
- post '/', :decode => [PARSING_PROC, 2...30] do
184
- content_type 'application/json'
185
- JSON.dump request.env['sinatra.decoded_input']
186
- end
187
- }
188
- post '/', input
189
- assert_equal 200, last_response.status
190
- assert_equal JSON.dump(input), last_response.body
191
- assert_equal 'application/json', last_response.headers['Content-Type']
192
- end
193
- test "should return 400 if the parsing proc raises a StandardError" do
194
- mock_app {
195
- register Sinatra::REST::Routes
196
- post '/', :decode => Proc.new{|content_type, content| raise(StandardError, "error message") } do
197
- request.env['sinatra.decoded_input'].inspect
198
- end
199
- }
200
- post '/', 'whatever content', {'CONTENT_TYPE' => "whatever type"}
201
- assert_equal 400, last_response.status
202
- assert_equal "StandardError: error message", last_response.body
203
- assert_equal 'text/plain', last_response.headers['Content-Type']
204
- end
205
- test "should raise an error if the first argument is not a proc" do
206
- assert_raise(ArgumentError){ mock_app {
207
- register Sinatra::REST::Routes
208
- disable :raise_errors, :show_exceptions
209
- post '/', :decode => :whatever do
210
- JSON.dump request.env['sinatra.decoded_input']
211
- end
212
- } }
213
- end
214
- end
215
-
216
22
  context "route option :allow" do
217
23
  test "should return 403 if the proc returns false" do
218
24
  mock_app {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-rest-addons
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Rohr
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-23 00:00:00 +01:00
12
+ date: 2010-01-07 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -51,6 +51,7 @@ files:
51
51
  - lib/sinatra/rest/routes.rb
52
52
  - sinatra-rest-addons.gemspec
53
53
  - test/helper.rb
54
+ - test/test_helpers.rb
54
55
  - test/test_routes.rb
55
56
  has_rdoc: true
56
57
  homepage: http://github.com/crohr/sinatra-rest-addons
@@ -82,4 +83,5 @@ specification_version: 3
82
83
  summary: A set of helpers and extensions for sinatra apps that expose REST resources.
83
84
  test_files:
84
85
  - test/helper.rb
86
+ - test/test_helpers.rb
85
87
  - test/test_routes.rb