rails 1.1.6 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails might be problematic. Click here for more details.

Files changed (104) hide show
  1. data/CHANGELOG +267 -2
  2. data/MIT-LICENSE +1 -1
  3. data/README +62 -63
  4. data/Rakefile +26 -15
  5. data/bin/process/inspector +3 -0
  6. data/configs/databases/frontbase.yml +28 -0
  7. data/configs/databases/mysql.yml +3 -2
  8. data/configs/databases/oracle.yml +10 -1
  9. data/configs/databases/sqlite3.yml +3 -0
  10. data/configs/lighttpd.conf +1 -0
  11. data/configs/routes.rb +1 -0
  12. data/environments/boot.rb +4 -3
  13. data/environments/environment.rb +9 -2
  14. data/environments/production.rb +1 -1
  15. data/helpers/application.rb +5 -2
  16. data/html/404.html +27 -5
  17. data/html/500.html +27 -5
  18. data/html/javascripts/controls.js +41 -23
  19. data/html/javascripts/dragdrop.js +105 -76
  20. data/html/javascripts/effects.js +293 -163
  21. data/html/javascripts/prototype.js +897 -389
  22. data/lib/breakpoint.rb +31 -1
  23. data/lib/breakpoint_client.rb +5 -5
  24. data/lib/code_statistics.rb +1 -1
  25. data/lib/commands/performance/profiler.rb +25 -9
  26. data/lib/commands/plugin.rb +69 -23
  27. data/lib/commands/process/inspector.rb +68 -0
  28. data/lib/commands/process/reaper.rb +88 -69
  29. data/lib/commands/process/spawner.rb +148 -33
  30. data/lib/commands/runner.rb +27 -6
  31. data/lib/commands/server.rb +18 -9
  32. data/lib/commands/servers/base.rb +19 -0
  33. data/lib/commands/servers/lighttpd.rb +20 -18
  34. data/lib/commands/servers/mongrel.rb +65 -0
  35. data/lib/console_sandbox.rb +2 -2
  36. data/lib/dispatcher.rb +67 -11
  37. data/lib/fcgi_handler.rb +52 -34
  38. data/lib/initializer.rb +190 -111
  39. data/lib/rails/version.rb +2 -2
  40. data/lib/rails_generator/base.rb +82 -24
  41. data/lib/rails_generator/commands.rb +87 -25
  42. data/lib/rails_generator/generated_attribute.rb +42 -0
  43. data/lib/rails_generator/generators/applications/app/app_generator.rb +13 -10
  44. data/lib/rails_generator/generators/components/controller/controller_generator.rb +1 -2
  45. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +10 -8
  46. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +1 -1
  47. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +4 -4
  48. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +1 -1
  49. data/lib/rails_generator/generators/components/migration/templates/migration.rb +1 -1
  50. data/lib/rails_generator/generators/components/model/USAGE +19 -12
  51. data/lib/rails_generator/generators/components/model/model_generator.rb +4 -0
  52. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +8 -2
  53. data/lib/rails_generator/generators/components/model/templates/migration.rb +3 -1
  54. data/lib/rails_generator/generators/components/observer/USAGE +15 -0
  55. data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
  56. data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
  57. data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +10 -0
  58. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +4 -0
  59. data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
  60. data/lib/rails_generator/generators/components/resource/resource_generator.rb +76 -0
  61. data/lib/rails_generator/generators/components/resource/templates/USAGE +18 -0
  62. data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
  63. data/lib/rails_generator/generators/components/resource/templates/fixtures.yml +11 -0
  64. data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +20 -0
  65. data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
  66. data/lib/rails_generator/generators/components/resource/templates/migration.rb +13 -0
  67. data/lib/rails_generator/generators/components/resource/templates/model.rb +2 -0
  68. data/lib/rails_generator/generators/components/resource/templates/unit_test.rb +10 -0
  69. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +10 -1
  70. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +11 -7
  71. data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +5 -1
  72. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +2 -2
  73. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +1 -1
  74. data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +2 -2
  75. data/lib/rails_generator/generators/components/scaffold_resource/USAGE +29 -0
  76. data/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb +92 -0
  77. data/lib/rails_generator/generators/components/scaffold_resource/templates/controller.rb +79 -0
  78. data/lib/rails_generator/generators/components/scaffold_resource/templates/fixtures.yml +11 -0
  79. data/lib/rails_generator/generators/components/scaffold_resource/templates/functional_test.rb +57 -0
  80. data/lib/rails_generator/generators/components/scaffold_resource/templates/helper.rb +2 -0
  81. data/lib/rails_generator/generators/components/scaffold_resource/templates/layout.rhtml +17 -0
  82. data/lib/rails_generator/generators/components/scaffold_resource/templates/migration.rb +13 -0
  83. data/lib/rails_generator/generators/components/scaffold_resource/templates/model.rb +2 -0
  84. data/lib/rails_generator/generators/components/scaffold_resource/templates/style.css +74 -0
  85. data/lib/rails_generator/generators/components/scaffold_resource/templates/unit_test.rb +10 -0
  86. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_edit.rhtml +19 -0
  87. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_index.rhtml +24 -0
  88. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_new.rhtml +18 -0
  89. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_show.rhtml +10 -0
  90. data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +7 -1
  91. data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +5 -4
  92. data/lib/rails_generator/lookup.rb +1 -2
  93. data/lib/rails_generator/options.rb +6 -3
  94. data/lib/tasks/databases.rake +46 -20
  95. data/lib/tasks/documentation.rake +1 -0
  96. data/lib/tasks/framework.rake +1 -3
  97. data/lib/tasks/pre_namespace_aliases.rake +34 -27
  98. data/lib/tasks/rails.rb +2 -2
  99. data/lib/tasks/statistics.rake +6 -5
  100. data/lib/tasks/testing.rake +28 -13
  101. data/lib/tasks/tmp.rake +8 -1
  102. data/lib/test_help.rb +3 -2
  103. data/lib/webrick_server.rb +6 -8
  104. metadata +50 -9
@@ -1,6 +1,6 @@
1
- ActiveRecord::Base.lock_mutex
1
+ ActiveRecord::Base.send :increment_open_transactions
2
2
  ActiveRecord::Base.connection.begin_db_transaction
3
3
  at_exit do
4
4
  ActiveRecord::Base.connection.rollback_db_transaction
5
- ActiveRecord::Base.unlock_mutex
5
+ ActiveRecord::Base.send :decrement_open_transactions
6
6
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2006 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -25,6 +25,7 @@
25
25
  # to the appropriate controller and action. It also takes care of resetting
26
26
  # the environment (when Dependencies.load? is true) after each request.
27
27
  class Dispatcher
28
+
28
29
  class << self
29
30
 
30
31
  # Dispatch the given CGI request, using the given session options, and
@@ -32,14 +33,18 @@ class Dispatcher
32
33
  # own CGI object be sure to handle the exceptions it raises on multipart
33
34
  # requests (EOFError and ArgumentError).
34
35
  def dispatch(cgi = nil, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
36
+ controller = nil
35
37
  if cgi ||= new_cgi(output)
36
38
  request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
37
39
  prepare_application
38
- ActionController::Routing::Routes.recognize!(request).process(request, response).out(output)
40
+ controller = ActionController::Routing::Routes.recognize(request)
41
+ controller.process(request, response).out(output)
39
42
  end
40
- rescue Object => exception
43
+ rescue Exception => exception # errors from CGI dispatch
41
44
  failsafe_response(output, '500 Internal Server Error', exception) do
42
- ActionController::Base.process_with_exception(request, response, exception).out(output)
45
+ controller ||= ApplicationController rescue LoadError nil
46
+ controller ||= ActionController::Base
47
+ controller.process_with_exception(request, response, exception).out(output)
43
48
  end
44
49
  ensure
45
50
  # Do not give a failsafe response here.
@@ -50,12 +55,44 @@ class Dispatcher
50
55
  # mailers, and so forth. This allows them to be loaded again without having
51
56
  # to restart the server (WEBrick, FastCGI, etc.).
52
57
  def reset_application!
58
+ ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
59
+
53
60
  Dependencies.clear
54
- ActiveRecord::Base.reset_subclasses
55
- Class.remove_class(*Reloadable.reloadable_classes)
61
+ ActiveSupport::Deprecation.silence do # TODO: Remove after 1.2
62
+ Class.remove_class(*Reloadable.reloadable_classes)
63
+ end
64
+
65
+ ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
66
+ end
67
+
68
+ # Add a preparation callback. Preparation callbacks are run before every
69
+ # request in development mode, and before the first request in production
70
+ # mode.
71
+ #
72
+ # An optional identifier may be supplied for the callback. If provided,
73
+ # to_prepare may be called again with the same identifier to replace the
74
+ # existing callback. Passing an identifier is a suggested practice if the
75
+ # code adding a preparation block may be reloaded.
76
+ def to_prepare(identifier = nil, &block)
77
+ unless identifier.nil?
78
+ callback = preparation_callbacks.detect { |ident, _| ident == identifier }
79
+
80
+ if callback # Already registered: update the existing callback
81
+ callback[-1] = block
82
+ return
83
+ end
84
+ end
85
+
86
+ preparation_callbacks << [identifier, block]
87
+
88
+ return
56
89
  end
57
90
 
58
91
  private
92
+
93
+ attr_accessor :preparation_callbacks, :preparation_callbacks_run
94
+ alias_method :preparation_callbacks_run?, :preparation_callbacks_run
95
+
59
96
  # CGI.new plus exception handling. CGI#read_multipart raises EOFError
60
97
  # if body.empty? or body.size != Content-Length and raises ArgumentError
61
98
  # if Content-Length is non-integer.
@@ -64,10 +101,15 @@ class Dispatcher
64
101
  end
65
102
 
66
103
  def prepare_application
67
- ActionController::Routing::Routes.reload if Dependencies.load?
104
+ if Dependencies.load?
105
+ ActionController::Routing::Routes.reload
106
+ self.preparation_callbacks_run = false
107
+ end
108
+
68
109
  prepare_breakpoint
69
- require_dependency('application.rb') unless Object.const_defined?(:ApplicationController)
70
- ActiveRecord::Base.verify_active_connections!
110
+ require_dependency 'application' unless Object.const_defined?(:ApplicationController)
111
+ ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)
112
+ run_preparation_callbacks
71
113
  end
72
114
 
73
115
  def reset_after_dispatch
@@ -84,10 +126,16 @@ class Dispatcher
84
126
  nil
85
127
  end
86
128
 
129
+ def run_preparation_callbacks
130
+ return if preparation_callbacks_run?
131
+ preparation_callbacks.each { |_, callback| callback.call }
132
+ self.preparation_callbacks_run = true
133
+ end
134
+
87
135
  # If the block raises, send status code as a last-ditch response.
88
136
  def failsafe_response(output, status, exception = nil)
89
137
  yield
90
- rescue Object
138
+ rescue Exception # errors from executed block
91
139
  begin
92
140
  output.write "Status: #{status}\r\n"
93
141
 
@@ -110,8 +158,16 @@ class Dispatcher
110
158
  output.write(message)
111
159
  end
112
160
  end
113
- rescue Object
161
+ rescue Exception # Logger or IO errors
114
162
  end
115
163
  end
116
164
  end
165
+
166
+ self.preparation_callbacks = []
167
+ self.preparation_callbacks_run = false
168
+
117
169
  end
170
+
171
+ Dispatcher.to_prepare :activerecord_instantiate_observers do
172
+ ActiveRecord::Base.instantiate_observers
173
+ end if defined?(ActiveRecord)
@@ -6,11 +6,13 @@ require 'rbconfig'
6
6
  class RailsFCGIHandler
7
7
  SIGNALS = {
8
8
  'HUP' => :reload,
9
+ 'INT' => :exit_now,
9
10
  'TERM' => :exit_now,
10
11
  'USR1' => :exit,
11
12
  'USR2' => :restart,
12
13
  'SIGTRAP' => :breakpoint
13
14
  }
15
+ GLOBAL_SIGNALS = SIGNALS.keys - %w(USR1)
14
16
 
15
17
  attr_reader :when_ready
16
18
 
@@ -50,25 +52,7 @@ class RailsFCGIHandler
50
52
 
51
53
  run_gc! if gc_request_period
52
54
 
53
- provider.each_cgi do |cgi|
54
- process_request(cgi)
55
-
56
- case when_ready
57
- when :reload
58
- reload!
59
- when :restart
60
- close_connection(cgi)
61
- restart!
62
- when :exit
63
- close_connection(cgi)
64
- break
65
- when :breakpoint
66
- close_connection(cgi)
67
- breakpoint!
68
- end
69
-
70
- gc_countdown
71
- end
55
+ process_each_request!(provider)
72
56
 
73
57
  GC.enable
74
58
  dispatcher_log :info, "terminated gracefully"
@@ -76,7 +60,7 @@ class RailsFCGIHandler
76
60
  rescue SystemExit => exit_error
77
61
  dispatcher_log :info, "terminated by explicit exit"
78
62
 
79
- rescue Object => fcgi_error
63
+ rescue Exception => fcgi_error # FCGI errors
80
64
  # retry on errors that would otherwise have terminated the FCGI process,
81
65
  # but only if they occur more than 10 seconds apart.
82
66
  if !(SignalException === fcgi_error) && Time.now - @last_error_on > 10
@@ -87,9 +71,9 @@ class RailsFCGIHandler
87
71
  dispatcher_error(fcgi_error, "killed by this error")
88
72
  end
89
73
  end
90
-
91
-
92
- private
74
+
75
+
76
+ protected
93
77
  def logger
94
78
  @logger ||= Logger.new(@log_file_path)
95
79
  end
@@ -97,7 +81,7 @@ class RailsFCGIHandler
97
81
  def dispatcher_log(level, msg)
98
82
  time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S")
99
83
  logger.send(level, "[#{time_str} :: #{$$}] #{msg}")
100
- rescue Object => log_error
84
+ rescue Exception => log_error # Logger errors
101
85
  STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n"
102
86
  STDERR << " #{log_error.class}: #{log_error.message}\n"
103
87
  end
@@ -110,17 +94,23 @@ class RailsFCGIHandler
110
94
  end
111
95
 
112
96
  def install_signal_handlers
113
- SIGNALS.each do |signal, handler_name|
114
- install_signal_handler(signal, method("#{handler_name}_handler").to_proc)
115
- end
97
+ GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) }
116
98
  end
117
99
 
118
- def install_signal_handler(signal, handler)
100
+ def install_signal_handler(signal, handler = nil)
101
+ handler ||= method("#{SIGNALS[signal]}_handler").to_proc
119
102
  trap(signal, handler)
120
103
  rescue ArgumentError
121
104
  dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
122
105
  end
123
106
 
107
+ def with_signal_handler(signal)
108
+ install_signal_handler(signal)
109
+ yield
110
+ ensure
111
+ install_signal_handler(signal, 'DEFAULT')
112
+ end
113
+
124
114
  def exit_now_handler(signal)
125
115
  dispatcher_log :info, "asked to terminate immediately"
126
116
  exit
@@ -146,9 +136,37 @@ class RailsFCGIHandler
146
136
  @when_ready = :breakpoint
147
137
  end
148
138
 
139
+ def process_each_request!(provider)
140
+ cgi = nil
141
+ provider.each_cgi do |cgi|
142
+ with_signal_handler 'USR1' do
143
+ process_request(cgi)
144
+ end
145
+
146
+ case when_ready
147
+ when :reload
148
+ reload!
149
+ when :restart
150
+ close_connection(cgi)
151
+ restart!
152
+ when :exit
153
+ close_connection(cgi)
154
+ break
155
+ when :breakpoint
156
+ close_connection(cgi)
157
+ breakpoint!
158
+ end
159
+
160
+ gc_countdown
161
+ end
162
+ rescue SignalException => signal
163
+ raise unless signal.message == 'SIGUSR1'
164
+ close_connection(cgi) if cgi
165
+ end
166
+
149
167
  def process_request(cgi)
150
168
  Dispatcher.dispatch(cgi)
151
- rescue Object => e
169
+ rescue Exception => e # errors from CGI dispatch
152
170
  raise if SignalException === e
153
171
  dispatcher_error(e)
154
172
  end
@@ -157,7 +175,7 @@ class RailsFCGIHandler
157
175
  config = ::Config::CONFIG
158
176
  ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
159
177
  command_line = [ruby, $0, ARGV].flatten.join(' ')
160
-
178
+
161
179
  dispatcher_log :info, "restarted"
162
180
 
163
181
  exec(command_line)
@@ -179,7 +197,7 @@ class RailsFCGIHandler
179
197
  Dispatcher.reset_application!
180
198
  ActionController::Routing::Routes.reload
181
199
  end
182
-
200
+
183
201
  def breakpoint!
184
202
  require 'breakpoint'
185
203
  port = defined?(BREAKPOINT_SERVER_PORT) ? BREAKPOINT_SERVER_PORT : 42531
@@ -193,15 +211,15 @@ class RailsFCGIHandler
193
211
  @gc_request_countdown = gc_request_period
194
212
  GC.enable; GC.start; GC.disable
195
213
  end
196
-
214
+
197
215
  def gc_countdown
198
216
  if gc_request_period
199
217
  @gc_request_countdown -= 1
200
218
  run_gc! if @gc_request_countdown <= 0
201
219
  end
202
220
  end
203
-
221
+
204
222
  def close_connection(cgi)
205
223
  cgi.instance_variable_get("@request").finish
206
224
  end
207
- end
225
+ end
@@ -1,6 +1,7 @@
1
1
  require 'logger'
2
2
  require 'set'
3
3
  require File.join(File.dirname(__FILE__), 'railties_path')
4
+ require File.join(File.dirname(__FILE__), 'rails/version')
4
5
 
5
6
  RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
6
7
 
@@ -35,19 +36,19 @@ module Rails
35
36
  # Rails::Initializer.run(:set_load_path)
36
37
  #
37
38
  # This is useful if you only want the load path initialized, without
38
- # incuring the overhead of completely loading the entire environment.
39
+ # incuring the overhead of completely loading the entire environment.
39
40
  def self.run(command = :process, configuration = Configuration.new)
40
41
  yield configuration if block_given?
41
42
  initializer = new configuration
42
43
  initializer.send(command)
43
44
  initializer
44
45
  end
45
-
46
+
46
47
  # Create a new Initializer instance that references the given Configuration
47
48
  # instance.
48
49
  def initialize(configuration)
49
50
  @configuration = configuration
50
- @loaded_plugins = Set.new
51
+ @loaded_plugins = []
51
52
  end
52
53
 
53
54
  # Sequentially step through all of the available initialization routines,
@@ -67,20 +68,23 @@ module Rails
67
68
  # * #initialize_framework_settings
68
69
  # * #load_environment
69
70
  # * #load_plugins
71
+ # * #load_observers
70
72
  # * #initialize_routing
71
73
  #
72
74
  # (Note that #load_environment is invoked twice, once at the start and
73
75
  # once at the end, to support the legacy configuration style where the
74
76
  # environment could overwrite the defaults directly, instead of via the
75
- # Configuration instance.
77
+ # Configuration instance.
76
78
  def process
77
79
  check_ruby_version
78
80
  set_load_path
79
81
  set_connection_adapters
80
82
 
81
83
  require_frameworks
84
+ set_autoload_paths
82
85
  load_environment
83
86
 
87
+ initialize_encoding
84
88
  initialize_database
85
89
  initialize_logger
86
90
  initialize_framework_logging
@@ -89,21 +93,23 @@ module Rails
89
93
  initialize_breakpoints
90
94
  initialize_whiny_nils
91
95
  initialize_temporary_directories
92
-
93
96
  initialize_framework_settings
94
-
97
+
95
98
  # Support for legacy configuration style where the environment
96
99
  # could overwrite anything set from the defaults/global through
97
100
  # the individual base class configurations.
98
101
  load_environment
99
-
102
+
100
103
  add_support_load_paths
101
104
 
102
105
  load_plugins
103
106
 
107
+ # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
108
+ load_observers
109
+
104
110
  # Routing must be initialized after plugins to allow the former to extend the routes
105
111
  initialize_routing
106
-
112
+
107
113
  # the framework is now fully initialized
108
114
  after_initialize
109
115
  end
@@ -111,17 +117,36 @@ module Rails
111
117
  # Check for valid Ruby version
112
118
  # This is done in an external file, so we can use it
113
119
  # from the `rails` program as well without duplication.
114
- def check_ruby_version
120
+ def check_ruby_version
115
121
  require 'ruby_version_check'
116
122
  end
117
123
 
118
124
  # Set the <tt>$LOAD_PATH</tt> based on the value of
119
125
  # Configuration#load_paths. Duplicates are removed.
120
126
  def set_load_path
121
- configuration.load_paths.reverse.each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
127
+ load_paths = configuration.load_paths + configuration.framework_paths
128
+ load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
122
129
  $LOAD_PATH.uniq!
123
130
  end
