merb 0.3.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. data/README +25 -26
  2. data/Rakefile +48 -36
  3. data/app_generators/merb/USAGE +5 -0
  4. data/app_generators/merb/merb_generator.rb +107 -0
  5. data/app_generators/merb/templates/Rakefile +99 -0
  6. data/{examples/skeleton/dist → app_generators/merb/templates}/app/controllers/application.rb +1 -1
  7. data/app_generators/merb/templates/app/controllers/exceptions.rb +13 -0
  8. data/{examples/skeleton/dist → app_generators/merb/templates}/app/helpers/global_helper.rb +0 -0
  9. data/{examples/skeleton/dist/app/mailers → app_generators/merb/templates/app/mailers/views}/layout/application.erb +0 -0
  10. data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +207 -0
  11. data/app_generators/merb/templates/app/views/exceptions/not_acceptable.html.erb +38 -0
  12. data/app_generators/merb/templates/app/views/exceptions/not_found.html.erb +40 -0
  13. data/app_generators/merb/templates/app/views/layout/application.html.erb +11 -0
  14. data/app_generators/merb/templates/config/boot.rb +11 -0
  15. data/app_generators/merb/templates/config/dependencies.rb +41 -0
  16. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/development.rb +0 -0
  17. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/production.rb +0 -0
  18. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/test.rb +0 -0
  19. data/app_generators/merb/templates/config/merb.yml +64 -0
  20. data/app_generators/merb/templates/config/merb_init.rb +16 -0
  21. data/app_generators/merb/templates/config/plugins.yml +1 -0
  22. data/app_generators/merb/templates/config/router.rb +32 -0
  23. data/{lib/merb/core_ext/merb_array.rb → app_generators/merb/templates/config/upload.conf} +0 -0
  24. data/app_generators/merb/templates/public/images/merb.jpg +0 -0
  25. data/app_generators/merb/templates/public/merb.fcgi +6 -0
  26. data/app_generators/merb/templates/public/stylesheets/master.css +119 -0
  27. data/app_generators/merb/templates/script/destroy +28 -0
  28. data/app_generators/merb/templates/script/generate +28 -0
  29. data/{examples/skeleton → app_generators/merb/templates}/script/stop_merb +0 -0
  30. data/app_generators/merb/templates/script/win_script.cmd +1 -0
  31. data/app_generators/merb/templates/spec/spec.opts +6 -0
  32. data/app_generators/merb/templates/spec/spec_helper.rb +10 -0
  33. data/app_generators/merb/templates/test/test_helper.rb +13 -0
  34. data/app_generators/merb_plugin/USAGE +5 -0
  35. data/app_generators/merb_plugin/merb_plugin_generator.rb +64 -0
  36. data/app_generators/merb_plugin/templates/LICENSE +20 -0
  37. data/app_generators/merb_plugin/templates/README +4 -0
  38. data/app_generators/merb_plugin/templates/Rakefile +35 -0
  39. data/app_generators/merb_plugin/templates/TODO +5 -0
  40. data/app_generators/merb_plugin/templates/merbtasks.rb +6 -0
  41. data/app_generators/merb_plugin/templates/sampleplugin.rb +10 -0
  42. data/app_generators/merb_plugin/templates/sampleplugin_spec.rb +7 -0
  43. data/app_generators/merb_plugin/templates/spec_helper.rb +2 -0
  44. data/bin/merb +1 -1
  45. data/lib/autotest/discover.rb +3 -0
  46. data/lib/autotest/merb_rspec.rb +79 -0
  47. data/lib/merb.rb +72 -93
  48. data/lib/merb/{merb_abstract_controller.rb → abstract_controller.rb} +28 -5
  49. data/lib/merb/caching/action_cache.rb +65 -29
  50. data/lib/merb/caching/fragment_cache.rb +9 -4
  51. data/lib/merb/caching/store/file_cache.rb +22 -14
  52. data/lib/merb/caching/store/memory_cache.rb +26 -8
  53. data/lib/merb/{merb_constants.rb → constants.rb} +9 -7
  54. data/lib/merb/controller.rb +178 -0
  55. data/lib/merb/core_ext.rb +13 -11
  56. data/lib/merb/core_ext/array.rb +0 -0
  57. data/lib/merb/core_ext/{merb_class.rb → class.rb} +0 -0
  58. data/lib/merb/core_ext/{merb_enumerable.rb → enumerable.rb} +0 -0
  59. data/lib/merb/core_ext/get_args.rb +52 -0
  60. data/lib/merb/core_ext/{merb_hash.rb → hash.rb} +40 -11
  61. data/lib/merb/core_ext/{merb_inflections.rb → inflections.rb} +0 -0
  62. data/lib/merb/core_ext/{merb_inflector.rb → inflector.rb} +1 -1
  63. data/lib/merb/core_ext/{merb_kernel.rb → kernel.rb} +56 -3
  64. data/lib/merb/core_ext/mash.rb +88 -0
  65. data/lib/merb/core_ext/{merb_module.rb → module.rb} +0 -0
  66. data/lib/merb/core_ext/{merb_numeric.rb → numeric.rb} +0 -0
  67. data/lib/merb/core_ext/{merb_object.rb → object.rb} +10 -47
  68. data/lib/merb/core_ext/string.rb +56 -0
  69. data/lib/merb/core_ext/{merb_symbol.rb → symbol.rb} +0 -0
  70. data/lib/merb/dispatcher.rb +109 -0
  71. data/lib/merb/{merb_drb_server.rb → drb_server.rb} +0 -0
  72. data/lib/merb/erubis_ext.rb +10 -0
  73. data/lib/merb/exceptions.rb +173 -0
  74. data/lib/merb/generators/merb_app/merb_app.rb +5 -25
  75. data/lib/merb/generators/merb_generator_helpers.rb +317 -0
  76. data/lib/merb/generators/merb_plugin.rb +19 -0
  77. data/lib/merb/logger.rb +65 -0
  78. data/lib/merb/{merb_mail_controller.rb → mail_controller.rb} +102 -49
  79. data/lib/merb/{merb_mailer.rb → mailer.rb} +31 -27
  80. data/lib/merb/mixins/{basic_authentication_mixin.rb → basic_authentication.rb} +3 -3
  81. data/lib/merb/mixins/{controller_mixin.rb → controller.rb} +131 -112
  82. data/lib/merb/mixins/{erubis_capture_mixin.rb → erubis_capture.rb} +12 -21
  83. data/lib/merb/mixins/{form_control_mixin.rb → form_control.rb} +6 -12
  84. data/lib/merb/mixins/render.rb +401 -0
  85. data/lib/merb/mixins/responder.rb +378 -0
  86. data/lib/merb/mixins/{view_context_mixin.rb → view_context.rb} +65 -10
  87. data/lib/merb/mixins/web_controller.rb +29 -0
  88. data/lib/merb/{merb_handler.rb → mongrel_handler.rb} +59 -38
  89. data/lib/merb/part_controller.rb +19 -0
  90. data/lib/merb/plugins.rb +16 -0
  91. data/lib/merb/rack_adapter.rb +37 -0
  92. data/lib/merb/request.rb +421 -0
  93. data/lib/merb/router.rb +576 -0
  94. data/lib/merb/{merb_server.rb → server.rb} +275 -71
  95. data/lib/merb/session.rb +10 -10
  96. data/lib/merb/session/cookie_store.rb +125 -0
  97. data/lib/merb/session/{merb_mem_cache_session.rb → mem_cache_session.rb} +22 -9
  98. data/lib/merb/session/{merb_memory_session.rb → memory_session.rb} +15 -11
  99. data/lib/merb/template.rb +35 -8
  100. data/lib/merb/template/erubis.rb +16 -10
  101. data/lib/merb/template/haml.rb +33 -20
  102. data/lib/merb/template/markaby.rb +16 -14
  103. data/lib/merb/template/xml_builder.rb +8 -4
  104. data/lib/merb/test/{merb_fake_request.rb → fake_request.rb} +11 -5
  105. data/lib/merb/test/helper.rb +31 -0
  106. data/lib/merb/test/hpricot.rb +136 -0
  107. data/lib/merb/test/{merb_multipart.rb → multipart.rb} +1 -1
  108. data/lib/merb/test/rspec.rb +93 -0
  109. data/lib/merb/{merb_upload_handler.rb → upload_handler.rb} +5 -6
  110. data/lib/merb/{merb_upload_progress.rb → upload_progress.rb} +1 -1
  111. data/lib/merb/{merb_view_context.rb → view_context.rb} +27 -42
  112. data/lib/{merb_tasks.rb → tasks.rb} +0 -0
  113. data/lib/tasks/merb.rake +21 -11
  114. data/merb_default_generators/model/USAGE +0 -0
  115. data/merb_default_generators/model/model_generator.rb +16 -0
  116. data/merb_default_generators/model/templates/new_model_template.erb +5 -0
  117. data/merb_default_generators/resource_controller/USAGE +0 -0
  118. data/merb_default_generators/resource_controller/resource_controller_generator.rb +26 -0
  119. data/merb_default_generators/resource_controller/templates/controller.rb +30 -0
  120. data/merb_default_generators/resource_controller/templates/edit.html.erb +1 -0
  121. data/merb_default_generators/resource_controller/templates/helper.rb +5 -0
  122. data/merb_default_generators/resource_controller/templates/index.html.erb +1 -0
  123. data/merb_default_generators/resource_controller/templates/new.html.erb +1 -0
  124. data/merb_default_generators/resource_controller/templates/show.html.erb +1 -0
  125. data/merb_generators/controller/USAGE +5 -0
  126. data/merb_generators/controller/controller_generator.rb +16 -0
  127. data/merb_generators/controller/templates/controller.rb +8 -0
  128. data/merb_generators/controller/templates/helper.rb +5 -0
  129. data/merb_generators/controller/templates/index.html.erb +3 -0
  130. data/merb_generators/resource/USAGE +0 -0
  131. data/merb_generators/resource/resource_generator.rb +60 -0
  132. data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +67 -0
  133. data/rspec_generators/merb_controller_test/templates/controller_spec.rb +8 -0
  134. data/rspec_generators/merb_controller_test/templates/edit_spec.rb +12 -0
  135. data/rspec_generators/merb_controller_test/templates/helper_spec.rb +5 -0
  136. data/rspec_generators/merb_controller_test/templates/index_spec.rb +12 -0
  137. data/rspec_generators/merb_controller_test/templates/new_spec.rb +12 -0
  138. data/rspec_generators/merb_controller_test/templates/show_spec.rb +5 -0
  139. data/rspec_generators/merb_model_test/merb_model_test_generator.rb +26 -0
  140. data/rspec_generators/merb_model_test/templates/model_spec_template.erb +7 -0
  141. data/script/destroy +14 -0
  142. data/script/generate +14 -0
  143. data/test_unit_generators/merb_controller_test/merb_controller_test_generator.rb +53 -0
  144. data/test_unit_generators/merb_controller_test/templates/functional_test.rb +17 -0
  145. data/test_unit_generators/merb_controller_test/templates/helper_test.rb +9 -0
  146. data/test_unit_generators/merb_model_test/merb_model_test_generator.rb +29 -0
  147. data/test_unit_generators/merb_model_test/templates/model_test_unit_template.erb +9 -0
  148. metadata +172 -94
  149. data/examples/README_EXAMPLES +0 -10
  150. data/examples/skeleton/Rakefile +0 -68
  151. data/examples/skeleton/dist/app/views/layout/application.herb +0 -12
  152. data/examples/skeleton/dist/conf/database.yml +0 -23
  153. data/examples/skeleton/dist/conf/merb.yml +0 -57
  154. data/examples/skeleton/dist/conf/merb_init.rb +0 -24
  155. data/examples/skeleton/dist/conf/router.rb +0 -22
  156. data/examples/skeleton/dist/conf/upload.conf +0 -5
  157. data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +0 -14
  158. data/examples/skeleton/script/new_migration +0 -21
  159. data/lib/merb/core_ext/merb_string.rb +0 -18
  160. data/lib/merb/merb_controller.rb +0 -206
  161. data/lib/merb/merb_dispatcher.rb +0 -87
  162. data/lib/merb/merb_exceptions.rb +0 -319
  163. data/lib/merb/merb_part_controller.rb +0 -42
  164. data/lib/merb/merb_plugins.rb +0 -293
  165. data/lib/merb/merb_request.rb +0 -165
  166. data/lib/merb/merb_router.rb +0 -309
  167. data/lib/merb/merb_yaml_store.rb +0 -31
  168. data/lib/merb/mixins/render_mixin.rb +0 -283
  169. data/lib/merb/mixins/responder_mixin.rb +0 -159
  170. data/lib/merb/session/merb_ar_session.rb +0 -131
  171. data/lib/merb/vendor/paginator/README.txt +0 -84
  172. data/lib/merb/vendor/paginator/paginator.rb +0 -124
  173. data/lib/tasks/db.rake +0 -55
