mojito 0.1.2 → 0.2.3
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/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
|