spiderfw 0.6.25 → 0.6.26.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG +15 -0
  2. data/VERSION +1 -1
  3. data/apps/core/auth/controllers/login_controller.rb +2 -0
  4. data/apps/core/auth/controllers/mixins/auth_helper.rb +1 -1
  5. data/apps/core/auth/public/css/login.css +49 -0
  6. data/apps/core/auth/views/login.layout.shtml +14 -0
  7. data/apps/core/auth/views/login.shtml +1 -0
  8. data/apps/core/components/public/js/jquery/plugins/jquery.ui.nestedSortable.js +356 -0
  9. data/apps/core/forms/public/date_time.js +1 -1
  10. data/apps/core/forms/public/select.js +1 -1
  11. data/apps/core/forms/tags/element_row.erb +2 -2
  12. data/apps/core/forms/widgets/form/form.rb +34 -22
  13. data/apps/messenger/_init.rb +1 -0
  14. data/apps/messenger/views/admin/index.shtml +1 -1
  15. data/apps/messenger/views/index.shtml +1 -1
  16. data/blueprints/.DS_Store +0 -0
  17. data/blueprints/home/.DS_Store +0 -0
  18. data/blueprints/install/.DS_Store +0 -0
  19. data/data/keys/spider.rsa +27 -0
  20. data/data/keys/spider.rsa.pub +1 -0
  21. data/lib/spiderfw/app.rb +64 -4
  22. data/lib/spiderfw/autoload.rb +0 -1
  23. data/lib/spiderfw/cmd/commands/app.rb +2 -1
  24. data/lib/spiderfw/controller/controller.rb +189 -90
  25. data/lib/spiderfw/controller/dispatcher.rb +13 -3
  26. data/lib/spiderfw/controller/http_controller.rb +18 -4
  27. data/lib/spiderfw/controller/mixins/http_mixin.rb +37 -10
  28. data/lib/spiderfw/controller/mixins/visual.rb +14 -5
  29. data/lib/spiderfw/http/http.rb +5 -0
  30. data/lib/spiderfw/model/base_model.rb +1 -11
  31. data/lib/spiderfw/model/condition.rb +7 -4
  32. data/lib/spiderfw/model/mappers/mapper.rb +2 -2
  33. data/lib/spiderfw/requires.rb +1 -0
  34. data/lib/spiderfw/setup/app_manager.rb +7 -2
  35. data/lib/spiderfw/setup/setup_task.rb +1 -1
  36. data/lib/spiderfw/setup/spider_setup_wizard.rb +1 -1
  37. data/lib/spiderfw/spider.rb +4 -1
  38. data/lib/spiderfw/templates/layout.rb +8 -3
  39. data/lib/spiderfw/templates/template.rb +2 -1
  40. data/lib/spiderfw/test/rack_tester.rb +10 -0
  41. data/lib/spiderfw/widget/widget_plugin.rb +8 -1
  42. metadata +254 -157
  43. data/lib/spiderfw/model/storage/db/connectors/mysql.rb +0 -16
  44. data/lib/spiderfw/model/storage/db/connectors/mysql2.rb +0 -9
data/lib/spiderfw/app.rb CHANGED
@@ -228,6 +228,12 @@ module Spider
228
228
  end
229
229
  end
230
230
 
231
+ def route_path(action='')
232
+ path = Spider::ControllerMixins::HTTPMixin.reverse_proxy_mapping('/'+@route_url)
233
+ action = action[1..-1] if action[0].chr == '/'
234
+ [path, action].reject{ |p| p.blank? }.join('/')
235
+ end
236
+
231
237
 
232
238
  # Convenience method: since all classes inside the app have an #app method,
233
239
  # the App itself has it too
@@ -237,14 +243,40 @@ module Spider
237
243
  end
238
244
 
239
245
  # Require files inside the App's path
240
- # @param [file1,file2...] files to require
246
+ #
247
+ # Can accept either a list of files to require, relative to the app's path; or, a Hash
248
+ # containing arrays for keys corresponding to folders inside app (e.g. :models, :controllers)
249
+ #
250
+ # If an Hash is provided, will load files in the order :lib, :models, :widgets, :controllers, followed
251
+ # by any additional keys, in the order they are defined in the Hash (under Ruby 1.9.x), or in random order (Ruby 1.8.x)
252
+ # @param [Hash|file1,file2,...] files to require
241
253
  # @return [nil]
242
254
  def req(*list)
243
- list.each do |file|
244
- require File.join(@path, file)
255
+ do_require = lambda{ |f|
256
+ Kernel.require File.join(@path, f)
257
+ }
258
+ if list.first.is_a?(Hash)
259
+ hash = list.first
260
+ load_keys = ([:lib, :models, :widgets, :controllers] + hash.keys).uniq
261
+ load_keys.each do |k|
262
+ if hash[k].is_a?(Array)
263
+ hash[k].each{ |file|
264
+ if k == :widgets
265
+ file = File.join(file, file)
266
+ end
267
+ file = File.join(k.to_s, file)
268
+ do_require.call(file)
269
+ }
270
+ end
271
+ end
272
+ else
273
+ list.each do |file|
274
+ do_require.call(file)
275
+ end
245
276
  end
246
277
  end
247
-
278
+
279
+ alias :app_require :req
248
280
 
249
281
 
250
282
  # Returns the currently installed version of an app
@@ -600,6 +632,34 @@ END_OF_EVAL
600
632
  include TSort
601
633
 
602
634
  end
635
+
636
+ # This module is included Controller and BaseModel, and provides the
637
+ # app method, returning the class' app.
638
+ module AppClass
639
+
640
+ def self.included(klass)
641
+ klass.extend(ClassMethods)
642
+ end
643
+
644
+ # @return [App] The app to which the object's class belongs
645
+ def app
646
+ return self.class.app
647
+ end
648
+
649
+ module ClassMethods
650
+
651
+ # @return [App] The app to which the class belongs
652
+ def app
653
+ return @app if @app
654
+ @app ||= self.parent_module
655
+ while @app && !@app.include?(Spider::App) && @app != Object
656
+ @app = @app.parent_module
657
+ end
658
+ @app = nil if @app && !@app.include?(Spider::App)
659
+ return @app
660
+ end
661
+ end
662
+ end
603
663
 
604
664
  end
605
665
 
@@ -1,6 +1,5 @@
1
1
  module Spider
2
2
  autoload :Logger, "spiderfw/utils/logger"
3
- autoload :App, "spiderfw/app"
4
3
  autoload :Controller, "spiderfw/controller/controller"
5
4
  autoload :Widget, "spiderfw/widget/widget"
6
5
  autoload :PageController, "spiderfw/controller/page_controller"
@@ -190,6 +190,7 @@ module Spider::CommandLine
190
190
  opt.on("--no-clear-cache", _("Don't clear cache"), "-C"){ |c| @no_clear_cache = true }
191
191
  opt.on("--no-restart", _("Don't restart the server after the udpate"), "-R"){ |r| @no_restart = true }
192
192
  opt.on("--branch [BRANCH]", _("Install app from specific branch"), "-b"){ |b| @branch = b }
193
+ opt.on("--no-rollback", _("Don't rollback if update fails")){ |rb| @no_rollback = rb }
193
194
  end
194
195
  update.set_execution_block do |args|
195
196
  $SPIDER_INTERACTIVE = true
@@ -201,7 +202,7 @@ module Spider::CommandLine
201
202
  options = {
202
203
  :no_git => @no_git, :all => @all, :no_deps => @no_deps, :no_optional => @no_optional,
203
204
  :no_gems => @no_gems, :no_optional_gems => @no_optional_gems, :no_activate => @no_activate,
204
- :clear_cache => !@no_clear_cache, :restart => !@no_restart
205
+ :clear_cache => !@no_clear_cache, :restart => !@no_restart, :no_rollback => @no_rollback
205
206
  }
206
207
  options[:url] = @server_url if @server_url
207
208
  options[:branch] = @branch if @branch
@@ -18,6 +18,7 @@ require 'spiderfw/utils/annotations'
18
18
  module Spider
19
19
 
20
20
  class Controller
21
+ include App::AppClass
21
22
  include Dispatcher
22
23
  include Logger
23
24
  include ControllerMixins
@@ -25,60 +26,47 @@ module Spider
25
26
  include Annotations
26
27
 
27
28
  class << self
28
-
29
- def options
30
- @options ||= {}
31
- end
32
-
33
- def option(k, v)
34
- self.option[k] = v
35
- end
36
29
 
37
30
  def default_action
38
31
  'index'
39
32
  end
40
33
 
41
- def app
42
- return @app if @app
43
- @app ||= self.parent_module
44
- while @app && !@app.include?(Spider::App) && @app != Object
45
- @app = @app.parent_module
46
- end
47
- @app = nil if @app && !@app.include?(Spider::App)
48
- return @app
49
- end
50
-
34
+ # @return [String] Path to this controller's templates
51
35
  def template_path
52
36
  return nil unless self.app
53
- return self.app.path+'/views'
37
+ return File.join(self.app.path, '/views')
54
38
  end
55
39
 
40
+ # @return [String] Path to this controller's layouts
56
41
  def layout_path
57
42
  return nil unless self.app
58
- return self.app.path+'/views'
43
+ return File.join(self.app.path, '/views')
59
44
  end
60
45
 
61
46
  # Defines a method that will be called before the controller's before,
62
47
  # if the action matches the given conditions.
63
- # - The first argument, the condition(s), may be a String, a Regexp, a Proc or a Symbol,
64
- # that will be checked against the action, or an Array containing several conditions.
65
- # - The second argument, a Symbol, is the method to be called if the conditions match.
66
- # - The third optional argument, an Hash, may contain :unless => true: in this case,
67
- # the conditions will be inverted, that is, the method will be executed unless the conditions
68
- # match.
69
48
  # Example:
70
- # before('list_', :before_lists)
49
+ # before(/^list_/, :before_lists)
71
50
  # will call the method before_lists if the action starts with 'list_'
51
+ # @param [String|Regexp|Proc|Symbol|Array] conditions what will be checked against the action
52
+ # @param [Symbol] method The method to be called if the conditions match.
53
+ # @param [Hash] params may contain :unless => true: in this case,
54
+ # the conditions will be inverted, that is, the method will
55
+ # be executed unless the conditions match.
56
+ # @return [void]
72
57
  def before(conditions, method, params={})
73
58
  @dispatch_methods ||= {}
74
59
  @dispatch_methods[:before] ||= []
75
60
  @dispatch_methods[:before] << [conditions, method, params]
76
61
  end
77
-
78
- def before_methods
79
- @dispatch_methods && @dispatch_methods[:before] ? @dispatch_methods[:before] : []
80
- end
81
-
62
+
63
+ # Like {Controller.before}, but calls the method unless the conditions match
64
+ # @param [String|Regexp|Proc|Symbol|Array] conditions what will be checked against the action
65
+ # @param [Symbol] method The method to be called if the conditions match.
66
+ # @param [Hash] params may contain :unless => true: in this case,
67
+ # the conditions will be inverted, that is, the method will
68
+ # be executed unless the conditions match.
69
+ # @return [void]
82
70
  def before_unless(condition, method, params={})
83
71
  @dispatch_methods ||= {}
84
72
  @dispatch_methods[:before] ||= []
@@ -86,6 +74,19 @@ module Spider
86
74
  @dispatch_methods[:before] << [condition, method, params]
87
75
  end
88
76
 
77
+ # @return [Array] An array of methods defined with {Controller.before}
78
+ def before_methods
79
+ @dispatch_methods && @dispatch_methods[:before] ? @dispatch_methods[:before] : []
80
+ end
81
+
82
+ # Registers a list of methods as controller actions, that is, methods that can
83
+ # be dispatched to.
84
+ #
85
+ # This method is not usually called directly; using the __.action annotation,
86
+ # or one of the format annotations (__.html, __.xml, __.json, __.text), will
87
+ # make a method a controller action.
88
+ # @param [*Symbol] A list of methods
89
+ # @return [Array] All defined controller actions
89
90
  def controller_actions(*methods)
90
91
  if (methods.length > 0)
91
92
  @controller_actions ||= []
@@ -93,7 +94,15 @@ module Spider
93
94
  end
94
95
  @controller_actions
95
96
  end
97
+
98
+ def controller_action(method, params)
99
+ @controller_actions ||= []
100
+ @controller_actions << method
101
+ @controller_action_params ||= {}
102
+ @controller_action_params[method] = params
103
+ end
96
104
 
105
+ # @return [bool] true if the method is a controller action
97
106
  def controller_action?(method)
98
107
  return false unless self.method_defined?(method)
99
108
  return true if default_action && method == default_action.to_sym
@@ -108,35 +117,75 @@ module Spider
108
117
  end
109
118
  end
110
119
 
120
+ # Finds a resource in the context of the controller's app
121
+ # See {Spider.find_resource}
122
+ # @param [Symbol] resource_type
123
+ # @param [String] path
124
+ # @param [String] cur_path Current path: if set, will be used to resolve relative paths
125
+ # @return [Resource]
111
126
  def find_resource(type, name, cur_path=nil)
112
127
  Spider.find_resource(type, name, cur_path, self)
113
128
  end
114
129
 
130
+ # Returns the path of a resource, or nil if none is found
131
+ # See {Controller.find_resource}
132
+ # @param [Symbol] resource_type
133
+ # @param [String] path
134
+ # @param [String] cur_path Current path: if set, will be used to resolve relative paths
135
+ # @return [Resource]
115
136
  def find_resource_path(type, name, cur_path=nil)
116
137
  res = Spider.find_resource(type, name, cur_path, self)
117
138
  return res ? res.path : nil
118
139
  end
119
140
 
120
- # Returns the canonical url for this controller
121
- def url(action=nil)
141
+ # @param [String] action Additional action to get path for
142
+ # @return [String] The canonical URL path for this controller
143
+ def route_path(action=nil)
122
144
  u = @default_route || ''
123
145
  u += "/#{action}" if action
124
146
  if @default_dispatcher && @default_dispatcher != self
125
- u = @default_dispatcher.url + '/' + u
147
+ u = @default_dispatcher.route_path(u)
126
148
  elsif self.app
127
- u = self.app.url + '/' + u
149
+ u = self.app.route_path(u)
128
150
  end
129
151
  u
130
152
  end
153
+
154
+ # Returns the full URL for the Controller
155
+ # The Controller's implementation returns the route_path.
156
+ #
157
+ # However, the HTTPMixin will override this method to return a full http url;
158
+ # other mixins can override the method in different ways.
159
+ # @param [String] action Additional action to get path for
160
+ # @return [String] The canonical URL for this controller
161
+ def url(action=nil)
162
+ route_path(action)
163
+ end
164
+ alias :route_url :url
131
165
 
132
166
 
133
167
  end
134
168
 
135
- define_annotation(:action) { |k, m| k.controller_actions(m) }
169
+ define_annotation(:action) { |k, m, params| k.controller_action(m, params) }
136
170
 
137
- attr_reader :request, :response, :executed_method, :scene
138
- attr_accessor :dispatch_action, :is_target
171
+ # @return [Spider::Request]
172
+ attr_reader :request
173
+ # @return [Spider::Response]
174
+ attr_reader :response
175
+ # @return [Symbol] The method currently set to be executed, if any
176
+ attr_reader :executed_method
177
+ # @return [Scene]
178
+ attr_reader :scene
179
+ # @return [String] Action used to reach this controller in the dispatch chain
180
+ attr_accessor :dispatch_action
181
+ # @return [bool] True if the controller is the target of the current action
182
+ attr_accessor :is_target
139
183
 
184
+ # Constructor. Note: you can use the {Controller#init} method for custom
185
+ # initialization, instead of overrideing this method
186
+ # @param [Spider::Request] request
187
+ # @param [Spider::Response] response
188
+ # @param [scene]
140
189
  def initialize(request, response, scene=nil)
141
190
  @request = request
142
191
  @response = response
@@ -144,19 +193,20 @@ module Spider
144
193
  @dispatch_path = ''
145
194
  @is_target = true
146
195
  init
147
- #@parent = parent
148
196
  end
149
197
 
150
198
  # Override this for controller initialization
199
+ # @return [void]
151
200
  def init
152
-
153
201
  end
154
202
 
