merb 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +21 -14
- data/Rakefile +157 -108
- data/SVN_REVISION +1 -0
- data/app_generators/merb/templates/Rakefile +20 -4
- data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +1 -1
- data/app_generators/merb/templates/config/boot.rb +1 -1
- data/app_generators/merb/templates/config/dependencies.rb +3 -3
- data/app_generators/merb/templates/config/merb.yml +5 -0
- data/app_generators/merb/templates/config/merb_init.rb +3 -3
- data/app_generators/merb/templates/script/destroy +3 -0
- data/app_generators/merb/templates/script/generate +1 -1
- data/app_generators/merb/templates/spec/spec_helper.rb +2 -2
- data/app_generators/merb/templates/test/test_helper.rb +1 -1
- data/app_generators/merb_plugin/merb_plugin_generator.rb +4 -0
- data/bin/merb +1 -3
- data/lib/merb.rb +144 -76
- data/lib/merb/abstract_controller.rb +6 -5
- data/lib/merb/assets.rb +119 -0
- data/lib/merb/boot_loader.rb +217 -0
- data/lib/merb/caching.rb +1 -1
- data/lib/merb/caching/action_cache.rb +1 -1
- data/lib/merb/caching/fragment_cache.rb +1 -1
- data/lib/merb/caching/store/file_cache.rb +1 -1
- data/lib/merb/config.rb +290 -0
- data/lib/merb/controller.rb +5 -5
- data/lib/merb/core_ext/get_args.rb +1 -0
- data/lib/merb/core_ext/hash.rb +182 -169
- data/lib/merb/core_ext/kernel.rb +57 -26
- data/lib/merb/dispatcher.rb +6 -6
- data/lib/merb/drb_server.rb +1 -1
- data/lib/merb/generators/merb_generator_helpers.rb +7 -6
- data/lib/merb/logger.rb +1 -1
- data/lib/merb/mail_controller.rb +3 -4
- data/lib/merb/mailer.rb +2 -2
- data/lib/merb/mixins/basic_authentication.rb +2 -2
- data/lib/merb/mixins/controller.rb +1 -1
- data/lib/merb/mixins/general_controller.rb +13 -20
- data/lib/merb/mixins/inline_partial.rb +32 -0
- data/lib/merb/mixins/render.rb +3 -3
- data/lib/merb/mixins/responder.rb +1 -1
- data/lib/merb/mixins/view_context.rb +159 -33
- data/lib/merb/mongrel_handler.rb +9 -9
- data/lib/merb/plugins.rb +1 -1
- data/lib/merb/request.rb +25 -1
- data/lib/merb/router.rb +264 -226
- data/lib/merb/server.rb +66 -560
- data/lib/merb/session/cookie_store.rb +14 -13
- data/lib/merb/session/mem_cache_session.rb +20 -10
- data/lib/merb/session/memory_session.rb +21 -11
- data/lib/merb/template.rb +2 -2
- data/lib/merb/template/erubis.rb +3 -33
- data/lib/merb/template/haml.rb +8 -3
- data/lib/merb/test/fake_request.rb +8 -3
- data/lib/merb/test/helper.rb +66 -22
- data/lib/merb/test/rspec.rb +9 -155
- data/lib/merb/test/rspec_matchers/controller_matchers.rb +117 -0
- data/lib/merb/test/rspec_matchers/markup_matchers.rb +98 -0
- data/lib/merb/upload_handler.rb +2 -1
- data/lib/merb/version.rb +38 -3
- data/lib/merb/view_context.rb +1 -2
- data/lib/tasks/merb.rake +11 -11
- data/merb_generators/part_controller/USAGE +5 -0
- data/merb_generators/part_controller/part_controller_generator.rb +27 -0
- data/merb_generators/part_controller/templates/controller.rb +8 -0
- data/merb_generators/part_controller/templates/helper.rb +5 -0
- data/merb_generators/part_controller/templates/index.html.erb +3 -0
- data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +1 -1
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/fixtures/controllers/dispatch_spec_controllers.rb +9 -1
- data/spec/fixtures/controllers/render_spec_controllers.rb +5 -5
- data/spec/fixtures/models/router_spec_models.rb +10 -0
- data/spec/merb/abstract_controller_spec.rb +2 -2
- data/spec/merb/assets_spec.rb +207 -0
- data/spec/merb/caching_spec.rb +2 -2
- data/spec/merb/controller_spec.rb +7 -2
- data/spec/merb/cookie_store_spec.rb +1 -1
- data/spec/merb/core_ext/class_spec.rb +97 -0
- data/spec/merb/core_ext/enumerable_spec.rb +27 -0
- data/spec/merb/core_ext/hash_spec.rb +251 -0
- data/spec/merb/core_ext/inflector_spec.rb +34 -0
- data/spec/merb/core_ext/kernel_spec.rb +25 -0
- data/spec/merb/core_ext/numeric_spec.rb +26 -0
- data/spec/merb/core_ext/object_spec.rb +47 -0
- data/spec/merb/core_ext/string_spec.rb +22 -0
- data/spec/merb/core_ext/symbol_spec.rb +7 -0
- data/spec/merb/dependency_spec.rb +22 -0
- data/spec/merb/dispatch_spec.rb +23 -12
- data/spec/merb/fake_request_spec.rb +8 -0
- data/spec/merb/generator_spec.rb +140 -21
- data/spec/merb/handler_spec.rb +5 -5
- data/spec/merb/mail_controller_spec.rb +3 -3
- data/spec/merb/render_spec.rb +1 -1
- data/spec/merb/responder_spec.rb +3 -3
- data/spec/merb/router_spec.rb +260 -191
- data/spec/merb/server_spec.rb +5 -5
- data/spec/merb/upload_handler_spec.rb +7 -0
- data/spec/merb/version_spec.rb +33 -0
- data/spec/merb/view_context_spec.rb +217 -59
- data/spec/spec_generator_helper.rb +15 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/spec_helpers/url_shared_behaviour.rb +5 -7
- metadata +32 -7
- data/lib/merb/caching/store/memcache.rb +0 -20
- data/lib/merb/mixins/form_control.rb +0 -332
- data/lib/patch +0 -69
- data/spec/merb/core_ext_spec.rb +0 -464
- data/spec/merb/form_control_mixin_spec.rb +0 -431
data/lib/merb/server.rb
CHANGED
@@ -1,580 +1,88 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
|
3
|
+
# Make the app's "gems" directory a place where gems are loaded from
|
4
|
+
# This needs to go here for using in a shared envirionment where Erubis may not
|
5
|
+
# be available
|
6
|
+
if File.exists?(File.join(Dir.pwd, "gems")) && File.directory?(File.join(Dir.pwd,"gems"))
|
7
|
+
Gem.clear_paths
|
8
|
+
Gem.path.unshift(File.join(Dir.pwd,"gems"))
|
9
|
+
end
|
10
|
+
|
11
|
+
|
2
12
|
require 'optparse'
|
3
13
|
require 'ostruct'
|
4
14
|
require 'fileutils'
|
5
15
|
require 'yaml'
|
6
16
|
|
7
|
-
|
8
|
-
|
17
|
+
# this is so we can test for HAML features for HAML partial inlining
|
18
|
+
unless Gem.cache.search("haml").empty?
|
19
|
+
gem "haml"
|
20
|
+
require "haml"
|
21
|
+
end
|
9
22
|
|
10
|
-
|
11
|
-
|
12
|
-
module GlobalHelper
|
13
|
-
end
|
23
|
+
require File.join(File.dirname(__FILE__), 'config')
|
14
24
|
|
15
|
-
|
16
|
-
class << self
|
17
|
-
def defaults
|
18
|
-
@defaults ||= {
|
19
|
-
:host => "0.0.0.0",
|
20
|
-
:port => "4000",
|
21
|
-
:reloader => true,
|
22
|
-
:cache_templates => false,
|
23
|
-
:merb_root => Dir.pwd,
|
24
|
-
:use_mutex => true,
|
25
|
-
:session_id_cookie_only => true,
|
26
|
-
:query_string_whitelist => [],
|
27
|
-
:mongrel_x_sendfile => true
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def setup(global_merb_yml = nil)
|
32
|
-
if FileTest.exist? "#{defaults[:merb_root]}/framework"
|
33
|
-
$LOAD_PATH.unshift( "#{defaults[:merb_root]}/framework" )
|
34
|
-
end
|
35
|
-
global_merb_yml ||= "#{defaults[:merb_root]}/config/merb.yml"
|
36
|
-
apply_configuration_from_file defaults, global_merb_yml
|
37
|
-
end
|
25
|
+
module Merb
|
38
26
|
|
39
|
-
def apply_configuration_from_file(configuration, file)
|
40
|
-
if File.exists?(file)
|
41
|
-
configuration.merge(Erubis.load_yaml_file(file))
|
42
|
-
else
|
43
|
-
configuration
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
27
|
class Server
|
50
28
|
|
51
29
|
class << self
|
52
30
|
|
53
|
-
def merb_config(argv = ARGV)
|
54
|
-
# Our primary configuration hash for the length of this method
|
55
|
-
options = {}
|
56
|
-
|
57
|
-
# Environment variables always win
|
58
|
-
options[:environment] = ENV['MERB_ENV']
|
59
|
-
|
60
|
-
# Build a parser for the command line arguements
|
61
|
-
opts = OptionParser.new do |opts|
|
62
|
-
opts.version = Merb::VERSION
|
63
|
-
opts.release = Merb::RELEASE
|
64
|
-
|
65
|
-
opts.banner = "Usage: merb [fdcepghmisluMG] [argument]"
|
66
|
-
opts.define_head "Merb Mongrel+ Erb. Lightweight replacement for ActionPack."
|
67
|
-
opts.separator '*'*80
|
68
|
-
opts.separator 'If no flags are given, Merb starts in the foreground on port 4000.'
|
69
|
-
opts.separator '*'*80
|
70
|
-
|
71
|
-
opts.on("-u", "--user USER", "This flag is for having merb run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect.") do |config|
|
72
|
-
options[:user] = config
|
73
|
-
end
|
74
|
-
|
75
|
-
opts.on("-G", "--group GROUP", "This flag is for having merb run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect.") do |config|
|
76
|
-
options[:group] = config
|
77
|
-
end
|
78
|
-
|
79
|
-
opts.on("-f", "--config-file FILENAME", "This flag is for adding extra config files for things like the upload progress module.") do |config|
|
80
|
-
options[:config] = config
|
81
|
-
end
|
82
|
-
|
83
|
-
opts.on("-d", "--daemonize", "This will run a single merb in the background.") do |config|
|
84
|
-
options[:daemonize] = true
|
85
|
-
end
|
86
|
-
|
87
|
-
opts.on("-c", "--cluster-nodes NUM_MERBS", "Number of merb daemons to run.") do |nodes|
|
88
|
-
options[:cluster] = nodes
|
89
|
-
end
|
90
|
-
|
91
|
-
opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000.") do |port|
|
92
|
-
options[:port] = port
|
93
|
-
end
|
94
|
-
|
95
|
-
opts.on("-h", "--host HOSTNAME", "Host to bind to (default is all IP's).") do |host|
|
96
|
-
if host
|
97
|
-
options[:host] = host
|
98
|
-
else
|
99
|
-
# If no host was given, assume they meant they wanted help.
|
100
|
-
puts opts
|
101
|
-
exit
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
opts.on("-m", "--merb-root MERB_ROOT", "The path to the MERB_ROOT for the app you want to run (default is current working dir).") do |merb_root|
|
106
|
-
options[:merb_root] = File.expand_path(merb_root)
|
107
|
-
end
|
108
|
-
|
109
|
-
opts.on("-i", "--irb-console", "This flag will start merb in irb console mode. All your models and other classes will be available for you in an irb session.") do |console|
|
110
|
-
options[:console] = true
|
111
|
-
end
|
112
|
-
|
113
|
-
opts.on("-s", "--start-drb PORTNUM", "This is the port number to run the drb daemon on for sessions and upload progress monitoring.") do |drb_port|
|
114
|
-
options[:start_drb] = true
|
115
|
-
options[:only_drb] = true
|
116
|
-
options[:drb_server_port] = drb_port
|
117
|
-
end
|
118
|
-
|
119
|
-
opts.on("-l", "--log-level LEVEL", "Log levels can be set to any of these options: DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN") do |loglevel|
|
120
|
-
options[:log_level] = loglevel
|
121
|
-
end
|
122
|
-
|
123
|
-
opts.on("-e", "--environment STRING", "Run merb in the correct mode(development, production, testing)") do |env|
|
124
|
-
options[:environment] ||= env
|
125
|
-
end
|
126
|
-
|
127
|
-
opts.on("-r", "--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]",
|
128
|
-
"Command-line option to run scripts and/or code in the merb app.") do |stuff_to_run|
|
129
|
-
options[:runner] = stuff_to_run
|
130
|
-
end
|
131
|
-
|
132
|
-
opts.on("-g", "--generate-app PATH", "Generate a fresh merb app at PATH.") do |path|
|
133
|
-
options[:generate] = path || Dir.pwd
|
134
|
-
end
|
135
|
-
|
136
|
-
opts.on("-P","--generate-plugin PATH", "Generate a fresh merb plugin at PATH.") do |path|
|
137
|
-
options[:generate_plugin] = path || Dir.pwd
|
138
|
-
end
|
139
|
-
|
140
|
-
opts.on("-k", "--kill PORT or all", "Kill one merb proceses by port number. Use merb -k all to kill all merbs.") do |ports|
|
141
|
-
options[:kill] = ports
|
142
|
-
end
|
143
|
-
|
144
|
-
opts.on("-K", "--graceful PORT or all", "Gracefully kill one merb proceses by port number. Use merb -K all to gracefully kill all merbs.") do |ports|
|
145
|
-
options[:graceful] = ports
|
146
|
-
end
|
147
|
-
|
148
|
-
opts.on("-M", "--merb-config FILENAME", "This flag is for explicitly declaring the merb app's config file.") do |config|
|
149
|
-
options[:merb_config] = config
|
150
|
-
end
|
151
|
-
|
152
|
-
opts.on("-w", "--webrick", "Run merb using Webrick Rack Adapter instead of mongrel.") do |webport|
|
153
|
-
options[:webrick] = true
|
154
|
-
end
|
155
|
-
|
156
|
-
opts.on("-F", "--fastcgi", "Run merb using FastCGI Rack Adapter instead of mongrel.") do
|
157
|
-
options[:fastcgi] = true
|
158
|
-
end
|
159
|
-
|
160
|
-
opts.on("-X", "--mutex on/off", "This flag is for turning the mutex lock on and off.") do |mutex|
|
161
|
-
if mutex == 'off'
|
162
|
-
options[:use_mutex] = false
|
163
|
-
else
|
164
|
-
options[:use_mutex] = true
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
opts.on("-?", "-H", "--help", "Show this help message") do
|
169
|
-
puts opts
|
170
|
-
exit
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# Parse what we have on the command line
|
175
|
-
opts.parse!(argv)
|
176
|
-
|
177
|
-
# merb <argument> is same as merb -g <argument>
|
178
|
-
if argv.size == 1
|
179
|
-
options[:generate] = File.expand_path(argv.last)
|
180
|
-
end
|
181
|
-
|
182
|
-
# If we run merb with no arguments and we are not inside a merb root
|
183
|
-
# show the help message
|
184
|
-
if (argv.size == 0) && !File.exists?("#{options[:merb_root] || Merb::Config.defaults[:merb_root]}/config/merb_init.rb") && !$TESTING
|
185
|
-
puts "You are not in the root of a merb application...\n"
|
186
|
-
puts opts
|
187
|
-
exit
|
188
|
-
end
|
189
|
-
# Load up the configuration from file, but keep the command line
|
190
|
-
# options that may have been chosen. Also, pass-through if we have
|
191
|
-
# a new merb_config path.
|
192
|
-
options = Merb::Config.setup(options[:merb_config]).merge(options)
|
193
|
-
|
194
|
-
# Finally, if all else fails... set the environment to 'development'
|
195
|
-
options[:environment] ||= 'development'
|
196
|
-
|
197
|
-
environment_merb_yml = "#{options[:merb_root]}/config/environments/#{options[:environment]}.yml"
|
198
|
-
options = Merb::Config.apply_configuration_from_file options, environment_merb_yml
|
199
|
-
|
200
|
-
@@merb_opts = options
|
201
|
-
end
|
202
|
-
|
203
|
-
def max_mtime( files = [] )
|
204
|
-
files.map{ |file| File.mtime(file) rescue @mtime }.max
|
205
|
-
end
|
206
|
-
|
207
|
-
def register_session_type(name, file, description = nil)
|
208
|
-
@registered_session_types ||= YAML::Omap.new
|
209
|
-
@registered_session_types[name] = {
|
210
|
-
:file => file,
|
211
|
-
:description => (description || "Using #{name} sessions")
|
212
|
-
}
|
213
|
-
end
|
214
|
-
|
215
|
-
def add_controller_mixins
|
216
|
-
types = @registered_session_types
|
217
|
-
Merb::Controller.class_eval do
|
218
|
-
lib = File.join(__DIR__, 'merb')
|
219
|
-
session_store = Merb::Server.config[:session_store].to_s
|
220
|
-
if ["", "false"].include?(session_store)
|
221
|
-
puts "Not Using Sessions"
|
222
|
-
elsif reg = types[session_store]
|
223
|
-
if session_store == "cookie"
|
224
|
-
unless @@merb_opts[:session_secret_key] && (@@merb_opts[:session_secret_key].length >= 16)
|
225
|
-
puts("You must specify a session_secret_key in your merb.yml, and it must be at least 16 characters\nbailing out...")
|
226
|
-
exit!
|
227
|
-
end
|
228
|
-
Merb::Controller.session_secret_key = @@merb_opts[:session_secret_key]
|
229
|
-
end
|
230
|
-
require reg[:file]
|
231
|
-
include ::Merb::SessionMixin
|
232
|
-
puts reg[:description]
|
233
|
-
else
|
234
|
-
puts "Session store not found, '#{Merb::Server.config[:session_store]}'."
|
235
|
-
puts "Defaulting to CookieStore Sessions"
|
236
|
-
unless @@merb_opts[:session_secret_key] && (@@merb_opts[:session_secret_key].length >= 16)
|
237
|
-
puts("You must specify a session_secret_key in your merb.yml, and it must be at least 16 characters\nbailing out...")
|
238
|
-
exit!
|
239
|
-
end
|
240
|
-
Merb::Controller.session_secret_key = @@merb_opts[:session_secret_key]
|
241
|
-
require types['cookie'][:file]
|
242
|
-
include ::Merb::SessionMixin
|
243
|
-
puts "(plugin not installed?)"
|
244
|
-
end
|
245
|
-
|
246
|
-
if Merb::Server.config[:basic_auth]
|
247
|
-
require lib + "/mixins/basic_authentication"
|
248
|
-
include ::Merb::AuthenticationMixin
|
249
|
-
puts "Basic Authentication mixed in"
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def initialize_merb
|
255
|
-
require 'merb'
|
256
|
-
@mtime = Time.now if @@merb_opts[:reloader] == true
|
257
|
-
# Register session types before merb_init.rb so that any additional
|
258
|
-
# session stores will be added to the end of the list and become the
|
259
|
-
# default.
|
260
|
-
register_session_type('memory',
|
261
|
-
__DIR__ / "merb" / "session" / "memory_session",
|
262
|
-
"Using in-memory sessions; sessions will be lost whenever the server stops.")
|
263
|
-
register_session_type('mem_cache',
|
264
|
-
__DIR__ / "merb" / "session" / "mem_cache_session",
|
265
|
-
"Using MemCache distributed memory sessions")
|
266
|
-
register_session_type('cookie', # Last session type becomes the default
|
267
|
-
__DIR__ / "merb" / "session" / "cookie_store",
|
268
|
-
"Using 'share-nothing' cookie sessions (4kb limit per client)")
|
269
|
-
require @@merb_opts[:merb_root] / 'config/merb_init.rb'
|
270
|
-
add_controller_mixins
|
271
|
-
end
|
272
|
-
|
273
|
-
def after_app_loads(&block)
|
274
|
-
@after_app_blocks ||= []
|
275
|
-
@after_app_blocks << block
|
276
|
-
end
|
277
|
-
|
278
|
-
def app_loaded?
|
279
|
-
@app_loaded
|
280
|
-
end
|
281
|
-
|
282
|
-
def load_action_arguments(klasses = Merb::Controller._subclasses)
|
283
|
-
begin
|
284
|
-
klasses.each do |controller|
|
285
|
-
controller = Object.full_const_get(controller)
|
286
|
-
controller.action_argument_list = {}
|
287
|
-
controller.callable_actions.each do |action, bool|
|
288
|
-
controller.action_argument_list[action.to_sym] = ParseTreeArray.translate(controller, action).get_args
|
289
|
-
end
|
290
|
-
end
|
291
|
-
rescue
|
292
|
-
klasses.each { |controller| controller.action_arguments = {} }
|
293
|
-
end if defined?(ParseTreeArray)
|
294
|
-
end
|
295
|
-
|
296
|
-
def template_paths(type = "*")
|
297
|
-
# This gets all templates set in the controllers template roots
|
298
|
-
template_paths = Merb::AbstractController._abstract_subclasses.map do |klass|
|
299
|
-
Object.full_const_get(klass)._template_root
|
300
|
-
end.uniq.map do |path|
|
301
|
-
Dir["#{path}/**/#{type}"]
|
302
|
-
end
|
303
|
-
|
304
|
-
# This gets the templates that might be created outside controllers
|
305
|
-
# template roots. eg app/views/shared/*
|
306
|
-
template_paths << Dir["#{MERB_ROOT}/app/views/**/*"] if type == "*"
|
307
|
-
|
308
|
-
template_paths.flatten.compact.uniq || []
|
309
|
-
end
|
310
|
-
|
311
|
-
def load_controller_template_path_cache
|
312
|
-
Merb::AbstractController.reset_template_path_cache!
|
313
|
-
|
314
|
-
template_paths.each do |template|
|
315
|
-
Merb::AbstractController.add_path_to_template_cache(template)
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def load_erubis_inline_helpers
|
320
|
-
partials = template_paths("_*.erb")
|
321
|
-
|
322
|
-
partials.each do |partial|
|
323
|
-
eruby = Erubis::Eruby.new(File.read(partial))
|
324
|
-
eruby.def_method(Merb::GlobalHelper, partial.gsub(/[^\.a-zA-Z0-9]/, "__").gsub(/\./, "_"), partial)
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
def load_application
|
329
|
-
MERB_PATHS.each do |glob|
|
330
|
-
Dir[MERB_ROOT + glob].each { |m| require m }
|
331
|
-
end
|
332
|
-
load_action_arguments
|
333
|
-
load_controller_template_path_cache
|
334
|
-
load_erubis_inline_helpers
|
335
|
-
@app_loaded = true
|
336
|
-
(@after_app_blocks || []).each { |b| b.call }
|
337
|
-
end
|
338
|
-
|
339
|
-
def remove_constant(const)
|
340
|
-
parts = const.to_s.split("::")
|
341
|
-
base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
|
342
|
-
object = parts[-1].intern
|
343
|
-
MERB_LOGGER.info("Removing constant #{object} from #{base}")
|
344
|
-
base.send(:remove_const, object) if object
|
345
|
-
Merb::Controller._subclasses.delete(const)
|
346
|
-
end
|
347
|
-
|
348
|
-
def reload
|
349
|
-
return if !@@merb_opts[:reloader] || !Object.const_defined?(:MERB_PATHS)
|
350
|
-
|
351
|
-
# First we collect all files in the project (this will also grab newly added files)
|
352
|
-
project_files = MERB_PATHS.map { |path| Dir[@@merb_opts[:merb_root] + path] }.flatten.uniq
|
353
|
-
erb_partials = template_paths("_*.erb").map { |path| Dir[path] }.flatten.uniq
|
354
|
-
project_mtime = max_mtime(project_files + erb_partials) # Latest changed time of all project files
|
355
|
-
|
356
|
-
return if @mtime.nil? || @mtime >= project_mtime # Only continue if a file has changed
|
357
|
-
|
358
|
-
project_files.each do |file|
|
359
|
-
if File.mtime(file) >= @mtime
|
360
|
-
# If the file has changed or been added since the last project reload time
|
361
|
-
# remove any cannonical constants, based on what type of project file it is
|
362
|
-
# and then reload the file
|
363
|
-
begin
|
364
|
-
constant = case file
|
365
|
-
when %r[/app/(models|controllers|parts|mailers)/(.+)\.rb$]
|
366
|
-
$2.to_const_string
|
367
|
-
when %r[/app/(helpers)/(.+)\.rb$]
|
368
|
-
"Merb::" + $2.to_const_string
|
369
|
-
end
|
370
|
-
remove_constant(constant)
|
371
|
-
rescue NameError => e
|
372
|
-
MERB_LOGGER.warn "Couldn't remove constant #{constant}"
|
373
|
-
end
|
374
|
-
|
375
|
-
begin
|
376
|
-
MERB_LOGGER.info("Reloading file #{file}")
|
377
|
-
old_subclasses = Merb::Controller._subclasses.dup
|
378
|
-
load(file)
|
379
|
-
loaded_classes = Merb::Controller._subclasses - old_subclasses
|
380
|
-
load_action_arguments(loaded_classes)
|
381
|
-
rescue Exception => e
|
382
|
-
puts "Error reloading file #{file}: #{e}"
|
383
|
-
MERB_LOGGER.warn " Error: #{e}"
|
384
|
-
end
|
385
|
-
|
386
|
-
# constant = file =~ /\/(controllers|models|mailers|helpers|parts)\/(.*).rb/ ? $2.to_const_string : nil
|
387
|
-
# remove_constant($2.to_const_string, ($1 == "helpers") ? Merb : nil)
|
388
|
-
# load file and puts "loaded file: #{file}"
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
# Rebuild the glob cache and erubis inline helpers
|
393
|
-
load_controller_template_path_cache
|
394
|
-
load_erubis_inline_helpers
|
395
|
-
|
396
|
-
@mtime = project_mtime # As the last action, update the current @mtime
|
397
|
-
end
|
398
|
-
|
399
31
|
def run
|
400
|
-
|
401
|
-
|
402
|
-
if
|
403
|
-
require 'merb/generators/merb_app/merb_app'
|
404
|
-
::Merb::AppGenerator.run @@merb_opts[:generate]
|
405
|
-
exit!
|
406
|
-
end
|
407
|
-
|
408
|
-
if ENV['EVENT'] || ENV['SWIFT']
|
409
|
-
@@merb_opts[:use_mutex] = false
|
410
|
-
end
|
411
|
-
|
412
|
-
if @@merb_opts[:graceful]
|
413
|
-
@@merb_opts[:kill] = @@merb_opts[:graceful]
|
414
|
-
graceful = true
|
415
|
-
end
|
416
|
-
|
417
|
-
if k = @@merb_opts[:kill]
|
418
|
-
begin
|
419
|
-
Dir[@@merb_opts[:merb_root] + "/log/merb.#{k == 'all' ? '*' : k }.pid"].each do |f|
|
420
|
-
puts f
|
421
|
-
pid = IO.read(f).chomp.to_i
|
422
|
-
signal = graceful ? 1 : 9
|
423
|
-
Process.kill(signal, pid)
|
424
|
-
FileUtils.rm f
|
425
|
-
puts "killed PID #{pid} with signal #{signal}"
|
426
|
-
end
|
427
|
-
rescue
|
428
|
-
puts "Failed to kill! #{k}"
|
429
|
-
ensure
|
430
|
-
exit
|
431
|
-
end
|
432
|
-
end
|
433
|
-
|
434
|
-
case @@merb_opts[:environment].to_s
|
435
|
-
when 'production'
|
436
|
-
@@merb_opts[:reloader] = @@merb_opts.fetch(:reloader, false)
|
437
|
-
@@merb_opts[:exception_details] = @@merb_opts.fetch(:exception_details, false)
|
438
|
-
@@merb_opts[:cache_templates] = true
|
439
|
-
else
|
440
|
-
@@merb_opts[:reloader] = @@merb_opts.fetch(:reloader, true)
|
441
|
-
@@merb_opts[:exception_details] = @@merb_opts.fetch(:exception_details, true)
|
442
|
-
end
|
443
|
-
|
444
|
-
@@merb_opts[:reloader_time] ||= 0.5 if @@merb_opts[:reloader] == true
|
445
|
-
|
446
|
-
$LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/app/models') )
|
447
|
-
$LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/app/controllers') )
|
448
|
-
$LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/lib') )
|
449
|
-
|
450
|
-
if @@merb_opts[:generate_plugin]
|
451
|
-
require 'merb/generators/merb_plugin'
|
452
|
-
::Merb::PluginGenerator.run @@merb_opts[:generate_plugin]
|
453
|
-
exit!
|
454
|
-
end
|
455
|
-
|
456
|
-
if @@merb_opts[:reloader]
|
457
|
-
Thread.abort_on_exception = true
|
458
|
-
Thread.new do
|
459
|
-
loop do
|
460
|
-
sleep( @@merb_opts[:reloader_time] )
|
461
|
-
reload if app_loaded?
|
462
|
-
end
|
463
|
-
Thread.exit
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
if @@merb_opts[:console]
|
468
|
-
initialize_merb
|
469
|
-
_merb = Class.new do
|
470
|
-
def self.show_routes(all_opts = false)
|
471
|
-
seen = []
|
472
|
-
unless Merb::Router.named_routes.empty?
|
473
|
-
puts "Named Routes"
|
474
|
-
Merb::Router.named_routes.each do |name,route|
|
475
|
-
puts " #{name}: #{route}"
|
476
|
-
seen << route
|
477
|
-
end
|
478
|
-
end
|
479
|
-
puts "Anonymous Routes"
|
480
|
-
(Merb::Router.routes - seen).each do |route|
|
481
|
-
puts " #{route}"
|
482
|
-
end
|
483
|
-
nil
|
484
|
-
end
|
485
|
-
|
486
|
-
def self.url(path, *args)
|
487
|
-
Merb::Router.generate(path,*args)
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
Object.send(:define_method, :merb) {
|
492
|
-
_merb
|
493
|
-
}
|
494
|
-
|
495
|
-
ARGV.clear # Avoid passing args to IRB
|
496
|
-
require 'irb'
|
497
|
-
require 'irb/completion'
|
498
|
-
def exit
|
499
|
-
exit!
|
500
|
-
end
|
501
|
-
if File.exists? ".irbrc"
|
502
|
-
ENV['IRBRC'] = ".irbrc"
|
503
|
-
end
|
504
|
-
IRB.start
|
505
|
-
exit!
|
506
|
-
end
|
507
|
-
|
508
|
-
if @@merb_opts[:runner]
|
509
|
-
initialize_merb
|
510
|
-
code_or_file = @@merb_opts[:runner]
|
511
|
-
if File.exists?(code_or_file)
|
512
|
-
eval(File.read(code_or_file))
|
513
|
-
else
|
514
|
-
eval(code_or_file)
|
515
|
-
end
|
516
|
-
exit!
|
517
|
-
end
|
518
|
-
|
519
|
-
if @@merb_opts[:start_drb]
|
520
|
-
puts "Starting merb drb server on port: #{@@merb_opts[:drb_server_port]}"
|
521
|
-
start(@@merb_opts[:drb_server_port], :drbserver_start)
|
522
|
-
exit if @@merb_opts[:only_drb]
|
523
|
-
end
|
524
|
-
|
525
|
-
if @@merb_opts[:webrick]
|
526
|
-
puts "Starting merb webrick server on port: #{@@merb_opts[:port]}"
|
527
|
-
trap('TERM') { exit }
|
528
|
-
webrick_start(@@merb_opts[:port])
|
529
|
-
end
|
530
|
-
|
531
|
-
if @@merb_opts[:fastcgi]
|
532
|
-
trap('TERM') { exit }
|
533
|
-
fastcgi_start
|
534
|
-
end
|
535
|
-
|
536
|
-
|
537
|
-
if @@merb_opts[:cluster]
|
32
|
+
::Merb::Config.parse_args
|
33
|
+
|
34
|
+
if Merb::Config[:cluster]
|
538
35
|
delete_pidfiles
|
539
|
-
|
36
|
+
Merb::Config[:port].to_i.upto(Merb::Config[:port].to_i+Merb::Config[:cluster].to_i-1) do |port|
|
540
37
|
puts "Starting merb server on port: #{port}"
|
541
38
|
start(port)
|
542
39
|
end
|
543
|
-
elsif
|
544
|
-
delete_pidfiles(
|
545
|
-
start(
|
40
|
+
elsif Merb::Config[:daemonize]
|
41
|
+
delete_pidfiles(Merb::Config[:port])
|
42
|
+
start(Merb::Config[:port])
|
546
43
|
else
|
547
44
|
trap('TERM') { exit }
|
548
|
-
mongrel_start(
|
45
|
+
mongrel_start(Merb::Config[:port])
|
549
46
|
end
|
550
|
-
|
47
|
+
|
551
48
|
end
|
552
49
|
|
553
50
|
def store_pid(pid,port)
|
554
|
-
File.open("#{
|
51
|
+
File.open("#{Merb::Config[:merb_root]}/log/merb.#{port}.pid", 'w'){|f| f.write("#{Process.pid}\n")}
|
555
52
|
end
|
556
53
|
|
54
|
+
def kill(ports, sig=9)
|
55
|
+
begin
|
56
|
+
Dir[Merb::Config[:merb_root] + "/log/merb.#{ports == 'all' ? '*' : ports }.pid"].each do |f|
|
57
|
+
pid = IO.read(f).chomp.to_i
|
58
|
+
Process.kill(sig, pid)
|
59
|
+
FileUtils.rm f
|
60
|
+
puts "killed PID #{pid} with signal #{sig}"
|
61
|
+
end
|
62
|
+
rescue
|
63
|
+
puts "Failed to kill! #{k}"
|
64
|
+
ensure
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
557
69
|
def start(port,what=:mongrel_start)
|
558
70
|
fork do
|
559
71
|
Process.setsid
|
560
72
|
exit if fork
|
561
|
-
if what == :mongrel_start
|
562
|
-
store_pid(Process.pid, port)
|
563
|
-
else
|
564
|
-
store_pid(Process.pid, "drb.#{port}")
|
565
|
-
end
|
566
|
-
Dir.chdir @@merb_opts[:merb_root]
|
567
73
|
File.umask 0000
|
568
74
|
STDIN.reopen "/dev/null"
|
569
75
|
STDOUT.reopen "/dev/null", "a"
|
570
76
|
STDERR.reopen STDOUT
|
571
77
|
trap("TERM") { exit }
|
78
|
+
Dir.chdir Merb::Config[:merb_root]
|
572
79
|
send(what, port)
|
573
80
|
end
|
574
81
|
end
|
575
82
|
|
576
83
|
def webrick_start(port)
|
577
|
-
initialize_merb
|
84
|
+
Merb::BootLoader.initialize_merb
|
85
|
+
store_pid(Process.pid, port)
|
578
86
|
require 'rack'
|
579
87
|
require 'merb/rack_adapter'
|
580
88
|
::Rack::Handler::WEBrick.run Merb::Rack::Adapter.new,
|
@@ -582,63 +90,61 @@ module Merb
|
|
582
90
|
end
|
583
91
|
|
584
92
|
def fastcgi_start
|
585
|
-
initialize_merb
|
93
|
+
Merb::BootLoader.initialize_merb
|
586
94
|
require 'rack'
|
587
95
|
require 'merb/rack_adapter'
|
588
96
|
::Rack::Handler::FastCGI.run Merb::Rack::Adapter.new
|
589
97
|
end
|
590
98
|
|
591
99
|
def delete_pidfiles(portor_star='*')
|
592
|
-
Dir["#{
|
100
|
+
Dir["#{Merb::Config[:merb_root]}/log/merb.#{portor_star}.pid"].each do |pid|
|
593
101
|
FileUtils.rm(pid) rescue nil
|
594
102
|
end
|
595
103
|
end
|
596
104
|
|
597
105
|
def drbserver_start(port)
|
598
106
|
puts "Starting merb drb server on port: #{port}"
|
599
|
-
require 'merb/
|
600
|
-
|
107
|
+
require 'merb/drb_server'
|
108
|
+
Merb::BootLoader.initialize_merb
|
109
|
+
store_pid(Process.pid, "drb.#{port}")
|
110
|
+
drb_init = File.join(Merb.root, "/config/drb_init")
|
601
111
|
require drb_init if File.exist?(drb_init)
|
602
|
-
DRb.start_service("druby://#{
|
112
|
+
DRb.start_service("druby://#{Merb::Config[:host]}:#{port}", Merb::DrbServiceProvider)
|
603
113
|
DRb.thread.join
|
604
114
|
end
|
605
115
|
|
606
116
|
def mongrel_start(port)
|
607
|
-
|
608
|
-
|
117
|
+
store_pid(Process.pid, port)
|
118
|
+
Merb::Config[:port] = port
|
119
|
+
unless Merb::Config[:generate] || Merb::Config[:console] || Merb::Config[:only_drb] || Merb::Config[:kill]
|
609
120
|
puts %{Merb started with these options:}
|
610
|
-
puts
|
121
|
+
puts Merb::Config.to_yaml; puts
|
611
122
|
end
|
612
|
-
initialize_merb
|
123
|
+
Merb::BootLoader.initialize_merb
|
613
124
|
|
614
|
-
mconf_hash = {:host => (
|
615
|
-
if
|
616
|
-
mconf_hash[:user] =
|
617
|
-
mconf_hash[:group] =
|
125
|
+
mconf_hash = {:host => (Merb::Config[:host]||"0.0.0.0"), :port => (port ||4000)}
|
126
|
+
if Merb::Config[:user] and Merb::Config[:group]
|
127
|
+
mconf_hash[:user] = Merb::Config[:user]
|
128
|
+
mconf_hash[:group] = Merb::Config[:group]
|
618
129
|
end
|
619
130
|
mconfig = Mongrel::Configurator.new(mconf_hash) do
|
620
131
|
listener do
|
621
|
-
uri( "/", :handler => MerbUploadHandler.new(
|
622
|
-
uri "/", :handler => MerbHandler.new(
|
132
|
+
uri( "/", :handler => MerbUploadHandler.new(Merb::Config), :in_front => true) if Merb::Config[:upload_path_match]
|
133
|
+
uri "/", :handler => MerbHandler.new(Merb.root+'/public', Merb::Config[:mongrel_x_sendfile])
|
623
134
|
uri "/favicon.ico", :handler => Mongrel::Error404Handler.new("")
|
624
135
|
end
|
625
|
-
MerbHandler.path_prefix =
|
136
|
+
MerbHandler.path_prefix = Merb::Config[:path_prefix]
|
626
137
|
|
627
138
|
trap("INT") { stop }
|
628
139
|
run
|
629
140
|
end
|
630
141
|
mconfig.join
|
631
|
-
end
|
142
|
+
end
|
632
143
|
|
633
144
|
def config
|
634
|
-
|
145
|
+
Merb::Config
|
635
146
|
end
|
636
147
|
|
637
|
-
def load_config
|
638
|
-
@@merb_raw_opts = ARGV
|
639
|
-
merb_config
|
640
|
-
end
|
641
|
-
|
642
148
|
end # class << self
|
643
149
|
|
644
150
|
end # Server
|