merb 0.3.7 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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