mojito 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,8 +1,8 @@
1
- h1. mojito - Next level ruby webframework
1
+ h1. mojito - Next level Ruby webframework
2
2
 
3
3
  p. Mojito is a lean and simple webframework.
4
4
 
5
- p. As the name implies mojito derives from cuba (https://github.com/soveran/cuba). Many thanks to Michel and the cuba sources for giving me some major insights on web-application-simplicity!
5
+ p. As the name implies mojito is Cuba-born (https://github.com/soveran/cuba). Many thanks to Michel and his cuba project for giving me some major insights on web-application-simplicity!
6
6
 
7
7
  h2. Installing
8
8
 
@@ -10,7 +10,7 @@ bc. $ gem install mojito
10
10
 
11
11
  h2. Your first application
12
12
 
13
- p. The easiest way to start with mojito is to use a plain config.ru script to develop and configure your application.
13
+ p. The easiest way to start with mojito is to use a plain @config.ru@ script to develop and configure your application.
14
14
 
15
15
  bc.. $ cat config.ru
16
16
  require 'mojito'
@@ -23,9 +23,9 @@ FirstApp = Mojito.application do
23
23
  end
24
24
  end
25
25
 
26
- run FirstApp
26
+ run FirstApp.to_app
27
27
 
28
- p. This installs a handler for GET requests to a path of /hello/ followed by a name (actually this notation catches all but a slash '/'). You can start this application by running @rackup@ from the same directory:
28
+ p. This installs a handler for GET requests to a path of /hello/ followed by a name (actually this notation catches everything but a slash '/'). You can start this application by running @rackup@ from the same directory:
29
29
 
30
30
  bc. $ rackup
31
31
 
@@ -34,7 +34,50 @@ p. This starts a http-server on port 9292. Now try to call your handler through
34
34
  bc. $ curl http://localhost:9292/hello/Fred
35
35
  Hello Fred! How are you?
36
36
 
37
- p. Please be aware that although this way is easy to start with it tends to messy very quick if your project becomes more complex, so please read on...
37
+ p. Please be aware that although this way is easy to start with it tends to get messy very quick if your project becomes more complex, so please read on...
38
+
39
+ h2. Structure of a real-world application
40
+
41
+ p. The above call to @Mojito.application@ actually created a class and included most of Mojitos foundation methods, so that you could start writing your application code without wondering what features you want to include in your application. As a tribute to simplicity (one of the most important I think), another helper method @Mojito.base_application@ can be used to create a blank application class, which only includes modules that are strictly necessary. Instead of using those methods you can also write out all of the generated classes code (here @Mojito@ is included, which in turn includes @Mojito::Base@, the basic module which is used by @Mojito.base_application@):
42
+
43
+ bc.. class FirstApp
44
+ include Mojito
45
+ routes do
46
+ on GET(), PATH('/hello/:name') do |name|
47
+ ...
48
+ end
49
+ end
50
+ end
51
+
52
+ p. which is not only perfectly legal but also favoured, when you need any special behaviour on your application class.
53
+
54
+ p. Although you can actually use any structure you want (including a single-file application), some of them are more useful than others. My preferred way of developing Mojito applications is to reuse most of the concepts found in product development with rubygems and git.
55
+
56
+ h2. Behind the scenes
57
+
58
+ p. Understanding how Mojito dispatches requests and selects handlers, which in turn use common functionality to create the response is vital to an efficient use of Mojito as web application framework. First of all Mojito applications (classes which include @Mojito::Base@ or @Mojito@) are simply Ruby classes, which are instantiated with the Rack-environment hash for each request. This is automatically triggered by a rack-enabled webserver through the call of @run ApplicationClass@, which tells rack to call @call(env)@ on that class. The Mojito implementation will then instantiate the Application (the instance is called a _controller_ from now on) and call @dispatch@ on that controller. The dispatch method then executes any block given to the @routes@-method in the class definition. As in Cuba the routes-definition is executed once for each request.
59
+
60
+ h3. Matching
61
+
62
+ p. A matcher is simply a Proc, instantiated with matcher-specific configuration, which returns whether or not a given request matches its criteria. The request-method matcher for example is implemented as follows:
63
+
64
+ bc.. def METHOD(method)
65
+ proc { request.request_method == method.to_s.upcase }
66
+ end
67
+
68
+ p. This method configures a Proc to return true when the requests method matches the given parameter. The returned Proc is evaluated in the context of the current controller. This is also where the @request@ method comes from. Like @request@, a matcher can access any method from the controller, within which it is executed. The naming convention is to name all matchers uppercase.
69
+
70
+ h3. Rendering
71
+
72
+ h3. Helpers
73
+
74
+ h2. Deployment/Hosting
75
+
76
+ p. tbd
77
+
78
+ h2. Writing extensions
79
+
80
+ p. tbd
38
81
 
39
82
  h2. Contributing to mojito
40
83
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
data/lib/mojito.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # encoding: UTF-8
2
2
  require 'rack'
3
- require 'slick/logging'
3
+ require 'extlib'
4
4
 
5
5
  module Mojito
6
- require 'mojito/utils/status_codes'
6
+ require 'mojito/request_extensions'
7
7
  require 'mojito/helpers'
8
+ require 'mojito/base'
9
+ require 'mojito/utils/status_codes'
8
10
  require 'mojito/rendering'
9
11
  require 'mojito/matchers'
10
12
 
@@ -26,7 +28,6 @@ module Mojito
26
28
  include Mojito::Base
27
29
  helpers.reverse.each do |helper|
28
30
  include helper
29
- extend helper::ClassMethods if helper.const_defined? :ClassMethods
30
31
  end
31
32
  end
32
33
  cl.routes &block if block
@@ -39,112 +40,12 @@ module Mojito
39
40
  include Mojito
40
41
  helpers.reverse.each do |helper|
41
42
  include helper
42
- extend helper::ClassMethods if helper.const_defined? :ClassMethods
43
43
  end
44
44
  end
45
45
  cl.routes &block if block
46
46
  end
47
47
  end
48
48
 
49
- module Base
50
-
51
- def self.included(type)
52
- type.extend ClassMethods
53
- end
54
-
55
- def initialize(env)
56
- @__env = env
57
- end
58
-
59
- def env
60
- @__env
61
- end
62
-
63
- def request
64
- @__request ||= Rack::Request.new(env)
65
- end
66
-
67
- def response
68
- @__response ||= Rack::Response.new
69
- end
70
-
71
- def captures
72
- @__captures ||= []
73
- end
74
-
75
- def locals
76
- @__locals ||= {}
77
- end
78
-
79
- def script_name
80
- env['SCRIPT_NAME']
81
- end
82
-
83
- def path_info
84
- env['PATH_INFO']
85
- end
86
-
87
- def halt!(resp = response)
88
- throw :halt, case resp
89
- when Rack::Response
90
- resp.finish
91
- when Array
92
- resp
93
- when Symbol, Integer
94
- response.status = STATUS[resp].code
95
- response.finish
96
- else
97
- [500, { 'Content-Type' => 'application/octet-stream' }, []]
98
- end
99
- end
100
-
101
- def dispatch
102
- instance_exec &self.class.routes if self.class.routes
103
- Rack::Response.new [], 404, 'Content-Type' => 'application/octet-stream'
104
- end
105
-
106
- def on(*matchers, &block)
107
- env_backup = env.dup
108
- param_size = captures.length
109
- return unless matchers.all? {|m| __match?(m) }
110
- params = captures[param_size..-1][0..block.arity].collect {|p| Rack::Utils.unescape(p) }
111
- instance_exec *params, &block
112
- ensure
113
- @__env = env_backup
114
- end
115
-
116
- def __match?(matcher)
117
- case matcher
118
- when String, Regexp
119
- instance_exec &Matchers::PATH(matcher)
120
- when Proc
121
- instance_exec &matcher
122
- else
123
- matcher
124
- end
125
- end
126
-
127
- module ClassMethods
128
-
129
- def call(env)
130
- catch :halt do
131
- new(env).dispatch
132
- end
133
- end
134
-
135
- def routes(&block)
136
- @__routing = block if block
137
- @__routing
138
- end
139
-
140
- def mock_request
141
- Rack::MockRequest.new self
142
- end
143
-
144
- end
145
-
146
- end
147
-
148
- ALL_HELPERS = [Mojito::Matchers, Mojito::Rendering, Mojito::Helpers::ExceptionHandling, Mojito::Base]
49
+ ALL_HELPERS = [Mojito::Matchers, Mojito::Rendering, Mojito::Helpers::ExceptionHandling, Mojito::Helpers::Shortcuts, Mojito::Base]
149
50
 
150
51
  end
@@ -0,0 +1,100 @@
1
+ # encoding: UTF-8
2
+
3
+ module Mojito
4
+
5
+ module Base
6
+
7
+ def self.included(type)
8
+ type.extend ClassMethods
9
+ end
10
+
11
+ def initialize(env)
12
+ @__env = env
13
+ end
14
+
15
+ def env
16
+ @__env
17
+ end
18
+
19
+ def request
20
+ @__request ||= Rack::Request.new(env)
21
+ end
22
+
23
+ def response
24
+ @__response ||= Rack::Response.new
25
+ end
26
+
27
+ def halt!(resp = response)
28
+ throw :halt, case resp
29
+ when Rack::Response
30
+ resp.finish
31
+ when Array
32
+ resp
33
+ when Symbol, Integer
34
+ response.status = STATUS[resp].code
35
+ response.finish
36
+ else
37
+ [500, { 'Content-Type' => 'text/plain', 'Content-Length' => '0' }, []]
38
+ end
39
+ end
40
+
41
+ ##
42
+ # Dispatches the current request to the matching routes.
43
+ def dispatch
44
+ instance_exec &self.class.routes if self.class.routes
45
+ Rack::Response.new [], 404, 'Content-Type' => 'application/octet-stream'
46
+ end
47
+
48
+ ##
49
+ # Defines a route which is matched when all given matchers evaluate to +true+.
50
+ def on(*matchers, &block)
51
+ env_backup = env.dup
52
+ param_size = request.captures.length
53
+ return unless matchers.all? {|m| __match?(m) }
54
+ params = request.captures[param_size..-1][0..block.arity].collect {|p| Rack::Utils.unescape(p) }
55
+ instance_exec *params, &block
56
+ ensure
57
+ @__env = env_backup
58
+ end
59
+
60
+ ##
61
+ # Evaluates a single matcher, returning whether it matched or not. Please be aware that matchers (most prominently
62
+ # the PATH matcher) may alter the current request, however a matcher is only allowed to do that when it matches.
63
+ def __match?(matcher)
64
+ case matcher
65
+ when String, Regexp
66
+ instance_exec &Matchers::PATH(matcher)
67
+ when Proc
68
+ instance_exec &matcher
69
+ else
70
+ matcher
71
+ end
72
+ end
73
+ private :__match?
74
+
75
+ module ClassMethods
76
+
77
+ def call(env)
78
+ catch :halt do
79
+ new(env).dispatch
80
+ end
81
+ end
82
+
83
+ def routes(&block)
84
+ @__routing = block if block
85
+ @__routing
86
+ end
87
+
88
+ def to_app
89
+ self
90
+ end
91
+
92
+ def mock_request
93
+ Rack::MockRequest.new self
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -3,5 +3,6 @@
3
3
  module Mojito::Helpers
4
4
 
5
5
  require 'mojito/helpers/exception_handling'
6
+ require 'mojito/helpers/shortcuts'
6
7
 
7
8
  end
@@ -22,7 +22,6 @@ module Mojito
22
22
  module ExceptionHandling
23
23
 
24
24
  def self.included(type)
25
- type.extend ClassMethods
26
25
  type.instance_exec do
27
26
  old_dispatch = instance_method(:dispatch)
28
27
  define_method :dispatch do
@@ -33,6 +32,7 @@ module Mojito
33
32
  end
34
33
  end
35
34
  end
35
+ type.extend ClassMethods
36
36
  end
37
37
 
38
38
  def raise(exception)
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ module Mojito::Helpers::Shortcuts
4
+
5
+ def captures
6
+ request.captures
7
+ end
8
+
9
+ def locals
10
+ request.locals
11
+ end
12
+
13
+ def script_name
14
+ request.script_name
15
+ end
16
+
17
+ def path_info
18
+ request.path_info
19
+ end
20
+
21
+ def session
22
+ request.session
23
+ end
24
+
25
+ module ClassMethods
26
+
27
+
28
+
29
+ end
30
+
31
+ end
@@ -6,11 +6,11 @@ module Mojito::Matchers
6
6
 
7
7
  def PATH(pattern)
8
8
  consume_path = proc do |pattern|
9
- if match = path_info.match(%r<\A/#{pattern}(?=/|\z)>)
9
+ if match = env['PATH_INFO'].match(%r<\A/#{pattern}(?=/|\z)>)
10
10
  env['SCRIPT_NAME'] = match.to_s
11
11
  env['PATH_INFO'] = match.post_match
12
- locals.update match.names.inject({}) {|hash, name| hash[name.to_sym] = match[name] ; hash }
13
- captures.push *match.captures
12
+ request.locals.update match.names.inject({}) {|hash, name| hash[name.to_sym] = match[name] ; hash }
13
+ request.captures.push *match.captures
14
14
  true
15
15
  else
16
16
  false
@@ -5,11 +5,13 @@ module Mojito::Rendering
5
5
  require 'mojito/rendering/content'
6
6
  require 'mojito/rendering/content_types'
7
7
  require 'mojito/rendering/delegation'
8
+ require 'mojito/rendering/file'
8
9
  require 'mojito/rendering/status_codes'
9
10
 
10
11
  include Content
11
12
  include ContentTypes
12
13
  include Delegation
14
+ include File
13
15
  include StatusCodes
14
16
 
15
17
  end
@@ -4,8 +4,8 @@ module Mojito::Rendering
4
4
 
5
5
  module Delegation
6
6
 
7
- def run(app)
8
- halt! app
7
+ def run!(app)
8
+ halt! app.call(env)
9
9
  end
10
10
 
11
11
  end
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+
3
+ module Mojito::Rendering
4
+
5
+ module File
6
+ require 'pathname'
7
+ require 'mime/types'
8
+ require 'time'
9
+
10
+ def file!(filename)
11
+ path = Pathname === filename ? filename : Pathname.new(filename.to_s)
12
+ restrict_path! path if respond_to? :restrict_path!
13
+ if path.readable? and path.file?
14
+ body = FileResponse.new path
15
+ halt! [response.status, response.headers.merge(body.compute_headers), body]
16
+ else
17
+ not_found!
18
+ end
19
+ end
20
+
21
+ class FileResponse
22
+
23
+ def initialize(pathname)
24
+ @pathname = pathname
25
+ end
26
+
27
+ def each(&block)
28
+ @pathname.open do |f|
29
+ yield f.read
30
+ end
31
+ end
32
+
33
+ def compute_headers
34
+ { 'Content-Type' => mime_type.to_s, 'Content-Length' => size.to_s, 'Last-Modified' => @pathname.mtime.rfc2822 }
35
+ end
36
+
37
+ def mime_type
38
+ MIME::Types.type_for(@pathname.to_s).first || MIME::Types['application/octet-stream'].first
39
+ end
40
+
41
+ def size
42
+ @pathname.size
43
+ end
44
+
45
+ def to_path
46
+ @pathname.to_s
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -25,8 +25,7 @@ module Mojito::Rendering
25
25
  end
26
26
 
27
27
  def redirect(target, status = 302)
28
- response['Location'] = target
29
- response.status = status
28
+ response.redirect(target, status)
30
29
  end
31
30
 
32
31
  def redirect!(target, status = 302)
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ class ::Rack::Request
4
+
5
+ def captures
6
+ @env['mojito/captures'] ||= []
7
+ end
8
+
9
+ def locals
10
+ @env['mojito/locals'] ||= Mash.new
11
+ end
12
+
13
+ def script_name
14
+ @env['SCRIPT_NAME']
15
+ end
16
+
17
+ def path_info
18
+ @env['PATH_INFO']
19
+ end
20
+
21
+ get_method = instance_method(:GET)
22
+ define_method :GET do
23
+ get_method.bind(self).call.to_mash
24
+ end
25
+
26
+ post_method = instance_method(:POST)
27
+ define_method :POST do
28
+ post_method.bind(self).call.to_mash
29
+ end
30
+
31
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+ require 'simplecov' and SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
5
+ require 'mojito'
6
+
7
+ describe Mojito::Helpers::ExceptionHandling do
8
+
9
+
10
+
11
+ end
@@ -1,4 +1,7 @@
1
1
  # encoding: UTF-8
2
+ require 'simplecov' and SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
2
5
  require 'mojito'
3
6
 
4
7
  describe Mojito::Matchers::Methods do
@@ -43,30 +46,51 @@ describe Mojito::Matchers::Path do
43
46
 
44
47
  it do
45
48
  subject.send(:__match?, Mojito::M::PATH('hello/:name'))
46
- subject.captures.should == ['world']
47
- subject.locals.should == { :name => 'world' }
48
- subject.path_info.should == '/rest'
49
+ subject.request.captures.should == ['world']
50
+ subject.request.locals.should == { 'name' => 'world' }
51
+ subject.request.path_info.should == '/rest'
49
52
  end
50
53
 
51
54
  it do
52
55
  subject.send(:__match?, 'hello/:name')
53
- subject.captures.should == ['world']
54
- subject.locals.should == { :name => 'world' }
55
- subject.path_info.should == '/rest'
56
+ subject.request.captures.should == ['world']
57
+ subject.request.locals.should == { 'name' => 'world' }
58
+ subject.request.path_info.should == '/rest'
56
59
  end
57
60
 
58
61
  it do
59
62
  subject.send(:__match?, Mojito::M::PATH(%r{hello/(?<name>[^/]+)}))
60
- subject.captures.should == ['world']
61
- subject.locals.should == { :name => 'world' }
62
- subject.path_info.should == '/rest'
63
+ subject.request.captures.should == ['world']
64
+ subject.request.locals.should == { 'name' => 'world' }
65
+ subject.request.path_info.should == '/rest'
63
66
  end
64
67
 
65
68
  it do
66
69
  subject.send(:__match?, %r{hello/(?<name>[^/]+)})
67
- subject.captures.should == ['world']
68
- subject.locals.should == { :name => 'world' }
69
- subject.path_info.should == '/rest'
70
+ subject.request.captures.should == ['world']
71
+ subject.request.locals.should == { 'name' => 'world' }
72
+ subject.request.path_info.should == '/rest'
73
+ end
74
+
75
+ context do
76
+ subject do
77
+ Mojito.base_application Mojito::M::Path, Mojito::R::Content do
78
+ on PATH('hello/:name') do
79
+ on PATH('another/:name') do
80
+ write request.locals[:name]
81
+ halt!
82
+ end
83
+ write request.locals[:name]
84
+ halt!
85
+ end
86
+ end.mock_request
87
+ end
88
+
89
+ it { subject.get('/hello/Fred').status.should == 200 }
90
+ it { subject.get('/hello/Fred').body.should == 'Fred' }
91
+ it { subject.get('/hello/Fred/another/Barney').status.should == 200 }
92
+ it { subject.get('/hello/Fred/another/Barney').body.should == 'Barney' }
93
+
70
94
  end
71
95
 
72
96
  end
@@ -1,4 +1,7 @@
1
1
  # encoding: UTF-8
2
+ require 'simplecov' and SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
2
5
  require 'mojito'
3
6
 
4
7
  describe Mojito::Rendering::Content do
@@ -12,3 +15,75 @@ describe Mojito::Rendering::Content do
12
15
  it { subject.get('/').body.should == 'test content' }
13
16
 
14
17
  end
18
+
19
+ describe Mojito::Rendering::StatusCodes do
20
+
21
+ subject do
22
+ Mojito.base_application Mojito::Matchers::Path, Mojito::Rendering::StatusCodes do
23
+ on 'ok' do ok! end
24
+ on 'not_found' do not_found! end
25
+ on 'internal_server_error' do internal_server_error! end
26
+ on 'unavailable' do unavailable! end
27
+ on 'redirect' do redirect! '/test' end
28
+ end.mock_request
29
+ end
30
+
31
+ it { subject.get('/ok').status.should == 200 }
32
+ it { subject.get('/not_found').status.should == 404 }
33
+ it { subject.get('/internal_server_error').status.should == 500 }
34
+ it { subject.get('/unavailable').status.should == 503 }
35
+ it { subject.get('/redirect').status.should == 302 }
36
+ it { subject.get('/redirect').headers['Location'].should == '/test' }
37
+
38
+ end
39
+
40
+ describe Mojito::Rendering::Delegation do
41
+
42
+ subject do
43
+ sub_app = Mojito.base_application Mojito::R::Content, Mojito::R::Delegation do
44
+ on true do write 'sub-application' ; halt! end
45
+ end
46
+ Mojito.base_application Mojito::Rendering::Content, Mojito::Rendering::Delegation do
47
+ on true do run! sub_app end
48
+ end.mock_request
49
+ end
50
+
51
+ it { subject.get('/').status.should == 200 }
52
+ it { subject.get('/').body.should == 'sub-application' }
53
+
54
+ context do
55
+
56
+ subject do
57
+ sub_app = Mojito.base_application Mojito::R::Content, Mojito::R::Delegation, Mojito::H::Shortcuts do
58
+ on true do write("#{path_info} #{captures.first}") ; halt! end
59
+ end
60
+ Mojito.base_application Mojito::M::Path, Mojito::R::Content, Mojito::R::Delegation do
61
+ on PATH('hello/:name') do run! sub_app end
62
+ end.mock_request
63
+ end
64
+
65
+ it { subject.get('/hello/world/rest').status.should == 200 }
66
+ it { subject.get('/hello/world/rest').body.should == '/rest world' }
67
+
68
+ end
69
+
70
+ end
71
+
72
+ describe Mojito::Rendering::File do
73
+
74
+ subject do
75
+ Mojito.base_application Mojito::Rendering::File do
76
+ file! __FILE__
77
+ end.mock_request
78
+ end
79
+
80
+ it { subject.get('/').status.should == 200 }
81
+ it { subject.get('/').headers.should include('Content-Type') }
82
+ it { subject.get('/').headers['Content-Type'].should == 'application/x-ruby' }
83
+ it { subject.get('/').headers.should include('Content-Length') }
84
+ it { subject.get('/').headers['Content-Length'].should == ::File.size(__FILE__).to_s }
85
+ it { subject.get('/').headers.should include('Last-Modified') }
86
+ it { subject.get('/').headers['Last-Modified'].should == ::File.mtime(__FILE__).rfc2822 }
87
+ it { subject.get('/').body.should == ::File.read(__FILE__) }
88
+
89
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+ require 'simplecov' and SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
5
+ require 'mojito'
6
+
7
+ describe ::Rack::Request do
8
+
9
+ subject do
10
+ Mojito.base_application Mojito::Rendering::Content do
11
+ write request.GET[:hello]
12
+ halt!
13
+ end.mock_request
14
+ end
15
+
16
+ it { subject.get('/?hello=world').status.should == 200 }
17
+ it { subject.get('/?hello=world').body.should == 'world' }
18
+
19
+ end
data/spec/mojito_spec.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  # encoding: UTF-8
2
+ require 'simplecov' and SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
2
5
  require 'mojito'
3
6
 
4
7
  describe Mojito do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mojito
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-14 00:00:00.000000000 Z
12
+ date: 2012-05-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &6514840 !ruby/object:Gem::Requirement
16
+ requirement: &20131580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.4.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *6514840
24
+ version_requirements: *20131580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: mime-types
27
- requirement: &6514180 !ruby/object:Gem::Requirement
27
+ requirement: &20130100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,32 @@ dependencies:
32
32
  version: '1.18'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *6514180
35
+ version_requirements: *20130100
36
+ - !ruby/object:Gem::Dependency
37
+ name: tilt
38
+ requirement: &20129340 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.3.3
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *20129340
47
+ - !ruby/object:Gem::Dependency
48
+ name: extlib
49
+ requirement: &20128340 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.15
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *20128340
36
58
  - !ruby/object:Gem::Dependency
37
59
  name: rspec
38
- requirement: &6513520 !ruby/object:Gem::Requirement
60
+ requirement: &20152720 !ruby/object:Gem::Requirement
39
61
  none: false
40
62
  requirements:
41
63
  - - ~>
@@ -43,10 +65,10 @@ dependencies:
43
65
  version: 2.8.0
44
66
  type: :development
45
67
  prerelease: false
46
- version_requirements: *6513520
68
+ version_requirements: *20152720
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: rdoc
49
- requirement: &7041900 !ruby/object:Gem::Requirement
71
+ requirement: &20151740 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ~>
@@ -54,10 +76,10 @@ dependencies:
54
76
  version: '3.12'
55
77
  type: :development
56
78
  prerelease: false
57
- version_requirements: *7041900
79
+ version_requirements: *20151740
58
80
  - !ruby/object:Gem::Dependency
59
81
  name: bundler
60
- requirement: &7040840 !ruby/object:Gem::Requirement
82
+ requirement: &20150340 !ruby/object:Gem::Requirement
61
83
  none: false
62
84
  requirements:
63
85
  - - ~>
@@ -65,10 +87,10 @@ dependencies:
65
87
  version: 1.0.0
66
88
  type: :development
67
89
  prerelease: false
68
- version_requirements: *7040840
90
+ version_requirements: *20150340
69
91
  - !ruby/object:Gem::Dependency
70
92
  name: jeweler
71
- requirement: &7039960 !ruby/object:Gem::Requirement
93
+ requirement: &20149300 !ruby/object:Gem::Requirement
72
94
  none: false
73
95
  requirements:
74
96
  - - ~>
@@ -76,10 +98,10 @@ dependencies:
76
98
  version: 1.8.3
77
99
  type: :development
78
100
  prerelease: false
79
- version_requirements: *7039960
101
+ version_requirements: *20149300
80
102
  - !ruby/object:Gem::Dependency
81
103
  name: rcov
82
- requirement: &7038500 !ruby/object:Gem::Requirement
104
+ requirement: &20148580 !ruby/object:Gem::Requirement
83
105
  none: false
84
106
  requirements:
85
107
  - - ! '>='
@@ -87,7 +109,7 @@ dependencies:
87
109
  version: '0'
88
110
  type: :development
89
111
  prerelease: false
90
- version_requirements: *7038500
112
+ version_requirements: *20148580
91
113
  description: A simple yet powerful webframework largely inspired by Rum and Cuba
92
114
  email: dev@trense.info
93
115
  executables: []
@@ -99,8 +121,10 @@ files:
99
121
  - LICENSE.txt
100
122
  - VERSION
101
123
  - lib/mojito.rb
124
+ - lib/mojito/base.rb
102
125
  - lib/mojito/helpers.rb
103
126
  - lib/mojito/helpers/exception_handling.rb
127
+ - lib/mojito/helpers/shortcuts.rb
104
128
  - lib/mojito/matchers.rb
105
129
  - lib/mojito/matchers/methods.rb
106
130
  - lib/mojito/matchers/path.rb
@@ -109,10 +133,14 @@ files:
109
133
  - lib/mojito/rendering/content.rb
110
134
  - lib/mojito/rendering/content_types.rb
111
135
  - lib/mojito/rendering/delegation.rb
136
+ - lib/mojito/rendering/file.rb
112
137
  - lib/mojito/rendering/status_codes.rb
138
+ - lib/mojito/request_extensions.rb
113
139
  - lib/mojito/utils/status_codes.rb
140
+ - spec/mojito/helpers_spec.rb
114
141
  - spec/mojito/matchers_spec.rb
115
142
  - spec/mojito/rendering_spec.rb
143
+ - spec/mojito/request_extensions_spec.rb
116
144
  - spec/mojito_spec.rb
117
145
  - README.textile
118
146
  homepage: http://github.com/mtrense/mojito
@@ -127,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
155
  requirements:
128
156
  - - ! '>='
129
157
  - !ruby/object:Gem::Version
130
- version: '0'
158
+ version: 1.9.0
131
159
  required_rubygems_version: !ruby/object:Gem::Requirement
132
160
  none: false
133
161
  requirements: