merb 0.0.8 → 0.0.9

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 (95) hide show
  1. data/README +64 -80
  2. data/Rakefile +25 -12
  3. data/bin/merb +2 -223
  4. data/examples/README_EXAMPLES +10 -0
  5. data/examples/skeleton.tar +0 -0
  6. data/lib/merb.rb +48 -21
  7. data/lib/merb/core_ext.rb +12 -2
  8. data/lib/merb/core_ext/merb_class.rb +21 -21
  9. data/lib/merb/core_ext/merb_kernel.rb +60 -0
  10. data/lib/merb/core_ext/merb_object.rb +14 -0
  11. data/lib/merb/core_ext/merb_string.rb +3 -13
  12. data/lib/merb/generators/merb_app/merb_app.rb +33 -0
  13. data/lib/merb/merb_constants.rb +7 -0
  14. data/lib/merb/merb_controller.rb +31 -23
  15. data/lib/merb/merb_drb_server.rb +6 -60
  16. data/lib/merb/merb_exceptions.rb +162 -2
  17. data/lib/merb/merb_handler.rb +8 -19
  18. data/lib/merb/merb_mailer.rb +60 -0
  19. data/lib/merb/merb_router.rb +1 -1
  20. data/lib/merb/merb_server.rb +240 -0
  21. data/lib/merb/merb_upload_handler.rb +1 -1
  22. data/lib/merb/merb_view_context.rb +11 -6
  23. data/lib/merb/mixins/basic_authentication_mixin.rb +11 -13
  24. data/lib/merb/mixins/controller_mixin.rb +12 -6
  25. data/lib/merb/mixins/form_control_mixin.rb +94 -0
  26. data/lib/merb/mixins/render_mixin.rb +50 -24
  27. data/lib/merb/mixins/view_context_mixin.rb +122 -0
  28. data/lib/merb/session/merb_ar_session.rb +13 -14
  29. data/lib/merb/session/merb_memory_session.rb +105 -0
  30. metadata +13 -132
  31. data/examples/app_skeleton/Rakefile +0 -82
  32. data/examples/app_skeleton/dist/app/helpers/global_helper.rb +0 -6
  33. data/examples/app_skeleton/dist/conf/merb.yml +0 -11
  34. data/examples/app_skeleton/dist/conf/merb_init.rb +0 -16
  35. data/examples/app_skeleton/dist/conf/mup.conf +0 -5
  36. data/examples/app_skeleton/dist/conf/router.rb +0 -19
  37. data/examples/app_skeleton/scripts/merb_stop +0 -13
  38. data/examples/app_skeleton/scripts/new_migration +0 -21
  39. data/examples/app_skeleton/test/test_helper.rb +0 -1
  40. data/examples/sample_app/Rakefile +0 -82
  41. data/examples/sample_app/dist/app/controllers/files.rb +0 -31
  42. data/examples/sample_app/dist/app/controllers/posts.rb +0 -71
  43. data/examples/sample_app/dist/app/controllers/test.rb +0 -40
  44. data/examples/sample_app/dist/app/helpers/global_helper.rb +0 -7
  45. data/examples/sample_app/dist/app/helpers/posts_helper.rb +0 -4
  46. data/examples/sample_app/dist/app/models/comment.rb +0 -3
  47. data/examples/sample_app/dist/app/models/post.rb +0 -4
  48. data/examples/sample_app/dist/app/views/files/progress.jerb +0 -3
  49. data/examples/sample_app/dist/app/views/files/start.herb +0 -62
  50. data/examples/sample_app/dist/app/views/files/upload.herb +0 -6
  51. data/examples/sample_app/dist/app/views/layout/application.herb +0 -61
  52. data/examples/sample_app/dist/app/views/layout/foo.herb +0 -6
  53. data/examples/sample_app/dist/app/views/posts/_comments.herb +0 -11
  54. data/examples/sample_app/dist/app/views/posts/comment.jerb +0 -1
  55. data/examples/sample_app/dist/app/views/posts/list.herb +0 -5
  56. data/examples/sample_app/dist/app/views/posts/new.herb +0 -37
  57. data/examples/sample_app/dist/app/views/posts/show.herb +0 -37
  58. data/examples/sample_app/dist/app/views/posts/xml_test.xerb +0 -3
  59. data/examples/sample_app/dist/app/views/shared/_test.herb +0 -1
  60. data/examples/sample_app/dist/app/views/test/foo.herb +0 -2
  61. data/examples/sample_app/dist/app/views/test/hello.herb +0 -5
  62. data/examples/sample_app/dist/app/views/test/json.jerb +0 -1
  63. data/examples/sample_app/dist/conf/merb.yml +0 -11
  64. data/examples/sample_app/dist/conf/merb_init.rb +0 -24
  65. data/examples/sample_app/dist/conf/mup.conf +0 -5
  66. data/examples/sample_app/dist/conf/router.rb +0 -19
  67. data/examples/sample_app/dist/public/images/bg.jpg +0 -0
  68. data/examples/sample_app/dist/public/images/book.gif +0 -0
  69. data/examples/sample_app/dist/public/images/booksmall.gif +0 -0
  70. data/examples/sample_app/dist/public/images/greenright.jpg +0 -0
  71. data/examples/sample_app/dist/public/images/louiecon.gif +0 -0
  72. data/examples/sample_app/dist/public/images/menu.gif +0 -0
  73. data/examples/sample_app/dist/public/images/menuleft.gif +0 -0
  74. data/examples/sample_app/dist/public/images/menuright.gif +0 -0
  75. data/examples/sample_app/dist/public/images/mountain.jpg +0 -0
  76. data/examples/sample_app/dist/public/images/n3.jpg +0 -0
  77. data/examples/sample_app/dist/public/images/nautica.jpg +0 -0
  78. data/examples/sample_app/dist/public/javascripts/application.js +0 -0
  79. data/examples/sample_app/dist/public/javascripts/effects.js +0 -975
  80. data/examples/sample_app/dist/public/javascripts/mup.js +0 -113
  81. data/examples/sample_app/dist/public/javascripts/prototype.js +0 -2264
  82. data/examples/sample_app/dist/public/stylesheets/merb.css +0 -277
  83. data/examples/sample_app/dist/public/test.html +0 -5
  84. data/examples/sample_app/dist/schema/migrations/001_add_comments_to_posts.rb +0 -22
  85. data/examples/sample_app/dist/schema/migrations/002_add_sessions_table.rb +0 -14
  86. data/examples/sample_app/dist/schema/schema.rb +0 -28
  87. data/examples/sample_app/foo.txt +0 -0
  88. data/examples/sample_app/log/merb.4000.pid +0 -1
  89. data/examples/sample_app/script/merb_stop +0 -13
  90. data/examples/sample_app/script/new_migration +0 -21
  91. data/examples/sample_app/test/test_helper.rb +0 -1
  92. data/lib/merb/mixins/javascript_mixin.rb +0 -147
  93. data/lib/merb/session/merb_drb_session.rb +0 -65
  94. data/test/test_helper.rb +0 -1
  95. data/test/unit/route_matcher_test.rb +0 -46
@@ -0,0 +1,10 @@
1
+ I have removed the useless example app from here for now.
2
+ PLease see mrblog for a better sample app:
3
+
4
+ svn co http://svn.devjavu.com/merb/mrblog/trunk
5
+
6
+ To generate your own new merb app first install the gem and then:
7
+
8
+ $ merb -g appname
9
+ or
10
+ $ merb --generate-app appname
Binary file
@@ -3,28 +3,55 @@ require 'mongrel'
3
3
  require 'fileutils'
4
4
  require 'erubis'
5
5
  require 'logger'
6
- require 'mime/types'
7
6
 
7
+ begin
8
+ require 'fjson'
9
+ puts "using fjson"
10
+ rescue LoadError
11
+ require 'json'
12
+ end
8
13
 
9
14
  module Merb
10
- VERSION='0.0.8' unless defined?VERSION
15
+ VERSION='0.0.9' unless defined?VERSION
11
16
  class Server
12
- def self.config
13
- @@merb_opts ||= {}
17
+ class << self
18
+ def config
19
+ @@merb_opts ||= {}
20
+ end
21
+ def method_missing(meth, *args, &block)
22
+ if meth.to_s[-1..-1] == '='
23
+ key = meth.to_s[0..-2].to_sym
24
+ config.send("[]=", key, *args)
25
+ elsif args.empty?
26
+ config[meth]
27
+ else
28
+ super
29
+ end
30
+ end
14
31
  end
