merb-core 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/CONTRIBUTORS +33 -0
  2. data/README +7 -3
  3. data/Rakefile +3 -3
  4. data/lib/merb-core.rb +165 -94
  5. data/lib/merb-core/bootloader.rb +469 -100
  6. data/lib/merb-core/config.rb +79 -3
  7. data/lib/merb-core/constants.rb +24 -2
  8. data/lib/merb-core/controller/abstract_controller.rb +172 -67
  9. data/lib/merb-core/controller/exceptions.rb +50 -6
  10. data/lib/merb-core/controller/merb_controller.rb +215 -108
  11. data/lib/merb-core/controller/mime.rb +36 -12
  12. data/lib/merb-core/controller/mixins/authentication.rb +52 -7
  13. data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
  14. data/lib/merb-core/controller/mixins/controller.rb +90 -58
  15. data/lib/merb-core/controller/mixins/render.rb +34 -10
  16. data/lib/merb-core/controller/mixins/responder.rb +40 -16
  17. data/lib/merb-core/controller/template.rb +37 -16
  18. data/lib/merb-core/core_ext/hash.rb +9 -0
  19. data/lib/merb-core/core_ext/kernel.rb +92 -41
  20. data/lib/merb-core/dispatch/dispatcher.rb +29 -45
  21. data/lib/merb-core/dispatch/request.rb +186 -82
  22. data/lib/merb-core/dispatch/router.rb +141 -53
  23. data/lib/merb-core/dispatch/router/behavior.rb +296 -139
  24. data/lib/merb-core/dispatch/router/resources.rb +51 -19
  25. data/lib/merb-core/dispatch/router/route.rb +76 -23
  26. data/lib/merb-core/dispatch/session.rb +80 -36
  27. data/lib/merb-core/dispatch/session/container.rb +31 -15
  28. data/lib/merb-core/dispatch/session/cookie.rb +51 -22
  29. data/lib/merb-core/dispatch/session/memcached.rb +10 -6
  30. data/lib/merb-core/dispatch/session/memory.rb +17 -5
  31. data/lib/merb-core/dispatch/session/store_container.rb +21 -9
  32. data/lib/merb-core/dispatch/worker.rb +16 -2
  33. data/lib/merb-core/gem_ext/erubis.rb +4 -0
  34. data/lib/merb-core/plugins.rb +13 -0
  35. data/lib/merb-core/rack.rb +1 -0
  36. data/lib/merb-core/rack/adapter.rb +1 -0
  37. data/lib/merb-core/rack/adapter/abstract.rb +95 -17
  38. data/lib/merb-core/rack/adapter/irb.rb +50 -5
  39. data/lib/merb-core/rack/application.rb +27 -5
  40. data/lib/merb-core/rack/handler/mongrel.rb +6 -6
  41. data/lib/merb-core/rack/helpers.rb +33 -0
  42. data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
  43. data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
  44. data/lib/merb-core/rack/middleware/static.rb +11 -7
  45. data/lib/merb-core/server.rb +134 -69
  46. data/lib/merb-core/tasks/gem_management.rb +153 -80
  47. data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
  48. data/lib/merb-core/tasks/stats.rake +1 -1
  49. data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
  50. data/lib/merb-core/test/helpers/request_helper.rb +1 -1
  51. data/lib/merb-core/test/helpers/route_helper.rb +50 -4
  52. data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
  53. data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
  54. data/lib/merb-core/test/run_specs.rb +6 -5
  55. data/lib/merb-core/test/test_ext/rspec.rb +6 -19
  56. data/lib/merb-core/version.rb +1 -1
  57. metadata +5 -4