@@ -3,29 +3,36 @@ require 'optparse'
3
3
  require 'ostruct'
4
4
  require 'fileutils'
5
5
  require 'yaml'
6
- require 'erubis'
7
6
 
8
7
  module Merb
9
8
 
10
9
  class Config
11
- def self.setup
12
- defaults = {
13
- :host => "0.0.0.0",
14
- :port => "4000",
15
- :allow_reloading => true,
16
- :merb_root => Dir.pwd,
17
- :cache_templates => false,
18
- :use_mutex => true,
19
- :session_id_cookie_only => true,
20
- :query_string_whitelist => []
21
- }
22
- begin
23
- options = defaults.merge(YAML.load(Erubis::Eruby.new(IO.read("#{defaults[:merb_root]}/dist/conf/merb.yml")).result))
24
- rescue
25
- options = defaults
10
+ class << self
11
+ def defaults
12
+ @defaults ||= {
13
+ :host => "0.0.0.0",
14
+ :port => "4000",
15
+ :reloader => true,
16
+ :merb_root => Dir.pwd,
17
+ :cache_templates => false,
18
+ :use_mutex => true,
19
+ :session_id_cookie_only => true,
20
+ :query_string_whitelist => []
21
+ }
26
22
  end
27
23
 
28
- options
24
+ def setup
25
+ if FileTest.exist? "#{defaults[:merb_root]}/framework"
26
+ $LOAD_PATH.unshift( "#{defaults[:merb_root]}/framework" )
27
+ end
28
+ merb_yml = "#{defaults[:merb_root]}/config/merb.yml"
29
+ if File.exists?(merb_yml)
30
+ require 'merb/erubis_ext'
31
+ defaults.merge(Erubis.load_yaml_file(merb_yml))
32
+ else
33
+ defaults
34
+ end
35
+ end
29
36
  end