124
-
131
+
132
+ # Set the paths from which Rails will automatically load source files, and
133
+ # the load_once paths.
134
+ def set_autoload_paths
135
+ Dependencies.load_paths = configuration.load_paths.uniq
136
+ Dependencies.load_once_paths = configuration.load_once_paths.uniq
137
+
138
+ extra = Dependencies.load_once_paths - Dependencies.load_paths
139
+ unless extra.empty?
140
+ abort <<-end_error
141
+ load_once_paths must be a subset of the load_paths.
142
+ Extra items in load_once_paths: #{extra * ','}
143
+ end_error
144
+ end
145
+
146
+ # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
147
+ configuration.load_once_paths.freeze
148
+ end
149
+
125
150
  # Sets the +RAILS_CONNECTION_ADAPTERS+ constant based on the value of
126
151
  # Configuration#connection_adapters. This constant is used to determine
127
152
  # which database adapters should be loaded (by default, all adapters are
@@ -129,18 +154,16 @@ module Rails
129
154
  def set_connection_adapters
130
155
  Object.const_set("RAILS_CONNECTION_ADAPTERS", configuration.connection_adapters) if configuration.connection_adapters
131
156
  end
132
-
157
+
133
158
  # Requires all frameworks specified by the Configuration#frameworks
134
159
  # list. By default, all frameworks (ActiveRecord, ActiveSupport,
135
160
  # ActionPack, ActionMailer, and ActionWebService) are loaded.
136
161
  def require_frameworks
137
162
  configuration.frameworks.each { |framework| require(framework.to_s) }
138
163
  end
139
-
164
+
140
165
  # Add the load paths used by support functions such as the info controller
141
166
  def add_support_load_paths
142
- builtins = File.join(File.dirname(File.dirname(__FILE__)), 'builtin', '*')
143
- $LOAD_PATH.concat(Dir[builtins])
144
167
  end
145
168
 
146
169
  # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
@@ -153,9 +176,22 @@ module Rails
153
176
  # * evaluate <tt>init.rb</tt> if present
154
177
  #
155
178
  # After all plugins are loaded, duplicates are removed from the load path.
156
- # Plugins are loaded in alphabetical order.
179
+ # If an array of plugin names is specified in config.plugins, the plugins
180
+ # will be loaded in that order. Otherwise, plugins are loaded in alphabetical
181
+ # order.
157
182
  def load_plugins
158
- find_plugins(configuration.plugin_paths).sort.each { |path| load_plugin path }
183
+ if configuration.plugins.nil?
184
+ # a nil value implies we don't care about plugins; load 'em all in a reliable order
185
+ find_plugins(configuration.plugin_paths).sort.each { |path| load_plugin path }
186
+ elsif !configuration.plugins.empty?
187
+ # we've specified a config.plugins array, so respect that order
188
+ plugin_paths = find_plugins(configuration.plugin_paths)
189
+ configuration.plugins.each do |name|
190
+ path = plugin_paths.find { |p| File.basename(p) == name }
191
+ raise(LoadError, "Cannot find the plugin '#{name}'!") if path.nil?
192
+ load_plugin path
193
+ end
194
+ end
159
195
  $LOAD_PATH.uniq!
160
196
  end
161
197
 
@@ -165,13 +201,24 @@ module Rails
165
201
  silence_warnings do
166
202
  config = configuration
167
203
  constants = self.class.constants
168
- eval(IO.read(configuration.environment_path), binding)
204
+ eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
169
205
  (self.class.constants - constants).each do |const|
170
206
  Object.const_set(const, self.class.const_get(const))
171
207
  end
172
208
  end
173
209
  end
174
-
210
+
211
+ def load_observers
212
+ ActiveRecord::Base.instantiate_observers
213
+ end
214
+
215
+ # This initialzation sets $KCODE to 'u' to enable the multibyte safe operations.
216
+ # Plugin authors supporting other encodings should override this behaviour and
217
+ # set the relevant +default_charset+ on ActionController::Base
218
+ def initialize_encoding
219
+ $KCODE='u'
220
+ end
221
+
175
222
  # This initialization routine does nothing unless <tt>:active_record</tt>
176
223
  # is one of the frameworks to load (Configuration#frameworks). If it is,
177
224
  # this sets the database configuration from Configuration#database_configuration
@@ -181,7 +228,7 @@ module Rails
181
228
  ActiveRecord::Base.configurations = configuration.database_configuration
182
229
  ActiveRecord::Base.establish_connection
183
230
  end
184
-
231
+
185
232
  # If the +RAILS_DEFAULT_LOGGER+ constant is already set, this initialization
186
233
  # routine does nothing. If the constant is not set, and Configuration#logger
187
234
  # is not +nil+, this also does nothing. Otherwise, a new logger instance
@@ -207,10 +254,10 @@ module Rails
207
254
  )
208
255
  end
209
256
  end
210
-
257
+
211
258
  silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
212
259
  end
213
-
260
+
214
261
  # Sets the logger for ActiveRecord, ActionController, and ActionMailer
215
262
  # (but only for those frameworks that are to be loaded). If the framework's
216
263
  # logger is already set, it is not changed, otherwise it is set to use
@@ -220,7 +267,7 @@ module Rails
220
267
  framework.to_s.camelize.constantize.const_get("Base").logger ||= RAILS_DEFAULT_LOGGER
221
268
  end
222
269
  end
223
-
270
+
224
271
  # Sets the +template_root+ for ActionController::Base and ActionMailer::Base