@@ -0,0 +1,33 @@
1
+ module Merb
2
+ module Rack
3
+ module Helpers
4
+
5
+ # A helper to build a rack response which implements a redirect. The status will be set to
6
+ # the passed in status if passed. If you pass in permanent it will be a 301, permanent redirect,
7
+ # otherwise it defaults to a temporary 302 redirect.
8
+ #
9
+ # ==== Parameters
10
+ # url<~to_s>:: The url to redirect to.
11
+ # options<Hash>:: A hash of options for the redirect
12
+ # status: The status code to use for the redirect
13
+ # permanent: True if this is a permanent redirect (301)
14
+ #
15
+ # ==== Returns
16
+ # <Array>:: A rack response to redirect to the specified url.
17
+ #
18
+ # @api plugin
19
+ def self.redirect(url, options = {})
20
+ # Build the rack array
21
+ status = options.delete(:status)
22
+ status ||= options[:permanent] ? 301 : 302
23
+
24
+ Merb.logger.info("Dispatcher redirecting to: #{url} (#{status})")
25
+ Merb.logger.flush
26
+
27
+ [status, { Merb::Const::LOCATION => url },
28
+ Merb::Rack::StreamWrapper.new("<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>")]
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -7,7 +7,7 @@ module Merb
7
7
 
8
8
  if document_not_modified?(env, headers)
9
9
  status = 304
10
- body = ""
10
+ body = Merb::Const::EMPTY_STRING
11
11
  # set Date header using RFC1123 date format as specified by HTTP
12
12
  # RFC2616 section 3.3.1.
13
13
  end
@@ -20,12 +20,12 @@ module Merb
20
20
  def strip_path_prefix(env)
21
21
  ['PATH_INFO', 'REQUEST_URI'].each do |path_key|
22
22
  if env[path_key] =~ @path_prefix
23
- env[path_key].sub!(@path_prefix, '')
24
- env[path_key] = '/' if env[path_key].empty?
23
+ env[path_key].sub!(@path_prefix, Merb::Const::EMPTY_STRING)
24
+ env[path_key] = Merb::Const::SLASH if env[path_key].empty?
25
25
  end
26
26
  end
27
27
  end
28
28
 
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -8,16 +8,20 @@ module Merb
8
8
  end
9
9
 
10
10
  def call(env)
11
- path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : ""
11
+ path = if env[Merb::Const::PATH_INFO]
12
+ env[Merb::Const::PATH_INFO].chomp(Merb::Const::SLASH)
13
+ else
14
+ Merb::Const::EMPTY_STRING
15
+ end
12
16
  cached_path = (path.empty? ? 'index' : path) + '.html'
13
17
 
