mojito 0.1.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/mojito.rb +21 -44
- data/lib/mojito/base.rb +29 -58
- data/lib/mojito/controllers.rb +10 -0
- data/lib/mojito/controllers/method.rb +65 -0
- data/lib/mojito/controllers/runtime.rb +80 -0
- data/lib/mojito/{matchers → controllers/runtime}/environment.rb +1 -3
- data/lib/mojito/{matchers → controllers/runtime}/methods.rb +1 -3
- data/lib/mojito/{matchers → controllers/runtime}/path.rb +4 -5
- data/lib/mojito/{matchers → controllers/runtime}/session.rb +1 -3
- data/lib/mojito/{matchers → controllers/runtime}/url_scheme.rb +1 -3
- data/lib/mojito/{matchers → controllers/runtime}/virtual_host.rb +1 -3
- data/lib/mojito/controllers/sinatra.rb +11 -0
- data/lib/mojito/helpers/exception_handling.rb +3 -5
- data/lib/mojito/helpers/shortcuts.rb +0 -2
- data/lib/mojito/rendering.rb +10 -6
- data/lib/mojito/rendering/content.rb +0 -2
- data/lib/mojito/rendering/content_types.rb +0 -2
- data/lib/mojito/rendering/delegation.rb +0 -2
- data/lib/mojito/rendering/file.rb +0 -2
- data/lib/mojito/rendering/status_codes.rb +0 -2
- data/lib/mojito/rendering/templates.rb +2 -4
- data/lib/mojito/request_extensions.rb +4 -0
- data/lib/mojito/utils/rspec.rb +26 -0
- data/spec/mojito/base_spec.rb +18 -2
- data/spec/mojito/controllers/method_spec.rb +56 -0
- data/spec/mojito/{matchers → controllers/runtime}/methods_spec.rb +4 -2
- data/spec/mojito/{matchers → controllers/runtime}/path_spec.rb +11 -10
- data/spec/mojito/{matchers → controllers/runtime}/session_spec.rb +2 -0
- data/spec/mojito/controllers/runtime/url_scheme_spec.rb +24 -0
- data/spec/mojito/controllers/runtime/virtual_host_spec.rb +24 -0
- data/spec/mojito/helpers_spec.rb +2 -0
- data/spec/mojito/rendering/content_spec.rb +4 -2
- data/spec/mojito/rendering/delegation_spec.rb +9 -9
- data/spec/mojito/rendering/file_spec.rb +9 -9
- data/spec/mojito/rendering/status_codes_spec.rb +6 -3
- data/spec/mojito/rendering/templates_spec.rb +18 -8
- data/spec/mojito/rendering_spec.rb +2 -0
- data/spec/mojito/request_extensions_spec.rb +3 -1
- data/spec/mojito_spec.rb +5 -3
- metadata +39 -35
- data/lib/mojito/matchers.rb +0 -23
- data/spec/mojito/matchers/url_scheme_spec.rb +0 -22
- data/spec/mojito/matchers/virtual_host_spec.rb +0 -22
- data/spec/mojito/matchers_spec.rb +0 -5
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.3
|
data/lib/mojito.rb
CHANGED
@@ -4,65 +4,42 @@ require 'extlib'
|
|
4
4
|
|
5
5
|
module Mojito
|
6
6
|
|
7
|
-
PLUGINS = {}
|
8
|
-
|
9
7
|
require 'mojito/request_extensions'
|
10
8
|
require 'mojito/helpers'
|
9
|
+
require 'mojito/controllers'
|
11
10
|
require 'mojito/base'
|
12
11
|
require 'mojito/utils/status_codes'
|
13
12
|
require 'mojito/rendering'
|
14
|
-
require 'mojito/matchers'
|
15
13
|
|
16
14
|
R = Rendering
|
17
|
-
M = Matchers
|
18
15
|
H = Helpers
|
16
|
+
C = Controllers
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
type
|
23
|
-
|
24
|
-
include mod
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.base_application(*helpers, &block)
|
30
|
-
Class.new.tap do |cl|
|
31
|
-
cl.instance_exec do
|
18
|
+
class << self
|
19
|
+
|
20
|
+
def included(type)
|
21
|
+
type.instance_exec do
|
32
22
|
include Mojito::Base
|
33
|
-
helpers.reverse.each do |helper|
|
34
|
-
case helper
|
35
|
-
when Symbol
|
36
|
-
include PLUGINS[helper]
|
37
|
-
when Module
|
38
|
-
include helper
|
39
|
-
end
|
40
|
-
end
|
41
23
|
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
24
|
+
type.extend ClassMethods
|
25
|
+
end
|
26
|
+
|
27
|
+
def mode
|
28
|
+
(ENV['RACK_ENV'] || :development).to_sym
|
29
|
+
end
|
45
30
|
|
46
|
-
|
47
|
-
|
48
|
-
cl.instance_exec do
|
49
|
-
include Mojito
|
50
|
-
helpers.reverse.each do |helper|
|
51
|
-
include helper
|
52
|
-
end
|
53
|
-
end
|
54
|
-
cl.routes &block if block
|
31
|
+
def development?
|
32
|
+
mode == :development
|
55
33
|
end
|
34
|
+
|
56
35
|
end
|
57
36
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
37
|
+
module ClassMethods
|
38
|
+
|
39
|
+
def mock_request
|
40
|
+
Rack::MockRequest.new self
|
41
|
+
end
|
42
|
+
|
64
43
|
end
|
65
|
-
|
66
|
-
ALL_HELPERS = [Mojito::Matchers, Mojito::Rendering, Mojito::Helpers::ExceptionHandling, Mojito::Helpers::Shortcuts, Mojito::Base]
|
67
44
|
|
68
45
|
end
|
data/lib/mojito/base.rb
CHANGED
@@ -10,8 +10,13 @@ module Mojito
|
|
10
10
|
type.extend ClassMethods
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@__request =
|
13
|
+
def initialize(request)
|
14
|
+
@__request = case request
|
15
|
+
when Rack::Request
|
16
|
+
request.dup
|
17
|
+
when Hash, Mash
|
18
|
+
Rack::Request.new(request.dup)
|
19
|
+
end
|
15
20
|
self.env['MOJITO/CONTEXT_PATH'] = self.env['SCRIPT_NAME']
|
16
21
|
end
|
17
22
|
|
@@ -25,17 +30,22 @@ module Mojito
|
|
25
30
|
|
26
31
|
def response
|
27
32
|
@__response ||= Rack::Response.new.tap do |res|
|
28
|
-
|
29
|
-
type = MIME::Types.type_for(extension).first
|
30
|
-
res.headers['Content-Type'] = type.to_s if type
|
31
|
-
end
|
33
|
+
res.headers.delete 'Content-Type'
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
37
|
def halt!(resp = response)
|
36
38
|
throw :halt, case resp
|
37
39
|
when Rack::Response
|
38
|
-
resp.
|
40
|
+
resp.tap {|res|
|
41
|
+
unless res.headers.include? 'Content-Type'
|
42
|
+
if extension = request.path[/(?<=\.)\w+$/] and res.status == 200 and type = MIME::Types.type_for(extension).first
|
43
|
+
res.headers['Content-Type'] = type.to_s
|
44
|
+
else
|
45
|
+
res.headers['Content-Type'] = 'text/html'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
}.finish
|
39
49
|
when Array
|
40
50
|
resp
|
41
51
|
when Symbol, Integer
|
@@ -46,62 +56,23 @@ module Mojito
|
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
instance_exec &self.class.routes if self.class.routes
|
53
|
-
[404, { 'Content-Type' => 'application/octet-stream' }, []]
|
54
|
-
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
55
62
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
return unless matchers.all? {|m| __match?(m) }
|
62
|
-
params = request.captures[param_size..-1][0..block.arity].collect {|p| Rack::Utils.unescape(p) }
|
63
|
-
instance_exec *params, &block
|
64
|
-
ensure
|
65
|
-
@__env = env_backup
|
66
|
-
request.instance_exec { @env = env_backup }
|
63
|
+
def call(env)
|
64
|
+
catch :halt do
|
65
|
+
request = Rack::Request.new env
|
66
|
+
call_with_handlers request
|
67
|
+
end
|
67
68
|
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
# the PATH matcher) may alter the current request, however a matcher is only allowed to do that when it matches.
|
72
|
-
def __match?(matcher)
|
73
|
-
case matcher
|
74
|
-
when String, Regexp
|
75
|
-
instance_exec &Mojito::Matchers::PATH(matcher)
|
76
|
-
when Proc
|
77
|
-
instance_exec &matcher
|
78
|
-
else
|
79
|
-
matcher
|
80
|
-
end
|
70
|
+
def call_with_handlers(request)
|
71
|
+
dispatch request
|
81
72
|
end
|
82
|
-
private :__match?
|
83
73
|
|
84
|
-
|
85
|
-
|
86
|
-
def call(env)
|
87
|
-
catch :halt do
|
88
|
-
self.new(env).dispatch
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def routes(&block)
|
93
|
-
@__routing = block if block
|
94
|
-
@__routing
|
95
|
-
end
|
96
|
-
|
97
|
-
def to_app
|
98
|
-
self
|
99
|
-
end
|
100
|
-
|
101
|
-
def mock_request
|
102
|
-
Rack::MockRequest.new self
|
103
|
-
end
|
104
|
-
|
74
|
+
def dispatch(request)
|
75
|
+
self.new(request).__dispatch
|
105
76
|
end
|
106
77
|
|
107
78
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Mojito::Controllers
|
4
|
+
|
5
|
+
module Method
|
6
|
+
require 'cgi'
|
7
|
+
|
8
|
+
def __dispatch
|
9
|
+
if m = %r{^/?(?<meth>\w+)(?:/|$)}.match(request.path_info)
|
10
|
+
meth = m['meth'].to_sym
|
11
|
+
if respond_to?(meth.to_sym)
|
12
|
+
env['SCRIPT_NAME'] += m.to_s
|
13
|
+
arity = method(meth).arity
|
14
|
+
args, env['PATH_INFO'] = Method.args_for(arity, m.post_match)
|
15
|
+
args.collect! {|a| CGI.unescape a } if args
|
16
|
+
if args
|
17
|
+
send meth, *args
|
18
|
+
ok!
|
19
|
+
else
|
20
|
+
Mojito::R::StatusCodes.instance_method(:not_found!).bind(self).call
|
21
|
+
end
|
22
|
+
else
|
23
|
+
Mojito::R::StatusCodes.instance_method(:not_found!).bind(self).call
|
24
|
+
end
|
25
|
+
else
|
26
|
+
Mojito::R::StatusCodes.instance_method(:not_found!).bind(self).call
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.args_for(arity, path_info)
|
31
|
+
if arity >= 0
|
32
|
+
args = path_info.split('/', arity + 1)
|
33
|
+
if args.length == arity
|
34
|
+
[args, '']
|
35
|
+
elsif args.length == arity + 1
|
36
|
+
[args, args.pop]
|
37
|
+
else
|
38
|
+
[nil, path_info]
|
39
|
+
end
|
40
|
+
else
|
41
|
+
args = path_info.split('/')
|
42
|
+
if args.length >= arity.abs - 1
|
43
|
+
[args, '']
|
44
|
+
else
|
45
|
+
[nil, path_info]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.method_controller(*modules, &block)
|
53
|
+
Class.new.tap do |controller|
|
54
|
+
controller.instance_exec do
|
55
|
+
include Mojito::Base
|
56
|
+
include Mojito::Controllers::Method
|
57
|
+
modules.each do |mod|
|
58
|
+
include mod
|
59
|
+
end
|
60
|
+
end
|
61
|
+
controller.class_exec &block if block
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Mojito::Controllers
|
4
|
+
|
5
|
+
module Runtime
|
6
|
+
require 'mojito/controllers/runtime/environment'
|
7
|
+
require 'mojito/controllers/runtime/methods'
|
8
|
+
require 'mojito/controllers/runtime/path'
|
9
|
+
require 'mojito/controllers/runtime/url_scheme'
|
10
|
+
require 'mojito/controllers/runtime/virtual_host'
|
11
|
+
|
12
|
+
def self.included(type)
|
13
|
+
type.extend ClassMethods
|
14
|
+
type.instance_exec do
|
15
|
+
include Environment
|
16
|
+
include Methods
|
17
|
+
include Path
|
18
|
+
include UrlScheme
|
19
|
+
include VirtualHost
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Defines a route which is matched when all given matchers evaluate to +true+.
|
25
|
+
def on(*matchers, &block)
|
26
|
+
env_backup = env.dup
|
27
|
+
param_size = request.captures.length
|
28
|
+
return unless matchers.all? {|m| __match?(m) }
|
29
|
+
params = request.captures[param_size..-1][0..block.arity].collect {|p| Rack::Utils.unescape(p) }
|
30
|
+
instance_exec *params, &block
|
31
|
+
ensure
|
32
|
+
@__env = env_backup
|
33
|
+
request.instance_exec { @env = env_backup }
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Evaluates a single matcher, returning whether it matched or not. Please be aware that matchers (most prominently
|
38
|
+
# the PATH matcher) may alter the current request, however a matcher is only allowed to do that when it matches.
|
39
|
+
def __match?(matcher)
|
40
|
+
case matcher
|
41
|
+
when String, Regexp
|
42
|
+
instance_exec &PATH(matcher)
|
43
|
+
when Proc
|
44
|
+
instance_exec &matcher
|
45
|
+
else
|
46
|
+
matcher
|
47
|
+
end
|
48
|
+
end
|
49
|
+
private :__match?
|
50
|
+
|
51
|
+
##
|
52
|
+
# Dispatches the current request to the matching routes.
|
53
|
+
def __dispatch
|
54
|
+
instance_exec &self.class.routes if self.class.routes
|
55
|
+
[404, { 'Content-Type' => 'application/octet-stream' }, []]
|
56
|
+
end
|
57
|
+
|
58
|
+
module ClassMethods
|
59
|
+
|
60
|
+
def routes(&block)
|
61
|
+
@routes = block if block
|
62
|
+
@routes
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.runtime_controller(*modules, &block)
|
70
|
+
Class.new do
|
71
|
+
include Mojito
|
72
|
+
include Mojito::C::Runtime
|
73
|
+
modules.each do |mod|
|
74
|
+
include mod
|
75
|
+
end
|
76
|
+
routes &block
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -1,16 +1,17 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
module Mojito::
|
3
|
+
module Mojito::Controllers::Runtime
|
4
4
|
|
5
5
|
module Path
|
6
|
+
require 'cgi'
|
6
7
|
|
7
8
|
def PATH(pattern, delimiter = %r{/|\z})
|
8
9
|
consume_path = proc do |pattern|
|
9
10
|
if match = env['PATH_INFO'].match(%r<\A/*#{pattern}(?=#{delimiter})>)
|
10
11
|
env['SCRIPT_NAME'] = match.to_s
|
11
12
|
env['PATH_INFO'] = match.post_match
|
12
|
-
request.locals.update match.names.inject({}) {|hash, name| hash[name.to_sym] = match[name] ; hash }
|
13
|
-
request.captures.push *match.captures
|
13
|
+
request.locals.update match.names.inject({}) {|hash, name| hash[name.to_sym] = CGI.unescape(match[name]) ; hash }
|
14
|
+
request.captures.push *(match.captures.collect {|c| CGI.unescape c })
|
14
15
|
true
|
15
16
|
else
|
16
17
|
false
|
@@ -32,6 +33,4 @@ module Mojito::Matchers
|
|
32
33
|
|
33
34
|
end
|
34
35
|
|
35
|
-
Mojito::PLUGINS[:path] = Path
|
36
|
-
|
37
36
|
end
|