merb-core 0.9.8 → 0.9.9
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/CONTRIBUTORS +33 -0
- data/README +7 -3
- data/Rakefile +3 -3
- data/lib/merb-core.rb +165 -94
- data/lib/merb-core/bootloader.rb +469 -100
- data/lib/merb-core/config.rb +79 -3
- data/lib/merb-core/constants.rb +24 -2
- data/lib/merb-core/controller/abstract_controller.rb +172 -67
- data/lib/merb-core/controller/exceptions.rb +50 -6
- data/lib/merb-core/controller/merb_controller.rb +215 -108
- data/lib/merb-core/controller/mime.rb +36 -12
- data/lib/merb-core/controller/mixins/authentication.rb +52 -7
- data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
- data/lib/merb-core/controller/mixins/controller.rb +90 -58
- data/lib/merb-core/controller/mixins/render.rb +34 -10
- data/lib/merb-core/controller/mixins/responder.rb +40 -16
- data/lib/merb-core/controller/template.rb +37 -16
- data/lib/merb-core/core_ext/hash.rb +9 -0
- data/lib/merb-core/core_ext/kernel.rb +92 -41
- data/lib/merb-core/dispatch/dispatcher.rb +29 -45
- data/lib/merb-core/dispatch/request.rb +186 -82
- data/lib/merb-core/dispatch/router.rb +141 -53
- data/lib/merb-core/dispatch/router/behavior.rb +296 -139
- data/lib/merb-core/dispatch/router/resources.rb +51 -19
- data/lib/merb-core/dispatch/router/route.rb +76 -23
- data/lib/merb-core/dispatch/session.rb +80 -36
- data/lib/merb-core/dispatch/session/container.rb +31 -15
- data/lib/merb-core/dispatch/session/cookie.rb +51 -22
- data/lib/merb-core/dispatch/session/memcached.rb +10 -6
- data/lib/merb-core/dispatch/session/memory.rb +17 -5
- data/lib/merb-core/dispatch/session/store_container.rb +21 -9
- data/lib/merb-core/dispatch/worker.rb +16 -2
- data/lib/merb-core/gem_ext/erubis.rb +4 -0
- data/lib/merb-core/plugins.rb +13 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/rack/adapter.rb +1 -0
- data/lib/merb-core/rack/adapter/abstract.rb +95 -17
- data/lib/merb-core/rack/adapter/irb.rb +50 -5
- data/lib/merb-core/rack/application.rb +27 -5
- data/lib/merb-core/rack/handler/mongrel.rb +6 -6
- data/lib/merb-core/rack/helpers.rb +33 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
- data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
- data/lib/merb-core/rack/middleware/static.rb +11 -7
- data/lib/merb-core/server.rb +134 -69
- data/lib/merb-core/tasks/gem_management.rb +153 -80
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
- data/lib/merb-core/tasks/stats.rake +1 -1
- data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
- data/lib/merb-core/test/helpers/request_helper.rb +1 -1
- data/lib/merb-core/test/helpers/route_helper.rb +50 -4
- data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
- data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
- data/lib/merb-core/test/run_specs.rb +6 -5
- data/lib/merb-core/test/test_ext/rspec.rb +6 -19
- data/lib/merb-core/version.rb +1 -1
- metadata +5 -4
@@ -1,4 +1,13 @@
|
|
1
1
|
class Hash
|
2
|
+
# Returns the value of self for each argument and deletes those entries.
|
3
|
+
#
|
4
|
+
# ==== Parameters
|
5
|
+
# *args:: the keys whose values should be extracted and deleted.
|
6
|
+
#
|
7
|
+
# ==== Returns
|
8
|
+
# Array[Object]:: The values of the provided arguments in corresponding order.
|
9
|
+
#
|
10
|
+
# @api public
|
2
11
|
def extract!(*args)
|
3
12
|
args.map do |arg|
|
4
13
|
self.delete(arg)
|
@@ -1,5 +1,11 @@
|
|
1
1
|
require 'rubygems/dependency'
|
2
2
|
|
3
|
+
module Gem
|
4
|
+
class Dependency
|
5
|
+
attr_accessor :require_block
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
3
9
|
module Kernel
|
4
10
|
|
5
11
|
# Keep track of all required dependencies.
|
@@ -11,8 +17,10 @@ module Kernel
|
|
11
17
|
# @return <Gem::Dependency> Dependency information
|
12
18
|
#
|
13
19
|
# @api private
|
14
|
-
def track_dependency(name, *ver)
|
15
|
-
dep = Gem::Dependency.new(name, ver)
|
20
|
+
def track_dependency(name, *ver, &blk)
|
21
|
+
dep = Gem::Dependency.new(name, ver.empty? ? nil : ver)
|
22
|
+
dep.require_block = blk
|
23
|
+
|
16
24
|
existing = Merb::BootLoader::Dependencies.dependencies.find { |d| d.name == dep.name }
|
17
25
|
if existing
|
18
26
|
index = Merb::BootLoader::Dependencies.dependencies.index(existing)
|
@@ -31,19 +39,23 @@ module Kernel
|
|
31
39
|
# If that has already happened, the gem will be activated
|
32
40
|
# immediately, but it will still be registered.
|
33
41
|
#
|
34
|
-
#
|
35
|
-
#
|
42
|
+
# ==== Parameters
|
43
|
+
# name<String> The name of the gem to load.
|
44
|
+
# *ver<Gem::Requirement, Gem::Version, Array, #to_str>
|
36
45
|
# Version requirements to be passed to Gem::Dependency.new.
|
37
46
|
# If the last argument is a Hash, extract the :immediate option,
|
38
47
|
# forcing a dependency to load immediately.
|
39
48
|
#
|
40
|
-
#
|
41
|
-
|
49
|
+
# ==== Returns
|
50
|
+
# Gem::Dependency:: The dependency information.
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def dependency(name, *ver, &blk)
|
42
54
|
immediate = ver.last.is_a?(Hash) && ver.pop[:immediate]
|
43
55
|
if immediate || Merb::BootLoader.finished?(Merb::BootLoader::Dependencies)
|
44
|
-
load_dependency(name, *ver)
|
56
|
+
load_dependency(name, *ver, &blk)
|
45
57
|
else
|
46
|
-
track_dependency(name, *ver)
|
58
|
+
track_dependency(name, *ver, &blk)
|
47
59
|
end
|
48
60
|
end
|
49
61
|
|
@@ -63,20 +75,38 @@ module Kernel
|
|
63
75
|
# as a library.
|
64
76
|
#
|
65
77
|
# @return <Gem::Dependency> The dependency information.
|
66
|
-
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
def load_dependency(name, *ver, &blk)
|
67
81
|
dep = name.is_a?(Gem::Dependency) ? name : track_dependency(name, *ver)
|
68
82
|
gem(dep)
|
69
|
-
rescue Gem::LoadError
|
83
|
+
rescue Gem::LoadError => e
|
84
|
+
Merb.fatal! "The gem #{name}, #{ver.inspect} was not found", e
|
70
85
|
ensure
|
71
|
-
|
72
|
-
|
86
|
+
if block = blk || dep.require_block
|
87
|
+
block.call
|
88
|
+
else
|
89
|
+
begin
|
90
|
+
require dep.name
|
91
|
+
rescue LoadError => e
|
92
|
+
Merb.fatal! "The file #{dep.name} was not found", e
|
93
|
+
end
|
94
|
+
end
|
95
|
+
Merb.logger.verbose!("loading gem '#{dep.name}' ...")
|
73
96
|
return dep # ensure needs explicit return
|
74
97
|
end
|
75
98
|
|
76
99
|
# Loads both gem and library dependencies that are passed in as arguments.
|
77
100
|
# Execution is deferred to the Merb::BootLoader::Dependencies.run during bootup.
|
78
101
|
#
|
79
|
-
#
|
102
|
+
# ==== Parameters
|
103
|
+
# *args<String, Hash, Array> The dependencies to load.
|
104
|
+
#
|
105
|
+
# ==== Returns
|
106
|
+
# Array[(Gem::Dependency, Array[Gem::Dependency])]:: Gem::Dependencies for the
|
107
|
+
# dependencies specified in args.
|
108
|
+
#
|
109
|
+
# @api public
|
80
110
|
def dependencies(*args)
|
81
111
|
args.map do |arg|
|
82
112
|
case arg
|
@@ -101,6 +131,8 @@ module Kernel
|
|
101
131
|
# @example dependencies "RedCloth" # Loads the the RedCloth gem
|
102
132
|
# @example dependencies "RedCloth", "merb_helpers" # Loads RedCloth and merb_helpers
|
103
133
|
# @example dependencies "RedCloth" => "3.0" # Loads RedCloth 3.0
|
134
|
+
#
|
135
|
+
# @api private
|
104
136
|
def load_dependencies(*args)
|
105
137
|
args.map do |arg|
|
106
138
|
case arg
|
@@ -115,7 +147,12 @@ module Kernel
|
|
115
147
|
#
|
116
148
|
# @param library<to_s> The library to attempt to include.
|
117
149
|
# @param message<String> The error to add to the log upon failure. Defaults to nil.
|
150
|
+
#
|
151
|
+
# @api private
|
152
|
+
# @deprecated
|
118
153
|
def rescue_require(library, message = nil)
|
154
|
+
Merb.logger.warn("Deprecation warning: rescue_require is deprecated")
|
155
|
+
sleep 2.0
|
119
156
|
require library
|
120
157
|
rescue LoadError, RuntimeError
|
121
158
|
Merb.logger.error!(message) if message
|
@@ -125,17 +162,22 @@ module Kernel
|
|
125
162
|
# Mapper) you wish to use. Currently Merb has plugins to support
|
126
163
|
# ActiveRecord, DataMapper, and Sequel.
|
127
164
|
#
|
128
|
-
#
|
165
|
+
# ==== Parameters
|
166
|
+
# orm<Symbol>:: The ORM to use.
|
129
167
|
#
|
130
|
-
#
|
168
|
+
# ==== Returns
|
169
|
+
# nil
|
170
|
+
#
|
171
|
+
# ==== Example
|
131
172
|
# use_orm :datamapper
|
132
173
|
#
|
133
174
|
# # This will use the DataMapper generator for your ORM
|
134
175
|
# $ merb-gen model ActivityEvent
|
135
176
|
#
|
136
|
-
#
|
177
|
+
# ==== Notes
|
137
178
|
# If for some reason this is called more than once, latter
|
138
179
|
# call takes over other.
|
180
|
+
#
|
139
181
|
# @api public
|
140
182
|
def use_orm(orm)
|
141
183
|
begin
|
@@ -146,37 +188,53 @@ module Kernel
|
|
146
188
|
Merb.logger.warn!("The #{orm_plugin} gem was not found. You may need to install it.")
|
147
189
|
raise e
|
148
190
|
end
|
191
|
+
nil
|
149
192
|
end
|
150
193
|
|
151
194
|
# Used in Merb.root/config/init.rb to tell Merb which testing framework to
|
152
195
|
# use. Currently Merb has plugins to support RSpec and Test::Unit.
|
153
196
|
#
|
154
|
-
#
|
197
|
+
# ==== Parameters
|
198
|
+
# test_framework<Symbol>::
|
155
199
|
# The test framework to use. Currently only supports :rspec and :test_unit.
|
156
200
|
#
|
157
|
-
#
|
201
|
+
# ==== Returns
|
202
|
+
# nil
|
203
|
+
#
|
204
|
+
# ==== Example
|
158
205
|
# use_test :rspec
|
159
206
|
#
|
160
207
|
# # This will now use the RSpec generator for tests
|
161
208
|
# $ merb-gen model ActivityEvent
|
209
|
+
#
|
162
210
|
# @api public
|
163
|
-
def
|
211
|
+
def use_testing_framework(test_framework, *test_dependencies)
|
164
212
|
Merb.test_framework = test_framework
|
165
213
|
|
166
214
|
Kernel.dependencies test_dependencies if Merb.env == "test" || Merb.env.nil?
|
215
|
+
nil
|
216
|
+
end
|
217
|
+
|
218
|
+
def use_test(*args)
|
219
|
+
use_testing_framework(*args)
|
167
220
|
end
|
168
221
|
|
169
222
|
# Used in Merb.root/config/init.rb to tell Merb which template engine to
|
170
223
|
# prefer.
|
171
224
|
#
|
172
|
-
#
|
225
|
+
# ==== Parameters
|
226
|
+
# template_engine<Symbol>
|
173
227
|
# The template engine to use.
|
174
228
|
#
|
175
|
-
#
|
229
|
+
# ==== Returns
|
230
|
+
# nil
|
231
|
+
#
|
232
|
+
# ==== Example
|
176
233
|
# use_template_engine :haml
|
177
234
|
#
|
178
235
|
# # This will now use haml templates in generators where available.
|
179
236
|
# $ merb-gen resource_controller Project
|
237
|
+
#
|
180
238
|
# @api public
|
181
239
|
def use_template_engine(template_engine)
|
182
240
|
Merb.template_engine = template_engine
|
@@ -189,11 +247,14 @@ module Kernel
|
|
189
247
|
end
|
190
248
|
Kernel.dependency(template_engine_plugin)
|
191
249
|
end
|
250
|
+
|
251
|
+
nil
|
192
252
|
rescue LoadError => e
|
193
253
|
Merb.logger.warn!("The #{template_engine_plugin} gem was not found. You may need to install it.")
|
194
254
|
raise e
|
195
255
|
end
|
196
256
|
|
257
|
+
|
197
258
|
# @param i<Fixnum> The caller number. Defaults to 1.
|
198
259
|
#
|
199
260
|
# @return <Array[Array]> The file, line and method of the caller.
|
@@ -201,6 +262,8 @@ module Kernel
|
|
201
262
|
# @example
|
202
263
|
# __caller_info__(1)
|
203
264
|
# # => ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding']
|
265
|
+
#
|
266
|
+
# @api private
|
204
267
|
def __caller_info__(i = 1)
|
205
268
|
file, line, meth = caller[i].scan(/(.*?):(\d+):in `(.*?)'/).first
|
206
269
|
end
|
@@ -224,6 +287,8 @@ module Kernel
|
|
224
287
|
# [ 123, " DEBUGGER__.waiting.push Thread.current", false ],
|
225
288
|
# [ 124, " @suspend_next = false", false ]
|
226
289
|
# ]
|
290
|
+
#
|
291
|
+
# @api private
|
227
292
|
def __caller_lines__(file, line, size = 4)
|
228
293
|
line = line.to_i
|
229
294
|
if file =~ /\(erubis\)/
|
@@ -241,26 +306,6 @@ module Kernel
|
|
241
306
|
yield index + line - size, str.chomp
|
242
307
|
end
|
243
308
|
end
|
244
|
-
#
|
245
|
-
# lines = File.readlines(file)
|
246
|
-
# current = line.to_i - 1
|
247
|
-
#
|
248
|
-
# first = current - size
|
249
|
-
# first = first < 0 ? 0 : first
|
250
|
-
#
|
251
|
-
# last = current + size
|
252
|
-
# last = last > lines.size ? lines.size : last
|
253
|
-
#
|
254
|
-
# log = lines[first..last]
|
255
|
-
#
|
256
|
-
# area = []
|
257
|
-
#
|
258
|
-
# log.each_with_index do |line, index|
|
259
|
-
# index = index + first + 1
|
260
|
-
# area << [index, line.chomp, index == current + 1]
|
261
|
-
# end
|
262
|
-
#
|
263
|
-
# area
|
264
309
|
end
|
265
310
|
|
266
311
|
# Takes a block, profiles the results of running the block
|
@@ -288,6 +333,8 @@ module Kernel
|
|
288
333
|
# Assuming that the total time taken for #puts calls was less than 5% of the
|
289
334
|
# total time to run, #puts won't appear in the profile report.
|
290
335
|
# The code block will be run 30 times in the example above.
|
336
|
+
#
|
337
|
+
# @api private
|
291
338
|
def __profile__(name, min=1, iter=100)
|
292
339
|
require 'ruby-prof' unless defined?(RubyProf)
|
293
340
|
return_result = ''
|
@@ -313,6 +360,8 @@ module Kernel
|
|
313
360
|
# opts = extract_options_from_args!(args) || {}
|
314
361
|
# # [...]
|
315
362
|
# end
|
363
|
+
#
|
364
|
+
# @api public
|
316
365
|
def extract_options_from_args!(args)
|
317
366
|
args.pop if Hash === args.last
|
318
367
|
end
|
@@ -325,6 +374,8 @@ module Kernel
|
|
325
374
|
#
|
326
375
|
# @raise <ArgumentError>
|
327
376
|
# An object failed to quack like a condition.
|
377
|
+
#
|
378
|
+
# @api public
|
328
379
|
def enforce!(opts = {})
|
329
380
|
opts.each do |k,v|
|
330
381
|
raise ArgumentError, "#{k.inspect} doesn't quack like #{v.inspect}" unless k.quacks_like?(v)
|
@@ -4,15 +4,19 @@ module Merb
|
|
4
4
|
class Dispatcher
|
5
5
|
class << self
|
6
6
|
include Merb::ControllerExceptions
|
7
|
-
|
7
|
+
|
8
8
|
attr_accessor :use_mutex
|
9
9
|
|
10
10
|
@@work_queue = Queue.new
|
11
|
-
|
11
|
+
|
12
|
+
# ==== Returns
|
13
|
+
# Queue:: the current queue of dispatch jobs.
|
14
|
+
#
|
15
|
+
# @api private
|
12
16
|
def work_queue
|
13
17
|
@@work_queue
|
14
18
|
end
|
15
|
-
|
19
|
+
|
16
20
|
Merb::Dispatcher.use_mutex = ::Merb::Config[:use_mutex]
|
17
21
|
|
18
22
|
# Dispatch the rack environment. ControllerExceptions are rescued here
|
@@ -25,9 +29,11 @@ module Merb
|
|
25
29
|
# ==== Returns
|
26
30
|
# Merb::Controller::
|
27
31
|
# The Merb::Controller that was dispatched to
|
32
|
+
#
|
33
|
+
# @api private
|
28
34
|
def handle(request)
|
29
35
|
request.handle
|
30
|
-
end
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
@@ -36,12 +42,18 @@ module Merb
|
|
36
42
|
|
37
43
|
@@mutex = Mutex.new
|
38
44
|
|
45
|
+
# Handles request routing and action dispatch.
|
46
|
+
#
|
47
|
+
# ==== Returns
|
48
|
+
# Merb::Controller:: the controller that handled the action dispatch.
|
49
|
+
#
|
50
|
+
# @api private
|
39
51
|
def handle
|
40
52
|
start = Time.now
|
41
53
|
Merb.logger.info "Started request handling: #{start.to_s}"
|
42
|
-
|
54
|
+
|
43
55
|
find_route!
|
44
|
-
return
|
56
|
+
return rack_response if handled?
|
45
57
|
|
46
58
|
klass = controller
|
47
59
|
Merb.logger.debug("Routed to: #{params.inspect}")
|
@@ -57,42 +69,14 @@ module Merb
|
|
57
69
|
if klass.abstract?
|
58
70
|
raise NotFound, "The '#{klass}' controller has no public actions"
|
59
71
|
end
|
60
|
-
|
72
|
+
|
61
73
|
controller = dispatch_action(klass, params[:action])
|
62
74
|
controller._benchmarks[:dispatch_time] = Time.now - start
|
63
75
|
Merb.logger.info controller._benchmarks.inspect
|
64
76
|
Merb.logger.flush
|
65
|
-
controller
|
77
|
+
controller.rack_response
|
66
78
|
rescue Object => exception
|
67
|
-
dispatch_exception(exception)
|
68
|
-
end
|
69
|
-
|
70
|
-
# Set up a faux controller to do redirection from the router
|
71
|
-
#
|
72
|
-
# ==== Parameters
|
73
|
-
# request<Merb::Request>::
|
74
|
-
# The Merb::Request object that was created in #handle
|
75
|
-
# status<Integer>::
|
76
|
-
# The status code to return with the controller
|
77
|
-
# url<String>::
|
78
|
-
# The URL to return
|
79
|
-
#
|
80
|
-
# ==== Example
|
81
|
-
# r.match("/my/old/crusty/url").redirect("http://example.com/index.html")
|
82
|
-
#
|
83
|
-
# ==== Returns
|
84
|
-
# Merb::Controller::
|
85
|
-
# Merb::Controller set with redirect headers and a 301/302 status
|
86
|
-
def redirect
|
87
|
-
status, url = redirect_status, redirect_url
|
88
|
-
controller = Merb::Controller.new(self, status)
|
89
|
-
|
90
|
-
Merb.logger.info("Dispatcher redirecting to: #{url} (#{status})")
|
91
|
-
Merb.logger.flush
|
92
|
-
|
93
|
-
controller.headers['Location'] = url
|
94
|
-
controller.body = "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
|
95
|
-
controller
|
79
|
+
dispatch_exception(exception).rack_response
|
96
80
|
end
|
97
81
|
|
98
82
|
private
|
@@ -101,13 +85,13 @@ module Merb
|
|
101
85
|
# ==== Parameters
|
102
86
|
# klass<Merb::Controller>:: The controller class to dispatch to.
|
103
87
|
# action<Symbol>:: The action to dispatch.
|
104
|
-
# request<Merb::Request>::
|
105
|
-
# The Merb::Request object that was created in #handle
|
106
88
|
# status<Integer>:: The status code to respond with.
|
107
89
|
#
|
108
90
|
# ==== Returns
|
109
91
|
# Merb::Controller::
|
110
92
|
# The Merb::Controller that was dispatched to.
|
93
|
+
#
|
94
|
+
# @api private
|
111
95
|
def dispatch_action(klass, action, status=200)
|
112
96
|
# build controller
|
113
97
|
controller = klass.new(self, status)
|
@@ -129,8 +113,6 @@ module Merb
|
|
129
113
|
# StandardError is caught in standard_error).
|
130
114
|
#
|
131
115
|
# ==== Parameters
|
132
|
-
# request<Merb::Request>::
|
133
|
-
# The request object associated with the failed request.
|
134
116
|
# exception<Object>::
|
135
117
|
# The exception object that was created when trying to dispatch the
|
136
118
|
# original controller.
|
@@ -138,6 +120,8 @@ module Merb
|
|
138
120
|
# ==== Returns
|
139
121
|
# Exceptions::
|
140
122
|
# The Merb::Controller that was dispatched to.
|
123
|
+
#
|
124
|
+
# @api private
|
141
125
|
def dispatch_exception(exception)
|
142
126
|
if(exception.is_a?(Merb::ControllerExceptions::Base) &&
|
143
127
|
!exception.is_a?(Merb::ControllerExceptions::ServerError))
|
@@ -145,12 +129,12 @@ module Merb
|
|
145
129
|
else
|
146
130
|
Merb.logger.error(Merb.exception(exception))
|
147
131
|
end
|
148
|
-
|
132
|
+
|
149
133
|
self.exceptions = [exception]
|
150
|
-
|
134
|
+
|
151
135
|
begin
|
152
136
|
e = exceptions.first
|
153
|
-
|
137
|
+
|
154
138
|
if action_name = e.action_name
|
155
139
|
dispatch_action(Exceptions, action_name, e.class.status)
|
156
140
|
else
|
@@ -162,7 +146,7 @@ module Merb
|
|
162
146
|
else
|
163
147
|
Merb.logger.error("Dispatching #{e.class} raised another error.")
|
164
148
|
Merb.logger.error(Merb.exception(dispatch_issue))
|
165
|
-
|
149
|
+
|
166
150
|
exceptions.unshift dispatch_issue
|
167
151
|
retry
|
168
152
|
end
|