14
- if file_exist?(path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD
18
+ if file_exist?(path) && env[Merb::Const::REQUEST_METHOD] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD
15
19
  serve_static(env)
16
- elsif file_exist?(cached_path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD
17
- env['PATH_INFO'] = cached_path
20
+ elsif file_exist?(cached_path) && env[Merb::Const::REQUEST_METHOD] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD
21
+ env[Merb::Const::PATH_INFO] = cached_path
18
22
  serve_static(env)
19
23
  elsif path =~ /favicon\.ico/
20
- return [404, {"Content-Type"=>"text/html"}, "404 Not Found."]
24
+ return [404, { Merb::Const::CONTENT_TYPE => Merb::Const::TEXT_SLASH_HTML }, "404 Not Found."]
21
25
  else
22
26
  @app.call(env)
23
27
  end
@@ -36,10 +40,10 @@ module Merb
36
40
  # ==== Parameters
37
41
  # env<Hash>:: Environment variables to pass on to the server.
38
42
  def serve_static(env)
39
- env["PATH_INFO"] = ::Merb::Request.unescape(env["PATH_INFO"])
43
+ env[Merb::Const::PATH_INFO] = ::Merb::Request.unescape(env[Merb::Const::PATH_INFO])
40
44
  @static_server.call(env)
41
45
  end
42
46
 
43
47
  end
44
48
  end
45
- end
49
+ end
@@ -18,10 +18,12 @@ module Merb
18
18
  # ==== Alternatives
19
19
  # If cluster is left out, then one process will be started. This process
20
20
  # will be daemonized if Merb::Config[:daemonize] is true.
21
+ #
22
+ # @api private
21
23
  def start(port, cluster=nil)
22
-
24
+
23
25
  @port = port
24
- @cluster = cluster
26
+ @cluster = cluster
25
27
 
26
28
  if Merb::Config[:daemonize]
27
29
  pidfile = pid_file(port)
@@ -29,7 +31,7 @@ module Merb
29
31
 
30
32
  unless alive?(@port)
31
33
  remove_pid_file(@port)
32
- puts "Daemonizing..." if Merb::Config[:verbose]
34
+ Merb.logger.warn! "Daemonizing..." if Merb::Config[:verbose]
33
35
  daemonize(@port)
34
36
  else
35
37
  Merb.fatal! "Merb is already running on port #{port}.\n" \
@@ -47,79 +49,96 @@ module Merb
47
49
  # ==== Returns
48
50
  # Boolean::
49
51
  # True if Merb is running on the specified port.
52
+ #
53
+ # @api private
50
54
  def alive?(port)
51
- puts "About to check if port #{port} is alive..." if Merb::Config[:verbose]
52
55
  pidfile = pid_file(port)
53
- puts "Pidfile is #{pidfile}..." if Merb::Config[:verbose]
54
- pid = File.read(pidfile).chomp.to_i
55
- puts "Process id is #{pid}" if Merb::Config[:verbose]
56
+ pid = pid_in_file(pidfile)
56
57
  Process.kill(0, pid)
57
58
  true
58
59
  rescue Errno::ESRCH, Errno::ENOENT
59
60
  false
60
61
  rescue Errno::EACCES => e
61
- Merb.fatal!("You don't have access to the PID file at #{pidfile}.", e)
62
+ Merb.fatal!("You don't have access to the PID file at #{pidfile}: #{e.message}")
63
+ end
64
+
65
+ def pid_in_file(pidfile)
66
+ File.read(pidfile).chomp.to_i
62
67
  end
63
68
 
64
69
  # ==== Parameters
65
70
  # port<~to_s>:: The port of the Merb process to kill.
66
- # sig<~to_s>:: The signal to send to the process. Defaults to 9.
71
+ # sig<~to_s>:: The signal to send to the process, the default is 9 - SIGKILL.
72
+ #
73
+ # No Name Default Action Description
74
+ # 1 SIGHUP terminate process terminal line hangup
75
+ # 2 SIGINT terminate process interrupt program
76
+ # 3 SIGQUIT create core image quit program
77
+ # 4 SIGILL create core image illegal instruction
78
+ # 9 SIGKILL terminate process kill program
79
+ # 15 SIGTERM terminate process software termination signal
80
+ # 30 SIGUSR1 terminate process User defined signal 1
81
+ # 31 SIGUSR2 terminate process User defined signal 2
67
82
  #
68
83
  # ==== Alternatives
69
- # If you pass "all" as the port, the signal will be sent to all Merb
70
- # processes.
71
- def kill(port, sig="INT")
72
- Merb::BootLoader::BuildFramework.run
73
- if sig == 9 && port == "main"
74
- kill_pid("INT", pid_file("main"))
75
- Dir["#{Merb.log_path}" / "*.pid"].each do |file|
76
- kill_pid(9, file)
77
- end
78
- else
79
- kill_pid(sig, pid_file(port))
80
- end
81
-
84
+ # If you pass "all" as the port, the signal will be sent to all Merb processes.
85
+ #
86
+ # @api private
87
+ def kill(port, sig = "INT")
82
88
  if sig.is_a?(Integer)
83
89
  sig = Signal.list.invert[sig]
84
90
  end
91
+
92
+ Merb::BootLoader::BuildFramework.run
85
93
 
86
- if sig == "KILL" && port == "main"
87
- Merb.fatal! "Killed all PIDs with signal KILL"
94
+ # If we kill the master, then the workers should be reaped also.
95
+ if %w(main master all).include?(port)
96
+ # If a graceful exit is requested then send INT to the master process.
97
+ #
98
+ # Otherwise read pids from pid files and try to kill each process in turn.
99
+ kill_pid(sig, pid_file("main")) if sig == "INT"
88
100
  else
89
- Merb.fatal! "Killed #{port} with signal #{sig}"
101
+ kill_pid(sig, pid_file(port))
90
102
  end
91
103
  end
92
-
104
+
105
+ # Sends the provided signal to the process pointed at by the provided pid file.
106
+ # @api private
93
107
  def kill_pid(sig, file)
94
108
  begin
95
- pid = File.read(file).chomp.to_i
96
- Merb.logger.warn! "Killing pid #{pid}"
109
+ pid = pid_in_file(file)
110
+ Merb.logger.fatal! "Killing pid #{pid} with #{sig}"
97
111
  Process.kill(sig, pid)
98
112
  FileUtils.rm(file) if File.exist?(file)
99
113
  rescue Errno::EINVAL
100
- Merb.fatal! "Failed to kill PID #{pid}: '#{sig}' is an invalid " \
114
+ Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: '#{sig}' is an invalid " \
101
115
  "or unsupported signal number."
102
116
  rescue Errno::EPERM
103
- Merb.fatal! "Failed to kill PID #{pid}: Insufficient permissions."
117
+ Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Insufficient permissions."
104
118
  rescue Errno::ESRCH
105
119
  FileUtils.rm file
106
- Merb.fatal! "Failed to kill PID #{pid}: Process is " \
120
+ Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Process is " \
107
121
  "deceased or zombie."
108
122
  rescue Errno::EACCES => e
109
- Merb.fatal! e.message, e
123
+ Merb.logger.fatal! e.message
110
124
  rescue Errno::ENOENT => e
111
- Merb.fatal! "Could not find a PID file at #{file}", e
125
+ # This should not cause abnormal exit, which is why
126
+ # we do not use Merb.fatal but instead just log with max level.
127
+ Merb.logger.fatal! "Could not find a PID file at #{file}. " \
128
+ "Most likely the process is no longer running and the pid file was not cleaned up."
112
129
  rescue Exception => e
113
130
  if !e.is_a?(SystemExit)
114
- Merb.fatal! "Failed to kill PID #{pid}", e
131
+ Merb.logger.fatal! "Failed to kill PID #{pid.inspect} with #{sig.inspect}: #{e.message}"
115
132
  end
116
133
  end
117
134
  end
118
135
 
119
136
  # ==== Parameters
120
137
  # port<~to_s>:: The port of the Merb process to daemonize.
138
+ #
139
+ # @api private
121
140
  def daemonize(port)
122
- puts "About to fork..." if Merb::Config[:verbose]
141
+ Merb.logger.warn! "About to fork..." if Merb::Config[:verbose]
123
142
  fork do
124
143
  Process.setsid
125
144
  exit if fork
@@ -131,26 +150,42 @@ module Merb
131
150
  begin
132
151
  Dir.chdir Merb::Config[:merb_root]
133
152
  rescue Errno::EACCES => e
134
- Merb.fatal! "You specified #{Merb::Config[:merb_root]} " \
135
- "as the Merb root, but you did not have access to it.", e
153
+ Merb.fatal! "You specified Merb root as #{Merb::Config[:merb_root]}, " \
154
+ "yet the current user does not have access to it. ", e
136
155
  end
137
156
  at_exit { remove_pid_file(port) }
138
157
  Merb::Config[:port] = port
139
158
  bootup
140
159
  end
141
160
  rescue NotImplementedError => e
142
- Merb.fatal! "Daemonized mode is not supported on your platform", e
161
+ Merb.fatal! "Daemonized mode is not supported on your platform. ", e
143
162
  end
144
163
 
164
+ # Starts up Merb by running the bootloader and starting the adapter.
165
+ #
166
+ # @api private
145
167
  def bootup
146
- Merb.trap('TERM') { exit }
168
+ Merb.trap("TERM") { shutdown }
147
169
 
148
- puts "Running bootloaders..." if Merb::Config[:verbose]
170
+ Merb.logger.warn! "Running bootloaders..." if Merb::Config[:verbose]
149
171
  BootLoader.run
150
- puts "Starting Rack adapter..." if Merb::Config[:verbose]
172
+ Merb.logger.warn! "Starting Rack adapter..." if Merb::Config[:verbose]
151
173
  Merb.adapter.start(Merb::Config.to_hash)
152
174
  end
153
175
 
176
+ # Shut down Merb, reap any workers if necessary.
177
+ #
178
+ # @api private
179
+ def shutdown(status = 0)
180
+ # reap_workers does exit but may not be called...
181
+ Merb::BootLoader::LoadClasses.reap_workers(status) if Merb::Config[:fork_for_class_load]
182
+ # which is why we exit explicitly here
183
+ exit(status)
184
+ end
185
+
186
+ # Change process user/group to those specified in Merb::Config.
187
+ #
188
+ # @api private
154
189
  def change_privilege
155
190
  if Merb::Config[:user] && Merb::Config[:group]
156
191
  Merb.logger.verbose! "About to change privilege to group " \
@@ -167,7 +202,7 @@ module Merb
167
202
 
168
203
  # Removes a PID file used by the server from the filesystem.
169
204
  # This uses :pid_file options from configuration when provided
170
- # or merb.<port>.pid in log directory by default.
205
+ # or merb.<port/socket>.pid in log directory by default.
171
206
  #
172
207
  # ==== Parameters
173
208
  # port<~to_s>::
@@ -175,11 +210,13 @@ module Merb
175
210
  #
176
211
  # ==== Alternatives
177
212
  # If Merb::Config[:pid_file] has been specified, that will be used
178
- # instead of the port based PID file.
213
+ # instead of the port/socket based PID file.
214
+ #
215
+ # @api private
179
216
  def remove_pid_file(port)
180
217
  pidfile = pid_file(port)
181
218
  if File.exist?(pidfile)
182
- puts "Removing pid file #{pidfile} (port is #{port})..."
219
+ Merb.logger.warn! "Removing pid file #{pidfile} (port/socket: #{port})..."
183
220
  FileUtils.rm(pidfile)
184
221
  end
185
222
  end
@@ -194,37 +231,61 @@ module Merb
194
231
  #
195
232
  # ==== Alternatives
196
233
  # If Merb::Config[:pid_file] has been specified, that will be used
197
- # instead of the port based PID file.
234
+ # instead of the port/socket based PID file.
235
+ #
236
+ # @api private
198
237
  def store_pid(port)
199
238
  store_details(port)
200
239
  end
201
240
 
241
+ # Delete the pidfile for the specified port/socket.
242
+ #
243
+ # @api private
202
244
  def remove_pid(port)
203
245
  FileUtils.rm(pid_file(port)) if File.file?(pid_file(port))
204
246
  end
205
247
 
248
+ # Stores a PID file on the filesystem.
249
+ # This uses :pid_file options from configuration when provided
250
+ # or merb.<port/socket>.pid in log directory by default.
251
+ #
252
+ # ==== Parameters
253
+ # port<~to_s>::
254
+ # The port of the Merb process to whom the the PID file belongs to.
255
+ #
256
+ # ==== Alternatives
257
+ # If Merb::Config[:pid_file] has been specified, that will be used
258
+ # instead of the port/socket based PID file.
259
+ #
260
+ # @api private
206
261
  def store_details(port = nil)
207
262
  file = pid_file(port)
208
263
  begin
209
264
  FileUtils.mkdir_p(File.dirname(file))
210
265
  rescue Errno::EACCES => e
211
- Merb.fatal! "You tried to store Merb logs in #{File.dirname(file)}, " \
212
- "but you did not have access.", e
266
+ Merb.fatal! "Failed to store Merb logs in #{File.dirname(file)}, " \
267
+ "permission denied. ", e
213
268
  end
214
269
  Merb.logger.warn! "Storing #{type} file to #{file}..." if Merb::Config[:verbose]
215
- File.open(file, 'w'){ |f| f.write(Process.pid.to_s) }
270
+ begin
271
+ File.open(file, 'w'){ |f| f.write(Process.pid.to_s) }
272
+ rescue Errno::EACCES => e
273
+ Merb.fatal! "Failed to access #{file}, permission denied.", e
274
+ end
216
275
  end
217
276
 
218
- # Gets the pid file for the specified port.
277
+ # Gets the pid file for the specified port/socket.
219
278
  #
220
279
  # ==== Parameters
221
280
  # port<~to_s>::
222
- # The port of the Merb process to whom the the PID file belongs to.
281
+ # The port/socket of the Merb process to whom the the PID file belongs to.
223
282
  #
224
283
  # ==== Returns
225
284
  # String::
226
285
  # Location of pid file for specified port. If clustered and pid_file option
227
- # is specified, it adds the port value to the path.
286
+ # is specified, it adds the port/socket value to the path.
287
+ #
288
+ # @api private
228
289
  def pid_file(port)
229
290
  pidfile = Merb::Config[:pid_file] || (Merb.log_path / "merb.%s.pid")
230
291
  pidfile % port
@@ -234,7 +295,9 @@ module Merb
234
295
  #
235
296
  # ==== Returns
236
297
  # Array::
237
- # List of pid file paths. If not clustered, array contains a single path.
298
+ # List of pid file paths. If not running clustered, the array contains a single path.
299
+ #
300
+ # @api private
238
301
  def pid_files
239
302
  if Merb::Config[:pid_file]
240
303
  if Merb::Config[:cluster]
@@ -250,34 +313,33 @@ module Merb
250
313
  # Change privileges of the process to the specified user and group.
251
314
  #
252
315
  # ==== Parameters
253
- # user<String>:: The user who should own the server process.
254
- # group<String>:: The group who should own the server process.
316
+ # user<String>:: The user to change the process to.
317
+ # group<String>:: The group to change the process to.
255
318
  #
256
319
  # ==== Alternatives
257
320
  # If group is left out, the user will be used as the group.
321
+ #
322
+ # @api private
258
323
  def _change_privilege(user, group=user)
259
-
260
324
  Merb.logger.warn! "Changing privileges to #{user}:#{group}"
261
325
 
262
326
  uid, gid = Process.euid, Process.egid
263
-
327
+
264
328
  begin
265
329
  target_uid = Etc.getpwnam(user).uid
266
330
  rescue ArgumentError => e
267
- Merb.fatal!(
268
- "You tried to use user #{user}, but no such user was found", e)
331
+ Merb.fatal!("Failed to change to user #{user}, does the user exist?", e)
269
332
  return false
270
333
  end
271
-
334
+
272
335
  begin
273
336
  target_gid = Etc.getgrnam(group).gid
274
337
  rescue ArgumentError => e
275
- Merb.fatal!(
276
- "You tried to use group #{group}, but no such group was found", e)
338
+ Merb.fatal!("Failed to change to group #{group}, does the group exist?", e)
277
339
  return false
278
340
  end
279
341
 
280
- if uid != target_uid || gid != target_gid
342
+ if (uid != target_uid) || (gid != target_gid)
281
343
  # Change process ownership
282
344
  Process.initgroups(user, target_gid)
283
345
  Process::GID.change_privilege(target_gid)
@@ -285,24 +347,27 @@ module Merb
285
347
  end
286
348
  true
287
349
  rescue Errno::EPERM => e
288
- Merb.fatal! "Couldn't change user and group to #{user}:#{group}", e
350
+ Merb.fatal! "Permission denied for changing user:group to #{user}:#{group}.", e
289
351
  false
290
352
  end
291
-
353
+
354
+ # Add trap to enter IRB on SIGINT. Process exit if second SIGINT is received.
355
+ #
356
+ # @api private
292
357
  def add_irb_trap
293
- Merb.trap('INT') do
358
+ Merb.trap("INT") do
294
359
  if @interrupted
295
- puts "Exiting\n"
360
+ Merb.logger.warn! "Interrupt received a second time, exiting!\n"
296
361
  exit
297
362
  end
298
363
 
299
364
  @interrupted = true
300
- puts "Interrupt a second time to quit"
365
+ Merb.logger.warn! "Interrupt a second time to quit."
301
366
  Kernel.sleep 1.5
302
367
  ARGV.clear # Avoid passing args to IRB
303
368
 
304
369
  if @irb.nil?
305
- require 'irb'
370
+ require "irb"
306
371
  IRB.setup(nil)
307
372
  @irb = IRB::Irb.new(nil)
308
373
  IRB.conf[:MAIN_CONTEXT] = @irb.context
@@ -311,7 +376,7 @@ module Merb
311
376
  Merb.trap(:INT) { @irb.signal_handle }
312
377
  catch(:IRB_EXIT) { @irb.eval_input }
313
378
 
314
- puts "Exiting IRB mode, back in server mode"
379
+ Merb.logger.warn! "Exiting from IRB mode back into server mode."
315
380
  @interrupted = false
316
381
  add_irb_trap
317
382
  end