30
37
  end
31
38
 
@@ -37,6 +44,9 @@ module Merb
37
44
  options = Merb::Config.setup
38
45
 
39
46
  opts = OptionParser.new do |opts|
47
+ opts.version = "0.4.0"
48
+ opts.release = "svn"
49
+
40
50
  opts.banner = "Usage: merb [fdcepghmisluMG] [argument]"
41
51
  opts.define_head "Merb Mongrel+ Erb. Lightweight replacement for ActionPack."
42
52
  opts.separator '*'*80
@@ -66,7 +76,7 @@ module Merb
66
76
  opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000.") do |port|
67
77
  options[:port] = port
68
78
  end
69
-
79
+
70
80
  opts.on("-h", "--host HOSTNAME", "Host to bind to (default is all IP's).") do |host|
71
81
  options[:host] = host
72
82
  end
@@ -93,26 +103,39 @@ module Merb
93
103
  options[:environment] = env
94
104
  end
95
105
 
96
- opts.on("-r", "--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]", "Command-line option to run scripts and/or code in the merb app.") do |stuff_to_run|
106
+ opts.on("-r", "--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]",
107
+ "Command-line option to run scripts and/or code in the merb app.") do |stuff_to_run|
97
108
  options[:runner] = stuff_to_run
98
109
  end
