mojito 0.1.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/VERSION +1 -1
  2. data/lib/mojito.rb +21 -44
  3. data/lib/mojito/base.rb +29 -58
  4. data/lib/mojito/controllers.rb +10 -0
  5. data/lib/mojito/controllers/method.rb +65 -0
  6. data/lib/mojito/controllers/runtime.rb +80 -0
  7. data/lib/mojito/{matchers → controllers/runtime}/environment.rb +1 -3
  8. data/lib/mojito/{matchers → controllers/runtime}/methods.rb +1 -3
  9. data/lib/mojito/{matchers → controllers/runtime}/path.rb +4 -5
  10. data/lib/mojito/{matchers → controllers/runtime}/session.rb +1 -3
  11. data/lib/mojito/{matchers → controllers/runtime}/url_scheme.rb +1 -3
  12. data/lib/mojito/{matchers → controllers/runtime}/virtual_host.rb +1 -3
  13. data/lib/mojito/controllers/sinatra.rb +11 -0
  14. data/lib/mojito/helpers/exception_handling.rb +3 -5
  15. data/lib/mojito/helpers/shortcuts.rb +0 -2
  16. data/lib/mojito/rendering.rb +10 -6
  17. data/lib/mojito/rendering/content.rb +0 -2
  18. data/lib/mojito/rendering/content_types.rb +0 -2
  19. data/lib/mojito/rendering/delegation.rb +0 -2
  20. data/lib/mojito/rendering/file.rb +0 -2
  21. data/lib/mojito/rendering/status_codes.rb +0 -2
  22. data/lib/mojito/rendering/templates.rb +2 -4
  23. data/lib/mojito/request_extensions.rb +4 -0
  24. data/lib/mojito/utils/rspec.rb +26 -0
  25. data/spec/mojito/base_spec.rb +18 -2
  26. data/spec/mojito/controllers/method_spec.rb +56 -0
  27. data/spec/mojito/{matchers → controllers/runtime}/methods_spec.rb +4 -2
  28. data/spec/mojito/{matchers → controllers/runtime}/path_spec.rb +11 -10
  29. data/spec/mojito/{matchers → controllers/runtime}/session_spec.rb +2 -0
  30. data/spec/mojito/controllers/runtime/url_scheme_spec.rb +24 -0
  31. data/spec/mojito/controllers/runtime/virtual_host_spec.rb +24 -0
  32. data/spec/mojito/helpers_spec.rb +2 -0
  33. data/spec/mojito/rendering/content_spec.rb +4 -2
  34. data/spec/mojito/rendering/delegation_spec.rb +9 -9
  35. data/spec/mojito/rendering/file_spec.rb +9 -9
  36. data/spec/mojito/rendering/status_codes_spec.rb +6 -3
  37. data/spec/mojito/rendering/templates_spec.rb +18 -8
  38. data/spec/mojito/rendering_spec.rb +2 -0
  39. data/spec/mojito/request_extensions_spec.rb +3 -1
  40. data/spec/mojito_spec.rb +5 -3
  41. metadata +39 -35
  42. data/lib/mojito/matchers.rb +0 -23
  43. data/spec/mojito/matchers/url_scheme_spec.rb +0 -22
  44. data/spec/mojito/matchers/virtual_host_spec.rb +0 -22
  45. data/spec/mojito/matchers_spec.rb +0 -5
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.3
@@ -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
- def self.included(type)
22
- type.instance_exec do
23
- ALL_HELPERS.reverse.each do |mod|
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
- cl.routes &block if block
43
- end
44
- end
24
+ type.extend ClassMethods
25
+ end
26
+
27
+ def mode
28
+ (ENV['RACK_ENV'] || :development).to_sym
29
+ end
45
30
 
46
- def self.application(*helpers, &block)
47
- Class.new.tap do |cl|
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
- def self.mode
59
- (ENV['RACK_ENV'] || :development).to_sym
60
- end
61
-
62
- def self.development?
63
- mode == :development
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
@@ -10,8 +10,13 @@ module Mojito
10
10
  type.extend ClassMethods
11
11
  end
12
12
 
13
- def initialize(env)
14
- @__request = Rack::Request.new env.dup
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
- if extension = request.path[/(?<=\.)\w+$/]
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.finish
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
- # Dispatches the current request to the matching routes.
51
- def dispatch
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
- # Defines a route which is matched when all given matchers evaluate to +true+.
58
- def on(*matchers, &block)
59
- env_backup = env.dup
60
- param_size = request.captures.length
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
- # Evaluates a single matcher, returning whether it matched or not. Please be aware that matchers (most prominently
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
- module ClassMethods
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,10 @@
1
+ # encoding: UTF-8
2
+
3
+ module Mojito::Controllers
4
+ require 'mojito/controllers/method'
5
+ require 'mojito/controllers/runtime'
6
+ require 'mojito/controllers/sinatra'
7
+
8
+
9
+
10
+ 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,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Mojito::Matchers
3
+ module Mojito::Controllers::Runtime
4
4
 
5
5
  module Environment
6
6
 
@@ -10,6 +10,4 @@ module Mojito::Matchers
10
10
 
11
11
  end
12
12
 
13
- Mojito::PLUGINS[:environment] = Environment
14
-
15
13
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Mojito::Matchers
3
+ module Mojito::Controllers::Runtime
4
4
 
5
5
  module Methods
6
6
 
@@ -30,6 +30,4 @@ module Mojito::Matchers
30
30
 
31
31
  end
32
32
 
33
- Mojito::PLUGINS[:methods] = Methods
34
-
35
33
  end
@@ -1,16 +1,17 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Mojito::Matchers
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
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Mojito::Matchers
3
+ module Mojito::Controllers::Runtime
4
4
 
5
5
  module Session
6
6
 
@@ -10,6 +10,4 @@ module Mojito::Matchers
10
10
 
11
11
  end
12
12
 
13
- Mojito::PLUGINS[:session] = Session
14
-
15
13
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Mojito::Matchers
3
+ module Mojito::Controllers::Runtime
4
4
 
5
5
  module UrlScheme
6
6
 
@@ -19,6 +19,4 @@ module Mojito::Matchers
19
19
 
20
20
  end
21
21
 
22
- Mojito::PLUGINS[:url_scheme] = UrlScheme
23
-
24
22
  end