203
+ # @return [String]
155
204
  def inspect
156
205
  self.class.to_s
157
206
  end
158
207
 
159
- def call_path
208
+ # @return [String] The actual action path used to reach this Controller
209
+ def request_path
160
210
  act = @dispatch_action || ''
161
211
  if (@dispatch_previous)
162
212
  prev = @dispatch_previous.call_path
@@ -164,16 +214,15 @@ module Spider
164
214
  end
165
215
  return ('/'+act).gsub(/\/+/, '/').sub(/\/$/, '')
166
216
  end
217
+ alias :call_path :request_path
167
218
 
168
- def request_path
169
- call_path
170
- end
171
-
219
+ # Returns the method to call on the controller given an action, and the arguments
220
+ # that should be passed to it.
221
+ # @param [String] action
222
+ # @return [Array] A two elements array, containing the method, and additional arguments
172
223
  def get_action_method(action)
173
224
  method = nil
174
225
  additional_arguments = nil
175
- # method = action.empty? ? self.class.default_action : action
176
- # method = method.split('/', 2)[0]
177
226
  if (action =~ /^([^:]+)(:.+)$/)
178
227
  method = $1
179
228
  elsif (action =~ /^([^\/]+)\/(.+)$/) # methods followed by a slash
@@ -191,16 +240,26 @@ module Spider
191
240
 
192
241
  # Returns true if this controller is the final target for the current action, that is, if it does not
193
242
  # dispatch to any route
243
+ # @return [bool] True if the controller is the final target
194
244
  def action_target?
195
- !@dispatch_next[@call_path] || @dispatch_next[@call_path].dest == self
245
+ !@dispatch_next[@call_path] || @dispatch_next[@call_path].dest == self \
246
+ || @dispatch_next[@call_path].dest == self.class
196
247
  end
197
248
 
198
- # Returns false if the target of the call is a widget, true otherwise
249
+ # @return [bool] false if the target of the call is a widget, true otherwise
199
250
  def is_target?
200
251
  @is_target
201
252
  end
202
253
 
203
254
 
255
+ # The main controller's execution method. The Controller will dispatch
256
+ # to another controller if a route is set; otherwise, it will call the
257
+ # method that should be executed according to action.
258
+ #
259
+ # This method can be overridden in subclasses, but remember to call super,
260
+ # or the dispatch chain will stop!
261
+ # @param [String] action The current action
262
+ # @param [*Object] arguments Additional action arguments
204
263
  def execute(action='', *arguments)
205
264
  return if @__done
206
265
  debug("Controller #{self} executing #{action} with arguments #{arguments}")
@@ -218,7 +277,7 @@ module Spider
218
277
  if @executed_method
219
278
  meth = self.method(@executed_method)
220
279
  args = arguments + @executed_method_arguments
221
- @controller_action = args[0]
280
+ @current_action = action
222
281
  arity = meth.arity
223
282
  unless arity == -1
224
283
  arity = (-arity + 1) if arity < 0
@@ -234,6 +293,9 @@ module Spider
234
293
  end
235
294
  end
236
295
 
296
+ # Helper method, that calls and propagates #before
297
+ # @param [String] action The current action
298
+ # @param [*Object] arguments Additional action arguments
237
299
  def call_before(action='', *arguments)
238
300
  return if respond_to?(:serving_static?) && self.serving_static?
239
301
  @call_path = action
@@ -246,11 +308,21 @@ module Spider
246
308
  end
247
309
  end
248
310
  end
249
-
311
+
312
+ # This method can be implemented by Controllers, and will be called
313
+ # on the controller chain before the execute method.
314
+ #
315
+ # This method is usually reserved for preprocessing that does not
316
+ # output to the browser, to allow other controllers in chain to set response
317
+ # headers.
318
+ # @param [String] action The current action
319
+ # @param [*Object] arguments Additional action arguments
250
320
  def before(action='', *arguments)
251
321
  end
252
322
 
253
-
323
+ # Helper method, that calls and propagates #after
324
+ # @param [String] action The current action
325
+ # @param [*Object] arguments Additional action arguments
254
326
  def call_after(action='', *arguments)
255
327
  return if respond_to?(:serving_static?) && self.serving_static?
256
328
  after(action, *arguments)
@@ -260,43 +332,63 @@ module Spider
260
332
  do_dispatch(:call_after, action, *arguments)
261
333
  end
262
334
  end
263
- # begin
264
- # run_chain(:after)
265
- # #dispatch(:after, action, params)
266
- # rescue => exc
267
- # try_rescue(exc)
268
- # end
269
335
  end
270
336
 
337
+ # This method can be implemented by Controllers, and will be called
338
+ # on the controller chain after the execute method.
339
+ #
340
+ # If the webserver supports it, this method will be called after the response
341
+ # has been returned to the browser; so, it's suitable for post processing.
342
+ # If you aren't using a threaded web server, though, keep in mind that the
343
+ # process won't be available to service other requests.
344
+ # @param [String] action The current action
345
+ # @param [*Object] arguments Additional action arguments
271
346
  def after(action='', *arguments)
272
347
  end
273
348
 
349
+ # @return [bool] True if the controller is done, and should not continue dispatching.
274
350
  def done?
275
351
  @__done
276
352
  end
277
353
 
354
+ # Stops the execution of the controller chain
355
+ # @return [void]
278
356
  def done
279
357
  self.done = true
280
358
  throw :done
281
359
  end
282
360
 
361
+ # Sets the controller chain's "done" state
362
+ # @param [bool] val
363
+ # @return [void]
283
364
  def done=(val)
284
365
  @__done = val
285
366
  @dispatch_previous.done = val if @dispatch_previous
286
367
  end
287
368
 
369
+ # Checks if an action responds to given route conditions. Is called by
370
+ # {Dispatcher#do_dispatch}.
371
+ # The default implementation calls Controller.check_action, which in turn is mixed in
372
+ # from {Dispatcher::ClassMethods#check_action}
373
+ # @param [String] action
374
+ # @param [Array] c An array of route conditions
375
+ # @return [bool]
288
376
  def check_action(action, c)
289
377
  self.class.check_action(action, c)
290
378
  end
291
379
 
380
+ # Returns a new Scene instance for use in the controller.
381
+ # @param [Hash] scene Hash to construct the scene from
382
+ # @return [Scene]
292
383
  def get_scene(scene=nil)
293
384
  scene = Scene.new(scene) if scene.class == Hash
294
385
  scene ||= Scene.new
295
- # debugger
296
- # scene.extend(SceneMethods)
297
386
  return scene
298
387
  end
299
388
 
389
+ # Sets controller information on a scene
390
+ # @param [Scene] scene
391
+ # @return [Scene]
300
392
  def prepare_scene(scene)
301
393
  req_path = @request.path
302
394
  req_path += 'index' if !req_path.blank? && req_path[-1].chr == '/'
@@ -312,19 +404,17 @@ module Spider
312
404
  return scene
313
405
  end
314
406
 
315
- def get_route(*args)
316
- route = super
317
- return route unless route
318
- action = route.path.split('/').first
319
- action_method, action_params = get_action_method(action)
320
- if route.nil_route && !action.blank? && self.respond_to?(action_method)
321
- route.action = action
322
- end
323
- route
407
+ # See {Controller.controller_action?}
408
+ # @return [bool] True if the method is a controller action for the class
409
+ def controller_action?(method)
410
+ self.class.controller_action?(method)
324
411
  end
325
412
 
326
413
  protected
327
414
 
415
+ # Instantiates an object dispatched by a route
416
+ # @param [Route]
417
+ # @return [Controller]
328
418
  def dispatched_object(route)
329
419
  klass = route.dest
330
420
  if klass.class != Class
@@ -332,6 +422,9 @@ module Spider
332
422
  set_executed_method(route.action)
333
423
  end
334
424
  return klass
425
+ elsif klass == self.class
426
+ self.set_action(route.action)
427
+ return self
335
428
  end
336
429
  obj = klass.new(@request, @response, @scene)
337
430
  obj.dispatch_action = route.matched || ''
@@ -341,46 +434,52 @@ module Spider
341
434
  return obj
342
435
  end
343
436
 
