1 require 'singleton'
2 require 'active_record'
3 require 'action_controller'
4 require 'action_mailer'
5 require 'action_view'
6 require 'yaml'
7 require 'needle'
8
9 require File.join(File.dirname(__FILE__), 'base-enhance')
10
11 module Rails
12
13 # A simple subclass of the Needle registry class, to make it easier to add
14 # component-specific namespaces.
15 class Registry < Needle::Registry
16
17 # If a namespace does not exist with the given name, create it. Regardless,
18 # return the namespace.
19 def component_space( name )
20 unless has_key?( name )
21 namespace name
22 end
23
24 self[ name ]
25 end
26
27 end
28
29 # A singleton class encapsulating the management of environments in Rails.
30 class Environment
31 include Singleton
32
33 # The array of additional load paths to add.
34 ADDITIONAL_LOAD_PATHS =
35 %w{app/models app/controllers app/helpers config lib vendor}
36
37 # A reference to the registry to use.
38 attr_reader :registry
39
40 # Create a new Environment. Since this is a singleton class, this cannot
41 # be called directly, and will only be invoked once when the singleton
42 # instance is created.
43 def initialize
44 ADDITIONAL_LOAD_PATHS.each do |dir|
45 $:.unshift "#{File.dirname(__FILE__)}/../../#{dir}"
46 end
47
48 ActionController::Base.template_root =
49 ActionMailer::Base.template_root =
50 File.dirname(__FILE__) + '/../../app/views/'
51
52 @registry = Rails::Registry.new :logs => { :device => STDOUT }
53
54 # Load the database configurations into a service, so they can be
55 # referenced and rereferenced without reloading the file. This also allows
56 # clients to override how database configurations are defined, simply by
57 # redefining the database_configurations service.
58 @registry.register :database_configurations do
59 YAML::load(
60 File.open(
61 File.dirname(__FILE__) + "/../../config/database.yml"))
62 end
63
64 # return the current database configuration. Use the 'prototype' model,
65 # so that the block is executed on every request. Otherwise, if the
66 # current_environment changed, the database_configuration service would
67 # never reflect the change.
68 @registry.register( :database_configuration, :model => :prototype ) do
69 @registry.database_configurations[ @registry.current_environment ]
70 end
71
72 # return the current system log file location. Use the 'prototype' model,
73 # so that the block is executed on every request. Otherwise, if the
74 # current_environment changed, the system_log_file service would
75 # never reflect the change.
76 #
77 # this allows clients to change where logs are written to, simply by
78 # registering a system_log_file service that replaces this one.
79 @registry.register( :system_log_file, :model => :prototype ) do
80 File.dirname(__FILE__) + "/../../log/#{@registry.current_environment}.log"
81 end
82
83 ActiveRecord::Base.registry = @registry.component_space :model
84 ActionController::Base.registry = @registry.component_space :controller
85 ActionMailer::Base.registry = @registry.component_space :mailer
86 ActionView::Base.registry = @registry.component_space :view
87
88 ActiveRecord::Base.logger = @registry.logs.get "[active-record]"
89 ActionController::Base.logger = @registry.logs.get "[action-controller]"
90 ActionMailer::Base.logger = @registry.logs.get "[action-mailer]"
91 end
92
93 # Select a new environment, by name. The only restriction is that, by default,
94 # there must be an identically named database configuration, or this will
95 # fail.
96 def set( environment_name )
97 @registry.register( :current_environment ) { environment_name }
98 @registry.logs.write_to(@registry.system_log_file)
99 ActiveRecord::Base.establish_connection(@registry.database_configuration)
100 true
101 end
102
103 # A convenience method for setting the environment. This allows you to do:
104 #
105 # Environment.set "production"
106 #
107 # instead of
108 #
109 # Environment.instance.set "production"
110 def self.set( environment_name )
111 instance.set( environment_name )
112 end
113
114 # A convenience accessor for accessing the Rails registry. This allows you
115 # to do:
116 #
117 # Environment.registry
118 #
119 # instead of
120 #
121 # Environment.instance.registry
122 def self.registry
123 instance.registry
124 end
125
126 end
127
128 end