99
-
110
+
100
111
  opts.on("-g", "--generate-app PATH", "Generate a fresh merb app at PATH.") do |path|
101
112
  options[:generate] = path || Dir.pwd
102
113
  end
103
-
104
- opts.on("-P", "--plugin ACTION NAME", "Do ACTION with a plugin called NAME.") do |action|
105
- options[:plugin] = [action, ARGV] || nil
114
+
115
+ opts.on("-P","--generate-plugin PATH", "Generate a fresh merb plugin at PATH.") do |path|
116
+ options[:generate_plugin] = path || Dir.pwd
106
117
  end
107
-
108
- opts.on("-k", "--kill PORT or all", "Kill one merb proceses by port number. use merb -k all to kill all merbs.") do |ports|
118
+
119
+ opts.on("-k", "--kill PORT or all", "Kill one merb proceses by port number. Use merb -k all to kill all merbs.") do |ports|
109
120
  options[:kill] = ports
110
121
  end
122
+
123
+ 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|
124
+ options[:graceful] = ports
125
+ end
111
126
 
112
127
  opts.on("-M", "--merb-config FILENAME", "This flag is for explicitly declaring the merb app's config file.") do |config|
113
128
  options[:merb_config] = config
114
129
  end
115
-
130
+
131
+ opts.on("-w", "--webrick", "Run merb using Webrick Rack Adapter instead of mongrel.") do |webport|
132
+ options[:webrick] = true
133
+ end
134
+
135
+ opts.on("-F", "--fastcgi", "Run merb using FastCGI Rack Adapter instead of mongrel.") do
136
+ options[:fastcgi] = true
137
+ end
138
+
116
139
  opts.on("-X", "--mutex on/off", "This flag is for turning the mutex lock on and off.") do |mutex|
