renee-core 0.4.0.pre1 → 0.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ pkg/*
4
+ .yardoc
5
+ doc
6
+ .DS_Store
7
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-18mode
6
+ - rbx-18mode
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'minitest', '~> 2.11.1'
7
+ gem 'rack-test', '>= 0.5.0'
8
+ gem 'shotgun'
9
+ gem 'rake'
10
+ gem 'json'
11
+ gem 'yard', '~> 0.7.4'
12
+ end
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2011 Joshua Hull, Nathan Esquenazi, Arthur Chiu
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # Renee Core
2
+
3
+ ## Routing
4
+
5
+ Routing in `Renee` is different from any web framework you are likely to have used in the past. The syntax is most familiar to Sinatra but allows
6
+ for far more flexibility and freedom in the way that routes and actions are defined. In a Renee, routes are defined using the `path`, `var`, `query_string`, `extension`, `remainder` and request methods.
7
+
8
+ **Request Methods**
9
+
10
+ The bread and butter of Renee are the request verbs reminiscent of Sinatra:
11
+
12
+ ```ruby
13
+ run Renee.core {
14
+ get { halt "a get!" }
15
+ post { halt "a post!" }
16
+ put { halt "a put!" }
17
+ delete { halt "a delete!" }
18
+ }
19
+ ```
20
+
21
+ These will declare the response to "/" for each of the common request types. Notice the use of the request method to
22
+ specify the http verb and the use of `halt` inside the block to send back the body of the response.
23
+
24
+ **Path**
25
+
26
+ Path is how Renee describes the basic uri path for a route:
27
+
28
+ ```ruby
29
+ run Renee.core {
30
+ path('blog') { ... }
31
+ }
32
+ ```
33
+
34
+ All declarations inside that block will start with `/blog`. Paths can also be nested within one another:
35
+
36
+ ```ruby
37
+ run Renee.core {
38
+ path('blog') {
39
+ path('foo') { get { halt "path is /blog/foo" } }
40
+ }
41
+ }
42
+ ```
43
+
44
+ You can also use `exact_path` for more precise path matching and/or `part` which doesn't look for leading slashes.
45
+
46
+ **Query String**
47
+
48
+ In addition to defining paths, you may find yourself wanting to describe the state of the query string for a request within the path:
49
+
50
+ ```ruby
51
+ path 'foo' do
52
+ query_string 'bar' do
53
+ get { halt 'BAR!' }
54
+ end
55
+
56
+ query_string 'baz' do
57
+ get { halt 'BAZ!' }
58
+ end
59
+ end
60
+ ```
61
+
62
+ This will respond to `/foo?bar` with "BAR!" and `/foo?baz` with "BAZ!". You can also specify query_string in a variety of other ways:
63
+
64
+ ```ruby
65
+ # Check key and value of query param
66
+ query_string 'foo=bar' do
67
+ post { halt [200,{},'foo'] }
68
+ end
69
+
70
+ # Declare query params as a hash
71
+ query :foo => "bar" do
72
+ halt 200
73
+ end
74
+
75
+ # Switch based on a query parameter
76
+ query :foo do |var|
77
+ case var
78
+ when 'bar' then halt 200
79
+ when 'bar2' then halt 500
80
+ end
81
+ end
82
+ ```
83
+
84
+ **Variables**
85
+
86
+ In Renee, you specify parameters for your request as explicit variables. Variables are declared like this:
87
+
88
+ ```ruby
89
+ path('blog') {
90
+ var { |id| get { halt "path is /blog/#{id}" } }
91
+ }
92
+ ```
93
+
94
+ You can access the variables (passed into the request) using the local variables yielded to the block. Variables are a powerful
95
+ way to express expected parameters for a given set of requests. You can specify variables that match a regex:
96
+
97
+ ```ruby
98
+ path('blog') {
99
+ var(/\d+/) { |id| get { halt "path is /blog/#{id}" } }
100
+ }
101
+ ```
102
+
103
+ and even explicitly cast your variable types:
104
+
105
+ ```ruby
106
+ path('blog') {
107
+ var :integer do |id|
108
+ get { halt "path is /blog/#{id} and id is an integer" }
109
+ end
110
+ end
111
+ ```
112
+
113
+ **Extensions**
114
+
115
+ You can also use `extension` as a way to define formats:
116
+
117
+ ```ruby
118
+ path '/test' do
119
+ extension 'html' do
120
+ halt 'html'
121
+ end
122
+ extension 'json' do
123
+ halt 'json'
124
+ end
125
+ end
126
+ ```
127
+
128
+ This will have `test.html` respond with 'html' and `test.json` respond with 'json'.
129
+
130
+ **Remainder**
131
+
132
+ In the event that no route has been matched, the `remainder` keyword makes defining the else case rather easy:
133
+
134
+ ```ruby
135
+ path 'foo' do
136
+ path 'bar' do
137
+ halt "BAR!"
138
+ end
139
+
140
+ remainder do |rest|
141
+ halt "Rest was #{rest}"
142
+ end
143
+ end
144
+ ```
145
+
146
+ Notice this allows you to handle the cases within a particular route scope and manage them based on the "rest" of the uri yielded in the `remainder` block. You
147
+ can handle different remainders in all the different path blocks.
148
+
149
+ **Named Routes**
150
+
151
+ Once you have defined your routes, you can then "register" a particular path mapping that to a symbol. This is useful for referencing routes without
152
+ having to specify the entire path:
153
+
154
+ ```ruby
155
+ run Renee.core {
156
+ register(:test, '/test/time')
157
+ register(:test_var, '/test/:id')
158
+ }
159
+ ```
160
+
161
+ You can then access these using the `path` method in a route or template:
162
+
163
+ ```ruby
164
+ path(:test) # => '/test/time'
165
+ path(:test_var, :id => 123) # => '/test/123'
166
+ ```
167
+
168
+ Using named routes makes referencing and modifying routes within an application much simpler to manage.
169
+
170
+ ## Responding
171
+
172
+ Responding to a request within a route can be managed with the `respond`, `halt`, `redirect` commands:
173
+
174
+ **Respond**
175
+
176
+ The `respond` command makes returning a rack response very explicit, you can respond as if you were constructing a Rack::Response
177
+
178
+ ```ruby
179
+ run Renee.core {
180
+ get { respond!("hello!", 403, "foo" => "bar") }
181
+ }
182
+ ```
183
+
184
+ or use the block DSL for convenience:
185
+
186
+ ```ruby
187
+ run Renee.core {
188
+ get { respond! { status 403; headers :foo => "bar"; body "hello!" } }
189
+ }
190
+ ```
191
+
192
+ **Halt**
193
+
194
+ Halting is the easiest way to render data within a route:
195
+
196
+ ```ruby
197
+ run Renee.core {
198
+ get { halt 'easy' }
199
+ }
200
+ ```
201
+
202
+ This will return a 200 status code and 'easy' as the body. You can also specify status code and header explicitly in the halt response:
203
+
204
+ ```ruby
205
+ get { halt [200, {}, 'body'] }
206
+ ```
207
+
208
+ This will set the status code to 200, pass no headers and return 'body'. You can also use several variations of halt:
209
+
210
+ ```ruby
211
+ # Return just status code
212
+ halt 200
213
+
214
+ # Return status with symbol
215
+ halt :not_found
216
+
217
+ # Return 200 with body
218
+ halt "hello!"
219
+
220
+ # Return 500 with body
221
+ halt 500, "hello!"
222
+ ```
223
+
224
+ Halt is the most straightforward way to control the response for a request.
225
+
226
+ **Redirect**
227
+
228
+ A redirect is a common action within a web route and can be achieved with the convenience method `redirect` command:
229
+
230
+ ```ruby
231
+ get {
232
+ halt redirect('/hello')
233
+ }
234
+ ```
235
+
236
+ You can also specify the status code for the redirect:
237
+
238
+ ```ruby
239
+ get {
240
+ halt redirect('/hello', 303)
241
+ }
242
+ ```
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rake/testtask'
2
+ require 'bundler/gem_tasks'
3
+ require 'yard'
4
+
5
+ ROOT = File.expand_path(File.dirname(__FILE__))
6
+
7
+ task :default => :test
8
+
9
+ Rake::TestTask.new do |t|
10
+ t.libs.push "lib"
11
+ t.test_files = FileList[File.expand_path("../test/**/*_test.rb", __FILE__)]
12
+ t.verbose = true
13
+ end
14
+
15
+ YARD::Rake::YardocTask.new do |t|
16
+ t.options = [
17
+ '-o', File.expand_path("../site/public/docs/core", __FILE__),
18
+ '--readme', 'README.md',
19
+ '--no-private',
20
+ '--markup', 'markdown'
21
+ ]
22
+ t.files = 'lib/**/*.rb'
23
+ end
24
+
@@ -51,7 +51,6 @@ module Renee
51
51
  define_method(:"#{m}_chainable") { }
52
52
  end
53
53
  end
54
-
55
54
  end
56
55
 
57
56
  def create_chain_proxy(method_name, *args)
@@ -19,7 +19,7 @@ module Renee
19
19
  # get { halt build { use Rack::ContentLength; run proc { |env| Rack::Response.new("Hello!").finish } } }
20
20
  #
21
21
  def build!(&blk)
22
- halt build(&blk)
22
+ halt! build(&blk)
23
23
  end
24
24
 
25
25
  # Runs a rack application. You must either use `app` or `blk`.
@@ -28,7 +28,7 @@ module Renee
28
28
  #
29
29
  #
30
30
  # @example
31
- # get { halt run proc { |env| Renee::Core::Response.new("Hello!").finish } }
31
+ # get { halt run proc { |env| Rack::Response.new("Hello!").finish } }
32
32
  #
33
33
  def run(app = nil, &blk)
34
34
  raise "You cannot supply both a block and an app" unless app.nil? ^ blk.nil?
@@ -40,10 +40,10 @@ module Renee
40
40
  #
41
41
  # @see #run!
42
42
  # @example
43
- # get { run proc { |env| Renee::Core::Response.new("Hello!").finish } }
43
+ # get { run proc { |env| Rack::Response.new("Hello!").finish } }
44
44
  #