15
32
  end
16
33
  end
17
34
 
18
- class MerbControllerError < RuntimeError; end
35
+ module Erubis
36
+ class MEruby < Erubis::Eruby
37
+ include PercentLineEnhancer
38
+ include StringBufferEnhancer
39
+ end
40
+ end
41
+
42
+ def __DIR__; File.dirname(__FILE__); end
19
43
 
20
- MERB_FRAMEWORK_ROOT = File.dirname(__FILE__)
44
+ require File.join(__DIR__, 'merb/core_ext')
21
45
 
22
- MERB_ROOT = Merb::Server.config[:merb_root] || Dir.pwd
23
- DIST_ROOT = Merb::Server.config[:dist_root] || Dir.pwd+'/dist'
46
+ MERB_FRAMEWORK_ROOT = __DIR__
24
47
 
25
- MERB_LOGGER = Logger.new("#{MERB_ROOT}/log/merb.#{Merb::Server.config[:port]}.log")
48
+ MERB_ROOT = Merb::Server.merb_root || Dir.pwd
49
+ DIST_ROOT = Merb::Server.dist_root || Dir.pwd+'/dist'
50
+
51
+ logpath = $TESTING ? "/tmp/merb_test.log" : "#{MERB_ROOT}/log/merb.#{Merb::Server.port}.log"
52
+ MERB_LOGGER = Logger.new(logpath)
26
53
  # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
27
- MERB_LOGGER.level = case (Merb::Server.config[:log_level].downcase rescue '')
54
+ MERB_LOGGER.level = case (Merb::Server.log_level.downcase rescue '')
28
55
  when 'debug'
29
56
  Logger::DEBUG
30
57
  when 'info'
@@ -40,23 +67,23 @@ MERB_LOGGER.level = case (Merb::Server.config[:log_level].downcase rescue '')
40
67
  else
41
68
  Logger::INFO
42
69
  end
70
+
43
71
 
44
- corelib = File.join(File.dirname(__FILE__), 'merb/core_ext')
45
- Dir.entries(corelib).sort.each {|fn| require File.join(corelib, fn) if fn =~ /\.rb$/}
46
- lib = File.join(File.dirname(__FILE__), 'merb')
72
+
73
+ lib = File.join(__DIR__, 'merb')
47
74
  Dir.entries(lib).sort.each {|fn| require File.join(lib, fn) if fn =~ /\.rb$/}
48
75
 
76
+ require File.join(__DIR__, 'merb/vendor/paginator/paginator')
77
+
49
78
  class Merb::Controller
50
- if Merb::Server.config[:session]
51
- require "drb"
52
- DRb.start_service('druby://localhost:0')
53
- Merb.const_set :DRbSession, DRbObject.new(nil, "druby://#{Merb::Server.config[:host]}:#{Merb::Server.config[:session]}")
54
- require "merb/session/merb_drb_session"
79
+ if Merb::Server.memory_session
80
+ require "merb/session/merb_memory_session"
81
+ Merb::MemorySession.setup
55
82
  include ::Merb::SessionMixin
56
- puts "drb session mixed in"
83
+ puts "memory session mixed in"
57
84
  end
58
85
 
59
- if Merb::Server.config[:sql_session]
86
+ if Merb::Server.sql_session
60
87
  puts "ActiveRecord session mixed in"
61
88
  begin
62
89
  require 'action_controller/flash'