117
140
  if mutex == 'off'
118
141
  options[:use_mutex] = false
@@ -121,21 +144,29 @@ module Merb
121
144
  end
122
145
  end
123
146
 
124
- opts.on("-?", "--help", "Show this help message") do
147
+ opts.on("-?", "-H", "--help", "Show this help message") do
125
148
  puts opts
126
149
  exit
127
- end
128
-
150
+ end
151
+ end
152
+
153
+ # Special case of looking for help
154
+ if ARGV == ["-h"]
155
+ puts opts
156
+ exit
129
157
  end
130
-
131
158
  opts.parse!(@@merb_raw_opts)
159
+ # merb <argument> is same as merb -g <argument>
160
+ if ARGV.size == 1
161
+ options[:generate] = File.expand_path(ARGV.last)
162
+ end
132
163
 
133
164
  # Added by: Rogelio J. Samour 2007-01-23
134
165
  # We need to reload the options that exist in the App's merb.yml
135
166
  # This is needed when one calls merb NOT from the merb_app ROOT
136
- # like so: merb --merb-config /path/to/dist/conf/merb.yml -m /path/to/merb/app
167
+ # like so: merb --merb-config /path/to/config/merb.yml -m /path/to/merb/app
137
168
  # or if we add :merb_root: /path/to/merb/app in the merb.yml we can now only call it
138
- # like so: merb --merb-config /path/to/dist/conf/merb.yml
169
+ # like so: merb --merb-config /path/to/config/merb.yml
139
170
  if options[:merb_config]
140
171
  # Check and see if an environment has been set through the CLI
141
172
  # if so, save it in a temp. In this case, if merb.yml has an :environment:
@@ -143,7 +174,7 @@ module Merb
143
174
  if options[:environment]
144
175
  temp_env = options[:environment]
145
176
  end
146
- options = options.merge(YAML.load(Erubis::Eruby.new(IO.read("#{options[:merb_config]}")).result))
177
+ options.merge!(Erubis.load_yaml_file("#{options[:merb_config]}"))
147
178
  if temp_env
148
179
  options[:environment] = temp_env
149
180
  end
@@ -161,26 +192,175 @@ module Merb
161
192
 
162
193
  @@merb_opts = options
163
194
  end
195
+
196
+ def max_mtime( files = [] )
197
+ files.map{ |file| File.mtime(file) rescue @mtime }.max
198
+ end
199
+
200
+ def register_session_type(name, file, description = nil)
201
+ @registered_session_types ||= YAML::Omap.new
202
+ @registered_session_types[name] = {
203
+ :file => file,
204
+ :description => (description || "Using #{name} sessions")
205
+ }
206
+ end
164
207
 
208
+ def add_controller_mixins
209
+ types = @registered_session_types
210
+ Merb::Controller.class_eval do
211
+ lib = File.join(__DIR__, 'merb')
212
+ session_store = Merb::Server.config[:session_store].to_s
213
+ if ["", "false"].include?(session_store)
214
+ puts "Not Using Sessions"
215
+ elsif reg = types[session_store]
216
+ require reg[:file]
217
+ include ::Merb::SessionMixin
218
+ puts reg[:description]
219
+ else
220
+ puts "Session store not found, '#{Merb::Server.config[:session_store]}'."
221
+ puts "Defaulting to CookieStore Sessions"
222
+ require types['cookie'][:file]
223
+ include ::Merb::SessionMixin
224
+ puts "(plugin not installed?)"
225
+ end
226
+
227
+ if Merb::Server.config[:basic_auth]
228
+ require lib + "/mixins/basic_authentication"
229
+ include ::Merb::AuthenticationMixin
230
+ puts "Basic Authentication mixed in"
231
+ end
232
+ end
233
+ end
234
+
165
235
  def initialize_merb