344
- def controller_action?(method)
345
- self.class.controller_action?(method)
346
- end
347
-
437
+ # Given an action, sets the executed method unless it can be dispatched
438
+ # @param [String] action
439
+ # @return [Symbol|nil] The executed method, if it was set, or nil
348
440
  def set_action(action)
349
441
  @executed_method = nil
350
442
  @executed_method_arguments = nil
351
443
  if !can_dispatch?(:execute, action)
352
- set_executed_method(action)
444
+ return set_executed_method(action)
353
445
  end
446
+ nil
354
447
  end
355
448
 
449
+ # Given an action, sets executed_method and executed_method_arguments
450
+ # @param [String] action
451
+ # @return [Symbol] The executed_method
356
452
  def set_executed_method(action)
357
453
  method, additional_arguments = get_action_method(action)
358
- if (method && controller_action?(method))
454
+ if method && controller_action?(method)
359
455
  @executed_method = method.to_sym
360
456
  @executed_method_arguments = additional_arguments || []
361
457
  end
362
458
  return @executed_method
363
459
  end
364
-
365
460
 
461
+ # This method can be overrided by subclasses, to provide custom handling of
462
+ # exceptions
463
+ # @param [Exception]
464
+ # @return [void]
366
465
  def try_rescue(exc)
367
466
  raise exc
368
467
  end
369
-
370
-
468
+
371
469
  private
372
-
373
- def pass
374
- action = @call_path
375
- return false unless can_dispatch?(:execute, action)
376
- #debug("CAN DISPATCH #{action}")
377
- do_dispatch(:execute, action)
378
- return true
379
- end
380
-
381
- module SceneMethods
382
- end
383
470
 
471
+ # Overrides {Dispatcher#get_route}, setting the action for nil routes
472
+ # @param [String] path
473
+ def get_route(*args)
474
+ route = super
475
+ return route unless route
476
+ action = route.path.split('/').first
477
+ action_method, action_params = get_action_method(action)
478
+ if route.nil_route && !action.blank? && self.respond_to?(action_method)
479
+ route.action = action
480
+ end
481
+ route
482
+ end
384
483
 
385
484
  end
386
485
 
@@ -62,7 +62,8 @@ module Spider
62
62
  return nil if obj == self && route_action == action # short circuit
63
63
  meth_action = route_action.length > 0 ? route_action : obj.class.default_action
64
64
  begin
65
- if (obj.class.dispatch_methods && obj.class.dispatch_methods[method])
65
+ # Apply dispatch methods (see {Controller.before})
66
+ if obj.class.dispatch_methods && obj.class.dispatch_methods[method]
66
67
  obj.class.dispatch_methods[method].each do |dm|
67
68
  conditions, d_method, params = dm
68
69
  test = check_action(route_action, conditions)
@@ -71,6 +72,7 @@ module Spider
71
72
  end
72
73
  end
73
74
  res = obj.send(method, route_action, *(new_arguments))
75
+ # Call, for example, before_my_method
74
76
  unless meth_action.empty?
75
77
  meth_action = meth_action[0..-2] if meth_action[-1].chr == '/'
76
78
  meth_action = meth_action.split('/', 2)[0]
@@ -131,6 +133,7 @@ module Spider
131
133
  try, dest, options = route
132
134
  action = nil
133
135
  nil_route = false
136
+ next if options[:http_method] && @request.http_method != options[:http_method]
134
137
  case try
135
138
  when true, nil
136
139
  action = path
@@ -157,8 +160,8 @@ module Spider
157
160
  end
158
161
  when Proc
159
162
  res = try.call(path, self)
160
- if (res)
161
- if (res.is_a?(Array))
163
+ if res
164
+ if res.is_a?(Array)
162
165
  action = res[0]
163
166
  params = res[1]
164
167
  matched = res[1]
@@ -166,6 +169,13 @@ module Spider
166
169
  action = res
167
170
  end
168
171
  end
172
+ when Symbol
173
+ if Spider::HTTP::METHODS.include?(try)
174
+ if @request.http_method == try
175
+ action = path
176
+ matched = nil
177
+ end
178
+ end
169
179
  end
170
180
  if action
171
181
  action = action[1..-1] if action[0] && action[0].chr == '/'