This file is indexed.

/usr/lib/ruby/vendor_ruby/merb-core/controller/abstract_controller.rb is in ruby-merb-core 1.1.3+dfsg-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
# ==== Why do we use Underscores?
# In Merb, views are actually methods on controllers. This provides
# not-insignificant speed benefits, as well as preventing us from
# needing to copy over instance variables, which we think is proof
# that everything belongs in one class to begin with.
#
# Unfortunately, this means that view helpers need to be included
# into the <strong>Controller</strong> class. To avoid causing confusion
# when your helpers potentially conflict with our instance methods,
# we use an _ to disambiguate. As long as you don't begin your helper
# methods with _, you only need to worry about conflicts with Merb
# methods that are part of the public API.
#
#
#
# ==== Filters
# #before is a class method that allows you to specify before filters in
# your controllers. Filters can either be a symbol or string that
# corresponds to a method name to call, or a proc object. if it is a method
# name that method will be called and if it is a proc it will be called
# with an argument of self where self is the current controller object.
# When you use a proc as a filter it needs to take one parameter.
# 
# #after is identical, but the filters are run after the action is invoked.
#
# ===== Examples
#   before :some_filter
#   before :authenticate, :exclude => [:login, :signup]
#   before :has_role, :with => ["Admin"], :exclude => [:index, :show]
#   before Proc.new { some_method }, :only => :foo
#   before :authorize, :unless => :logged_in?  
#
# You can use either <code>:only => :actionname</code> or 
# <code>:exclude => [:this, :that]</code> but not both at once. 
# <code>:only</code> will only run before the listed actions and 
# <code>:exclude</code> will run for every action that is not listed.
#
# Merb's before filter chain is very flexible. To halt the filter chain you
# use <code>throw :halt</code>. If <code>throw</code> is called with only one 
# argument of <code>:halt</code> the return value of the method 
# <code>filters_halted</code> will be what is rendered to the view. You can 
# override <code>filters_halted</code> in your own controllers to control what 
# it outputs. But the <code>throw</code> construct is much more powerful than 
# just that.
#
# <code>throw :halt</code> can also take a second argument. Here is what that 
# second argument can be and the behavior each type can have:
#
# * +String+:
#   when the second argument is a string then that string will be what
#   is rendered to the browser. Since merb's <code>#render</code> method returns
#   a string you can render a template or just use a plain string:
#
#     throw :halt, "You don't have permissions to do that!"
#     throw :halt, render(:action => :access_denied)
#
# * +Symbol+:
#   If the second arg is a symbol, then the method named after that
#   symbol will be called
#
#     throw :halt, :must_click_disclaimer
#
# * +Proc+:
#   If the second arg is a Proc, it will be called and its return
#   value will be what is rendered to the browser:
#
#     throw :halt, proc { access_denied }
#     throw :halt, proc { Tidy.new(c.index) }
#
# ===== Filter Options (.before, .after, .add_filter, .if, .unless)
# :only<Symbol, Array[Symbol]>::
#   A list of actions that this filter should apply to
#
# :exclude<Symbol, Array[Symbol]::
#   A list of actions that this filter should *not* apply to
# 
# :if<Symbol, Proc>::
#   Only apply the filter if the method named after the symbol or calling the proc evaluates to true
# 
# :unless<Symbol, Proc>::
#   Only apply the filter if the method named after the symbol or calling the proc evaluates to false
#
# :with<Array[Object]>::
#   Arguments to be passed to the filter. Since we are talking method/proc calls,
#   filter method or Proc should to have the same arity
#   as number of elements in Array you pass to this option.
#
# ===== Types (shortcuts for use in this file)
# Filter:: <Array[Symbol, (Symbol, String, Proc)]>
#
# ==== params[:action] and params[:controller] deprecated
# <code>params[:action]</code> and <code>params[:controller]</code> have been deprecated as of
# the 0.9.0 release. They are no longer set during dispatch, and
# have been replaced by <code>action_name</code> and <code>controller_name</code> respectively.