166
236
  require 'merb'
167
- require @@merb_opts[:merb_root] / 'dist/conf/router.rb'
168
- require @@merb_opts[:merb_root] / 'dist/conf/merb_init.rb'
169
-
170
- end
237
+ @mtime = Time.now if @@merb_opts[:reloader] == true
238
+ # Register session types before merb_init.rb so that any additional
239
+ # session stores will be added to the end of the list and become the
240
+ # default.
241
+ register_session_type('memory',
242
+ __DIR__ / "merb" / "session" / "memory_session",
243
+ "Using in-memory sessions; sessions will be lost whenever the server stops.")
244
+ register_session_type('mem_cache',
245
+ __DIR__ / "merb" / "session" / "mem_cache_session",
246
+ "Using MemCache distributed memory sessions")
247
+ register_session_type('cookie', # Last session type becomes the default
248
+ __DIR__ / "merb" / "session" / "cookie_store",
249
+ "Using 'share-nothing' cookie sessions (4kb limit per client)")
250
+ require @@merb_opts[:merb_root] / 'config/merb_init.rb'
251
+ add_controller_mixins
252
+ end
253
+
254
+ def after_app_loads(&block)
255
+ @after_app_blocks ||= []
256
+ @after_app_blocks << block
257
+ end
258
+
259
+ def app_loaded?
260
+ @app_loaded
261
+ end
262
+
263
+ def load_action_arguments(klasses = Merb::Controller._subclasses)
264
+ klasses.each do |controller|
265
+ controller = Object.full_const_get(controller)
266
+ controller.action_argument_list = {}
267
+ controller.callable_actions.each do |action, bool|
268
+ controller.action_argument_list[action.to_sym] = ParseTreeArray.translate(controller, action).get_args
269
+ end
270
+ end if defined?(ParseTreeArray)
271
+ end
272
+
273
+ def load_application
274
+ MERB_PATHS.each do |glob|
275
+ Dir[MERB_ROOT + glob].each { |m| require m }
276
+ end
277
+ load_action_arguments
278
+ @app_loaded = true
279
+ (@after_app_blocks || []).each { |b| b.call }
280
+ end
171
281
 
282
+ def remove_constant(const)
283
+ parts = const.to_s.split("::")
284
+ base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
285
+ object = parts[-1].intern
286
+ MERB_LOGGER.info("Removing constant #{object} from #{base}")
287
+ base.send(:remove_const, object) if object
288
+ Merb::Controller._subclasses.delete(const)
289
+ end
290
+
291
+ def reload
292
+ return if !@@merb_opts[:reloader] || !Object.const_defined?(:MERB_PATHS)
293
+ # First we collect all files in the project (this will also grab newly added files)
294
+ project_files = MERB_PATHS.map { |path| Dir[@@merb_opts[:merb_root] + path] }.flatten.uniq
295
+ project_mtime = max_mtime project_files # Latest changed time of all project files
296
+
297
+ return if @mtime.nil? || @mtime >= project_mtime # Only continue if a file has changed
298
+
299
+ project_files.each do |file|
300
+ if File.mtime(file) >= @mtime
301
+ # If the file has changed or been added since the last project reload time
302
+ # remove any cannonical constants, based on what type of project file it is
303
+ # and then reload the file
304
+ begin
305
+ constant = case file
306
+ when %r[/app/(models|controllers|parts|mailers)/(.+)\.rb$]
307
+ $2.to_const_string
308
+ when %r[/app/(helpers)/(.+)\.rb$]
309
+ "Merb::" + $2.to_const_string
310
+ end
311
+ remove_constant(constant)
312
+ rescue NameError => e
313
+ MERB_LOGGER.warn "Couldn't remove constant #{constant}"
314
+ end
315
+
316
+ begin
317
+ MERB_LOGGER.info("Reloading file #{file}")
318
+ old_subclasses = Merb::Controller._subclasses.dup
319
+ load(file)
320
+ loaded_classes = Merb::Controller._subclasses - old_subclasses
321
+ load_action_arguments(loaded_classes)
322
+ rescue Exception => e
323
+ puts "Error reloading file #{file}: #{e}"
324
+ MERB_LOGGER.warn " Error: #{e}"
325
+ end
326
+
327
+ # constant = file =~ /\/(controllers|models|mailers|helpers|parts)\/(.*).rb/ ? $2.to_const_string : nil
328
+ # remove_constant($2.to_const_string, ($1 == "helpers") ? Merb : nil)
329
+ # load file and puts "loaded file: #{file}"
330
+ end
331
+ end
332
+
333
+ @mtime = project_mtime # As the last action, update the current @mtime
334
+ end
335
+
172
336
  def run