225
272
  # (but only for those frameworks that are to be loaded). If the framework's
226
273
  # +template_root+ has already been set, it is not changed, otherwise it is
@@ -236,15 +283,16 @@ module Rails
236
283
  # loading module used to lazily load controllers (Configuration#controller_paths).
237
284
  def initialize_routing
238
285
  return unless configuration.frameworks.include?(:action_controller)
286
+ ActionController::Routing.controller_paths = configuration.controller_paths
239
287
  ActionController::Routing::Routes.reload
240
288
  end
241
-
289
+
242
290
  # Sets the dependency loading mechanism based on the value of
243
291
  # Configuration#cache_classes.
244
292
  def initialize_dependency_mechanism
245
293
  Dependencies.mechanism = configuration.cache_classes ? :require : :load
246
294
  end
247
-
295
+
248
296
  # Sets the +BREAKPOINT_SERVER_PORT+ if Configuration#breakpoint_server
249
297
  # is true.
250
298
  def initialize_breakpoints
@@ -261,7 +309,7 @@ module Rails
261
309
  if configuration.frameworks.include?(:action_controller)
262
310
  session_path = "#{RAILS_ROOT}/tmp/sessions/"
263
311
  ActionController::Base.session_options[:tmpdir] = File.exist?(session_path) ? session_path : Dir::tmpdir
264
-
312
+
265
313
  cache_path = "#{RAILS_ROOT}/tmp/cache/"
266
314
  if File.exist?(cache_path)
267
315
  ActionController::Base.fragment_cache_store = :file_store, cache_path
@@ -281,12 +329,11 @@ module Rails
281
329
  end
282
330
  end
283
331
  end
284
-
285
- # Fires the user-supplied after_initialize block (Configuration#after_initialize)
332
+
333
+ # Fires the user-supplied after_initialize block (Configuration#after_initialize)
286
334
  def after_initialize
287
335
  configuration.after_initialize_block.call if configuration.after_initialize_block
288
336
  end
289
-
290
337
 
291
338
  protected
292
339
  # Return a list of plugin paths within base_path. A plugin path is
@@ -297,7 +344,7 @@ module Rails
297
344
  base_paths.flatten.inject([]) do |plugins, base_path|
298
345
  Dir.glob(File.join(base_path, '*')).each do |path|
299
346
  if plugin_path?(path)
300
- plugins << path
347
+ plugins << path if plugin_enabled?(path)
301
348
  elsif File.directory?(path)
302
349
  plugins += find_plugins(path)
303
350
  end
@@ -310,6 +357,10 @@ module Rails
310
357
  File.directory?(path) and (File.directory?(File.join(path, 'lib')) or File.file?(File.join(path, 'init.rb')))
311
358
  end
312
359
 
360
+ def plugin_enabled?(path)
361
+ configuration.plugins.nil? || configuration.plugins.include?(File.basename(path))
362
+ end
363
+
313
364
  # Load the plugin at <tt>path</tt> unless already loaded.
314
365
  #
315
366
  # Each plugin is initialized:
@@ -334,12 +385,14 @@ module Rails
334
385
  # Add lib to load path *after* the application lib, to allow
335
386
  # application libraries to override plugin libraries.
336
387
  if has_lib
337
- application_lib_index = $LOAD_PATH.index(File.join(RAILS_ROOT, "lib")) || 0
388
+ application_lib_index = $LOAD_PATH.index(File.join(RAILS_ROOT, "lib")) || 0
338
389
  $LOAD_PATH.insert(application_lib_index + 1, lib_path)
390
+ Dependencies.load_paths << lib_path
391
+ Dependencies.load_once_paths << lib_path
339
392
  end
340
393
 
341
394
  # Allow plugins to reference the current configuration object
342
- config = configuration
395
+ config = configuration
343
396
 
344
397
  # Add to set of loaded plugins before 'name' collapsed in eval.
345
398
  loaded_plugins << name
@@ -363,31 +416,31 @@ module Rails
363
416
  class Configuration
364
417
  # A stub for setting options on ActionController::Base
365
418
  attr_accessor :action_controller
366
-
419
+
367
420
  # A stub for setting options on ActionMailer::Base
368
421
  attr_accessor :action_mailer
369
-
422
+
370
423
  # A stub for setting options on ActionView::Base
371
424
  attr_accessor :action_view
372
-
425
+
373
426
  # A stub for setting options on ActionWebService::Base
374
427
  attr_accessor :action_web_service
375
-
428
+
376
429
  # A stub for setting options on ActiveRecord::Base
377
430
  attr_accessor :active_record
378
-
431
+
379
432
  # Whether or not to use the breakpoint server (boolean)
380
433
  attr_accessor :breakpoint_server
381
-
434
+
382
435
  # Whether or not classes should be cached (set to false if you want
383
436
  # application classes to be reloaded on each request)
384
437
  attr_accessor :cache_classes
385
-
438
+
386
439
  # The list of connection adapters to load. (By default, all connection
387
440
  # adapters are loaded. You can set this to be just the adapter(s) you
388
441
  # will use to reduce your application's load time.)
389
442
  attr_accessor :connection_adapters
390
-
443
+
391
444
  # The list of paths that should be searched for controllers. (Defaults
392
445
  # to <tt>app/controllers</tt> and <tt>components</tt>.)
393
446
  attr_accessor :controller_paths
