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
data/lib/merb-core/bootloader.rb
CHANGED
@@ -3,10 +3,10 @@ module Merb
|
|
3
3
|
class BootLoader
|
4
4
|
|
5
5
|
# def self.subclasses
|
6
|
-
|
7
|
-
# @
|
6
|
+
#
|
7
|
+
# @api plugin
|
8
8
|
cattr_accessor :subclasses, :after_load_callbacks, :before_load_callbacks, :finished
|
9
|
-
self.subclasses, self.after_load_callbacks,
|
9
|
+
self.subclasses, self.after_load_callbacks,
|
10
10
|
self.before_load_callbacks, self.finished = [], [], [], []
|
11
11
|
|
12
12
|
class << self
|
@@ -16,29 +16,44 @@ module Merb
|
|
16
16
|
#
|
17
17
|
# ==== Parameters
|
18
18
|
# klass<Class>:: The class inheriting from Merb::BootLoader.
|
19
|
+
#
|
20
|
+
# ==== Returns
|
21
|
+
# nil
|
22
|
+
#
|
23
|
+
# @api plugin
|
19
24
|
def inherited(klass)
|
20
25
|
subclasses << klass.to_s
|
21
26
|
super
|
22
27
|
end
|
23
28
|
|
29
|
+
# Execute this boot loader after the specified boot loader.
|
30
|
+
#
|
24
31
|
# ==== Parameters
|
25
32
|
# klass<~to_s>::
|
26
33
|
# The boot loader class after which this boot loader should be run.
|
27
34
|
#
|
28
|
-
|
29
|
-
#
|
35
|
+
# ==== Returns
|
36
|
+
# nil
|
37
|
+
#
|
38
|
+
# @api plugin
|
30
39
|
def after(klass)
|
31
40
|
move_klass(klass, 1)
|
41
|
+
nil
|
32
42
|
end
|
33
43
|
|
44
|
+
# Execute this boot loader before the specified boot loader.
|
45
|
+
#
|
34
46
|
# ==== Parameters
|
35
47
|
# klass<~to_s>::
|
36
48
|
# The boot loader class before which this boot loader should be run.
|
37
49
|
#
|
38
|
-
|
39
|
-
#
|
50
|
+
# ==== Returns
|
51
|
+
# nil
|
52
|
+
#
|
53
|
+
# @api plugin
|
40
54
|
def before(klass)
|
41
55
|
move_klass(klass, 0)
|
56
|
+
nil
|
42
57
|
end
|
43
58
|
|
44
59
|
# Move a class that is inside the bootloader to some place in the Array,
|
@@ -49,15 +64,26 @@ module Merb
|
|
49
64
|
# The klass to move the bootloader relative to
|
50
65
|
# where<Integer>::
|
51
66
|
# 0 means insert it before; 1 means insert it after
|
67
|
+
#
|
68
|
+
# ==== Returns
|
69
|
+
# nil
|
70
|
+
#
|
71
|
+
# @api private
|
52
72
|
def move_klass(klass, where)
|
53
73
|
index = Merb::BootLoader.subclasses.index(klass.to_s)
|
54
74
|
if index
|
55
75
|
Merb::BootLoader.subclasses.delete(self.to_s)
|
56
76
|
Merb::BootLoader.subclasses.insert(index + where, self.to_s)
|
57
77
|
end
|
78
|
+
nil
|
58
79
|
end
|
59
80
|
|
60
81
|
# Runs all boot loader classes by calling their run methods.
|
82
|
+
#
|
83
|
+
# ==== Returns
|
84
|
+
# nil
|
85
|
+
#
|
86
|
+
# @api plugin
|
61
87
|
def run
|
62
88
|
Merb.started = true
|
63
89
|
subklasses = subclasses.dup
|
@@ -74,8 +100,9 @@ module Merb
|
|
74
100
|
self.finished << bootloader
|
75
101
|
end
|
76
102
|
self.subclasses = subklasses
|
103
|
+
nil
|
77
104
|
end
|
78
|
-
|
105
|
+
|
79
106
|
# Determines whether or not a specific bootloader has finished yet.
|
80
107
|
#
|
81
108
|
# ==== Parameters
|
@@ -83,6 +110,8 @@ module Merb
|
|
83
110
|
#
|
84
111
|
# ==== Returns
|
85
112
|
# Boolean:: Whether or not the bootloader has finished.
|
113
|
+
#
|
114
|
+
# @api private
|
86
115
|
def finished?(bootloader)
|
87
116
|
self.finished.include?(bootloader.to_s)
|
88
117
|
end
|
@@ -92,8 +121,8 @@ module Merb
|
|
92
121
|
# ==== Returns
|
93
122
|
# nil
|
94
123
|
#
|
95
|
-
|
96
|
-
# @
|
124
|
+
# @api plugin
|
125
|
+
# @overridable
|
97
126
|
def default_framework
|
98
127
|
%w[view model helper controller mailer part].each do |component|
|
99
128
|
Merb.push_path(component.to_sym, Merb.root_path("app/#{component}s"))
|
@@ -102,6 +131,7 @@ module Merb
|
|
102
131
|
Merb.push_path(:config, Merb.root_path("config"), nil)
|
103
132
|
Merb.push_path(:router, Merb.dir_for(:config), (Merb::Config[:router_file] || "router.rb"))
|
104
133
|
Merb.push_path(:lib, Merb.root_path("lib"), nil)
|
134
|
+
Merb.push_path(:merb, Merb.root_path("merb"))
|
105
135
|
Merb.push_path(:log, Merb.log_path, nil)
|
106
136
|
Merb.push_path(:public, Merb.root_path("public"), nil)
|
107
137
|
Merb.push_path(:stylesheet, Merb.dir_for(:public) / "stylesheets", nil)
|
@@ -110,24 +140,26 @@ module Merb
|
|
110
140
|
nil
|
111
141
|
end
|
112
142
|
|
143
|
+
# Execute a block of code after the app loads.
|
144
|
+
#
|
113
145
|
# ==== Parameters
|
114
146
|
# &block::
|
115
147
|
# A block to be added to the callbacks that will be executed after the
|
116
148
|
# app loads.
|
117
149
|
#
|
118
|
-
|
119
|
-
# @public
|
150
|
+
# @api public
|
120
151
|
def after_app_loads(&block)
|
121
152
|
after_load_callbacks << block
|
122
153
|
end
|
123
154
|
|
155
|
+
# Execute a block of code before the app loads but after dependencies load.
|
156
|
+
#
|
124
157
|
# ==== Parameters
|
125
158
|
# &block::
|
126
159
|
# A block to be added to the callbacks that will be executed before the
|
127
160
|
# app loads.
|
128
161
|
#
|
129
|
-
|
130
|
-
# @public
|
162
|
+
# @api public
|
131
163
|
def before_app_loads(&block)
|
132
164
|
before_load_callbacks << block
|
133
165
|
end
|
@@ -144,20 +176,33 @@ end
|
|
144
176
|
class Merb::BootLoader::Logger < Merb::BootLoader
|
145
177
|
|
146
178
|
# Sets Merb.logger to a new logger created based on the config settings.
|
179
|
+
#
|
180
|
+
# ==== Returns
|
181
|
+
# nil
|
182
|
+
#
|
183
|
+
# @api plugin
|
147
184
|
def self.run
|
148
185
|
Merb::Config[:log_level] ||= begin
|
149
186
|
if Merb.environment == "production"
|
150
187
|
Merb::Logger::Levels[:warn]
|
151
188
|
else
|
152
189
|
Merb::Logger::Levels[:debug]
|
153
|
-
end
|
190
|
+
end
|
154
191
|
end
|
155
|
-
|
192
|
+
|
156
193
|
Merb::Config[:log_stream] = Merb.log_stream
|
157
|
-
|
194
|
+
|
158
195
|
print_warnings
|
196
|
+
|
197
|
+
nil
|
159
198
|
end
|
160
|
-
|
199
|
+
|
200
|
+
# Print a warning if the installed version of rubygems is not supported
|
201
|
+
#
|
202
|
+
# ==== Returns
|
203
|
+
# nil
|
204
|
+
#
|
205
|
+
# @api private
|
161
206
|
def self.print_warnings
|
162
207
|
if Gem::Version.new(Gem::RubyGemsVersion) < Gem::Version.new("1.1")
|
163
208
|
Merb.fatal! "Merb requires Rubygems 1.1 and later. " \
|
@@ -174,19 +219,32 @@ class Merb::BootLoader::DropPidFile < Merb::BootLoader
|
|
174
219
|
class << self
|
175
220
|
|
176
221
|
# Stores a PID file if Merb is running daemonized or clustered.
|
222
|
+
#
|
223
|
+
# ==== Returns
|
224
|
+
# nil
|
225
|
+
#
|
226
|
+
# @api plugin
|
177
227
|
def run
|
178
228
|
Merb::Server.store_pid("main") #if Merb::Config[:daemonize] || Merb::Config[:cluster]
|
229
|
+
nil
|
179
230
|
end
|
180
231
|
end
|
181
232
|
end
|
182
233
|
|
183
234
|
# Setup some useful defaults
|
184
235
|
class Merb::BootLoader::Defaults < Merb::BootLoader
|
236
|
+
# Sets up the defaults
|
237
|
+
#
|
238
|
+
# ==== Returns
|
239
|
+
# nil
|
240
|
+
#
|
241
|
+
# @api plugin
|
185
242
|
def self.run
|
186
243
|
Merb::Request.http_method_overrides.concat([
|
187
244
|
proc { |c| c.params[:_method] },
|
188
245
|
proc { |c| c.env['HTTP_X_HTTP_METHOD_OVERRIDE'] }
|
189
246
|
])
|
247
|
+
nil
|
190
248
|
end
|
191
249
|
end
|
192
250
|
|
@@ -230,12 +288,24 @@ class Merb::BootLoader::BuildFramework < Merb::BootLoader
|
|
230
288
|
class << self
|
231
289
|
|
232
290
|
# Builds the framework directory structure.
|
291
|
+
#
|
292
|
+
# ==== Returns
|
293
|
+
# nil
|
233
294
|
def run
|
234
295
|
build_framework
|
296
|
+
nil
|
235
297
|
end
|
236
298
|
|
237
|
-
#
|
238
|
-
#
|
299
|
+
# Sets up merb paths to support the app's file layout. First, config/framework.rb is checked,
|
300
|
+
# next we look for Merb.root/framework.rb, finally we use the default merb layout (Merb::BootLoader.default_framework)
|
301
|
+
#
|
302
|
+
# This method can be overriden to support other application layouts.
|
303
|
+
#
|
304
|
+
# ==== Returns
|
305
|
+
# nil
|
306
|
+
#
|
307
|
+
# @api plugin
|
308
|
+
# @overridable
|
239
309
|
def build_framework
|
240
310
|
if File.exists?(Merb.root / "config" / "framework.rb")
|
241
311
|
require Merb.root / "config" / "framework"
|
@@ -248,12 +318,17 @@ class Merb::BootLoader::BuildFramework < Merb::BootLoader
|
|
248
318
|
path = Array(path)
|
249
319
|
Merb.push_path(name, path.first, path.length == 2 ? path[1] : "**/*.rb")
|
250
320
|
end
|
321
|
+
nil
|
251
322
|
end
|
252
323
|
end
|
253
324
|
end
|
254
325
|
|
255
326
|
class Merb::BootLoader::Dependencies < Merb::BootLoader
|
256
327
|
|
328
|
+
# ==== Returns
|
329
|
+
# Array[Gem::Dependency]:: The dependencies regiestered in init.rb.
|
330
|
+
#
|
331
|
+
# @api plugin
|
257
332
|
cattr_accessor :dependencies
|
258
333
|
self.dependencies = []
|
259
334
|
|
@@ -266,20 +341,41 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
|
|
266
341
|
# before or after insertion methods. Since these are loaded from this
|
267
342
|
# bootloader (Dependencies), they can only adapt the bootloaders that
|
268
343
|
# haven't been loaded up until this point.
|
269
|
-
|
344
|
+
#
|
345
|
+
# ==== Returns
|
346
|
+
# nil
|
347
|
+
#
|
348
|
+
# @api plugin
|
270
349
|
def self.run
|
271
350
|
set_encoding
|
272
|
-
|
273
|
-
|
351
|
+
# this is crucial: load init file with all the preferences
|
352
|
+
# then environment init file, then start enabling specific
|
353
|
+
# components, load dependencies and update logger.
|
354
|
+
unless Merb::disabled?(:initfile)
|
355
|
+
load_initfile
|
356
|
+
load_env_config
|
357
|
+
end
|
274
358
|
enable_json_gem unless Merb::disabled?(:json)
|
275
359
|
load_dependencies
|
276
360
|
update_logger
|
361
|
+
nil
|
277
362
|
end
|
278
363
|
|
364
|
+
# Load each dependency that has been declared so far.
|
365
|
+
#
|
366
|
+
# ==== Returns
|
367
|
+
# nil
|
368
|
+
#
|
369
|
+
# @api private
|
279
370
|
def self.load_dependencies
|
280
371
|
dependencies.each { |dependency| Kernel.load_dependency(dependency) }
|
372
|
+
nil
|
281
373
|
end
|
282
374
|
|
375
|
+
# Loads json or json_pure and requires it.
|
376
|
+
#
|
377
|
+
# ==== Returns
|
378
|
+
# nil
|
283
379
|
def self.enable_json_gem
|
284
380
|
gem "json"
|
285
381
|
require "json/ext"
|
@@ -288,35 +384,83 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
|
|
288
384
|
require "json/pure"
|
289
385
|
end
|
290
386
|
|
387
|
+
# Resets the logger and sets the log_stream to Merb::Config[:log_file]
|
388
|
+
# if one is specified, falling back to STDOUT.
|
389
|
+
#
|
390
|
+
# ==== Returns
|
391
|
+
# nil
|
392
|
+
#
|
393
|
+
# @api private
|
291
394
|
def self.update_logger
|
292
|
-
Merb.
|
293
|
-
|
294
|
-
|
395
|
+
Merb.reset_logger!
|
396
|
+
|
397
|
+
# If log file is given, use it and not log stream we have.
|
398
|
+
if Merb::Config[:log_file]
|
399
|
+
raise "log file should be a string, got: #{Merb::Config[:log_file].inspect}" unless Merb::Config[:log_file].is_a?(String)
|
400
|
+
STDOUT.puts "Logging to file at #{Merb::Config[:log_file]}" unless Merb.testing?
|
401
|
+
Merb::Config[:log_stream] = File.open(Merb::Config[:log_file], "w+")
|
402
|
+
# but if it's not given, fallback to log stream or stdout
|
403
|
+
else
|
404
|
+
Merb::Config[:log_stream] ||= STDOUT
|
405
|
+
end
|
406
|
+
|
407
|
+
nil
|
295
408
|
end
|
296
|
-
|
409
|
+
|
410
|
+
# Default encoding to UTF8 if it has not already been set to something else.
|
411
|
+
#
|
412
|
+
# ==== Returns
|
413
|
+
# nil
|
414
|
+
#
|
415
|
+
# @api private
|
297
416
|
def self.set_encoding
|
298
417
|
$KCODE = 'UTF8' if $KCODE == 'NONE' || $KCODE.blank?
|
418
|
+
nil
|
299
419
|
end
|
300
420
|
|
301
421
|
private
|
302
422
|
|
303
423
|
# Determines the path for the environment configuration file
|
424
|
+
#
|
425
|
+
# ==== Returns
|
426
|
+
# String:: The path to the config file for the environment
|
427
|
+
#
|
428
|
+
# @api private
|
304
429
|
def self.env_config
|
305
430
|
Merb.dir_for(:config) / "environments" / (Merb.environment + ".rb")
|
306
431
|
end
|
307
432
|
|
308
433
|
# Checks to see whether or not an environment configuration exists
|
434
|
+
#
|
435
|
+
# ==== Returns
|
436
|
+
# Boolean:: Whether or not the environment configuration file exists.
|
437
|
+
#
|
438
|
+
# @api private
|
309
439
|
def self.env_config?
|
310
440
|
Merb.environment && File.exist?(env_config)
|
311
441
|
end
|
312
442
|
|
313
|
-
# Loads the environment configuration file, if
|
443
|
+
# Loads the environment configuration file, if it is present
|
444
|
+
#
|
445
|
+
# ==== Returns
|
446
|
+
# nil
|
447
|
+
#
|
448
|
+
# @api private
|
314
449
|
def self.load_env_config
|
315
|
-
|
450
|
+
if env_config?
|
451
|
+
STDOUT.puts "Loading #{env_config}" unless Merb.testing?
|
452
|
+
load(env_config)
|
453
|
+
end
|
454
|
+
nil
|
316
455
|
end
|
317
456
|
|
318
457
|
# Determines the init file to use, if any.
|
319
458
|
# By default Merb uses init.rb from application config directory.
|
459
|
+
#
|
460
|
+
# ==== Returns
|
461
|
+
# nil
|
462
|
+
#
|
463
|
+
# @api private
|
320
464
|
def self.initfile
|
321
465
|
if Merb::Config[:init_file]
|
322
466
|
Merb::Config[:init_file].chomp(".rb") + ".rb"
|
@@ -326,10 +470,22 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
|
|
326
470
|
end
|
327
471
|
|
328
472
|
# Loads the init file, should one exist
|
473
|
+
#
|
474
|
+
# ==== Returns
|
475
|
+
# nil
|
476
|
+
#
|
477
|
+
# @api private
|
329
478
|
def self.load_initfile
|
330
|
-
|
479
|
+
if File.exists?(initfile)
|
480
|
+
STDOUT.puts "Loading init file from #{initfile}" unless Merb.testing?
|
481
|
+
load(initfile)
|
482
|
+
elsif !Merb.testing?
|
483
|
+
Merb.fatal! "You are not in a Merb application, or you are in " \
|
484
|
+
"a flat application and have not specified the init file. If you " \
|
485
|
+
"are trying to create a new merb application, use merb-gen app."
|
486
|
+
end
|
487
|
+
nil
|
331
488
|
end
|
332
|
-
|
333
489
|
end
|
334
490
|
|
335
491
|
class Merb::BootLoader::MixinSession < Merb::BootLoader
|
@@ -339,8 +495,13 @@ class Merb::BootLoader::MixinSession < Merb::BootLoader
|
|
339
495
|
# plugin session stores for example - these need to be loaded in a
|
340
496
|
# before_app_loads block or a BootLoader that runs after MixinSession.
|
341
497
|
#
|
342
|
-
# Note: access to Merb::Config is needed, so it needs to run after
|
498
|
+
# Note: access to Merb::Config is needed, so it needs to run after
|
343
499
|
# Merb::BootLoader::Dependencies is done.
|
500
|
+
#
|
501
|
+
# ==== Returns
|
502
|
+
# nil
|
503
|
+
#
|
504
|
+
# @api plugin
|
344
505
|
def self.run
|
345
506
|
require 'merb-core/dispatch/session'
|
346
507
|
Merb::Controller.send(:include, ::Merb::SessionMixin)
|
@@ -353,8 +514,14 @@ class Merb::BootLoader::BeforeAppLoads < Merb::BootLoader
|
|
353
514
|
|
354
515
|
# Call any before_app_loads hooks that were registered via before_app_loads
|
355
516
|
# in any plugins.
|
517
|
+
#
|
518
|
+
# ==== Returns
|
519
|
+
# nil
|
520
|
+
#
|
521
|
+
# @api plugin
|
356
522
|
def self.run
|
357
523
|
Merb::BootLoader.before_load_callbacks.each { |x| x.call }
|
524
|
+
nil
|
358
525
|
end
|
359
526
|
end
|
360
527
|
|
@@ -373,6 +540,18 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
373
540
|
class << self
|
374
541
|
|
375
542
|
# Load all classes from Merb's native load paths.
|
543
|
+
#
|
544
|
+
# If fork-based loading is used, every time classes are loaded this will return in a new spawner process
|
545
|
+
# and boot loading will continue from this point in the boot loading process.
|
546
|
+
#
|
547
|
+
# If fork-based loading is not in use, this only returns once and does not fork a new
|
548
|
+
# process.
|
549
|
+
#
|
550
|
+
# ==== Returns
|
551
|
+
# Returns at least once:
|
552
|
+
# nil
|
553
|
+
#
|
554
|
+
# @api plugin
|
376
555
|
def run
|
377
556
|
# Add models, controllers, helpers and lib to the load path
|
378
557
|
unless @ran
|
@@ -383,20 +562,26 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
383
562
|
end
|
384
563
|
|
385
564
|
@ran = true
|
565
|
+
# process name you see in ps output
|
386
566
|
$0 = "merb#{" : " + Merb::Config[:name] if Merb::Config[:name]} : master"
|
387
567
|
|
568
|
+
# Log the process configuration user defined signal 1 (SIGUSR1) is received.
|
569
|
+
Merb.trap("USR1") do
|
570
|
+
Merb.logger.fatal! "Configuration:\n#{Merb::Config.to_hash.merge(:pid => $$).to_yaml}\n\n"
|
571
|
+
end
|
572
|
+
|
388
573
|
if Merb::Config[:fork_for_class_load] && !Merb.testing?
|
389
574
|
start_transaction
|
390
575
|
else
|
391
576
|
Merb.trap('INT') do
|
392
|
-
Merb.logger.warn! "
|
393
|
-
|
577
|
+
Merb.logger.warn! "Reaping Workers"
|
578
|
+
reap_workers
|
394
579
|
end
|
395
580
|
end
|
396
581
|
|
397
582
|
# Load application file if it exists - for flat applications
|
398
583
|
load_file Merb.dir_for(:application) if File.file?(Merb.dir_for(:application))
|
399
|
-
|
584
|
+
|
400
585
|
# Load classes and their requirements
|
401
586
|
Merb.load_paths.each do |component, path|
|
402
587
|
next if path.last.blank? || component == :application || component == :router
|
@@ -404,18 +589,41 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
404
589
|
end
|
405
590
|
|
406
591
|
Merb::Controller.send :include, Merb::GlobalHelpers
|
592
|
+
|
593
|
+
nil
|
407
594
|
end
|
408
|
-
|
595
|
+
|
409
596
|
# Wait for any children to exit, remove the "main" PID, and
|
410
597
|
# exit.
|
598
|
+
#
|
599
|
+
# ==== Returns
|
600
|
+
# (Does not return.)
|
601
|
+
#
|
602
|
+
# @api private
|
411
603
|
def exit_gracefully
|
604
|
+
# wait all workers to exit
|
412
605
|
Process.waitall
|
606
|
+
# remove master process pid
|
413
607
|
Merb::Server.remove_pid("main")
|
608
|
+
# terminate, workers remove their own pids
|
609
|
+
# in on exit hook
|
414
610
|
exit
|
415
611
|
end
|
416
612
|
|
417
|
-
#
|
418
|
-
#
|
613
|
+
# Set up the BEGIN point for fork-based loading and sets up
|
614
|
+
# any signals in the parent and child. This is done by forking
|
615
|
+
# the app. The child process continues on to run the app. The parent
|
616
|
+
# process waits for the child process to finish and either forks again
|
617
|
+
#
|
618
|
+
#
|
619
|
+
# ==== Returns
|
620
|
+
# Parent Process:
|
621
|
+
# (Does not return.)
|
622
|
+
# Child Process returns at least once:
|
623
|
+
# nil
|
624
|
+
#
|
625
|
+
# @api private
|
626
|
+
|
419
627
|
def start_transaction
|
420
628
|
Merb.logger.warn! "Parent pid: #{Process.pid}"
|
421
629
|
reader, writer = nil, nil
|
@@ -425,20 +633,25 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
425
633
|
end
|
426
634
|
|
427
635
|
loop do
|
636
|
+
# create two connected endpoints
|
637
|
+
# we use them for master/workers communication
|
428
638
|
reader, @writer = IO.pipe
|
429
639
|
pid = Kernel.fork
|
430
640
|
|
431
|
-
# pid means we're in the parent; only stay in the loop
|
641
|
+
# pid means we're in the parent; only stay in the loop if that is case
|
432
642
|
break unless pid
|
643
|
+
# writer must be closed so reader can generate EOF condition
|
433
644
|
@writer.close
|
434
645
|
|
646
|
+
# master process stores pid to merb.main.pid
|
435
647
|
Merb::Server.store_pid("main")
|
436
648
|
|
437
649
|
if Merb::Config[:console_trap]
|
438
650
|
Merb.trap("INT") {}
|
439
651
|
else
|
652
|
+
# send ABRT to worker on INT
|
440
653
|
Merb.trap("INT") do
|
441
|
-
Merb.logger.warn! "
|
654
|
+
Merb.logger.warn! "Reaping Workers"
|
442
655
|
begin
|
443
656
|
Process.kill("ABRT", pid)
|
444
657
|
rescue SystemCallError
|
@@ -454,14 +667,26 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
454
667
|
|
455
668
|
reader_ary = [reader]
|
456
669
|
loop do
|
670
|
+
# wait for worker to exit and capture exit status
|
671
|
+
#
|
672
|
+
#
|
673
|
+
# WNOHANG specifies that wait2 exists without waiting
|
674
|
+
# if no worker processes are ready to be noticed.
|
457
675
|
if exit_status = Process.wait2(pid, Process::WNOHANG)
|
458
|
-
|
676
|
+
# wait2 returns a 2-tuple of process id and exit
|
677
|
+
# status.
|
678
|
+
#
|
679
|
+
# We do not care about specific pid here.
|
680
|
+
exit_status[1] && exit_status[1].exitstatus == 128 ? break : exit
|
459
681
|
end
|
682
|
+
# wait for data to become available, timeout in 0.25 of a second
|
460
683
|
if select(reader_ary, nil, nil, 0.25)
|
461
684
|
begin
|
685
|
+
# no open writers
|
462
686
|
next if reader.eof?
|
463
687
|
msg = reader.readline
|
464
688
|
if msg =~ /128/
|
689
|
+
Process.detach(pid)
|
465
690
|
break
|
466
691
|
else
|
467
692
|
exit_gracefully
|
@@ -475,39 +700,47 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
475
700
|
|
476
701
|
reader.close
|
477
702
|
|
478
|
-
# add traps to the
|
703
|
+
# add traps to the worker
|
479
704
|
if Merb::Config[:console_trap]
|
480
705
|
Merb::Server.add_irb_trap
|
481
|
-
at_exit {
|
706
|
+
at_exit { reap_workers }
|
482
707
|
else
|
483
708
|
Merb.trap('INT') {}
|
484
|
-
Merb.trap('ABRT') {
|
485
|
-
Merb.trap('HUP') {
|
709
|
+
Merb.trap('ABRT') { reap_workers }
|
710
|
+
Merb.trap('HUP') { reap_workers(128) }
|
486
711
|
end
|
487
712
|
end
|
488
713
|
|
489
|
-
#
|
490
|
-
# an appropriate status code.
|
714
|
+
# Reap any workers of the spawner process and
|
715
|
+
# exit with an appropriate status code.
|
491
716
|
#
|
492
717
|
# Note that exiting the spawner process with a status code
|
493
718
|
# of 128 when a master process exists will cause the
|
494
719
|
# spawner process to be recreated, and the app code reloaded.
|
495
720
|
#
|
721
|
+
# ==== Parameters
|
722
|
+
# status<Integer>:: The status code to exit with. Defaults to 0.
|
723
|
+
#
|
724
|
+
# ==== Returns
|
725
|
+
# (Does not return.)
|
726
|
+
#
|
727
|
+
# @api private
|
496
728
|
# @param status<Integer> The status code to exit with
|
497
|
-
|
729
|
+
# @param sig<String> The signal to send to workers
|
730
|
+
def reap_workers(status = 0, sig = "ABRT")
|
498
731
|
Merb.exiting = true unless status == 128
|
499
|
-
|
732
|
+
|
500
733
|
begin
|
501
734
|
@writer.puts(status.to_s) if @writer
|
502
735
|
rescue SystemCallError
|
503
736
|
end
|
504
|
-
|
737
|
+
|
505
738
|
threads = []
|
506
|
-
|
507
|
-
($
|
739
|
+
|
740
|
+
($WORKERS || []).each do |p|
|
508
741
|
threads << Thread.new do
|
509
742
|
begin
|
510
|
-
Process.kill(
|
743
|
+
Process.kill(sig, p)
|
511
744
|
Process.wait2(p)
|
512
745
|
rescue SystemCallError
|
513
746
|
end
|
@@ -516,37 +749,52 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
516
749
|
threads.each {|t| t.join }
|
517
750
|
exit(status)
|
518
751
|
end
|
519
|
-
|
752
|
+
|
753
|
+
# Loads a file, tracking its modified time and, if necessary, the classes it declared.
|
754
|
+
#
|
520
755
|
# ==== Parameters
|
521
756
|
# file<String>:: The file to load.
|
757
|
+
#
|
758
|
+
# ==== Returns
|
759
|
+
# nil
|
760
|
+
#
|
761
|
+
# @api private
|
522
762
|
def load_file(file)
|
523
763
|
# Don't do this expensive operation unless we need to
|
524
764
|
unless Merb::Config[:fork_for_class_load]
|
525
765
|
klasses = ObjectSpace.classes.dup
|
526
766
|
end
|
527
|
-
|
767
|
+
|
528
768
|
# Ignore the file for syntax errors. The next time
|
529
769
|
# the file is changed, it'll be reloaded again
|
530
770
|
begin
|
531
771
|
load file
|
532
|
-
rescue SyntaxError
|
533
|
-
|
772
|
+
rescue SyntaxError => e
|
773
|
+
Merb.logger.error "Cannot load #{file} because of syntax error: #{e.message}"
|
534
774
|
ensure
|
535
775
|
if Merb::Config[:reload_classes]
|
536
776
|
MTIMES[file] = File.mtime(file)
|
537
777
|
end
|
538
778
|
end
|
539
|
-
|
779
|
+
|
540
780
|
# Don't do this expensive operation unless we need to
|
541
781
|
unless Merb::Config[:fork_for_class_load]
|
542
782
|
LOADED_CLASSES[file] = ObjectSpace.classes - klasses
|
543
783
|
end
|
784
|
+
|
785
|
+
nil
|
544
786
|
end
|
545
|
-
|
787
|
+
|
546
788
|
# Load classes from given paths - using path/glob pattern.
|
547
789
|
#
|
790
|
+
# ==== Parameters
|
548
791
|
# *paths<Array>::
|
549
792
|
# Array of paths to load classes from - may contain glob pattern
|
793
|
+
#
|
794
|
+
# ==== Returns
|
795
|
+
# nil
|
796
|
+
#
|
797
|
+
# @api private
|
550
798
|
def load_classes(*paths)
|
551
799
|
orphaned_classes = []
|
552
800
|
paths.flatten.each do |path|
|
@@ -560,20 +808,44 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
560
808
|
end
|
561
809
|
load_classes_with_requirements(orphaned_classes)
|
562
810
|
end
|
563
|
-
|
811
|
+
|
812
|
+
# Reloads the classes in the specified file. If fork-based loading is used,
|
813
|
+
# this causes the current processes to be killed and and all classes to be
|
814
|
+
# reloaded. If class-based loading is not in use, the classes declared in that file
|
815
|
+
# are removed and the file is reloaded.
|
816
|
+
#
|
564
817
|
# ==== Parameters
|
565
818
|
# file<String>:: The file to reload.
|
819
|
+
#
|
820
|
+
# ==== Returns
|
821
|
+
# When fork-based loading is used:
|
822
|
+
# (Does not return.)
|
823
|
+
# When fork-based loading is not in use:
|
824
|
+
# nil
|
825
|
+
#
|
826
|
+
# @api private
|
566
827
|
def reload(file)
|
567
828
|
if Merb::Config[:fork_for_class_load]
|
568
|
-
|
829
|
+
reap_workers(128)
|
569
830
|
else
|
570
831
|
remove_classes_in_file(file) { |f| load_file(f) }
|
571
832
|
end
|
572
833
|
end
|
573
|
-
|
834
|
+
|
835
|
+
# Removes all classes declared in the specified file. Any hashes which use classes as keys
|
836
|
+
# will be protected provided they have been added to Merb.klass_hashes. These hashes have their
|
837
|
+
# keys substituted with placeholders before the file's classes are unloaded. If a block is provided,
|
838
|
+
# it is called before the substituted keys are reconstituted.
|
839
|
+
#
|
574
840
|
# ==== Parameters
|
575
841
|
# file<String>:: The file to remove classes for.
|
576
|
-
# &block:: A block to call with the file that has been removed
|
842
|
+
# &block:: A block to call with the file that has been removed before klass_hashes are updated
|
843
|
+
# to use the current values of the constants they used as keys.
|
844
|
+
#
|
845
|
+
# ==== Returns
|
846
|
+
# nil
|
847
|
+
#
|
848
|
+
# @api private
|
577
849
|
def remove_classes_in_file(file, &block)
|
578
850
|
Merb.klass_hashes.each { |x| x.protect_keys! }
|
579
851
|
if klasses = LOADED_CLASSES.delete(file)
|
@@ -581,15 +853,26 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
581
853
|
end
|
582
854
|
yield file if block_given?
|
583
855
|
Merb.klass_hashes.each {|x| x.unprotect_keys!}
|
856
|
+
nil
|
584
857
|
end
|
585
858
|
|
859
|
+
# Removes the specified class.
|
860
|
+
#
|
861
|
+
# Additionally, removes the specified class from the subclass list of every superclass that
|
862
|
+
# tracks it's subclasses in an array returned by _subclasses_list. Classes that wish to use this
|
863
|
+
# functionality are required to alias the reader for their list of subclasses
|
864
|
+
# to _subclasses_list. Plugins for ORMs and other libraries should keep this in mind.
|
865
|
+
#
|
586
866
|
# ==== Parameters
|
587
867
|
# const<Class>:: The class to remove.
|
868
|
+
#
|
869
|
+
# ==== Returns
|
870
|
+
# nil
|
871
|
+
#
|
872
|
+
# @api private
|
588
873
|
def remove_constant(const)
|
589
874
|
# This is to support superclasses (like AbstractController) that track
|
590
|
-
# their subclasses in a class variable.
|
591
|
-
# functionality are required to alias it to _subclasses_list. Plugins
|
592
|
-
# for ORMs and other libraries should keep this in mind.
|
875
|
+
# their subclasses in a class variable.
|
593
876
|
superklass = const
|
594
877
|
until (superklass = superklass.superclass).nil?
|
595
878
|
if superklass.respond_to?(:_subclasses_list)
|
@@ -607,16 +890,22 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
607
890
|
rescue NameError
|
608
891
|
Merb.logger.debug("Failed to remove constant #{object} from #{base}")
|
609
892
|
end
|
893
|
+
nil
|
610
894
|
end
|
611
|
-
|
895
|
+
|
612
896
|
private
|
613
897
|
|
614
|
-
# "Better loading" of classes. If a
|
898
|
+
# "Better loading" of classes. If a file fails to load due to a NameError
|
615
899
|
# it will be added to the failed_classes and load cycle will be repeated unless
|
616
900
|
# no classes load.
|
617
901
|
#
|
618
902
|
# ==== Parameters
|
619
903
|
# klasses<Array[Class]>:: Classes to load.
|
904
|
+
#
|
905
|
+
# ==== Returns
|
906
|
+
# nil
|
907
|
+
#
|
908
|
+
# @api private
|
620
909
|
def load_classes_with_requirements(klasses)
|
621
910
|
klasses.uniq!
|
622
911
|
|
@@ -646,7 +935,7 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
646
935
|
if klasses.size == size_at_start && klasses.size != 0
|
647
936
|
# Write all remaining failed classes and their exceptions to the log
|
648
937
|
messages = error_map.only(*failed_classes).map do |klass, e|
|
649
|
-
["Could not load #{klass}:\n\n#{e.message} - (#{e.class})",
|
938
|
+
["Could not load #{klass}:\n\n#{e.message} - (#{e.class})",
|
650
939
|
"#{(e.backtrace || []).join("\n")}"]
|
651
940
|
end
|
652
941
|
messages.each { |msg, trace| Merb.logger.fatal!("#{msg}\n\n#{trace}") }
|
@@ -654,26 +943,35 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
654
943
|
end
|
655
944
|
break if(klasses.size == size_at_start || klasses.size == 0)
|
656
945
|
end
|
946
|
+
|
947
|
+
nil
|
657
948
|
end
|
658
949
|
|
659
950
|
end
|
660
951
|
|
661
952
|
end
|
662
953
|
|
954
|
+
# Loads the router file. This needs to happen after everything else is loaded while merb is starting up to ensure
|
955
|
+
# the router has everything it needs to run.
|
663
956
|
class Merb::BootLoader::Router < Merb::BootLoader
|
664
957
|
class << self
|
665
958
|
|
959
|
+
# load the router file
|
960
|
+
#
|
961
|
+
# ==== Returns
|
962
|
+
# nil
|
963
|
+
#
|
964
|
+
# @api plugin
|
666
965
|
def run
|
667
966
|
Merb::BootLoader::LoadClasses.load_file(router_file) if router_file
|
967
|
+
|
968
|
+
nil
|
668
969
|
end
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
970
|
+
|
971
|
+
# Tries to find the router file.
|
972
|
+
#
|
973
|
+
# ==== Returns
|
974
|
+
# String:: The path to the router file if it exists, nil otherwise.
|
677
975
|
def router_file
|
678
976
|
@router_file ||= begin
|
679
977
|
if File.file?(router = Merb.dir_for(:router) / Merb.glob_for(:router))
|
@@ -681,22 +979,32 @@ class Merb::BootLoader::Router < Merb::BootLoader
|
|
681
979
|
end
|
682
980
|
end
|
683
981
|
end
|
684
|
-
|
982
|
+
|
685
983
|
end
|
686
984
|
end
|
687
985
|
|
986
|
+
# Precompiles all non-partial templates.
|
688
987
|
class Merb::BootLoader::Templates < Merb::BootLoader
|
689
988
|
class << self
|
690
989
|
|
691
|
-
# Loads
|
990
|
+
# Loads all non-partial templates into the Merb::InlineTemplates module.
|
991
|
+
#
|
992
|
+
# ==== Returns
|
993
|
+
# Array[String]:: The list of template files which were loaded.
|
994
|
+
#
|
995
|
+
# @api plugin
|
692
996
|
def run
|
693
997
|
template_paths.each do |path|
|
694
998
|
Merb::Template.inline_template(File.open(path))
|
695
999
|
end
|
696
1000
|
end
|
697
1001
|
|
1002
|
+
# Finds a list of templates to load.
|
1003
|
+
#
|
698
1004
|
# ==== Returns
|
699
|
-
# Array[String]::
|
1005
|
+
# Array[String]:: All found template files whose basename does not begin with "_".
|
1006
|
+
#
|
1007
|
+
# @api private
|
700
1008
|
def template_paths
|
701
1009
|
extension_glob = "{#{Merb::Template.template_extensions.join(',')}}"
|
702
1010
|
|
@@ -735,6 +1043,11 @@ end
|
|
735
1043
|
class Merb::BootLoader::MimeTypes < Merb::BootLoader
|
736
1044
|
|
737
1045
|
# Registers the default MIME types.
|
1046
|
+
#
|
1047
|
+
# ==== Returns
|
1048
|
+
# nil
|
1049
|
+
#
|
1050
|
+
# @api plugin
|
738
1051
|
def self.run
|
739
1052
|
Merb.add_mime_type(:all, nil, %w[*/*])
|
740
1053
|
Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml], :charset => "utf-8")
|
@@ -743,47 +1056,62 @@ class Merb::BootLoader::MimeTypes < Merb::BootLoader
|
|
743
1056
|
Merb.add_mime_type(:xml, :to_xml, %w[application/xml text/xml application/x-xml], {:charset => "utf-8"}, 0.9998)
|
744
1057
|
Merb.add_mime_type(:js, :to_json, %w[text/javascript application/javascript application/x-javascript], :charset => "utf-8")
|
745
1058
|
Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json], :charset => "utf-8")
|
1059
|
+
nil
|
746
1060
|
end
|
747
1061
|
end
|
748
1062
|
|
1063
|
+
# Set up cookies support in Merb::Controller and Merb::Request
|
749
1064
|
class Merb::BootLoader::Cookies < Merb::BootLoader
|
750
|
-
|
1065
|
+
|
1066
|
+
# Set up cookies support in Merb::Controller and Merb::Request
|
1067
|
+
#
|
1068
|
+
# ==== Returns
|
1069
|
+
# nil
|
1070
|
+
#
|
1071
|
+
# @api plugin
|
751
1072
|
def self.run
|
752
1073
|
require 'merb-core/dispatch/cookies'
|
753
1074
|
Merb::Controller.send(:include, Merb::CookiesMixin)
|
754
1075
|
Merb::Request.send(:include, Merb::CookiesMixin::RequestMixin)
|
1076
|
+
nil
|
755
1077
|
end
|
756
|
-
|
1078
|
+
|
757
1079
|
end
|
758
1080
|
|
759
1081
|
class Merb::BootLoader::SetupSession < Merb::BootLoader
|
760
1082
|
|
761
1083
|
# Enable the configured session container(s); any class that inherits from
|
762
1084
|
# SessionContainer will be considered by its session_store_type attribute.
|
1085
|
+
#
|
1086
|
+
# ==== Returns
|
1087
|
+
# nil
|
1088
|
+
#
|
1089
|
+
# @api plugin
|
763
1090
|
def self.run
|
764
1091
|
# Require all standard session containers.
|
765
1092
|
Dir[Merb.framework_root / "merb-core" / "dispatch" / "session" / "*.rb"].each do |file|
|
766
1093
|
base_name = File.basename(file, ".rb")
|
767
1094
|
require file unless base_name == "container" || base_name == "store_container"
|
768
1095
|
end
|
769
|
-
|
1096
|
+
|
770
1097
|
# Set some defaults.
|
771
1098
|
Merb::Config[:session_id_key] ||= "_session_id"
|
772
|
-
|
1099
|
+
|
773
1100
|
# List of all session_stores from :session_stores and :session_store config options.
|
774
1101
|
config_stores = Merb::Config.session_stores
|
775
|
-
|
1102
|
+
|
776
1103
|
# Register all configured session stores - any loaded session container class
|
777
1104
|
# (subclassed from Merb::SessionContainer) will be available for registration.
|
778
1105
|
Merb::SessionContainer.subclasses.each do |class_name|
|
779
|
-
if(store = Object.full_const_get(class_name)) &&
|
1106
|
+
if(store = Object.full_const_get(class_name)) &&
|
780
1107
|
config_stores.include?(store.session_store_type)
|
781
1108
|
Merb::Request.register_session_type(store.session_store_type, class_name)
|
782
1109
|
end
|
783
1110
|
end
|
784
|
-
|
1111
|
+
|
785
1112
|
# Mixin the Merb::Session module to add app-level functionality to sessions
|
786
1113
|
Merb::SessionContainer.send(:include, Merb::Session)
|
1114
|
+
nil
|
787
1115
|
end
|
788
1116
|
|
789
1117
|
end
|
@@ -792,14 +1120,26 @@ class Merb::BootLoader::AfterAppLoads < Merb::BootLoader
|
|
792
1120
|
|
793
1121
|
# Call any after_app_loads hooks that were registered via after_app_loads in
|
794
1122
|
# init.rb.
|
1123
|
+
#
|
1124
|
+
# ==== Returns
|
1125
|
+
# nil
|
1126
|
+
#
|
1127
|
+
# @api plugin
|
795
1128
|
def self.run
|
796
1129
|
Merb::BootLoader.after_load_callbacks.each {|x| x.call }
|
1130
|
+
nil
|
797
1131
|
end
|
798
1132
|
end
|
799
1133
|
|
800
1134
|
# In case someone's running a sparse app, the default exceptions require the
|
801
1135
|
# Exceptions class.
|
802
1136
|
class Merb::BootLoader::SetupStubClasses < Merb::BootLoader
|
1137
|
+
# Declares empty Application and Exception controllers.
|
1138
|
+
#
|
1139
|
+
# ==== Returns
|
1140
|
+
# nil
|
1141
|
+
#
|
1142
|
+
# @api plugin
|
803
1143
|
def self.run
|
804
1144
|
unless defined?(Exceptions)
|
805
1145
|
Object.class_eval <<-RUBY
|
@@ -811,31 +1151,34 @@ class Merb::BootLoader::SetupStubClasses < Merb::BootLoader
|
|
811
1151
|
end
|
812
1152
|
RUBY
|
813
1153
|
end
|
1154
|
+
nil
|
814
1155
|
end
|
815
1156
|
end
|
816
1157
|
|
817
1158
|
class Merb::BootLoader::ChooseAdapter < Merb::BootLoader
|
818
1159
|
|
819
1160
|
# Choose the Rack adapter/server to use and set Merb.adapter.
|
1161
|
+
#
|
1162
|
+
# ==== Returns
|
1163
|
+
# nil
|
1164
|
+
#
|
1165
|
+
# @api plugin
|
820
1166
|
def self.run
|
821
1167
|
Merb.adapter = Merb::Rack::Adapter.get(Merb::Config[:adapter])
|
822
1168
|
end
|
823
1169
|
end
|
824
1170
|
|
825
|
-
class Merb::BootLoader::StartWorkerThread < Merb::BootLoader
|
826
|
-
|
827
|
-
# Choose the Rack adapter/server to use and set Merb.adapter.
|
828
|
-
def self.run
|
829
|
-
Merb::Worker.new
|
830
|
-
end
|
831
|
-
end
|
832
|
-
|
833
1171
|
class Merb::BootLoader::RackUpApplication < Merb::BootLoader
|
834
1172
|
# Setup the Merb Rack App or read a rackup file located at
|
835
1173
|
# Merb::Config[:rackup] with the same syntax as the
|
836
1174
|
# rackup tool that comes with rack. Automatically evals the file in
|
837
1175
|
# the context of a Rack::Builder.new { } block. Allows for mounting
|
838
1176
|
# additional apps or middleware.
|
1177
|
+
#
|
1178
|
+
# ==== Returns
|
1179
|
+
# nil
|
1180
|
+
#
|
1181
|
+
# @api plugin
|
839
1182
|
def self.run
|
840
1183
|
require 'rack'
|
841
1184
|
if File.exists?(Merb.dir_for(:config) / "rack.rb")
|
@@ -855,12 +1198,23 @@ class Merb::BootLoader::RackUpApplication < Merb::BootLoader
|
|
855
1198
|
}.to_app
|
856
1199
|
end
|
857
1200
|
|
1201
|
+
nil
|
858
1202
|
end
|
859
1203
|
end
|
860
1204
|
|
861
1205
|
class Merb::BootLoader::ReloadClasses < Merb::BootLoader
|
862
1206
|
|
863
1207
|
class TimedExecutor
|
1208
|
+
# Executes the associated block every @seconds@ seconds in a separate thread.
|
1209
|
+
#
|
1210
|
+
# ==== Parameters
|
1211
|
+
# seconds<Integer>:: Number of seconds to sleep in between runs of &block.
|
1212
|
+
# &block:: The block to execute periodically.
|
1213
|
+
#
|
1214
|
+
# ==== Returns
|
1215
|
+
# Thread:: The thread executing the block periodically.
|
1216
|
+
#
|
1217
|
+
# @api private
|
864
1218
|
def self.every(seconds, &block)
|
865
1219
|
Thread.abort_on_exception = true
|
866
1220
|
Thread.new do
|
@@ -873,7 +1227,14 @@ class Merb::BootLoader::ReloadClasses < Merb::BootLoader
|
|
873
1227
|
end
|
874
1228
|
end
|
875
1229
|
|
876
|
-
#
|
1230
|
+
# Set up the class reloader if class reloading is enabled. This checks periodically
|
1231
|
+
# for modifications to files loaded by the LoadClasses BootLoader and reloads them
|
1232
|
+
# when they are modified.
|
1233
|
+
#
|
1234
|
+
# ==== Returns
|
1235
|
+
# nil
|
1236
|
+
#
|
1237
|
+
# @api plugin
|
877
1238
|
def self.run
|
878
1239
|
return unless Merb::Config[:reload_classes]
|
879
1240
|
|
@@ -883,7 +1244,7 @@ class Merb::BootLoader::ReloadClasses < Merb::BootLoader
|
|
883
1244
|
next unless glob
|
884
1245
|
paths << Dir[path / glob]
|
885
1246
|
end
|
886
|
-
|
1247
|
+
|
887
1248
|
if Merb.dir_for(:application) && File.file?(Merb.dir_for(:application))
|
888
1249
|
paths << Merb.dir_for(:application)
|
889
1250
|
end
|
@@ -895,15 +1256,23 @@ class Merb::BootLoader::ReloadClasses < Merb::BootLoader
|
|
895
1256
|
reload(paths)
|
896
1257
|
end
|
897
1258
|
|
1259
|
+
nil
|
898
1260
|
end
|
899
1261
|
|
900
|
-
# Reloads all files.
|
1262
|
+
# Reloads all files which have been modified since they were last loaded.
|
1263
|
+
#
|
1264
|
+
# ==== Returns
|
1265
|
+
# nil
|
1266
|
+
#
|
1267
|
+
# @api private
|
901
1268
|
def self.reload(paths)
|
902
1269
|
paths.each do |file|
|
903
|
-
next if LoadClasses::MTIMES[file] &&
|
1270
|
+
next if LoadClasses::MTIMES[file] &&
|
904
1271
|
LoadClasses::MTIMES[file] == File.mtime(file)
|
905
|
-
|
1272
|
+
|
906
1273
|
LoadClasses.reload(file)
|
907
1274
|
end
|
1275
|
+
|
1276
|
+
nil
|
908
1277
|
end
|
909
1278
|
end
|