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.
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