@@ -395,39 +448,48 @@ module Rails
395
448
  # The path to the database configuration file to use. (Defaults to
396
449
  # <tt>config/database.yml</tt>.)
397
450
  attr_accessor :database_configuration_file
398
-
451
+
399
452
  # The list of rails framework components that should be loaded. (Defaults
400
453
  # to <tt>:active_record</tt>, <tt>:action_controller</tt>,
401
454
  # <tt>:action_view</tt>, <tt>:action_mailer</tt>, and
402
455
  # <tt>:action_web_service</tt>).
403
456
  attr_accessor :frameworks
404
-
457
+
405
458
  # An array of additional paths to prepend to the load path. By default,
406
459
  # all +app+, +lib+, +vendor+ and mock paths are included in this list.
407
460
  attr_accessor :load_paths
408
-
461
+
462
+ # An array of paths from which Rails will automatically load from only once.
463
+ # All elements of this array must also be in +load_paths+.
464
+ attr_accessor :load_once_paths
465
+
409
466
  # The log level to use for the default Rails logger. In production mode,
410
467
  # this defaults to <tt>:info</tt>. In development mode, it defaults to
411
468
  # <tt>:debug</tt>.
412
469
  attr_accessor :log_level
413
-
470
+
414
471
  # The path to the log file to use. Defaults to log/#{environment}.log
415
472
  # (e.g. log/development.log or log/production.log).
416
473
  attr_accessor :log_path
417
-
474
+
418
475
  # The specific logger to use. By default, a logger will be created and
419
476
  # initialized using #log_path and #log_level, but a programmer may
420
477
  # specifically set the logger to use via this accessor and it will be
421
478
  # used directly.
422
479
  attr_accessor :logger
423
-
480
+
424
481
  # The root of the application's views. (Defaults to <tt>app/views</tt>.)
425
482
  attr_accessor :view_path
426
-
483
+
427
484
  # Set to +true+ if you want to be warned (noisily) when you try to invoke
428
485
  # any method of +nil+. Set to +false+ for the standard Ruby behavior.
429
486
  attr_accessor :whiny_nils
430
-
487
+
488
+ # The list of plugins to load. If this is set to <tt>nil</tt>, all plugins will
489
+ # be loaded. If this is set to <tt>[]</tt>, no plugins will be loaded. Otherwise,
490
+ # plugins will be loaded in the order specified.
491
+ attr_accessor :plugins
492
+
431
493
  # The path to the root of the plugins directory. By default, it is in
432
494
  # <tt>vendor/plugins</tt>.
433
495
  attr_accessor :plugin_paths
@@ -437,6 +499,7 @@ module Rails
437
499
  def initialize
438
500
  self.frameworks = default_frameworks
439
501
  self.load_paths = default_load_paths
502
+ self.load_once_paths = default_load_once_paths
440
503
  self.log_path = default_log_path
441
504
  self.log_level = default_log_level
442
505
  self.view_path = default_view_path
@@ -444,21 +507,22 @@ module Rails
444
507
  self.cache_classes = default_cache_classes
445
508
  self.breakpoint_server = default_breakpoint_server
446
509
  self.whiny_nils = default_whiny_nils
510
+ self.plugins = default_plugins
447
511
  self.plugin_paths = default_plugin_paths
448
512
  self.database_configuration_file = default_database_configuration_file
449
513
 
450
514
  for framework in default_frameworks
451
- self.send("#{framework}=", OrderedOptions.new)
515
+ self.send("#{framework}=", Rails::OrderedOptions.new)
452
516
  end
453
517
  end
454
-
518
+
455
519
  # Loads and returns the contents of the #database_configuration_file. The
456
520
  # contents of the file are processed via ERB before being sent through
457
521
  # YAML::load.
458
522
  def database_configuration
459
523
  YAML::load(ERB.new(IO.read(database_configuration_file)).result)
460
524
  end
461
-
525
+
462
526
  # The path to the current environment's file (development.rb, etc.). By
463
527
  # default the file is at <tt>config/environments/#{environment}.rb</tt>.
464
528
  def environment_path
@@ -470,19 +534,45 @@ module Rails
470
534
  def environment
471
535
  ::RAILS_ENV
472
536
  end
473
-
537
+
474
538
  # Sets a block which will be executed after rails has been fully initialized.
475
- # Useful for per-environment configuration which depends on the framework being
539
+ # Useful for per-environment configuration which depends on the framework being
476
540
  # fully initialized.
477
541
  def after_initialize(&after_initialize_block)
478
542
  @after_initialize_block = after_initialize_block
479
543
  end
480
-
544
+
481
545
  # Returns the block set in Configuration#after_initialize
482
546
  def after_initialize_block
483
547
  @after_initialize_block
484
548
  end