@@ -68,7 +95,7 @@ class Merb::Controller
68
95
  include ::Merb::SessionMixin
69
96
  end
70
97
 
71
- if Merb::Server.config[:basic_auth]
98
+ if Merb::Server.basic_auth
72
99
  require "merb/mixins/basic_authentication_mixin"
73
100
  include ::Merb::Authentication
74
101
  puts "Basic Authentication mixed in"
@@ -1,2 +1,12 @@
1
- require File.dirname(__FILE__)+'/core_ext/merb_kernel'
2
- aquire File.dirname(__FILE__)+'/core_ext/*'
1
+ corelib = __DIR__+'/merb/core_ext'
2
+
3
+ %w[ merb_class
4
+ merb_kernel
5
+ merb_object
6
+ merb_enumerable
7
+ merb_module
8
+ merb_string
9
+ merb_hash
10
+ merb_numeric
11
+ merb_symbol
12
+ ].each {|fn| require File.join(corelib, fn)}
@@ -41,11 +41,11 @@ class Class # :nodoc:
41
41
  cattr_writer(*syms)
42
42
  end
43
43
 
44
- def meta_reader(*syms)
44
+ def shared_reader(*syms)
45
45
  syms.each do |sym|
46
46
  class_eval <<-EOS
47
47
  def self.#{sym}