173
337
  @@merb_raw_opts = ARGV
174
338
  merb_config
339
+
340
+ if @@merb_opts[:generate] #|| @@merb_opts.size == 1
341
+ require 'merb/generators/merb_app/merb_app'
342
+ ::Merb::AppGenerator.run @@merb_opts[:generate]
343
+ exit!
344
+ end
345
+
346
+ if ENV['EVENT'] || ENV['SWIFT']
347
+ @@merb_opts[:use_mutex] = false
348
+ end
175
349
 
350
+ if @@merb_opts[:graceful]
351
+ @@merb_opts[:kill] = @@merb_opts[:graceful]
352
+ graceful = true
353
+ end
354
+
176
355
  if k = @@merb_opts[:kill]
177
356
  begin
178
357
  Dir[@@merb_opts[:merb_root] + "/log/merb.#{k == 'all' ? '*' : k }.pid"].each do |f|
179
358
  puts f
180
359
  pid = IO.read(f).chomp.to_i
181
- Process.kill(9, pid)
360
+ signal = graceful ? 1 : 9
361
+ Process.kill(signal, pid)
182
362
  FileUtils.rm f
183
- puts "killed PID: #{pid}"
363
+ puts "killed PID #{pid} with signal #{signal}"
184
364
  end
185
365
  rescue
186
366
  puts "Failed to kill! #{k}"
@@ -190,39 +370,36 @@ module Merb
190
370
  end
191
371
 
192
372
  case @@merb_opts[:environment].to_s
193
- when 'development'
194
- @@merb_opts[:allow_reloading] ||= true
195
- @@merb_opts[:show_error] ||= true
196
373
  when 'production'
197
- @@merb_opts[:allow_reloading] = false
198
- @@merb_opts[:show_error] ||= false
374
+ @@merb_opts[:reloader] = @@merb_opts.fetch(:reloader, false)
375
+ @@merb_opts[:exception_details] = @@merb_opts.fetch(:exception_details, false)
199
376
  @@merb_opts[:cache_templates] = true
200
- when 'test'
201
- @@merb_opts[:allow_reloading] ||= true
202
- @@merb_opts[:show_error] ||= true
203
377
  else
204
- @@merb_opts[:allow_reloading] ||= true
205
- @@merb_opts[:show_error] ||= true
206
- end
207
-
208
- @@merb_opts[:dist_root] = @@merb_opts[:merb_root]+'/dist'
209
- $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/models') )
210
- $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/controllers') )
211
- $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/lib') )
212
- if File.exist? File.join(@@merb_opts[:dist_root] , '/framework')
213
- $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/framework') )
378
+ @@merb_opts[:reloader] = @@merb_opts.fetch(:reloader, true)
379
+ @@merb_opts[:exception_details] = @@merb_opts.fetch(:exception_details, true)
214
380
  end
215
-
216
- if @@merb_opts[:generate]
217
- require 'merb/generators/merb_app/merb_app'
218
- ::Merb::AppGenerator.run @@merb_opts[:generate]
381
+
382
+ @@merb_opts[:reloader_time] ||= 0.5 if @@merb_opts[:reloader] == true
383
+
384
+ $LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/app/models') )
385
+ $LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/app/controllers') )
386
+ $LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/lib') )
387
+
388
+ if @@merb_opts[:generate_plugin]
389
+ require 'merb/generators/merb_plugin'
390
+ ::Merb::PluginGenerator.run @@merb_opts[:generate_plugin]
219
391
  exit!
220
392
  end
221
393
 