module Merb
  module InlineTemplates; end
  
  class AbstractController
    include Merb::RenderMixin
    include Merb::InlineTemplates

    class_inheritable_accessor :_layout, :_template_root, :template_roots
    class_inheritable_accessor :_before_filters, :_after_filters
    class_inheritable_accessor :_before_dispatch_callbacks, :_after_dispatch_callbacks

    cattr_accessor :_abstract_subclasses

    # :api: plugin
    attr_accessor :body, :action_name, :_benchmarks
    # :api: private
    attr_accessor :_thrown_content  

    # Stub so content-type support in RenderMixin doesn't throw errors
    # :api: private
    attr_accessor :content_type

    FILTER_OPTIONS = [:only, :exclude, :if, :unless, :with]

    self._before_filters, self._after_filters = [], []
    self._before_dispatch_callbacks, self._after_dispatch_callbacks = [], []

    #---
    # We're using abstract_subclasses so that Merb::Controller can have its
    # own subclasses. We're using a Set so we don't have to worry about
    # uniqueness.
    self._abstract_subclasses = Set.new

    # ==== Returns
    # String:: The controller name in path form, e.g. "admin/items".
    # :api: public
    def self.controller_name() @controller_name ||= self.name.to_const_path end

    # ==== Returns
    # String:: The controller name in path form, e.g. "admin/items".
    #
    # :api: public
    def controller_name()      self.class.controller_name                   end
  
    # This is called after the controller is instantiated to figure out where to
    # look for templates under the _template_root. Override this to define a new
    # structure for your app.
    #
    # ==== Parameters
    # context<~to_s>:: The controller context (the action or template name).
    # type<~to_s>:: The content type. Could be nil. 
    # controller<~to_s>::
    #   The name of the controller. Defaults to being called with the controller_name.  Set t
    #
    #
    # ==== Returns
    # String:: 
    #   Indicating where to look for the template for the current controller,
    #   context, and content-type.
    #
    # ==== Notes
    # The type is irrelevant for controller-types that don't support
    # content-type negotiation, so we default to not include it in the
    # superclass.
    #
    # ==== Examples
    #   def _template_location
    #     "#{params[:controller]}.#{params[:action]}.#{content_type}"
    #   end
    #
    # This would look for templates at controller.action.mime.type instead
    # of controller/action.mime.type
    #
    # :api: public
    # @overridable
    def _template_location(context, type, controller)
      controller ? "#{controller}/#{context}" : context
    end

    # The location to look for a template - override this method for particular behaviour. 
    #
    # ==== Parameters
    # template<String>:: The absolute path to a template - without template extension.
    # type<~to_s>::
    #    The mime-type of the template that will be rendered. Defaults to being called with nil.
    #
    # :api: public
    # @overridable
    def _absolute_template_location(template, type)
      template
    end

    # Resets the template roots to the template root passed in.
    #
    # ==== Parameters
    # root<~to_s>:: 
    #   The new path to set the template root to.  
    #
    # :api: public
    def self._template_root=(root)
      @_template_root = root
      _reset_template_roots
    end

    # Reset the template root based on the @_template_root ivar.
    #
    # :api: private
    def self._reset_template_roots
      self.template_roots = [[self._template_root, :_template_location]]
    end

    # ==== Returns
    # roots<Array[Array]>::
    #   Template roots as pairs of template root path and template location
    #   method.
    #
    # :api: plugin
    def self._template_roots
      self.template_roots || _reset_template_roots
    end

    # ==== Parameters
    # roots<Array[Array]>::
    #   Template roots as pairs of template root path and template location
    #   method.
    #
    # :api: plugin
    def self._template_roots=(roots)
      self.template_roots = roots
    end
  
    # Returns the list of classes that have specifically subclassed AbstractController.  
    # Does not include all decendents.  
    #
    # ==== Returns
    # Set:: The subclasses.
    #
    # :api: private
    def self.subclasses_list() _abstract_subclasses end
  
    # ==== Parameters
    # klass<Merb::AbstractController>::
    #   The controller that is being inherited from Merb::AbstractController
    #
    # :api: private
    def self.inherited(klass)
      _abstract_subclasses << klass.to_s
      helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
      # support for unnamed module like "#<Class:0xa2e5e50>::TestController"
      helper_module_name.gsub!(/(::)|[:#<>]/, "\\1")

      Object.make_module helper_module_name
      klass.class_eval <<-HERE
        include Object.full_const_get("#{helper_module_name}") rescue nil
      HERE
      super
    end    
  
    # This will initialize the controller, it is designed to be overridden in subclasses (like MerbController)
    # ==== Parameters
    # *args:: The args are ignored in this class, but we need this so that subclassed initializes can have parameters
    #
    # :api: private
    def initialize(*args)
      @_benchmarks = {}
      @_caught_content = {}
    end
  
    # This will dispatch the request, calling internal before/after dispatch callbacks.  
    # If the return value of _call_filters is not :filter_chain_completed the action is not called, and the return from the filters is used instead. 
    # 
    # ==== Parameters
    # action<~to_s>::
    #   The action to dispatch to. This will be #send'ed in _call_action.
    #   Defaults to :to_s.
    #
    # ==== Returns
    # <~to_s>::
    #   Returns the string that was returned from the action. 
    #
    # ==== Raises
    # ArgumentError:: Invalid result caught from before filters.
    #
    # :api: plugin
    def _dispatch(action)
      self.action_name = action
      self._before_dispatch_callbacks.each { |cb| cb.call(self) }

      caught = catch(:halt) do
        start = Time.now
        result = _call_filters(_before_filters)
        @_benchmarks[:before_filters_time] = Time.now - start if _before_filters

        @body = _call_action(action_name) if result == :filter_chain_completed

        result
      end
  
      @body = case caught
      when :filter_chain_completed  then @body
      when String                   then caught
      # return *something* if you throw halt with nothing
      when nil                      then "<html><body><h1>Filter Chain Halted!</h1></body></html>"
      when Symbol                   then __send__(caught)
      when Proc                     then self.instance_eval(&caught)
      else
        raise ArgumentError, "Threw :halt, #{caught}. Expected String, nil, Symbol, Proc."
      end
      start = Time.now
      _call_filters(_after_filters)
      @_benchmarks[:after_filters_time] = Time.now - start if _after_filters
    
      self._after_dispatch_callbacks.each { |cb| cb.call(self) }
    
      @body
    end
  
    # This method exists to provide an overridable hook for ActionArgs.  It uses #send to call the action method.
    #
    # ==== Parameters
    # action<~to_s>:: the action method to dispatch to
    #
    # :api: plugin
    # @overridable
    def _call_action(action)
      send(action)
    end
  
    # Calls a filter chain. 
    #
    # ==== Parameters
    # filter_set<Array[Filter]>::
    #   A set of filters in the form [[:filter, rule], [:filter, rule]]
    #
    # ==== Returns
    # Symbol:: :filter_chain_completed.
    #
    # ==== Notes
    # Filter rules can be Symbols, Strings, or Procs.
    #
    # Symbols or Strings::
    #   Call the method represented by the +Symbol+ or +String+.
    # Procs::
    #   Execute the +Proc+, in the context of the controller (self will be the
    #   controller)
    #
    # :api: private
    def _call_filters(filter_set)
      (filter_set || []).each do |filter, rule|
        if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
          case filter
          when Symbol, String
            if rule.key?(:with)
              args = rule[:with]
              send(filter, *args)
            else
              send(filter)
            end
          when Proc then self.instance_eval(&filter)
          end
        end
      end
      return :filter_chain_completed
    end

    # Determine whether the filter should be called for the current action using :only and :exclude.
    #
    # ==== Parameters
    # rule<Hash>:: Rules for the filter (see below).
    # action_name<~to_s>:: The name of the action to be called.
    #
    # ==== Options (rule)
    # :only<Array>::
    #   Optional list of actions to fire. If given, action_name must be a part of
    #   it for this function to return true.
    # :exclude<Array>::
    #   Optional list of actions not to fire. If given, action_name must not be a
    #   part of it for this function to return true.
    #
    # ==== Returns
    # Boolean:: True if the action should be called.
    #
    # :api: private
    def _call_filter_for_action?(rule, action_name)
      # Both:
      # * no :only or the current action is in the :only list
      # * no :exclude or the current action is not in the :exclude list
      (!rule.key?(:only) || rule[:only].include?(action_name)) &&
      (!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
    end

    # Determines whether the filter should be run based on the conditions passed (:if and :unless)
    #
    # ==== Parameters
    # rule<Hash>:: Rules for the filter (see below).
    #
    # ==== Options (rule)
    # :if<Array>:: Optional conditions that must be met for the filter to fire.
    # :unless<Array>::
    #   Optional conditions that must not be met for the filter to fire.
    #
    # ==== Returns
    # Boolean:: True if the conditions are met.
    #
    # :api: private
    def _filter_condition_met?(rule)
      # Both:
      # * no :if or the if condition evaluates to true
      # * no :unless or the unless condition evaluates to false
      (!rule.key?(:if) || _evaluate_condition(rule[:if])) &&
      (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
    end

    # Evaluates a filter condition (:if or :unless)
    #
    # ==== Parameters
    # condition<Symbol, Proc>:: The condition to evaluate.
    #
    # ==== Raises
    # ArgumentError:: condition not a Symbol or Proc.
    #
    # ==== Returns
    # Boolean:: True if the condition is met.
    #
    # ==== Alternatives
    # If condition is a symbol, it will be send'ed. If it is a Proc it will be
    # called directly with self as an argument.
    #
    # :api: private
    def _evaluate_condition(condition)
      case condition
      when Symbol then self.send(condition)
      when Proc then self.instance_eval(&condition)
      else
        raise ArgumentError,
              'Filter condtions need to be either a Symbol or a Proc'
      end
    end

    # Adds a filter to the after filter chain
    # ==== Parameters
    # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
    # opts<Hash>::
    #   Filter options (see class documentation under <tt>Filter Options</tt>).
    # &block:: A block to use as a filter if filter is nil.
    #
    # ==== Notes
    # If the filter already exists, its options will be replaced with opts.;
    #
    # :api: public
    def self.after(filter = nil, opts = {}, &block)
      add_filter(self._after_filters, filter || block, opts)
    end

    # Adds a filter to the before filter chain.  
    #
    # ==== Parameters
    # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
    # opts<Hash>::
    #   Filter options (see class documentation under <tt>Filter Options</tt>).
    # &block:: A block to use as a filter if filter is nil.
    #
    # ==== Notes
    # If the filter already exists, its options will be replaced with opts.
    #
    # :api: public
    def self.before(filter = nil, opts = {}, &block)
      add_filter(self._before_filters, filter || block, opts)
    end
     
    # Removes a filter from the after filter chain.  This removes the 
    # filter from the filter chain for the whole controller and does not 
    # take any options. 
    #
    # ==== Parameters
    # filter<Symbol, String>:: A filter name to skip.
    #
    # :api: public
    def self.skip_after(filter)
      skip_filter(self._after_filters, filter)
    end
  
    # Removes a filter from the before filter chain.  This removes the 
    # filter from the filter chain for the whole controller and does not 
    # take any options.
    #
    # ==== Parameters
    # filter<Symbol, String>:: A filter name to skip.
    #
    # :api: public
    def self.skip_before(filter)
      skip_filter(self._before_filters , filter)
    end  

    # There are three possible ways to use this method.  First, if you have a named route, 
    # you can specify the route as the first parameter as a symbol and any paramters in a 
    # hash.  Second, you can generate the default route by just passing the params hash, 
    # just passing the params hash.  Finally, you can use the anonymous parameters.  This 
    # allows you to specify the parameters to a named route in the order they appear in the 
    # router.  
    #
    # ==== Parameters(Named Route)
    # name<Symbol>:: 
    #   The name of the route. 
    # args<Hash>:: 
    #   Parameters for the route generation.
    #
    # ==== Parameters(Default Route)
    # args<Hash>:: 
    #   Parameters for the route generation.  This route will use the default route. 
    #
    # ==== Parameters(Anonymous Parameters)
    # name<Symbol>::
    #   The name of the route.  
    # args<Array>:: 
    #   An array of anonymous parameters to generate the route
    #   with. These parameters are assigned to the route parameters
    #   in the order that they are passed.
    #
    # ==== Returns
    # String:: The generated URL.
    #
    # ==== Examples
    # Named Route
    #
    # Merb::Router.prepare do
    #   match("/articles/:title").to(:controller => :articles, :action => :show).name("articles")
    # end
    #
    # url(:articles, :title => "new_article")
    #
    # Default Route
    #
    # Merb::Router.prepare do
    #   default_routes
    # end
    #
    # url(:controller => "articles", :action => "new")
    #
    # Anonymous Paramters
    #
    # Merb::Router.prepare do
    #   match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles")
    # end
    #
    # url(:articles, 2008, 10, "test_article")
    #
    # :api: public
    def url(name, *args)
      args << {}
      Merb::Router.url(name, *args)
    end
  
    alias_method :relative_url, :url

    # Returns the absolute url including the passed protocol and host.  
    # 
    # This uses the same arguments as the url method, with added requirements 
    # of protocol and host options. 
    #
    # :api: public
    def absolute_url(*args)
      # FIXME: arrgh, why request.protocol returns http://?
      # :// is not part of protocol name
      options  = extract_options_from_args!(args) || {}
      protocol = options.delete(:protocol)
      host     = options.delete(:host)
    
      raise ArgumentError, "The :protocol option must be specified" unless protocol
      raise ArgumentError, "The :host option must be specified"     unless host
    
      args << options
    
      protocol + "://" + host + url(*args)
    end
  
    # Generates a URL for a single or nested resource.
    #
    # ==== Parameters
    # resources<Symbol,Object>:: The resources for which the URL
    #   should be generated. These resources should be specified
    #   in the router.rb file using #resources and #resource.
    #
    # options<Hash>:: Any extra parameters that are needed to
    #   generate the URL.
    #
    # ==== Returns
    # String:: The generated URL.
    #
    # ==== Examples
    #
    # Merb::Router.prepare do
    #   resources :users do
    #     resources :comments
    #   end
    # end
    #
    # resource(:users)            # => /users
    # resource(@user)             # => /users/10
    # resource(@user, :comments)  # => /users/10/comments
    # resource(@user, @comment)   # => /users/10/comments/15
    # resource(:users, :new)      # => /users/new
    # resource(:@user, :edit)     # => /users/10/edit
    #
    # :api: public
    def resource(*args)
      args << {}
      Merb::Router.resource(*args)
    end

    # Calls the capture method for the selected template engine.
    #
    # ==== Parameters
    # *args:: Arguments to pass to the block.
    # &block:: The block to call.
    #
    # ==== Returns
    # String:: The output of a template block or the return value of a non-template block converted to a string.
    #
    # :api: public
    def capture(*args, &block)
      ret = nil

      captured = send("capture_#{@_engine}", *args) do |*args|
        ret = yield *args
      end

      # return captured value only if it is not empty
      captured.empty? ? ret.to_s : captured
    end

    # Calls the concatenate method for the selected template engine.
    #
    # ==== Parameters
    # str<String>:: The string to concatenate to the buffer.
    # binding<Binding>:: The binding to use for the buffer.
    #
    # :api: public
    def concat(str, binding)
      send("concat_#{@_engine}", str, binding)
    end

    private
    # adds a filter to the specified filter chain
    # ==== Parameters
    # filters<Array[Filter]>:: The filter chain that this should be added to.
    # filter<Filter>:: A filter that should be added.
    # opts<Hash>::
    #   Filter options (see class documentation under <tt>Filter Options</tt>).
    #
    # ==== Raises
    # ArgumentError::
    #   Both :only and :exclude, or :if and :unless given, if filter is not a
    #   Symbol, String or Proc, or if an unknown option is passed.
    #
    # :api: private
    def self.add_filter(filters, filter, opts={})
      raise(ArgumentError,
        "You can specify either :only or :exclude but 
         not both at the same time for the same filter.") if opts.key?(:only) && opts.key?(:exclude)
       
       raise(ArgumentError,
         "You can specify either :if or :unless but 
          not both at the same time for the same filter.") if opts.key?(:if) && opts.key?(:unless)
        
      opts.each_key do |key| raise(ArgumentError,
        "You can only specify known filter options, #{key} is invalid.") unless FILTER_OPTIONS.include?(key)
      end

      opts = normalize_filters!(opts)
    
      case filter
      when Proc
        # filters with procs created via class methods have identical signature
        # regardless if they handle content differently or not. So procs just
        # get appended
        filters << [filter, opts]
      when Symbol, String
        if existing_filter = filters.find {|f| f.first.to_s == filter.to_s}
          filters[ filters.index(existing_filter) ] = [filter, opts]
        else
          filters << [filter, opts]
        end
      else
        raise(ArgumentError, 
          'Filters need to be either a Symbol, String or a Proc'
        )        
      end
    end  

    # Skip a filter that was previously added to the filter chain. Useful in
    # inheritence hierarchies.
    #
    # ==== Parameters
    # filters<Array[Filter]>:: The filter chain that this should be removed from.
    # filter<Filter>:: A filter that should be removed.
    #
    # ==== Raises
    # ArgumentError:: filter not Symbol or String.
    #
    # :api: private
    def self.skip_filter(filters, filter)
      raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless
        [Symbol, String].include? filter.class

      Merb.logger.warn("Filter #{filter} was not found in your filter chain.") unless
        filters.reject! {|f| f.first.to_s[filter.to_s] }
    end

    # Ensures that the passed in hash values are always arrays.
    #
    # ==== Parameters
    # opts<Hash>:: Options for the filters (see below).
    #
    # ==== Options (opts)
    # :only<Symbol, Array[Symbol]>:: A list of actions.
    # :exclude<Symbol, Array[Symbol]>:: A list of actions.
    #
    # ==== Examples
    #   normalize_filters!(:only => :new) #=> {:only => [:new]}
    #
    # :api: public
    def self.normalize_filters!(opts={})
      opts[:only]     = Array(opts[:only]).map {|x| x.to_s} if opts[:only]
      opts[:exclude]  = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude]
      return opts
    end
  end
end