racket-mvc 0.0.3 → 0.0.5
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.
- checksums.yaml +4 -4
- data/lib/racket.rb +1 -1
- data/lib/racket/application.rb +152 -143
- data/lib/racket/controller.rb +30 -13
- data/lib/racket/current.rb +2 -2
- data/lib/racket/router.rb +33 -21
- data/lib/racket/utils.rb +5 -0
- data/lib/racket/version.rb +9 -1
- data/lib/racket/view_cache.rb +11 -13
- data/spec/_custom.rb +13 -3
- data/spec/_default.rb +18 -4
- data/spec/_invalid.rb +14 -0
- data/spec/racket.rb +2 -3
- data/spec/test_custom_app/controllers/sub1/custom_sub_controller_1.rb +4 -0
- data/spec/test_default_app/controllers/sub1/default_sub_controller_1.rb +4 -0
- data/spec/test_default_app/public/hello.txt +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2780584b9d4ab769bd0e1aef25544d15aee4eab
|
4
|
+
data.tar.gz: 391cf9ae48c6ed99634b0d224f3351c0b0b9c1a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97cacd90e6986b5a0946cfbcb018c993521696aa54e654dc2d593eaf01129554e446ad9c3e4b4709c1186a7443f8ab24c7d9ef209e8c6f760561132b0131d01f
|
7
|
+
data.tar.gz: dd360e6ff448e1216008453962ccb8b091dee5c0c01804263b4e7495bd48802d39d546978aa64ee40a269fe6da23afa4083245f3c166316ac6a7053c3b1f00e4
|
data/lib/racket.rb
CHANGED
@@ -30,7 +30,6 @@ require_relative 'racket/router.rb'
|
|
30
30
|
require_relative 'racket/session.rb'
|
31
31
|
require_relative 'racket/view_cache.rb'
|
32
32
|
require_relative 'racket/utils.rb'
|
33
|
-
require_relative 'racket/version.rb'
|
34
33
|
|
35
34
|
module Racket
|
36
35
|
# Requires a file using the current application directory as a base path.
|
@@ -46,6 +45,7 @@ module Racket
|
|
46
45
|
#
|
47
46
|
# @return [String]
|
48
47
|
def version
|
48
|
+
require_relative 'racket/version.rb'
|
49
49
|
Version.current
|
50
50
|
end
|
51
51
|
|
data/lib/racket/application.rb
CHANGED
@@ -24,16 +24,76 @@ module Racket
|
|
24
24
|
# Racket main application class.
|
25
25
|
class Application
|
26
26
|
|
27
|
-
|
27
|
+
@options = nil
|
28
28
|
|
29
|
-
|
29
|
+
# Returns the internal application object. When called for the first time this method will use
|
30
|
+
# Rack::Builder to build
|
31
|
+
#
|
32
|
+
# @return [Rack::Builder]
|
33
|
+
def self.application
|
34
|
+
return @application if @application
|
35
|
+
@options[:middleware].unshift([Rack::ShowExceptions]) if dev_mode?
|
36
|
+
instance = self
|
37
|
+
@application = Rack::Builder.new do
|
38
|
+
instance.options[:middleware].each do |middleware|
|
39
|
+
klass, opts = middleware
|
40
|
+
instance.inform_dev("Loading middleware #{klass} with options #{opts}.")
|
41
|
+
if opts
|
42
|
+
use klass, opts
|
43
|
+
else
|
44
|
+
use klass
|
45
|
+
end
|
46
|
+
end
|
47
|
+
run lambda { |env|
|
48
|
+
static_result = instance.serve_static_file(env)
|
49
|
+
return static_result unless static_result.nil? || static_result.first >= 400
|
50
|
+
instance.router.route(env)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
30
54
|
|
31
55
|
# Called whenever Rack sends a request to the application.
|
32
56
|
#
|
33
57
|
# @param [Hash] env Rack environment
|
34
58
|
# @return [Array] A Rack response array
|
35
59
|
def self.call(env)
|
36
|
-
|
60
|
+
application.call(env.dup)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns a list of default options for Racket::Application.
|
64
|
+
#
|
65
|
+
# @return [Hash]
|
66
|
+
def self.default_options
|
67
|
+
root_dir = Utils.build_path(Dir.pwd)
|
68
|
+
{
|
69
|
+
controller_dir: Utils.build_path(root_dir, 'controllers'),
|
70
|
+
default_action: :index,
|
71
|
+
default_layout: '_default.*',
|
72
|
+
default_view: nil,
|
73
|
+
layout_dir: Utils.build_path(root_dir, 'layouts'),
|
74
|
+
logger: Logger.new($stdout),
|
75
|
+
middleware: [
|
76
|
+
[
|
77
|
+
Rack::Session::Cookie,
|
78
|
+
{
|
79
|
+
key: 'racket.session',
|
80
|
+
old_secret: SecureRandom.hex(16),
|
81
|
+
secret: SecureRandom.hex(16)
|
82
|
+
}
|
83
|
+
]
|
84
|
+
],
|
85
|
+
mode: :live,
|
86
|
+
public_dir: Utils.build_path(root_dir, 'public'),
|
87
|
+
root_dir: root_dir,
|
88
|
+
view_dir: Utils.build_path(root_dir, 'views')
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns whether the application runs in dev mode.
|
93
|
+
#
|
94
|
+
# @return [true|false]
|
95
|
+
def self.dev_mode?
|
96
|
+
@options[:mode] == :dev
|
37
97
|
end
|
38
98
|
|
39
99
|
# Returns a route to the specified controller/action/parameter combination.
|
@@ -43,27 +103,24 @@ module Racket
|
|
43
103
|
# @param [Array] params
|
44
104
|
# @return [String]
|
45
105
|
def self.get_route(controller, action, params)
|
46
|
-
router.get_route(controller, action, params)
|
106
|
+
@router.get_route(controller, action, params)
|
47
107
|
end
|
48
108
|
|
49
109
|
# Initializes a new Racket::Application object with default options.
|
50
110
|
#
|
111
|
+
# @param [true|false] reboot
|
51
112
|
# @return [Class]
|
52
|
-
def self.default
|
53
|
-
|
54
|
-
@current = self.new
|
55
|
-
@current.reload
|
56
|
-
self
|
113
|
+
def self.default(reboot = false)
|
114
|
+
init({}, reboot)
|
57
115
|
end
|
58
116
|
|
59
|
-
#
|
117
|
+
# Writes a message to the logger if there is one present.
|
60
118
|
#
|
61
119
|
# @param [String] message
|
62
120
|
# @param [Symbol] level
|
63
121
|
# @return nil
|
64
|
-
def self.
|
65
|
-
@
|
66
|
-
nil
|
122
|
+
def self.inform(message, level)
|
123
|
+
(@options[:logger].send(level, message) if @options[:logger]) && nil
|
67
124
|
end
|
68
125
|
|
69
126
|
# Sends a message to the logger.
|
@@ -72,182 +129,134 @@ module Racket
|
|
72
129
|
# @param [Symbol] level
|
73
130
|
# @return nil
|
74
131
|
def self.inform_all(message, level = :info)
|
75
|
-
|
132
|
+
inform(message, level)
|
76
133
|
end
|
77
134
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# @return [Hash]
|
81
|
-
def self.options
|
82
|
-
@current.options
|
83
|
-
end
|
84
|
-
|
85
|
-
# Requires a file using the current application directory as a base path.
|
135
|
+
# Sends a message to the logger, but only if the application is running in dev mode.
|
86
136
|
#
|
87
|
-
# @param [
|
137
|
+
# @param [String] message
|
138
|
+
# @param [Symbol] level
|
88
139
|
# @return nil
|
89
|
-
def self.
|
90
|
-
|
91
|
-
nil
|
92
|
-
end
|
93
|
-
|
94
|
-
# Returns the router associated with the currenntly running Racket::Application.
|
95
|
-
#
|
96
|
-
# @return [Racket::Router]
|
97
|
-
def self.router
|
98
|
-
@current.router
|
140
|
+
def self.inform_dev(message, level = :debug)
|
141
|
+
(inform(message, level) if dev_mode?) && nil
|
99
142
|
end
|
100
143
|
|
101
|
-
|
102
|
-
|
103
|
-
# Initializes a new Racket::Application object with options specified by +options+.
|
144
|
+
# Initializes the Racket application.
|
104
145
|
#
|
105
146
|
# @param [Hash] options
|
147
|
+
# @param [true|false] reboot
|
106
148
|
# @return [Class]
|
107
|
-
def self.
|
108
|
-
|
109
|
-
|
110
|
-
@
|
149
|
+
def self.init(options, reboot)
|
150
|
+
instance_variables.each { |ivar| instance_variable_set(ivar, nil) } if reboot
|
151
|
+
fail 'Application has already been initialized!' if @options
|
152
|
+
@options = default_options.merge(options)
|
153
|
+
setup_static_server
|
154
|
+
reload
|
111
155
|
self
|
112
156
|
end
|
113
157
|
|
114
|
-
#
|
115
|
-
#
|
116
|
-
# @return [ViewCache]
|
117
|
-
def self.view_cache
|
118
|
-
@current.view_cache
|
119
|
-
end
|
120
|
-
|
121
|
-
# Internal dispatch handler. Should not be called directly.
|
158
|
+
# Loads controllers and associates each controller with a route.
|
122
159
|
#
|
123
|
-
# @
|
124
|
-
|
125
|
-
|
126
|
-
|
160
|
+
# @return [nil]
|
161
|
+
def self.load_controllers
|
162
|
+
inform_dev('Loading controllers.')
|
163
|
+
@options[:last_added_controller] = []
|
164
|
+
@controller = nil
|
165
|
+
Dir.chdir(@options[:controller_dir]) do
|
166
|
+
files = Pathname.glob(File.join('**', '*.rb'))
|
167
|
+
files.map! { |file| file.to_s }
|
168
|
+
# Sort by longest path so that the longer paths gets matched first
|
169
|
+
# HttpRouter claims to be doing this already, but this "hack" is needed in order
|
170
|
+
# for the router to work.
|
171
|
+
files.sort! do |a, b|
|
172
|
+
b.split('/').length <=> a.split('/').length
|
173
|
+
end
|
174
|
+
files.each do |file|
|
175
|
+
::Kernel.require File.expand_path(file)
|
176
|
+
path = "/#{File.dirname(file)}"
|
177
|
+
path = '' if path == '/.'
|
178
|
+
@router.map(path, @options[:last_added_controller].pop)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
@options.delete(:last_added_controller)
|
182
|
+
inform_dev('Done loading controllers.') && nil
|
127
183
|
end
|
128
184
|
|
129
|
-
#
|
185
|
+
# Returns options for the currently running Racket::Application.
|
130
186
|
#
|
131
|
-
# @
|
132
|
-
|
133
|
-
|
134
|
-
def inform(message, level)
|
135
|
-
options[:logger].send(level, message) if options[:logger]
|
136
|
-
nil
|
187
|
+
# @return [Hash]
|
188
|
+
def self.options
|
189
|
+
@options
|
137
190
|
end
|
138
191
|
|
139
192
|
# Reloads the application, making any changes to the controller configuration visible
|
140
193
|
# to the application.
|
141
194
|
#
|
142
195
|
# @return [nil]
|
143
|
-
def reload
|
196
|
+
def self.reload
|
144
197
|
setup_routes
|
145
|
-
|
146
|
-
nil
|
198
|
+
@view_cache = nil
|
147
199
|
end
|
148
200
|
|
149
201
|
# Requires a file using the current application directory as a base path.
|
150
202
|
#
|
151
203
|
# @param [Object] args
|
152
|
-
# @return nil
|
153
|
-
def require(*args)
|
154
|
-
::Kernel.require Utils.build_path(*args)
|
155
|
-
nil
|
204
|
+
# @return [nil]
|
205
|
+
def self.require(*args)
|
206
|
+
(::Kernel.require Utils.build_path(*args)) && nil
|
156
207
|
end
|
157
208
|
|
158
|
-
# Returns the
|
209
|
+
# Returns the router associated with the currenntly running Racket::Application.
|
159
210
|
#
|
160
|
-
# @return [
|
161
|
-
def
|
162
|
-
@
|
163
|
-
end
|
164
|
-
|
165
|
-
private
|
166
|
-
|
167
|
-
def app
|
168
|
-
@app ||= build_app
|
211
|
+
# @return [Racket::Router]
|
212
|
+
def self.router
|
213
|
+
@router
|
169
214
|
end
|
170
215
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
run lambda { |env| instance.router.route(env) }
|
179
|
-
end
|
216
|
+
# Serves a static file (if Racket is configured to serve static files).
|
217
|
+
#
|
218
|
+
# @param [Hash] env Rack environment
|
219
|
+
# @return [Array|nil] A Rack response array if Rack::File handled the file, nil otherwise.
|
220
|
+
def self.serve_static_file(env)
|
221
|
+
return nil if @static_server.nil?
|
222
|
+
@static_server.call(env)
|
180
223
|
end
|
181
224
|
|
182
|
-
#
|
225
|
+
# Initializes routing.
|
183
226
|
#
|
184
|
-
# @
|
185
|
-
|
186
|
-
|
187
|
-
|
227
|
+
# @return [nil]
|
228
|
+
def self.setup_routes
|
229
|
+
@router = Router.new
|
230
|
+
load_controllers
|
188
231
|
end
|
189
232
|
|
190
|
-
#
|
233
|
+
# Initializes static server (if a public dir is specified).
|
191
234
|
#
|
192
|
-
# @return [
|
193
|
-
def
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
default_layout: '_default.*',
|
199
|
-
default_view: nil,
|
200
|
-
layout_dir: Utils.build_path(root_dir, 'layouts'),
|
201
|
-
logger: Logger.new($stdout),
|
202
|
-
middleware: {
|
203
|
-
Rack::Session::Cookie => {
|
204
|
-
key: 'racket.session',
|
205
|
-
old_secret: SecureRandom.hex(16),
|
206
|
-
secret: SecureRandom.hex(16)
|
207
|
-
}
|
208
|
-
},
|
209
|
-
mode: :live,
|
210
|
-
root_dir: root_dir,
|
211
|
-
view_dir: Utils.build_path(root_dir, 'views')
|
212
|
-
}
|
235
|
+
# @return [nil]
|
236
|
+
def self.setup_static_server
|
237
|
+
@static_server = nil
|
238
|
+
return nil unless (public_dir = @options[:public_dir]) && Utils.dir_readable?(public_dir)
|
239
|
+
inform_dev("Setting up static server to serve files from #{public_dir}.")
|
240
|
+
(@static_server = Rack::File.new(public_dir)) && nil
|
213
241
|
end
|
214
242
|
|
215
|
-
#
|
243
|
+
# Initializes a new Racket::Application object with options specified by +options+.
|
216
244
|
#
|
217
|
-
# @
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
Dir.chdir(@options[:controller_dir]) do
|
223
|
-
files = Pathname.glob(File.join('**', '*.rb'))
|
224
|
-
files.map! { |file| file.to_s }
|
225
|
-
# Sort by longest path so that the longer paths gets matched first
|
226
|
-
# HttpRouter claims to be doing this already, but this "hack" is needed in order
|
227
|
-
# for the router to work.
|
228
|
-
files.sort! do |a, b|
|
229
|
-
b.split('/').length <=> a.split('/').length
|
230
|
-
end
|
231
|
-
files.each do |file|
|
232
|
-
::Kernel.require File.expand_path(file)
|
233
|
-
path = "/#{File.dirname(file)}"
|
234
|
-
path = '' if path == '/.'
|
235
|
-
@router.map(path, options[:last_added_controller].pop)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
options.delete(:last_added_controller)
|
239
|
-
Application.inform_dev('Done loading controllers.')
|
240
|
-
nil
|
245
|
+
# @param [Hash] options
|
246
|
+
# @param [true|false] reboot
|
247
|
+
# @return [Class]
|
248
|
+
def self.using(options, reboot = false)
|
249
|
+
init(options, reboot)
|
241
250
|
end
|
242
251
|
|
243
|
-
#
|
252
|
+
# Returns the view cache of the currently running application.
|
244
253
|
#
|
245
|
-
# @return [
|
246
|
-
def
|
247
|
-
@
|
248
|
-
load_controllers
|
249
|
-
nil
|
254
|
+
# @return [ViewCache]
|
255
|
+
def self.view_cache
|
256
|
+
@view_cache ||= ViewCache.new(@options[:layout_dir], @options[:view_dir])
|
250
257
|
end
|
251
258
|
|
259
|
+
private_class_method :application, :default_options, :inform, :init, :load_controllers,
|
260
|
+
:setup_routes, :setup_static_server
|
252
261
|
end
|
253
262
|
end
|
data/lib/racket/controller.rb
CHANGED
@@ -29,7 +29,7 @@ module Racket
|
|
29
29
|
# @param [Array] methods
|
30
30
|
# @param [Proc] blk
|
31
31
|
# @return [nil]
|
32
|
-
def self.
|
32
|
+
def self.__register_hook(type, methods, blk)
|
33
33
|
key = "#{type}_hooks".to_sym
|
34
34
|
meths = public_instance_methods(false)
|
35
35
|
meths = meths & methods.map { |method| method.to_sym} unless methods.empty?
|
@@ -39,7 +39,7 @@ module Racket
|
|
39
39
|
nil
|
40
40
|
end
|
41
41
|
|
42
|
-
private_class_method :
|
42
|
+
private_class_method :__register_hook
|
43
43
|
|
44
44
|
# Adds a before hook to one or more actions. Actions should be given as a list of symbols.
|
45
45
|
# If no symbols are provided, *all* actions on the controller is affected.
|
@@ -47,7 +47,7 @@ module Racket
|
|
47
47
|
# @param [Array] methods
|
48
48
|
# @return [nil]
|
49
49
|
def self.after(*methods, &blk)
|
50
|
-
|
50
|
+
__register_hook(:after, methods, blk) if block_given?
|
51
51
|
end
|
52
52
|
|
53
53
|
# Adds an after hook to one or more actions. Actions should be given as a list of symbols.
|
@@ -56,7 +56,7 @@ module Racket
|
|
56
56
|
# @param [Array] methods
|
57
57
|
# @return [nil]
|
58
58
|
def self.before(*methods, &blk)
|
59
|
-
|
59
|
+
__register_hook(:before, methods, blk) if block_given?
|
60
60
|
end
|
61
61
|
|
62
62
|
# :nodoc:
|
@@ -113,14 +113,28 @@ module Racket
|
|
113
113
|
Application.get_route(controller, action, params)
|
114
114
|
end
|
115
115
|
|
116
|
-
# Redirects the client.
|
116
|
+
# Redirects the client. After hooks are
|
117
117
|
#
|
118
|
-
# @param [String] target
|
119
|
-
# @param [Fixnum] status
|
118
|
+
# @param [String] target URL to redirect to
|
119
|
+
# @param [Fixnum] status HTTP status to send
|
120
|
+
# @param [true|false] run_after_hook Whether after hook should be run before redirecting
|
120
121
|
# @return [Object]
|
121
|
-
def redirect(target, status = 302)
|
122
|
-
racket.redirected = true
|
122
|
+
def redirect(target, status = 302, run_after_hook = true)
|
123
123
|
response.redirect(target, status)
|
124
|
+
respond(response.status, response.headers, '', run_after_hook);
|
125
|
+
end
|
126
|
+
|
127
|
+
# Stop processing request and send a custom response. After calling this method, no further
|
128
|
+
# processing of the request is done unless +run_after_hook+ is set to true. If +run_after_hook+
|
129
|
+
# is set to true, any after hook associated with the action (but no other code) will be run.
|
130
|
+
#
|
131
|
+
# @param [Fixnum] status
|
132
|
+
# @param [Hash] headers
|
133
|
+
# @param [String] body
|
134
|
+
# @param [true|false] run_after_hook Whether after hook should be run
|
135
|
+
def respond(status = 200, headers = {}, body = '', run_after_hook = false)
|
136
|
+
__run_hook(:after, racket.action) if run_after_hook
|
137
|
+
throw :response, [status, headers, body]
|
124
138
|
end
|
125
139
|
|
126
140
|
# Renders an action.
|
@@ -135,13 +149,16 @@ module Racket
|
|
135
149
|
private
|
136
150
|
|
137
151
|
def __execute(action)
|
138
|
-
|
139
|
-
self.instance_eval &before_hooks[action] if before_hooks.key?(action)
|
152
|
+
__run_hook(:before, action)
|
140
153
|
meth = method(action)
|
141
154
|
params = racket.params[0...meth.parameters.length]
|
142
155
|
racket.action_result = meth.call(*params)
|
143
|
-
|
144
|
-
|
156
|
+
__run_hook(:after, action)
|
157
|
+
end
|
158
|
+
|
159
|
+
def __run_hook(type, action)
|
160
|
+
hooks = controller_option("#{type}_hooks".to_sym) || {}
|
161
|
+
self.instance_eval &hooks[action] if hooks.key?(action)
|
145
162
|
end
|
146
163
|
|
147
164
|
end
|
data/lib/racket/current.rb
CHANGED
@@ -25,7 +25,7 @@ module Racket
|
|
25
25
|
class Current
|
26
26
|
# Holds Racket internal state, available to the controller instance but mostly used for keeping
|
27
27
|
# track of things that don't belong to the actual request.
|
28
|
-
State = Struct.new(:action, :action_result, :params
|
28
|
+
State = Struct.new(:action, :action_result, :params)
|
29
29
|
|
30
30
|
# Called whenever a new request needs to be processed.
|
31
31
|
#
|
@@ -34,7 +34,7 @@ module Racket
|
|
34
34
|
# @param [Array] params Parameters sent to the action
|
35
35
|
# @return [Module] A module encapsulating all state relating to the current request
|
36
36
|
def self.init(env, action, params)
|
37
|
-
racket = State.new(action, nil, params
|
37
|
+
racket = State.new(action, nil, params)
|
38
38
|
request = Request.new(env)
|
39
39
|
response = Response.new
|
40
40
|
session = Session.new(env['rack.session']) if env.key?('rack.session')
|
data/lib/racket/router.rb
CHANGED
@@ -76,8 +76,14 @@ module Racket
|
|
76
76
|
end
|
77
77
|
|
78
78
|
# @todo: Allow the user to set custom handlers for different errors
|
79
|
-
def
|
80
|
-
|
79
|
+
def render_error(status, error = nil)
|
80
|
+
# If running in dev mode, let Rack::ShowExceptions handle the error.
|
81
|
+
raise error if error && Application.dev_mode?
|
82
|
+
|
83
|
+
# Not running in dev mode, let us handle the error ourselves.
|
84
|
+
response = Response.new([], status, { 'Content-Type' => 'text/plain' })
|
85
|
+
response.write("#{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}")
|
86
|
+
response.finish
|
81
87
|
end
|
82
88
|
|
83
89
|
# Routes a request and renders it.
|
@@ -85,28 +91,34 @@ module Racket
|
|
85
91
|
# @param [Hash] env Rack environment
|
86
92
|
# @return [Array] A Rack response triplet
|
87
93
|
def route(env)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
begin
|
95
|
+
catch :response do # Catches early exits from Controller.respond.
|
96
|
+
# Find controller in map
|
97
|
+
# If controller exists, call it
|
98
|
+
# Otherwise, send a 404
|
99
|
+
matching_routes = @router.recognize(env)
|
100
|
+
unless matching_routes.first.nil?
|
101
|
+
target_klass = matching_routes.first.first.route.dest
|
102
|
+
params = matching_routes.first.first.param_values.first.reject { |e| e.empty? }
|
103
|
+
action = params.empty? ? target_klass.get_option(:default_action) : params.shift.to_sym
|
96
104
|
|
97
|
-
|
98
|
-
|
105
|
+
# Check if action is available on target
|
106
|
+
return render_error(404) unless @actions_by_controller[target_klass].include?(action)
|
99
107
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
108
|
+
# Initialize target
|
109
|
+
target = target_klass.new
|
110
|
+
# @fixme: File.dirname should not be used on urls!
|
111
|
+
1.upto(params.count) do
|
112
|
+
env['PATH_INFO'] = File.dirname(env['PATH_INFO'])
|
113
|
+
end
|
114
|
+
target.extend(Current.init(env, action, params))
|
115
|
+
target.render(action)
|
116
|
+
else
|
117
|
+
render_error(404)
|
118
|
+
end
|
105
119
|
end
|
106
|
-
|
107
|
-
|
108
|
-
else
|
109
|
-
render_404
|
120
|
+
rescue => err
|
121
|
+
render_error(500, err)
|
110
122
|
end
|
111
123
|
end
|
112
124
|
|
data/lib/racket/utils.rb
CHANGED
data/lib/racket/version.rb
CHANGED
@@ -19,11 +19,19 @@ along with Racket. If not, see <http://www.gnu.org/licenses/>.
|
|
19
19
|
=end
|
20
20
|
|
21
21
|
module Racket
|
22
|
+
# The only purpose of this module is to keep track of the current Racket version. It is *not*
|
23
|
+
# loaded automatically unless you make an explicit call to Racket.version.
|
22
24
|
module Version
|
25
|
+
# Major version
|
23
26
|
MAJOR = 0
|
27
|
+
# Minor version
|
24
28
|
MINOR = 0
|
25
|
-
|
29
|
+
# Teeny version
|
30
|
+
TEENY = 5
|
26
31
|
|
32
|
+
# Returns the current version of Racket as a string.
|
33
|
+
#
|
34
|
+
# @return [String]
|
27
35
|
def current
|
28
36
|
[MAJOR, MINOR, TEENY].join('.')
|
29
37
|
end
|
data/lib/racket/view_cache.rb
CHANGED
@@ -37,19 +37,17 @@ module Racket
|
|
37
37
|
# @param [Controller] controller
|
38
38
|
# @return [Hash]
|
39
39
|
def render(controller)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
output = controller.racket.action_result
|
50
|
-
end
|
51
|
-
controller.response.write(output)
|
40
|
+
template =
|
41
|
+
find_template(controller.request.path, controller.controller_option(:default_view))
|
42
|
+
if template
|
43
|
+
output = Tilt.new(template).render(controller)
|
44
|
+
layout =
|
45
|
+
find_layout(controller.request.path, controller.controller_option(:default_layout))
|
46
|
+
output = Tilt.new(layout).render(controller) { output } if layout
|
47
|
+
else
|
48
|
+
output = controller.racket.action_result
|
52
49
|
end
|
50
|
+
controller.response.write(output)
|
53
51
|
controller.response.finish
|
54
52
|
end
|
55
53
|
|
@@ -90,7 +88,7 @@ module Racket
|
|
90
88
|
file_path = File.join(base_file_path, url_path)
|
91
89
|
action = File.basename(file_path)
|
92
90
|
file_path = File.dirname(file_path)
|
93
|
-
return nil unless
|
91
|
+
return nil unless Utils.dir_readable?(file_path)
|
94
92
|
Dir.chdir(file_path) do
|
95
93
|
files = Pathname.glob("#{action}.*")
|
96
94
|
if files.empty?
|
data/spec/_custom.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
describe '
|
1
|
+
describe 'A custom Racket test Application' do
|
2
2
|
extend Rack::Test::Methods
|
3
3
|
def app
|
4
|
-
@app ||= Racket::Application.using(
|
4
|
+
@app ||= Racket::Application.using(
|
5
|
+
{ default_layout: 'zebra.*', logger: nil, mode: :dev, view_dir: 'templates' },
|
6
|
+
true
|
7
|
+
)
|
5
8
|
end
|
6
9
|
|
7
10
|
it 'should set requested options' do
|
@@ -19,7 +22,7 @@ describe 'The custom Racket test Application' do
|
|
19
22
|
it 'should return a 404 on a nonexisting url' do
|
20
23
|
get '/nosuchurl'
|
21
24
|
last_response.status.should.equal(404)
|
22
|
-
last_response.body.should.equal('404 Not
|
25
|
+
last_response.body.should.equal('404 Not Found')
|
23
26
|
end
|
24
27
|
|
25
28
|
it 'should be able to render a template and a layout' do
|
@@ -45,4 +48,11 @@ describe 'The custom Racket test Application' do
|
|
45
48
|
response = JSON.parse(last_response.body)
|
46
49
|
response.should.equal(["Data added in before block", "Data added in action"])
|
47
50
|
end
|
51
|
+
|
52
|
+
it 'should let Rack::ShowExceptions handle the error' do
|
53
|
+
get '/sub1/epic_fail'
|
54
|
+
last_response.status.should.equal(500)
|
55
|
+
last_response.headers['Content-Type'].should.equal('text/plain')
|
56
|
+
last_response.body.should.match(%r(^RuntimeError: Epic fail!))
|
57
|
+
end
|
48
58
|
end
|
data/spec/_default.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
describe '
|
1
|
+
describe 'A default Racket test Application' do
|
2
2
|
extend Rack::Test::Methods
|
3
3
|
|
4
4
|
def app
|
@@ -28,7 +28,7 @@ describe 'The default Racket test Application' do
|
|
28
28
|
actions_by_controller[DefaultRootController].include?(:index).should.equal(true)
|
29
29
|
actions_by_controller[DefaultRootController].include?(:my_first_route).should.equal(true)
|
30
30
|
actions_by_controller[DefaultRootController].include?(:my_second_route).should.equal(true)
|
31
|
-
actions_by_controller[DefaultSubController1].length.should.equal(
|
31
|
+
actions_by_controller[DefaultSubController1].length.should.equal(4)
|
32
32
|
actions_by_controller[DefaultSubController1].include?(:route_to_root).should.equal(true)
|
33
33
|
actions_by_controller[DefaultSubController1].include?(:route_to_nonexisting).should.equal(true)
|
34
34
|
actions_by_controller[DefaultSubController2].length.should.equal(3)
|
@@ -79,11 +79,11 @@ describe 'The default Racket test Application' do
|
|
79
79
|
it 'should return 404 on calling nonexisting action' do
|
80
80
|
get '/nonono'
|
81
81
|
last_response.status.should.equal(404)
|
82
|
-
last_response.body.should.equal('404 Not
|
82
|
+
last_response.body.should.equal('404 Not Found')
|
83
83
|
|
84
84
|
get '/sub2/nonono'
|
85
85
|
last_response.status.should.equal(404)
|
86
|
-
last_response.body.should.equal('404 Not
|
86
|
+
last_response.body.should.equal('404 Not Found')
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'should be able to find routes within the same controller' do
|
@@ -172,4 +172,18 @@ describe 'The default Racket test Application' do
|
|
172
172
|
)
|
173
173
|
end
|
174
174
|
|
175
|
+
it 'should be able to serve static files' do
|
176
|
+
get '/hello.txt'
|
177
|
+
last_response.status.should.equal(200)
|
178
|
+
last_response.headers['Content-Type'].should.equal('text/plain')
|
179
|
+
last_response.body.should.equal("Hello there\n")
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should handle exceptions correctly' do
|
183
|
+
get '/sub1/epic_fail'
|
184
|
+
last_response.status.should.equal(500)
|
185
|
+
last_response.headers['Content-Type'].should.equal('text/plain')
|
186
|
+
last_response.body.should.equal('500 Internal Server Error')
|
187
|
+
end
|
188
|
+
|
175
189
|
end
|
data/spec/_invalid.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
describe 'An invalid Racket test Application' do
|
2
|
+
extend Rack::Test::Methods
|
3
|
+
|
4
|
+
def app
|
5
|
+
@app ||= Racket::Application.default
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should never initialize' do
|
9
|
+
lambda { get '/' }
|
10
|
+
.should.raise(RuntimeError)
|
11
|
+
.message.should.equal('Application has already been initialized!')
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/spec/racket.rb
CHANGED
@@ -18,7 +18,6 @@ require 'rack/test'
|
|
18
18
|
require 'bacon'
|
19
19
|
|
20
20
|
Dir.chdir(TEST_DEFAULT_APP_DIR) { require_relative '_default.rb' }
|
21
|
-
|
22
|
-
Racket::Application.class_eval { @current = nil }
|
23
|
-
|
24
21
|
Dir.chdir(TEST_CUSTOM_APP_DIR) { require_relative '_custom.rb' }
|
22
|
+
|
23
|
+
require_relative '_invalid.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello there
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: racket-mvc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Olsson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http_router
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- lib/racket/view_cache.rb
|
159
159
|
- spec/_custom.rb
|
160
160
|
- spec/_default.rb
|
161
|
+
- spec/_invalid.rb
|
161
162
|
- spec/racket.rb
|
162
163
|
- spec/test_custom_app/controllers/sub1/custom_sub_controller_1.rb
|
163
164
|
- spec/test_custom_app/controllers/sub2/custom_sub_controller_2.rb
|
@@ -172,6 +173,7 @@ files:
|
|
172
173
|
- spec/test_default_app/controllers/sub2/default_sub_controller_2.rb
|
173
174
|
- spec/test_default_app/controllers/sub3/default_sub_controller_3.rb
|
174
175
|
- spec/test_default_app/controllers/sub3/inherited/default_inherited_controller.rb
|
176
|
+
- spec/test_default_app/public/hello.txt
|
175
177
|
homepage: https://github.com/lasso/racket
|
176
178
|
licenses:
|
177
179
|
- GNU AFFERO GENERAL PUBLIC LICENSE, version 3
|