222
- if @@merb_opts[:plugin]
223
- require 'merb/merb_plugins'
224
- ::Merb::PluginManager.action(@@merb_opts[:plugin].shift, @@merb_opts[:plugin][0].shift, @@merb_opts[:plugin])
225
- exit!
394
+ if @@merb_opts[:reloader]
395
+ Thread.abort_on_exception = true
396
+ Thread.new do
397
+ loop do
398
+ sleep( @@merb_opts[:reloader_time] )
399
+ reload
400
+ end
401
+ Thread.exit
402
+ end
226
403
  end
227
404
 
228
405
  if @@merb_opts[:console]
@@ -278,6 +455,18 @@ module Merb
278
455
  exit if @@merb_opts[:only_drb]
279
456
  end
280
457
 
458
+ if @@merb_opts[:webrick]
459
+ puts "Starting merb webrick server on port: #{@@merb_opts[:port]}"
460
+ trap('TERM') { exit }
461
+ webrick_start(@@merb_opts[:port])
462
+ end
463
+
464
+ if @@merb_opts[:fastcgi]
465
+ trap('TERM') { exit }
466
+ fastcgi_start
467
+ end
468
+
469
+
281
470
  if @@merb_opts[:cluster]
282
471
  delete_pidfiles
283
472
  @@merb_opts[:port].to_i.upto(@@merb_opts[:port].to_i+@@merb_opts[:cluster].to_i-1) do |port|
@@ -317,6 +506,21 @@ module Merb
317
506
  end
318
507
  end
319
508
 
509
+ def webrick_start(port)
510
+ initialize_merb
511
+ require 'rack'
512
+ require 'merb/rack_adapter'
513
+ ::Rack::Handler::WEBrick.run Merb::Rack::Adapter.new,
514
+ :Port => port
515
+ end
516
+
517
+ def fastcgi_start
518
+ initialize_merb
519
+ require 'rack'
520
+ require 'merb/rack_adapter'
521
+ ::Rack::Handler::FastCGI.run Merb::Rack::Adapter.new
522
+ end
523
+
320
524
  def delete_pidfiles(portor_star='*')
321
525
  Dir["#{@@merb_opts[:merb_root]}/log/merb.#{portor_star}.pid"].each do |pid|
322
526
  FileUtils.rm(pid) rescue nil
@@ -326,7 +530,7 @@ module Merb
326
530
  def drbserver_start(port)
327
531
  puts "Starting merb drb server on port: #{port}"
328
532
  require 'merb/merb_drb_server'
329
- drb_init = File.join(@@merb_opts[:merb_root], "/dist/conf/merb_drb_init")
533
+ drb_init = File.join(@@merb_opts[:merb_root], "/config/merb_drb_init")
330
534
  require drb_init if File.exist?(drb_init)
331
535
  DRb.start_service("druby://#{@@merb_opts[:host]}:#{port}", Merb::DrbServiceProvider)
332
536
  DRb.thread.join
@@ -346,12 +550,12 @@ module Merb
346
550
  mconf_hash[:group] = @@merb_opts[:group]
347
551
  end
348
552
  mconfig = Mongrel::Configurator.new(mconf_hash) do
349
- yconfig = YAML.load(Erubis::Eruby.new(IO.read(File.expand_path(@@merb_opts[:config]))).result) if @@merb_opts[:config]
350
553
  listener do
351
- uri( "/", :handler => MerbUploadHandler.new(yconfig), :in_front => true) if @@merb_opts[:config]
352
- uri "/", :handler => MerbHandler.new(@@merb_opts[:dist_root]+'/public')
554
+ uri( "/", :handler => MerbUploadHandler.new(@@merb_opts), :in_front => true) if @@merb_opts[:upload_path_match]
555
+ uri "/", :handler => MerbHandler.new(@@merb_opts[:merb_root]+'/public')
353
556
  uri "/favicon.ico", :handler => Mongrel::Error404Handler.new("")
354
557
  end
558
+ MerbHandler.path_prefix = @@merb_opts[:path_prefix]
355
559
 
356
560
  trap("INT") { stop }
357
561
  run
@@ -362,8 +566,8 @@ module Merb
362
566
  def config
363
567
  @@merb_opts
364
568
  end
365
-
366
- end
569
+
570
+ end # class << self
367
571
 
368
572
  end # Server
369
573