45
45
  def run!(app = nil, &blk)
46
- halt run(app, &blk)
46
+ halt! run(app, &blk)
47
47
  end
48
48
  end
49
49
  end
@@ -11,10 +11,10 @@ module Renee
11
11
  :created => 201,
12
12
  :accepted => 202,
13
13
  :no_content => 204,
14
- :no_content => 204,
15
14
  :bad_request => 400,
16
15
  :unauthorized => 401,
17
- :payment_required => 403,
16
+ :payment_required => 402,
17
+ :forbidden => 403,
18
18
  :not_found => 404,
19
19
  :method_not_found => 405,
20
20
  :not_acceptable => 406,
@@ -29,6 +29,14 @@ module Renee
29
29
  throw :halt, interpret_response(response.size == 1 ? response.first : response)
30
30
  end
31
31
 
32
+ # Halts current processing to the top-level calling Renee application and uses that as a response.
33
+ # This version of halt does not pass your response through #interpret_response.
34
+ # @param [Object] response The response to use.
35
+ # @see #interpret_response, #halt
36
+ def halt!(response)
37
+ throw :halt, response
38
+ end
39
+
32
40
  ##
33
41
  # Creates a response by allowing the response header, body and status to be passed into the block.
34
42
  #
@@ -41,23 +49,52 @@ module Renee
41
49
  # respond { status 200; body "Yay!" }
42
50
  # respond("Hello", 200, "foo" => "bar")
43
51
  #
44
- def respond(body=[], status=200, header={}, &blk)
45
- response = Renee::Core::Response.new(body, status, header)
46
- response.instance_eval(&blk) if block_given?
47
- response.finish
52
+ def respond(response_body = nil, response_status = nil, response_headers = nil)
53
+ body(response_body) if response_body
54
+ status(response_status) if response_status
55
+ headers(response_headers) if response_headers
56
+ yield if block_given?
57
+ raise NoResponseSetError unless @body or @status or @headers
58
+ Rack::Response.new(@body || [], @status || 200, @headers || {})
48
59
  end
49
60
 
50
- ##
51
- # Creates a response by allowing the response header, body and status to be passed into the block.
52
- #
53
- # @example
54
- # respond! { status 200; body "Yay!" }
55
- #
56
- # @param (see #respond)
57
- # @see #respond
58
- def respond!(*args, &blk)
59
- halt respond(*args, &blk)
61
+ def respond!(response_body = nil, response_status = nil, response_headers = nil, &blk)
62
+ halt! respond(response_body, response_status, response_headers, &blk)
63
+ end
64
+
65
+ def status(code)
66
+ @status = code
67
+ end
68
+
69
+ def status!(code)
70
+ status code
71
+ respond!
72
+ end
73
+
74
+ def body(*args)
75
+ @body ||= []
76
+ @body.concat(args) unless args.empty?
77
+ @body
78
+ end
79
+
80
+ def body!(*args)
81
+ body *args
82
+ respond!
83
+ end
84
+
85
+ def header(headers)
86
+ @headers ||= {}
87
+ headers.each do |k, v|
88
+ @headers[k.to_s] = v.to_s
89
+ end
90
+ end
91
+ alias_method :headers, :header
92
+
93
+ def header!(headers)
94
+ header headers
95
+ respond!
60
96
  end
97
+ alias_method :headers!, :header!
61
98
 
62
99
  # Interprets responses returns by #halt.
63
100
  #
@@ -74,13 +111,13 @@ module Renee
74
111
  when Array then
75
112
  case response.size
76
113
  when 3 then response
77
- when 2 then Renee::Core::Response.new(response[1], HTTP_CODES[response[0]] || response[0]).finish
114
+ when 2 then Rack::Response.new(response[1], HTTP_CODES[response[0]] || response[0]).finish
78
115
  else raise "I don't know how to render #{response.inspect}"
79
116
  end
80
- when String then Renee::Core::Response.new(response).finish
81
- when Integer then Renee::Core::Response.new("Status code #{response}", response).finish
117
+ when String then Rack::Response.new(response).finish
118
+ when Integer then Rack::Response.new("Status code #{response}", response).finish
82
119
  when Symbol then interpret_response(HTTP_CODES[response] || response.to_s)
83
- when Proc then instance_eval(&response)
120
+ when Proc then response.call
84
121
  else response # pass through response
85
122
  end
86
123
  end