renee 0.3.11 → 0.4.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +17 -0
- data/Gemfile-renee +8 -0
- data/Gemfile-renee-core +8 -0
- data/Gemfile-renee-render +9 -0
- data/Gemfile-renee-session +9 -0
- data/Gemfile-renee-url-generation +8 -0
- data/MIT-LICENSE.txt +7 -0
- data/README-renee-core.md +242 -0
- data/README-renee-render.md +38 -0
- data/README-renee-session.md +3 -0
- data/README-renee-url-generation.md +3 -0
- data/README.md +131 -6
- data/Rakefile +109 -9
- data/TODO.txt +45 -0
- data/config.ru +26 -0
- data/examples/blog/blog.rb +3 -1
- data/examples/blog/config.ru +24 -19
- data/examples/blog/views/edit.erb +10 -1
- data/examples/blog/views/show.erb +5 -0
- data/lib/renee.rb +11 -4
- data/lib/renee/core.rb +98 -0
- data/lib/renee/core/chaining.rb +66 -0
- data/lib/renee/core/env_accessors.rb +72 -0
- data/lib/renee/core/exceptions.rb +15 -0
- data/lib/renee/core/matcher.rb +61 -0
- data/lib/renee/core/plugins.rb +31 -0
- data/lib/renee/core/rack_interaction.rb +50 -0
- data/lib/renee/core/request_context.rb +56 -0
- data/lib/renee/core/responding.rb +112 -0
- data/lib/renee/core/response.rb +78 -0
- data/lib/renee/core/routing.rb +319 -0
- data/lib/renee/core/transform.rb +18 -0
- data/lib/renee/render.rb +221 -0
- data/lib/renee/session.rb +50 -0
- data/lib/renee/url_generation.rb +117 -0
- data/lib/renee/util.rb +7 -0
- data/lib/renee/version.rb +2 -4
- data/plan.txt +19 -0
- data/renee-core.gemspec +26 -0
- data/renee-render.gemspec +30 -0
- data/renee-session.gemspec +28 -0
- data/renee-url-generation.gemspec +24 -0
- data/renee.gemspec +5 -6
- data/site/MIT-LICENSE.txt +7 -0
- data/site/public/css/app.css +75 -0
- data/site/public/docs/renee-core/Renee.html +208 -0
- data/site/public/docs/renee-core/Renee/Core.html +366 -0
- data/site/public/docs/renee-core/Renee/Core/Chaining.html +192 -0
- data/site/public/docs/renee-core/Renee/Core/ClassMethods.html +725 -0
- data/site/public/docs/renee-core/Renee/Core/ClientError.html +317 -0
- data/site/public/docs/renee-core/Renee/Core/EnvAccessors.html +152 -0
- data/site/public/docs/renee-core/Renee/Core/EnvAccessors/ClassMethods.html +354 -0
- data/site/public/docs/renee-core/Renee/Core/Matcher.html +675 -0
- data/site/public/docs/renee-core/Renee/Core/Plugins.html +475 -0
- data/site/public/docs/renee-core/Renee/Core/RackInteraction.html +488 -0
- data/site/public/docs/renee-core/Renee/Core/RequestContext.html +511 -0
- data/site/public/docs/renee-core/Renee/Core/Responding.html +877 -0
- data/site/public/docs/renee-core/Renee/Core/Response.html +691 -0
- data/site/public/docs/renee-core/Renee/Core/Routing.html +1589 -0
- data/site/public/docs/renee-core/Renee/Core/Transform.html +249 -0
- data/site/public/docs/renee-core/Renee/Core/URLGeneration.html +597 -0
- data/site/public/docs/renee-core/_index.html +244 -0
- data/site/public/docs/renee-core/class_list.html +47 -0
- data/site/public/docs/renee-core/css/common.css +1 -0
- data/site/public/docs/renee-core/css/full_list.css +55 -0
- data/site/public/docs/renee-core/css/style.css +322 -0
- data/site/public/docs/renee-core/file.README-renee-core.html +341 -0
- data/site/public/docs/renee-core/file.README.html +212 -0
- data/site/public/docs/renee-core/file_list.html +49 -0
- data/site/public/docs/renee-core/frames.html +13 -0
- data/site/public/docs/renee-core/index.html +341 -0
- data/site/public/docs/renee-core/js/app.js +205 -0
- data/site/public/docs/renee-core/js/full_list.js +167 -0
- data/site/public/docs/renee-core/js/jquery.js +16 -0
- data/site/public/docs/renee-core/method_list.html +590 -0
- data/site/public/docs/renee-core/top-level-namespace.html +103 -0
- data/site/public/docs/renee-render/Renee.html +116 -0
- data/site/public/docs/renee-render/Renee/Core.html +346 -0
- data/site/public/docs/renee-render/Renee/Core/Chaining.html +125 -0
- data/site/public/docs/renee-render/Renee/Core/ClassMethods.html +620 -0
- data/site/public/docs/renee-render/Renee/Core/ClientError.html +317 -0
- data/site/public/docs/renee-render/Renee/Core/EnvAccessors.html +152 -0
- data/site/public/docs/renee-render/Renee/Core/EnvAccessors/ClassMethods.html +354 -0
- data/site/public/docs/renee-render/Renee/Core/Matcher.html +675 -0
- data/site/public/docs/renee-render/Renee/Core/RackInteraction.html +488 -0
- data/site/public/docs/renee-render/Renee/Core/RequestContext.html +421 -0
- data/site/public/docs/renee-render/Renee/Core/Responding.html +873 -0
- data/site/public/docs/renee-render/Renee/Core/Response.html +691 -0
- data/site/public/docs/renee-render/Renee/Core/Routing.html +1682 -0
- data/site/public/docs/renee-render/Renee/Core/Transform.html +249 -0
- data/site/public/docs/renee-render/Renee/Core/URLGeneration.html +597 -0
- data/site/public/docs/renee-render/Renee/Render.html +873 -0
- data/site/public/docs/renee-render/Renee/Render/ClassMethods.html +382 -0
- data/site/public/docs/renee-render/Renee/Render/TemplateNotFound.html +126 -0
- data/site/public/docs/renee-render/_index.html +143 -0
- data/site/public/docs/renee-render/class_list.html +47 -0
- data/site/public/docs/renee-render/css/common.css +1 -0
- data/site/public/docs/renee-render/css/full_list.css +55 -0
- data/site/public/docs/renee-render/css/style.css +322 -0
- data/site/public/docs/renee-render/file.README-renee-render.html +104 -0
- data/site/public/docs/renee-render/file.README.html +212 -0
- data/site/public/docs/renee-render/file_list.html +49 -0
- data/site/public/docs/renee-render/frames.html +13 -0
- data/site/public/docs/renee-render/index.html +104 -0
- data/site/public/docs/renee-render/js/app.js +205 -0
- data/site/public/docs/renee-render/js/full_list.js +167 -0
- data/site/public/docs/renee-render/js/jquery.js +16 -0
- data/site/public/docs/renee-render/method_list.html +110 -0
- data/site/public/docs/renee-render/top-level-namespace.html +103 -0
- data/site/public/docs/renee-session/Renee.html +106 -0
- data/site/public/docs/renee-session/Renee/Session.html +173 -0
- data/site/public/docs/renee-session/Renee/Session/ClassMethods.html +470 -0
- data/site/public/docs/renee-session/_index.html +136 -0
- data/site/public/docs/renee-session/class_list.html +47 -0
- data/site/public/docs/renee-session/css/common.css +1 -0
- data/site/public/docs/renee-session/css/full_list.css +55 -0
- data/site/public/docs/renee-session/css/style.css +322 -0
- data/site/public/docs/renee-session/file.README-renee-core.html +341 -0
- data/site/public/docs/renee-session/file.README-renee-session.html +69 -0
- data/site/public/docs/renee-session/file_list.html +49 -0
- data/site/public/docs/renee-session/frames.html +13 -0
- data/site/public/docs/renee-session/index.html +69 -0
- data/site/public/docs/renee-session/js/app.js +205 -0
- data/site/public/docs/renee-session/js/full_list.js +167 -0
- data/site/public/docs/renee-session/js/jquery.js +16 -0
- data/site/public/docs/renee-session/method_list.html +102 -0
- data/site/public/docs/renee-session/top-level-namespace.html +103 -0
- data/site/public/docs/renee-url-generation/Renee.html +208 -0
- data/site/public/docs/renee-url-generation/Renee/Core.html +366 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Chaining.html +192 -0
- data/site/public/docs/renee-url-generation/Renee/Core/ClassMethods.html +725 -0
- data/site/public/docs/renee-url-generation/Renee/Core/ClientError.html +317 -0
- data/site/public/docs/renee-url-generation/Renee/Core/EnvAccessors.html +152 -0
- data/site/public/docs/renee-url-generation/Renee/Core/EnvAccessors/ClassMethods.html +354 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Matcher.html +675 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Plugins.html +475 -0
- data/site/public/docs/renee-url-generation/Renee/Core/RackInteraction.html +488 -0
- data/site/public/docs/renee-url-generation/Renee/Core/RequestContext.html +511 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Responding.html +877 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Response.html +691 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Routing.html +1589 -0
- data/site/public/docs/renee-url-generation/Renee/Core/Transform.html +249 -0
- data/site/public/docs/renee-url-generation/_index.html +244 -0
- data/site/public/docs/renee-url-generation/class_list.html +47 -0
- data/site/public/docs/renee-url-generation/css/common.css +1 -0
- data/site/public/docs/renee-url-generation/css/full_list.css +55 -0
- data/site/public/docs/renee-url-generation/css/style.css +322 -0
- data/site/public/docs/renee-url-generation/file.README-renee-url-generation.html +69 -0
- data/site/public/docs/renee-url-generation/file_list.html +49 -0
- data/site/public/docs/renee-url-generation/frames.html +13 -0
- data/site/public/docs/renee-url-generation/index.html +69 -0
- data/site/public/docs/renee-url-generation/js/app.js +205 -0
- data/site/public/docs/renee-url-generation/js/full_list.js +167 -0
- data/site/public/docs/renee-url-generation/js/jquery.js +16 -0
- data/site/public/docs/renee-url-generation/method_list.html +590 -0
- data/site/public/docs/renee-url-generation/top-level-namespace.html +103 -0
- data/site/public/docs/renee/Renee.html +232 -0
- data/site/public/docs/renee/Renee/Application.html +367 -0
- data/site/public/docs/renee/Renee/Core.html +370 -0
- data/site/public/docs/renee/Renee/Core/Chaining.html +192 -0
- data/site/public/docs/renee/Renee/Core/ClassMethods.html +725 -0
- data/site/public/docs/renee/Renee/Core/ClientError.html +317 -0
- data/site/public/docs/renee/Renee/Core/EnvAccessors.html +152 -0
- data/site/public/docs/renee/Renee/Core/EnvAccessors/ClassMethods.html +354 -0
- data/site/public/docs/renee/Renee/Core/Matcher.html +675 -0
- data/site/public/docs/renee/Renee/Core/Plugins.html +475 -0
- data/site/public/docs/renee/Renee/Core/RackInteraction.html +488 -0
- data/site/public/docs/renee/Renee/Core/RequestContext.html +511 -0
- data/site/public/docs/renee/Renee/Core/Responding.html +877 -0
- data/site/public/docs/renee/Renee/Core/Response.html +691 -0
- data/site/public/docs/renee/Renee/Core/Routing.html +1589 -0
- data/site/public/docs/renee/Renee/Core/Transform.html +249 -0
- data/site/public/docs/renee/Renee/Core/URLGeneration.html +597 -0
- data/site/public/docs/renee/Renee/Render.html +877 -0
- data/site/public/docs/renee/Renee/Render/ClassMethods.html +382 -0
- data/site/public/docs/renee/Renee/Render/TemplateNotFound.html +126 -0
- data/site/public/docs/renee/Renee/Session.html +177 -0
- data/site/public/docs/renee/Renee/Session/ClassMethods.html +470 -0
- data/site/public/docs/renee/Renee/URLGeneration.html +142 -0
- data/site/public/docs/renee/Renee/URLGeneration/ClassMethods.html +593 -0
- data/site/public/docs/renee/Renee/Util.html +163 -0
- data/site/public/docs/renee/_index.html +336 -0
- data/site/public/docs/renee/class_list.html +47 -0
- data/site/public/docs/renee/css/common.css +1 -0
- data/site/public/docs/renee/css/full_list.css +55 -0
- data/site/public/docs/renee/css/style.css +322 -0
- data/site/public/docs/renee/file.README.html +212 -0
- data/site/public/docs/renee/file_list.html +49 -0
- data/site/public/docs/renee/frames.html +13 -0
- data/site/public/docs/renee/index.html +212 -0
- data/site/public/docs/renee/js/app.js +205 -0
- data/site/public/docs/renee/js/full_list.js +167 -0
- data/site/public/docs/renee/js/jquery.js +16 -0
- data/site/public/docs/renee/method_list.html +758 -0
- data/site/public/docs/renee/top-level-namespace.html +202 -0
- data/site/public/img/favicon.ico +0 -0
- data/site/public/img/reneeclean.png +0 -0
- data/site/public/img/russiangithub.png +0 -0
- data/site/public/img/stoneposter.png +0 -0
- data/site/public/img/vospit.jpeg +0 -0
- data/site/views/chaining.md +32 -0
- data/site/views/index.md +219 -0
- data/site/views/layouts/app.haml +16 -0
- data/site/views/rack-integration.md +51 -0
- data/site/views/responding.md +103 -0
- data/site/views/route-generation.md +82 -0
- data/site/views/routing.md +261 -0
- data/site/views/settings.md +19 -0
- data/site/views/team-renee.md +13 -0
- data/site/views/tutorial.md +57 -0
- data/site/views/variable-types.md +57 -0
- data/test.watchr +61 -0
- data/test/renee-core/chaining_test.rb +33 -0
- data/test/renee-core/env_accessors_test.rb +43 -0
- data/test/renee-core/include_test.rb +14 -0
- data/test/renee-core/request_context_test.rb +70 -0
- data/test/renee-core/responding_test.rb +128 -0
- data/test/renee-core/routing_test.rb +443 -0
- data/test/renee-core/test_helper.rb +4 -0
- data/test/renee-core/variable_type_test.rb +57 -0
- data/test/renee-render/render_test.rb +162 -0
- data/test/renee-render/test_helper.rb +9 -0
- data/test/renee-session/session_test.rb +31 -0
- data/test/renee-session/test_helper.rb +9 -0
- data/test/renee-url-generation/test_helper.rb +10 -0
- data/test/renee-url-generation/url_generation_test.rb +63 -0
- data/test/{blog_test.rb → renee/blog_test.rb} +10 -5
- data/test/renee/test_helper.rb +56 -0
- data/test/test_helper.rb +23 -10
- metadata +333 -156
- data/.yardopts +0 -6
@@ -0,0 +1,72 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
# Defines class-level methods for creating accessors for variables in your environment.
|
4
|
+
module EnvAccessors
|
5
|
+
|
6
|
+
# Exception for attempting to define an env accessor cannot be written as a method name.
|
7
|
+
# @example
|
8
|
+
# env_accessor "current.user" # raises InvalidEnvNameError
|
9
|
+
# env_accessor "current.user" => :current_user # this works
|
10
|
+
InvalidEnvNameError = Class.new(RuntimeError)
|
11
|
+
|
12
|
+
# Class-methods included by this module.
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
# Defines getters and setters for a list of attributes. If the attributes cannot easily be expressed, use the
|
16
|
+
# hash-syntax for defining them.
|
17
|
+
# @example
|
18
|
+
# env_accessor "some_value" # will define methods to read and write env['some_value']
|
19
|
+
# env_accessor "current.user" => :current_user will define methods to read and write env['current.user']
|
20
|
+
def env_accessor(*attrs)
|
21
|
+
env_reader(*attrs)
|
22
|
+
env_writer(*attrs)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Defines getters for a list of attributes.
|
26
|
+
# @see env_accessor
|
27
|
+
def env_reader(*attrs)
|
28
|
+
instance_eval do
|
29
|
+
env_attr_iter(*attrs) do |key, meth|
|
30
|
+
define_method(meth) do
|
31
|
+
env[key]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Defines setters for a list of attributes.
|
38
|
+
# @see env_accessor
|
39
|
+
def env_writer(*attrs)
|
40
|
+
instance_eval do
|
41
|
+
env_attr_iter(*attrs) do |key, meth|
|
42
|
+
define_method("#{meth}=") do |val|
|
43
|
+
env[key] = val
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def env_attr_iter(*attrs)
|
51
|
+
attrs.each do |a|
|
52
|
+
case a
|
53
|
+
when Hash
|
54
|
+
a.each do |k, v|
|
55
|
+
yield k, v
|
56
|
+
end
|
57
|
+
else
|
58
|
+
raise InvalidEnvNameError, "Called env attr for #{a.inspect}, to use this, call your env method like this. env_reader #{a.inspect} => #{a.to_s.gsub(/-\./, '_').to_sym.inspect}" if a.to_s[/[-\.]/]
|
59
|
+
yield a, a.to_sym
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# @private
|
67
|
+
def self.included(o)
|
68
|
+
o.extend(ClassMethods)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
# Used to indicate a client-error has occurred (e.g. 4xx)
|
4
|
+
class ClientError < StandardError
|
5
|
+
attr_reader :response
|
6
|
+
|
7
|
+
# @param [String] message The message for this exception.
|
8
|
+
# @yield The optional block to instance-eval in the case this error is raised.
|
9
|
+
def initialize(message, &response)
|
10
|
+
super(message)
|
11
|
+
@response = response
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
# Class used for variable matching.
|
4
|
+
class Matcher
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
# @param [Regexp] matcher The regexp matcher to determine what is part of the variable.
|
8
|
+
def initialize(matcher)
|
9
|
+
@matcher = matcher
|
10
|
+
end
|
11
|
+
|
12
|
+
# Used to specific the error handler if the matcher doesn't match anything. By default, there is no error handler.
|
13
|
+
# @yield The block to be executed it fails to match.
|
14
|
+
def on_error(&blk)
|
15
|
+
@error_handler = blk
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Used to transform the value matched.
|
20
|
+
# @yield TODO
|
21
|
+
def on_transform(&blk)
|
22
|
+
@transform_handler = blk
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
# Convienence method to creating halting error handler.
|
27
|
+
# @param [Symbol, Integer] error_code The HTTP code to halt with.
|
28
|
+
# @see #interpret_response
|
29
|
+
def raise_on_error!(error_code = :bad_request)
|
30
|
+
on_error { halt error_code }
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Matcher for string
|
35
|
+
# @param [String] val The value to attempt to match on.
|
36
|
+
# @raise [ClientError] If the match fails to match and there is an error handler defined.
|
37
|
+
def [](val)
|
38
|
+
match = nil
|
39
|
+
case @matcher
|
40
|
+
when Array
|
41
|
+
match = nil
|
42
|
+
@matcher.find { |m| match = m[val] }
|
43
|
+
else
|
44
|
+
if match = /^#{@matcher.to_s}/.match(val)
|
45
|
+
match = [match[0]]
|
46
|
+
match << @transform_handler.call(match.first) if @transform_handler
|
47
|
+
match
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if match
|
51
|
+
match
|
52
|
+
elsif @error_handler
|
53
|
+
raise ClientError.new("There was an error interpreting the value #{val.inspect} for #{name.inspect}", &@error_handler)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Matcher for Integers
|
59
|
+
IntegerMatcher = Matcher.new(/\d+/).on_transform{|v| Integer(v)}
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
module Plugins
|
4
|
+
attr_reader :init_blocks, :before_blocks, :after_blocks
|
5
|
+
|
6
|
+
def on_init(&blk)
|
7
|
+
init_blocks << blk
|
8
|
+
end
|
9
|
+
|
10
|
+
def init_blocks
|
11
|
+
(@init_blocks ||= [])
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_before(&blk)
|
15
|
+
before_blocks << blk
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_blocks
|
19
|
+
(@before_blocks ||= [])
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_after(&blk)
|
23
|
+
before_blocks << blk
|
24
|
+
end
|
25
|
+
|
26
|
+
def after_blocks
|
27
|
+
(@after_blocks ||= [])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
# A module that defines useful Rack interaction methods.
|
4
|
+
module RackInteraction
|
5
|
+
# Creates an ad-hoc Rack application within the context of a Rack::Builder.
|
6
|
+
# @yield The block to be used to instantiate the `Rack::Builder`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# get { halt build { use Rack::ContentLength; run proc { |env| Rack::Response.new("Hello!").finish } } }
|
10
|
+
#
|
11
|
+
def build(&blk)
|
12
|
+
run Rack::Builder.new(&blk).to_app
|
13
|
+
end
|
14
|
+
|
15
|
+
# Creates an ad-hoc Rack application within the context of a Rack::Builder that immediately halts when done.
|
16
|
+
# @param (see #build)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# get { halt build { use Rack::ContentLength; run proc { |env| Rack::Response.new("Hello!").finish } } }
|
20
|
+
#
|
21
|
+
def build!(&blk)
|
22
|
+
halt build(&blk)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Runs a rack application. You must either use `app` or `blk`.
|
26
|
+
# @param [#call] app The application to call.
|
27
|
+
# @yield [env] The block to yield to
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# get { halt run proc { |env| Renee::Core::Response.new("Hello!").finish } }
|
32
|
+
#
|
33
|
+
def run(app = nil, &blk)
|
34
|
+
raise "You cannot supply both a block and an app" unless app.nil? ^ blk.nil?
|
35
|
+
(app || blk).call(env)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Runs a rack application and halts immediately.
|
39
|
+
# @param (see #run)
|
40
|
+
#
|
41
|
+
# @see #run!
|
42
|
+
# @example
|
43
|
+
# get { run proc { |env| Renee::Core::Response.new("Hello!").finish } }
|
44
|
+
#
|
45
|
+
def run!(app = nil, &blk)
|
46
|
+
halt run(app, &blk)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
module ClassMethods
|
4
|
+
def use(mw, *args, &blk)
|
5
|
+
middlewares << [mw, args, blk]
|
6
|
+
end
|
7
|
+
|
8
|
+
def middlewares
|
9
|
+
@middlewares ||= []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# This module deals with the Rack#call compilance. It defines #call and also defines several critical methods
|
14
|
+
# used by interaction by other application modules.
|
15
|
+
module RequestContext
|
16
|
+
attr_reader :env, :request, :detected_extension
|
17
|
+
|
18
|
+
# Provides a rack interface compliant call method.
|
19
|
+
# @param[Hash] env The rack environment.
|
20
|
+
def call(e)
|
21
|
+
initialize_plugins
|
22
|
+
idx = 0
|
23
|
+
next_app = proc do |env|
|
24
|
+
if idx == self.class.middlewares.size
|
25
|
+
@env, @request = env, Rack::Request.new(env)
|
26
|
+
@detected_extension = env['PATH_INFO'][/\.([^\.\/]+)$/, 1]
|
27
|
+
# TODO clear template cache in development? `template_cache.clear`
|
28
|
+
out = catch(:halt) do
|
29
|
+
begin
|
30
|
+
self.class.before_blocks.each { |b| instance_eval(&b) }
|
31
|
+
instance_eval(&self.class.application_block)
|
32
|
+
rescue ClientError => e
|
33
|
+
e.response ? instance_eval(&e.response) : halt("There was an error with your request", 400)
|
34
|
+
rescue NotMatchedError => e
|
35
|
+
# unmatched, continue on
|
36
|
+
end
|
37
|
+
Renee::Core::Response.new("Not found", 404).finish
|
38
|
+
end
|
39
|
+
self.class.after_blocks.each { |a| out = instance_exec(out, &a) }
|
40
|
+
out
|
41
|
+
else
|
42
|
+
middleware = self.class.middlewares[idx]
|
43
|
+
idx += 1
|
44
|
+
middleware[0].new(next_app, *middleware[1], &middleware[2]).call(env)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
next_app[e]
|
48
|
+
end # call
|
49
|
+
|
50
|
+
def initialize_plugins
|
51
|
+
self.class.init_blocks.each { |init_block| self.class.class_eval(&init_block) }
|
52
|
+
self.class.send(:define_method, :initialize_plugins) { }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
# Collection of useful methods for responding within a {Renee::Core} app.
|
4
|
+
module Responding
|
5
|
+
# Codes used by Symbol lookup in interpret_response.
|
6
|
+
# @example
|
7
|
+
# halt :unauthorized # would return a 401.
|
8
|
+
#
|
9
|
+
HTTP_CODES = {
|
10
|
+
:ok => 200,
|
11
|
+
:created => 201,
|
12
|
+
:accepted => 202,
|
13
|
+
:no_content => 204,
|
14
|
+
:no_content => 204,
|
15
|
+
:bad_request => 400,
|
16
|
+
:unauthorized => 401,
|
17
|
+
:payment_required => 403,
|
18
|
+
:not_found => 404,
|
19
|
+
:method_not_found => 405,
|
20
|
+
:not_acceptable => 406,
|
21
|
+
:gone => 410,
|
22
|
+
:error => 500,
|
23
|
+
:not_implemented => 501}.freeze
|
24
|
+
|
25
|
+
# Halts current processing to the top-level calling Renee application and uses that as a response.
|
26
|
+
# @param [Object...] response The response to use.
|
27
|
+
# @see #interpret_response
|
28
|
+
def halt(*response)
|
29
|
+
throw :halt, interpret_response(response.size == 1 ? response.first : response)
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Creates a response by allowing the response header, body and status to be passed into the block.
|
34
|
+
#
|
35
|
+
# @param [Array] body The contents to return.
|
36
|
+
# @param [Integer] status The status code to return.
|
37
|
+
# @param [Hash] header The headers to return.
|
38
|
+
# @param [Proc] &blk The response options to specify
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# respond { status 200; body "Yay!" }
|
42
|
+
# respond("Hello", 200, "foo" => "bar")
|
43
|
+
#
|
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
|
48
|
+
end
|
49
|
+
|
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)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Interprets responses returns by #halt.
|
63
|
+
#
|
64
|
+
# * If it is a Symbol, it will be looked up in {HTTP_CODES}.
|
65
|
+
# * If it is a Symbol, it will use Rack::Response to return the value.
|
66
|
+
# * If it is a Symbol, it will either be used as a Rack response or as a body and status code.
|
67
|
+
# * If it is an Integer, it will use Rack::Response to return the status code.
|
68
|
+
# * Otherwise, #to_s will be called on it and it will be treated as a Symbol.
|
69
|
+
#
|
70
|
+
# @param [Object] response This can be either a Symbol, String, Array or any Object.
|
71
|
+
#
|
72
|
+
def interpret_response(response)
|
73
|
+
case response
|
74
|
+
when Array then
|
75
|
+
case response.size
|
76
|
+
when 3 then response
|
77
|
+
when 2 then Renee::Core::Response.new(response[1], HTTP_CODES[response[0]] || response[0]).finish
|
78
|
+
else raise "I don't know how to render #{response.inspect}"
|
79
|
+
end
|
80
|
+
when String then Renee::Core::Response.new(response).finish
|
81
|
+
when Integer then Renee::Core::Response.new("Status code #{response}", response).finish
|
82
|
+
when Symbol then interpret_response(HTTP_CODES[response] || response.to_s)
|
83
|
+
when Proc then instance_eval(&response)
|
84
|
+
else response # pass through response
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns a rack-based response for redirection.
|
89
|
+
# @param [String] path The URL to redirect to.
|
90
|
+
# @param [Integer] code The HTTP code to use.
|
91
|
+
# @example
|
92
|
+
# r = Renee.core { get { halt redirect '/index' } }
|
93
|
+
# r.call(Rack::MockResponse("/")) # => [302, {"Location" => "/index"}, []]
|
94
|
+
def redirect(path, code = 302)
|
95
|
+
response = ::Rack::Response.new
|
96
|
+
response.redirect(path, code)
|
97
|
+
response.finish
|
98
|
+
end
|
99
|
+
|
100
|
+
# Halts with a rack-based response for redirection.
|
101
|
+
# @see #redirect
|
102
|
+
# @param [String] path The URL to redirect to.
|
103
|
+
# @param [Integer] code The HTTP code to use.
|
104
|
+
# @example
|
105
|
+
# r = Renee.core { get { redirect! '/index' } }
|
106
|
+
# r.call(Rack::MockResponse("/")) # => [302, {"Location" => "/index"}, []]
|
107
|
+
def redirect!(path, code = 302)
|
108
|
+
halt redirect(path, code)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Renee
|
2
|
+
class Core
|
3
|
+
# The response object for a Renee request. Inherits from the `Rack#Response` object.
|
4
|
+
class Response < Rack::Response
|
5
|
+
# Augment body to allow strings.
|
6
|
+
#
|
7
|
+
# @param [String] The contents for the response.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# res.body = "Hello"
|
11
|
+
#
|
12
|
+
# @api semipublic
|
13
|
+
def body=(value)
|
14
|
+
value = value.body while Rack::Response === value
|
15
|
+
@body = String === value ? [value.to_str] : value
|
16
|
+
end
|
17
|
+
|
18
|
+
# Alias status and body methods to allow redefinition
|
19
|
+
alias :status_attr :status
|
20
|
+
alias :status_attr= :status=
|
21
|
+
alias :body_attr :body
|
22
|
+
alias :body_attr= :body=
|
23
|
+
|
24
|
+
# Get or set the status of the response.
|
25
|
+
#
|
26
|
+
# @param [String] val The status code to return.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# res.status 400
|
30
|
+
# res.status => 400
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def status(val=nil)
|
34
|
+
val ? self.status_attr = val : self.status_attr
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get or set the body of the response.
|
38
|
+
#
|
39
|
+
# @param [String] val The contents to return.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# res.body "hello"
|
43
|
+
# res.body => "hello"
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def body(val=nil)
|
47
|
+
val ? self.body_attr = val : self.body_attr
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get or set the headers of the response.
|
51
|
+
#
|
52
|
+
# @param [Hash] attrs The contents to return.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# res.headers :foo => "bar"
|
56
|
+
# res.headers => { :foo => "bar" }
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def headers(attrs={})
|
60
|
+
attrs ? attrs.each { |k, v| self[k.to_s] = v } : self.header
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finishs the response based on the accumulated options.
|
64
|
+
# Calculates the size of the body content length and removes headers for 1xx status codes.
|
65
|
+
def finish
|
66
|
+
if status.to_i / 100 == 1
|
67
|
+
headers.delete "Content-Length"
|
68
|
+
headers.delete "Content-Type"
|
69
|
+
elsif Array === body and not [204, 304].include?(status.to_i)
|
70
|
+
headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
status, headers, result = super
|
74
|
+
[status, headers, result]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|