485
-
549
+
550
+ # Add a preparation callback that will run before every request in development
551
+ # mode, or before the first request in production.
552
+ #
553
+ # See Dispatcher#to_prepare.
554
+ def to_prepare(&callback)
555
+ Dispatcher.to_prepare(&callback)
556
+ end
557
+
558
+ def builtin_directories
559
+ # Include builtins only in the development environment.
560
+ (environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
561
+ end
562
+
563
+ def framework_paths
564
+ # TODO: Don't include dirs for frameworks that are not used
565
+ %w(
566
+ railties
567
+ railties/lib
568
+ actionpack/lib
569
+ activesupport/lib
570
+ activerecord/lib
571
+ actionmailer/lib
572
+ actionwebservice/lib
573
+ ).map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
574
+ end
575
+
486
576
  private
487
577
  def root_path
488
578
  ::RAILS_ROOT
@@ -495,80 +585,80 @@ module Rails
495
585
  def default_frameworks
496
586
  [ :active_record, :action_controller, :action_view, :action_mailer, :action_web_service ]
497
587
  end
498
-
588
+
499
589
  def default_load_paths
500
590
  paths = ["#{root_path}/test/mocks/#{environment}"]
501
-
591
+
502
592
  # Add the app's controller directory
503
593
  paths.concat(Dir["#{root_path}/app/controllers/"])
504
594
 
505
- # Then model subdirectories.
506
- # TODO: Don't include .rb models as load paths
507
- paths.concat(Dir["#{root_path}/app/models/[_a-z]*"])
595
+ # Then components subdirectories.
508
596
  paths.concat(Dir["#{root_path}/components/[_a-z]*"])
509
597
 
510
598
  # Followed by the standard includes.
511
599
  paths.concat %w(
512
- app
513
- app/models
600
+ app
601
+ app/models
514
602
  app/controllers
515
603
  app/helpers
516
604
  app/services
517
- app/apis
518
- components
519
- config
520
- lib
521
- vendor
605
+ app/apis
606
+ components
607
+ config
608
+ lib
609
+ vendor
522
610
  ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
523
611
 
524
- # TODO: Don't include dirs for frameworks that are not used
525
- paths.concat %w(
526
- railties
527
- railties/lib
528
- actionpack/lib
529
- activesupport/lib
530
- activerecord/lib
531
- actionmailer/lib
532
- actionwebservice/lib
533
- ).map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
612
+ paths.concat builtin_directories
613
+ end
614
+
615
+ # Doesn't matter since plugins aren't in load_paths yet.
616
+ def default_load_once_paths
617
+ []
534
618
  end
535
619
 
536
620
  def default_log_path
537
621
  File.join(root_path, 'log', "#{environment}.log")
538
622
  end
539
-
623
+
540
624
  def default_log_level
541
625
  environment == 'production' ? :info : :debug
542
626
  end
543
-
627
+
544
628
  def default_database_configuration_file
545
629
  File.join(root_path, 'config', 'database.yml')
546
630
  end
547
-
631
+
548
632
  def default_view_path
549
633
  File.join(root_path, 'app', 'views')
550
634
  end
551
-
635
+
552
636
  def default_controller_paths
553
- [ File.join(root_path, 'app', 'controllers'), File.join(root_path, 'components'), File.join(RAILTIES_PATH, 'builtin', 'controllers') ]
637
+ paths = [ File.join(root_path, 'app', 'controllers'), File.join(root_path, 'components') ]
638
+ paths.concat builtin_directories
639
+ paths
554
640
  end
555
-
641
+
556
642
  def default_dependency_mechanism
557
643
  :load
558
644
  end
559
-
645
+
560
646
  def default_cache_classes
561
647
  false
562
648
  end
563
-
649
+
564
650
  def default_breakpoint_server
565
651
  false
566
652
  end
567
-
653
+
568
654
  def default_whiny_nils
569
655
  false
570
656
  end
571
657
 
658
+ def default_plugins
659
+ nil
660
+ end
661
+
572
662
  def default_plugin_paths
573
663
  ["#{root_path}/vendor/plugins"]
574
664
  end
@@ -576,9 +666,12 @@ module Rails
576
666
  end
577
667
 
578
668
  # Needs to be duplicated from Active Support since its needed before Active
579
- # Support is available.
580
- class OrderedHash < Array #:nodoc:
581
- def []=(key, value)
669
+ # Support is available. Here both Options and Hash are namespaced to prevent
670
+ # conflicts with other implementations AND with the classes residing in ActiveSupport.
671
+ class Rails::OrderedOptions < Array #:nodoc:
672
+ def []=(key, value)
673
+ key = key.to_sym
674
+
582
675
  if pair = find_pair(key)
583
676
  pair.pop
584
677
  pair << value
@@ -586,14 +679,18 @@ class OrderedHash < Array #:nodoc:
586
679
  self << [key, value]
587
680
  end
588
681
  end
589
-
682
+
590
683
  def [](key)
591
- pair = find_pair(key)
684
+ pair = find_pair(key.to_sym)
592
685
  pair ? pair.last : nil
593
686
  end
594
687
 
595
- def keys
596
- self.collect { |i| i.first }
688
+ def method_missing(name, *args)
689
+ if name.to_s =~ /(.*)=$/
690
+ self[$1.to_sym] = args.first
691
+ else
692
+ self[name]
693
+ end
597
694
  end
598
695
 
599
696
  private
@@ -602,21 +699,3 @@ class OrderedHash < Array #:nodoc:
602
699
  return false
603
700
  end
604
701
  end
605
-
606
- class OrderedOptions < OrderedHash #:nodoc:
607
- def []=(key, value)
608
- super(key.to_sym, value)
609
- end
610
-
611
- def [](key)
612
- super(key.to_sym)
613
- end
614
-
615
- def method_missing(name, *args)
616
- if name.to_s =~ /(.*)=$/
617
- self[$1.to_sym] = args.first
618
- else
619
- self[name]
620
- end
621
- end
622
- end