48
- read_meta_attribute(:#{sym})
48
+ read_shared_attribute(:#{sym})
49
49
  end
50
50
 
51
51
  def #{sym}
@@ -55,11 +55,11 @@ class Class # :nodoc:
55
55
  end
56
56
  end
57
57
 
58
- def meta_writer(*syms)
58
+ def shared_writer(*syms)
59
59
  syms.each do |sym|
60
60
  class_eval <<-EOS
61
61
  def self.#{sym}=(obj)
62
- write_meta_attribute(:#{sym}, obj)
62
+ write_shared_attribute(:#{sym}, obj)
63
63
  end
64
64
 
65
65
  def #{sym}=(obj)
@@ -69,38 +69,38 @@ class Class # :nodoc:
69
69
  end
70
70
  end
71
71
 
72
- def meta_accessor(*syms)
73
- meta_reader(*syms)
74
- meta_writer(*syms)
72
+ def shared_accessor(*syms)
73
+ shared_reader(*syms)
74
+ shared_writer(*syms)
75
75
  end
76
76
 
77
- def meta_attributes
78
- @meta_attributes ||= {}
77
+ def shared_attributes
78
+ @shared_attributes ||= {}
79
79
  end
80
80
 
81
- def write_meta_attribute(key, value)
82
- meta_attributes[key] = value
81
+ def write_shared_attribute(key, value)
82
+ shared_attributes[key] = value
83
83
  end
84
84
 
85
- def read_meta_attribute(key)
86
- meta_attributes[key]
85
+ def read_shared_attribute(key)
86
+ shared_attributes[key]
87
87
  end
88
88
 
89
- def reset_meta_attributes
90
- meta_attributes.clear
89
+ def reset_shared_attributes
90
+ shared_attributes.clear
91
91
  end
92
92
 
93
93
  private
94
- def inherited_with_meta_attributes(child)
95
- inherited_without_meta_attributes(child) if respond_to?(:inherited_without_meta_attributes)
94
+ def inherited_with_shared_attributes(child)
95
+ inherited_without_shared_attributes(child) if respond_to?(:inherited_without_shared_attributes)
96
96
 
97
- new_meta_attributes = meta_attributes.inject({}) do |memo, (key, value)|
97
+ new_shared_attributes = shared_attributes.inject({}) do |memo, (key, value)|
98
98
  memo.update(key => (value.dup rescue value))
99
99
  end
100
100
 
101
- child.instance_variable_set('@meta_attributes', new_meta_attributes)
101
+ child.instance_variable_set('@shared_attributes', new_shared_attributes)
102
102
  end
103
103
 
104
- alias inherited_without_meta_attributes inherited
105
- alias inherited inherited_with_meta_attributes
104
+ alias inherited_without_shared_attributes inherited
105
+ alias inherited inherited_with_shared_attributes
106
106
  end
@@ -13,4 +13,64 @@ module Kernel
13
13
  end
14
14
  end
15
15
  end
16
+
17
+ def rescue_require(sym, message = nil)
18
+ require sym
19
+ rescue LoadError, RuntimeError
20
+ puts message if message
21
+ end
22
+
23
+ # Gives you back the file, line and method of the caller number i
24
+ # Example:
25
+ # __caller_info__(1) # -> ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding']
26
+
27
+ def __caller_info__(i = 1)
28
+ file, line, meth = caller[i].scan(/(.*?):(\d+):in `(.*?)'/).first
29
+ end
30
+
31
+ # Gives you some context around a specific line in a file.
32
+ # the size argument works in both directions + the actual line,
33
+ # size = 2 gives you 5 lines of source, the returned array has the
34
+ # following format.
35
+ # [
36
+ # line = [
37
+ # lineno = Integer,
38
+ # line = String,
39
+ # is_searched_line = (lineno == initial_lineno)
40
+ # ],
41
+ # ...,
42
+ # ...
43
+ # ]
44
+ # Example:
45
+ # __caller_lines__('/usr/lib/ruby/1.8/debug.rb', 122, 2) # ->
46
+ # [
47
+ # [ 120, " def check_suspend", false ],
48
+ # [ 121, " return if Thread.critical", false ],
49
+ # [ 122, " while (Thread.critical = true; @suspend_next)", true ],
50
+ # [ 123, " DEBUGGER__.waiting.push Thread.current", false ],
51
+ # [ 124, " @suspend_next = false", false ]
52
+ # ]
53
+
54
+ def __caller_lines__ file, line, size = 4
55
+ return [['Template Error!', "problem while rendering", false]] if file =~ /\(erubis\)/
56
+ lines = File.readlines(file)
57
+ current = line.to_i - 1
58
+
59
+ first = current - size
60
+ first = first < 0 ? 0 : first
61
+
62
+ last = current + size
63
+ last = last > lines.size ? lines.size : last
64
+
65
+ log = lines[first..last]
66
+
67
+ area = []
68
+
69
+ log.each_with_index do |line, index|
70
+ index = index + first + 1
71
+ area << [index, line.chomp, index == current + 1]
72
+ end
73
+
74
+ area
75
+ end
16
76
  end
@@ -3,4 +3,18 @@ class Object
3
3
  yield(value)
4
4
  value
5
5
  end
6
+
7
+ def __meta() class << self; self end end
8
+ def meta_eval(&blk) __meta.instance_eval( &blk ) end
9
+ def meta_def(name, &blk) meta_eval { define_method name, &blk } end
10
+ def class_def name, &blk
11
+ self.class.class_eval { define_method name, &blk }
12
+ end
13
+ def blank?
14
+ if respond_to? :empty? then empty?
15
+ elsif respond_to? :zero? then zero?
16
+ else !self
17
+ end
18
+ end
19
+
6
20
  end
@@ -4,7 +4,7 @@ class String
4
4
  # :allow_reloading is set to true in the config
5
5
  # file or command line options.
6
6
  def import
7
- if Merb::Server.config[:allow_reloading]
7
+ if Merb::Server.allow_reloading
8
8
  Object.send(:remove_const, self.camel_case.intern) rescue nil
9
9
  load(self.snake_case + '.rb')
10
10
  else
@@ -14,16 +14,12 @@ class String
14
14
 
15
15
  # "FooBar".snake_case #=> "foo_bar"
16
16
  def snake_case
17
- return self unless self =~ %r/[A-Z]/
18
- self.reverse.scan(%r/[A-Z]+|[^A-Z]*[A-Z]+?/).reverse.map{|word| word.reverse.downcase}.join '_'
17
+ gsub(/\B[A-Z]/, '_\&').downcase
19
18
  end
20
19
 
21
20
  # "foo_bar".camel_case #=> "FooBar"
22
21
  def camel_case
23
- return self if self =~ %r/[A-Z]/ and self !~ %r/_/
24
- words = self.strip.split %r/\s*_+\s*/
25
- words.map!{|w| w.downcase.sub(%r/^./){|c| c.upcase}}
26
- words.join
22
+ split('_').map{|e| e.capitalize}.join
27
23
  end
28
24
 
29
25
  # Concatenates a path
@@ -31,10 +27,4 @@ class String
31
27
  File.join(self, o.to_s)
32
28
  end
33
29
 
34
- def to_const
35
- const = const.to_s.dup
36
- base = const.sub!(/^::/, '') ? Object : ( self.kind_of?(Module) ? self : self.class )
37
- const.split(/::/).inject(base){ |mod, name| mod.const_get(name) }
38
- end
39
-
40
30
  end
@@ -0,0 +1,33 @@
1
+ require 'fileutils'
2
+ require 'find'
3
+
4
+ begin
5
+ require 'archive/tar/minitar'
6
+ rescue LoadError
7
+ puts "You must gem install archive-tar-minitar to use the merb app generator"
8
+ exit!
9
+ end
10
+
11
+ module Merb
12
+
13
+ class AppGenerator
14
+ SKELETON = File.expand_path File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'examples/skeleton.tar')
15
+
16
+ def self.run(path)
17
+ @path = path
18
+ @path = File.expand_path(@path)
19
+ if File.exists? @path
20
+ STDERR.puts "ERROR: Path #{@path} already exists! Aborting!"
21
+ exit 1
22
+ end
23
+
24
+ puts "Copying skeleton app to '#@path'"
25
+ # Unpacks 'test.tar' to 'x', creating 'x' if necessary.
26
+ Archive::Tar::Minitar.unpack(SKELETON, @path)
27
+ puts 'Done'
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
@@ -14,5 +14,12 @@ module Merb
14
14
  :disposition => 'attachment'.freeze
15
15
  }.freeze
16
16
 
17
+ SET_COOKIE = " %s=%s; path=/; expires=%s".freeze
18
+ COOKIE_SPLIT = /[;,] */n.freeze
19
+ COOKIE_REGEXP = /\s*(.+)=(.*)\s*/.freeze
20
+ COOKIE_EXPIRED_TIME = Time.at(0).freeze
21
+ HOUR = 60*60
22
+ DAY = HOUR*24
23
+ WEEK = DAY*7
17
24
  end
18
25
  end
@@ -13,8 +13,8 @@ module Merb
13
13
  # puts that into params as well.
14
14
  class Controller
15
15
 
16
- meta_accessor :layout
17
-
16
+ shared_accessor :layout, :session_id_key, :cache_templates
17
+
18
18
  include Merb::ControllerMixin
19
19
  include Merb::RenderMixin
20
20
  include Merb::ResponderMixin
@@ -37,6 +37,7 @@ module Merb
37
37
  cookies = query_parse(env['HTTP_COOKIE'], ';,')
38
38
  querystring = query_parse(env['QUERY_STRING'])
39
39
  self.layout ||= :application
40
+ self.session_id_key ||= :_session_id
40
41
  @in = req
41
42
  if MULTIPART_REGEXP =~ env['CONTENT_TYPE']
42
43
  boundary_regexp = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/
@@ -66,7 +67,11 @@ module Merb
66
67
  end
67
68
  io_buffer << chunk
68
69
  end
69
- querystring[name]=attrs if name
70
+ if name =~ /(.*)?\[\]/
71
+ (querystring[$1] ||= []) << attrs
72
+ else
73
+ querystring[name]=attrs if name
74
+ end
70
75
  attrs[:tempfile].rewind if attrs.is_a?MerbHash
71
76
  end
72
77
  elsif @method == :post
@@ -80,7 +85,7 @@ module Merb
80
85
  end
81
86
  end
82
87
  @cookies, @params = cookies.dup, querystring.dup.merge(args)
83
- @cookies.merge!(:session_id => @params[:session_id]) if @params.has_key?(:session_id)
88
+ @cookies.merge!(:_session_id => @params[:_session_id]) if @params.has_key?(:_session_id)
84
89
  @method = @params.delete(:_method).downcase.to_sym if @params.has_key?(:_method)
85
90
  @request = Request.new(@env, @method)
86
91
  MERB_LOGGER.info("Params: #{params.inspect}")
@@ -90,19 +95,19 @@ module Merb
90
95
  start = Time.now
91
96
  setup_session if respond_to?:setup_session
92
97
  cought = catch(:halt) { call_filters(before_filters) }
93
- case cought
98
+ @body = case cought
94
99
  when :filter_chain_completed
95
- @body = send(action)
100
+ send(action)
96
101
  when String
97
- @body = cought
102
+ cought
98
103
  when nil
99
- @body = filters_halted
104
+ filters_halted
100
105
  when Symbol
101
- @body = send(cought)
106
+ send(cought)
102
107
  when Proc
103
- @body = cought.call(self)
108
+ cought.call(self)
104
109
  else
105
- raise MerbControllerError, "The before filter chain is broken dude."
110
+ raise MerbControllerError, "The before filter chain is broken dude. wtf?"
106
111
  end
107
112
  call_filters(after_filters)
108
113
  finalize_session if respond_to?:finalize_session
@@ -145,13 +150,13 @@ module Merb
145
150
  @session
146
151
  end
147
152
 
148
- # meta_accessor sets up a class instance variable that can
153
+ # shared_accessor sets up a class instance variable that can
149
154
  # be unique for each class but also inherits the meta attrs
150
155
  # from its superclasses. Since @@class variables are almost
151
156
  # global vars within an inheritance tree, we use
152
157
  # @class_instance_variables instead
153
- meta_accessor :before_filters
154
- meta_accessor :after_filters
158
+ shared_accessor :before_filters
159
+ shared_accessor :after_filters
155
160
 
156
161
  # calls a filter chain according to rules.
157
162
  def call_filters(filter_set)
@@ -229,18 +234,13 @@ module Merb
229
234
  not both at the same time for the same filter."
230
235
  ) if opts.has_key?(:only) && opts.has_key?(:exclude)
231
236
 
232
- if opts[:only] && opts[:only].is_a?(Symbol)
233
- opts[:only] = [opts[:only]]
234
- end
235
- if opts[:exclude] && opts[:exclude].is_a?(Symbol)
236
- opts[:exclude] = [opts[:exclude]]
237
- end
237
+ opts = shuffle_filters!(opts)
238
238
 
239
239
  case filter
240
240
  when Symbol, String, Proc
241
241
  (self.before_filters ||= []) << [filter, opts]
242
242
  else
243
- raise(MerbControllerError,
243
+ raise(ArgumentError,
244
244
  'filters need to be either a Symbol, String or a Proc'
245
245
  )
246
246
  end
@@ -260,17 +260,25 @@ module Merb
260
260
  "You can specify either :only or :exclude but
261
261
  not both at the same time for the same filter."
262
262
  ) if opts.has_key?(:only) && opts.has_key?(:exclude)
263
+
263
264
  raise(ArgumentError,
264
265
  'after filters can only be a Proc object'
265
266
  ) unless Proc === filter
267
+
268
+ opts = shuffle_filters!(opts)
269
+
270
+ (self.after_filters ||= []) << [filter, opts]
271
+ end
272
+
273
+ def self.shuffle_filters!(opts={})
266
274
  if opts[:only] && opts[:only].is_a?(Symbol)
267
275
  opts[:only] = [opts[:only]]
268
276
  end
269
277
  if opts[:exclude] && opts[:exclude].is_a?(Symbol)
270
278
  opts[:exclude] = [opts[:exclude]]
271
279
  end
272
- (self.after_filters ||= []) << [filter, opts]
273
- end
280
+ return opts
281
+ end
274
282
 
275
283
  end
276
284