merb 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/README +22 -4
  2. data/Rakefile +15 -3
  3. data/TODO +2 -3
  4. data/bin/merb +61 -36
  5. data/examples/sample_app/dist/app/controllers/files.rb +31 -0
  6. data/examples/sample_app/dist/app/controllers/posts.rb +26 -2
  7. data/examples/sample_app/dist/app/controllers/test.rb +7 -1
  8. data/examples/sample_app/dist/app/views/files/progress.jerb +3 -0
  9. data/examples/sample_app/dist/app/views/files/start.herb +62 -0
  10. data/examples/sample_app/dist/app/views/files/upload.herb +6 -0
  11. data/examples/sample_app/dist/app/views/layout/{application.rhtml → application.herb} +2 -3
  12. data/examples/sample_app/dist/app/views/layout/{foo.rhtml → foo.herb} +0 -0
  13. data/examples/sample_app/dist/app/views/posts/{_comments.rhtml → _comments.herb} +0 -0
  14. data/examples/sample_app/dist/app/views/posts/comment.jerb +1 -0
  15. data/examples/sample_app/dist/app/views/posts/{list.rhtml → list.herb} +0 -0
  16. data/examples/sample_app/dist/app/views/posts/{new.rhtml → new.herb} +0 -0
  17. data/examples/sample_app/dist/app/views/posts/{show.rhtml → show.herb} +0 -0
  18. data/examples/sample_app/dist/app/views/posts/xml_test.xerb +3 -0
  19. data/examples/sample_app/dist/app/views/test/{foo.rhtml → foo.herb} +0 -0
  20. data/examples/sample_app/dist/app/views/test/{hello.rhtml → hello.herb} +0 -0
  21. data/examples/sample_app/dist/app/views/test/json.jerb +1 -0
  22. data/examples/sample_app/dist/conf/merb.yml +11 -0
  23. data/examples/sample_app/dist/conf/merb_init.rb +1 -1
  24. data/examples/sample_app/dist/conf/mup.conf +11 -0
  25. data/examples/sample_app/dist/public/javascripts/mup.js +113 -0
  26. data/examples/sample_app/script/merb_stop +7 -3
  27. data/examples/sample_app/script/startdrb +8 -0
  28. data/lib/merb.rb +37 -2
  29. data/lib/merb/merb_class_extensions.rb +21 -22
  30. data/lib/merb/merb_controller.rb +101 -33
  31. data/lib/merb/merb_handler.rb +26 -25
  32. data/lib/merb/merb_router.rb +1 -1
  33. data/lib/merb/merb_utils.rb +35 -37
  34. data/lib/merb/mixins/basic_authentication_mixin.rb +39 -0
  35. data/lib/merb/mixins/controller_mixin.rb +119 -115
  36. data/lib/merb/mixins/javascript_mixin.rb +63 -0
  37. data/lib/merb/mixins/render_mixin.rb +85 -69
  38. data/lib/merb/mixins/responder_mixin.rb +38 -0
  39. data/lib/merb/session/merb_drb_server.rb +107 -0
  40. data/lib/merb/session/merb_drb_session.rb +71 -0
  41. data/lib/merb/session/merb_session.rb +1 -0
  42. data/lib/merb/vendor/paginator/README.txt +84 -0
  43. data/lib/merb/vendor/paginator/paginator.rb +121 -0
  44. data/lib/mutex_hotfix.rb +34 -0
  45. metadata +41 -63
  46. data/doc/rdoc/classes/ControllerMixin.html +0 -676
  47. data/doc/rdoc/classes/Hash.html +0 -148
  48. data/doc/rdoc/classes/Merb.html +0 -140
  49. data/doc/rdoc/classes/Merb/Controller.html +0 -338
  50. data/doc/rdoc/classes/Merb/RouteMatcher.html +0 -388
  51. data/doc/rdoc/classes/Merb/Server.html +0 -148
  52. data/doc/rdoc/classes/Merb/Session.html +0 -201
  53. data/doc/rdoc/classes/Merb/SessionMixin.html +0 -199
  54. data/doc/rdoc/classes/MerbControllerError.html +0 -111
  55. data/doc/rdoc/classes/MerbHandler.html +0 -430
  56. data/doc/rdoc/classes/MerbHash.html +0 -469
  57. data/doc/rdoc/classes/MerbHash/Mutex.html +0 -198
  58. data/doc/rdoc/classes/Noroutefound.html +0 -153
  59. data/doc/rdoc/classes/Object.html +0 -149
  60. data/doc/rdoc/classes/RenderMixin.html +0 -362
  61. data/doc/rdoc/classes/String.html +0 -212
  62. data/doc/rdoc/classes/Symbol.html +0 -179
  63. data/doc/rdoc/created.rid +0 -1
  64. data/doc/rdoc/files/LICENSE.html +0 -129
  65. data/doc/rdoc/files/README.html +0 -417
  66. data/doc/rdoc/files/TODO.html +0 -151
  67. data/doc/rdoc/files/lib/merb/merb_class_extensions_rb.html +0 -101
  68. data/doc/rdoc/files/lib/merb/merb_controller_rb.html +0 -101
  69. data/doc/rdoc/files/lib/merb/merb_handler_rb.html +0 -101
  70. data/doc/rdoc/files/lib/merb/merb_router_rb.html +0 -101
  71. data/doc/rdoc/files/lib/merb/merb_utils_rb.html +0 -108
  72. data/doc/rdoc/files/lib/merb/mixins/controller_mixin_rb.html +0 -101
  73. data/doc/rdoc/files/lib/merb/mixins/render_mixin_rb.html +0 -101
  74. data/doc/rdoc/files/lib/merb/session/merb_session_rb.html +0 -101
  75. data/doc/rdoc/files/lib/merb_rb.html +0 -140
  76. data/doc/rdoc/files/lib/merb_tasks_rb.html +0 -101
  77. data/doc/rdoc/fr_class_index.html +0 -43
  78. data/doc/rdoc/fr_file_index.html +0 -40
  79. data/doc/rdoc/fr_method_index.html +0 -104
  80. data/doc/rdoc/index.html +0 -24
  81. data/doc/rdoc/rdoc-style.css +0 -208
  82. data/examples/sample_app/dist/app/controllers/upload.rb +0 -29
  83. data/examples/sample_app/dist/app/views/posts/comment.merbjs +0 -1
  84. data/examples/sample_app/dist/app/views/upload/start.rhtml +0 -15
  85. data/examples/sample_app/dist/app/views/upload/upload.rhtml +0 -4
  86. data/examples/sample_app/dist/public/files/README +0 -35
  87. data/examples/sample_app/dist/public/files/setup.rb +0 -1346
  88. data/examples/sample_app/log/merb.log +0 -778
@@ -0,0 +1,6 @@
1
+ <h2>File uploaded successfully</h2>
2
+
3
+ "UPLOADED: <%= params.inspect %><script type='text/javascript'>window.parent.UploadProgress.finish();</script>"
4
+
5
+
6
+
@@ -4,9 +4,8 @@
4
4
  <head>
5
5
  <title>Merb: Mongrel + Erb</title>
6
6
  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
7
- <link rel="stylesheet" href="/stylesheets/merb.css" type="text/css" />
8
- <script src="/javascripts/prototype.js" type="text/javascript"></script>
9
- <script src="/javascripts/effects.js" type="text/javascript"></script>
7
+ <%= require_css :merb %>
8
+ <%= require_js :prototype, :effects %>
10
9
  </head>
11
10
 
12
11
  <body>
@@ -0,0 +1 @@
1
+ $('comments').update(<%=js partial(:comments) %>);
@@ -0,0 +1,3 @@
1
+ xml.foo {
2
+ xml.bar "baz"
3
+ }
@@ -0,0 +1 @@
1
+ <%= @post.attributes.inspect.to_json %>
@@ -0,0 +1,11 @@
1
+ ---
2
+ :host: 0.0.0.0
3
+ :port: "4000"
4
+ :allow_reloading: true
5
+ :basic_auth:
6
+ :username: ezra
7
+ :password: test
8
+ :domain: localhost
9
+ #:daemonize: true
10
+ #:cluster: 3
11
+ #:session: true
@@ -9,7 +9,7 @@ ActiveRecord::Base.logger = MERB_LOGGER
9
9
  ActiveRecord::Base.establish_connection(
10
10
  :adapter => 'mysql',
11
11
  :username => 'root',
12
- :password => 'xxxxx',
12
+ :password => 'reversal',
13
13
  :database => 'merb'
14
14
  )
15
15
  ActiveRecord::Base.verification_timeout = 14400
@@ -0,0 +1,11 @@
1
+ uri "/",
2
+ :handler => plugin("/handlers/upload", :path_info => '/files/upload'),
3
+ :in_front => true,
4
+ :frequency => 1
5
+
6
+ #uri "/",
7
+ # :handler => plugin("/handlers/upload",
8
+ # :path_info => '/files/upload',
9
+ # :frequency => 1,
10
+ # :drb => 'druby://0.0.0.0:2999'),
11
+ # :in_front => true
@@ -0,0 +1,113 @@
1
+ var UploadProgress = {
2
+ uploading: null,
3
+ monitor: function(upid) {
4
+ if(!this.periodicExecuter) {
5
+ this.periodicExecuter = new PeriodicalExecuter(function() {
6
+ if(!UploadProgress.uploading) return;
7
+ new Ajax.Request('/files/progress?upload_id=' + upid);
8
+ }, 3);
9
+ }
10
+
11
+ this.uploading = true;
12
+ this.StatusBar.create();
13
+ },
14
+
15
+ update: function(total, current) {
16
+ if(!this.uploading) return;
17
+ var status = current / total;
18
+ var statusHTML = status.toPercentage();
19
+ $('results').innerHTML = statusHTML + "<br /><small>" + current.toHumanSize() + ' of ' + total.toHumanSize() + " uploaded.</small>";
20
+ this.StatusBar.update(status, statusHTML);
21
+ },
22
+
23
+ finish: function() {
24
+ this.uploading = false;
25
+ this.StatusBar.finish();
26
+ $('results').innerHTML = 'finished!';
27
+ },
28
+
29
+ cancel: function(msg) {
30
+ if(!this.uploading) return;
31
+ this.uploading = false;
32
+ if(this.StatusBar.statusText) this.StatusBar.statusText.innerHTML = msg || 'canceled';
33
+ },
34
+
35
+ StatusBar: {
36
+ statusBar: null,
37
+ statusText: null,
38
+ statusBarWidth: 500,
39
+
40
+ create: function() {
41
+ this.statusBar = this._createStatus('status-bar');
42
+ this.statusText = this._createStatus('status-text');
43
+ this.statusText.innerHTML = '0%';
44
+ this.statusBar.style.width = '0';
45
+ },
46
+
47
+ update: function(status, statusHTML) {
48
+ this.statusText.innerHTML = statusHTML;
49
+ this.statusBar.style.width = Math.floor(this.statusBarWidth * status);
50
+ },
51
+
52
+ finish: function() {
53
+ this.statusText.innerHTML = '100%';
54
+ this.statusBar.style.width = '100%';
55
+ },
56
+
57
+ _createStatus: function(id) {
58
+ el = $(id);
59
+ if(!el) {
60
+ el = document.createElement('span');
61
+ el.setAttribute('id', id);
62
+ $('progress-bar').appendChild(el);
63
+ }
64
+ return el;
65
+ }
66
+ },
67
+
68
+ FileField: {
69
+ add: function() {
70
+ new Insertion.Bottom('file-fields', '<p style="display:none"><input id="data" name="data" type="file" /> <a href="#" onclick="UploadProgress.FileField.remove(this);return false;">x</a></p>')
71
+ $$('#file-fields p').last().visualEffect('blind_down', {duration:0.3});
72
+ },
73
+
74
+ remove: function(anchor) {
75
+ anchor.parentNode.visualEffect('drop_out', {duration:0.25});
76
+ }
77
+ }
78
+ }
79
+
80
+ Number.prototype.bytes = function() { return this; };
81
+ Number.prototype.kilobytes = function() { return this * 1024; };
82
+ Number.prototype.megabytes = function() { return this * (1024).kilobytes(); };
83
+ Number.prototype.gigabytes = function() { return this * (1024).megabytes(); };
84
+ Number.prototype.terabytes = function() { return this * (1024).gigabytes(); };
85
+ Number.prototype.petabytes = function() { return this * (1024).terabytes(); };
86
+ Number.prototype.exabytes = function() { return this * (1024).petabytes(); };
87
+ ['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte', 'petabyte', 'exabyte'].each(function(meth) {
88
+ Number.prototype[meth] = Number.prototype[meth+'s'];
89
+ });
90
+
91
+ Number.prototype.toPrecision = function() {
92
+ var precision = arguments[0] || 2;
93
+ var s = Math.round(this * Math.pow(10, precision)).toString();
94
+ var pos = s.length - precision;
95
+ var last = s.substr(pos, precision);
96
+ return s.substr(0, pos) + (last.match("^0{" + precision + "}$") ? '' : '.' + last);
97
+ }
98
+
99
+ // (1/10).toPercentage()
100
+ // # => '10%'
101
+ Number.prototype.toPercentage = function() {
102
+ return (this * 100).toPrecision() + '%';
103
+ }
104
+
105
+ Number.prototype.toHumanSize = function() {
106
+ if(this < (1).kilobyte()) return this + " Bytes";
107
+ if(this < (1).megabyte()) return (this / (1).kilobyte()).toPrecision() + ' KB';
108
+ if(this < (1).gigabytes()) return (this / (1).megabyte()).toPrecision() + ' MB';
109
+ if(this < (1).terabytes()) return (this / (1).gigabytes()).toPrecision() + ' GB';
110
+ if(this < (1).petabytes()) return (this / (1).terabytes()).toPrecision() + ' TB';
111
+ if(this < (1).exabytes()) return (this / (1).petabytes()).toPrecision() + ' PB';
112
+ return (this / (1).exabytes()).toPrecision() + ' EB';
113
+ }
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'fileutils'
3
- pids = IO.readlines(File.dirname(__FILE__)+"/../log/merb.pid").map{|p| p.to_i}
4
3
 
5
- pids.each do |pid|
4
+ pids=[]
5
+
6
+ port_or_star = ARGV[0] || '*'
7
+
8
+ Dir[File.dirname(__FILE__)+"/../log/merb.#{port_or_star}.pid"].each do |f|
9
+ pid = IO.read(f).chomp.to_i
6
10
  puts "killing PID: #{pid}"
7
11
  Process.kill(9, pid)
12
+ FileUtils.rm f
8
13
  end
9
- FileUtils.rm File.dirname(__FILE__)+"/../log/merb.pid"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'merb/session/merb_drb_server'
5
+ DRb.start_service("druby://localhost:2222", Merb::DRbSession.setup)
6
+ puts "DRb URI: #{DRb.uri}"
7
+ puts "Pid: #{Process.pid}"
8
+ DRb.thread.join
data/lib/merb.rb CHANGED
@@ -5,7 +5,7 @@ require 'erubis'
5
5
  require 'logger'
6
6
 
7
7
  module Merb
8
- VERSION='0.0.6' unless defined?VERSION
8
+ VERSION='0.0.7' unless defined?VERSION
9
9
  class Server
10
10
  def self.config
11
11
  @@merb_opts ||= {}
@@ -16,8 +16,43 @@ end
16
16
  class MerbControllerError < RuntimeError; end
17
17
 
18
18
  MERB_FRAMEWORK_ROOT = File.dirname(__FILE__)
19
+
20
+ begin
21
+ require 'thread'
22
+ require 'fastthread'
23
+ puts 'Using FastThread'
24
+ rescue LoadError
25
+ require 'mutex_hotfix'
26
+ end
27
+
28
+ begin
29
+ require 'fjson'
30
+ puts "using fjson"
31
+ rescue LoadError
32
+ require 'json'
33
+ end
34
+
19
35
  MERB_ROOT = Merb::Server.config[:merb_root] || Dir.pwd
20
36
  DIST_ROOT = Merb::Server.config[:dist_root] || Dir.pwd+'/dist'
21
- MERB_LOGGER = Logger.new("#{MERB_ROOT}/log/merb.log")
37
+
38
+ MERB_LOGGER = Logger.new("#{MERB_ROOT}/log/merb.log")
39
+ # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
40
+ MERB_LOGGER.level = case (Merb::Server.config[:log_level].downcase rescue '')
41
+ when 'debug'
42
+ Logger::DEBUG
43
+ when 'info'
44
+ Logger::INFO
45
+ when 'warn'
46
+ Logger::WARN
47
+ when 'error'
48
+ Logger::ERROR
49
+ when 'fatal'
50
+ Logger::FATAL
51
+ when 'unknown'
52
+ Logger::UNKNOWN
53
+ else
54
+ Logger::INFO
55
+ end
56
+
22
57
  lib = File.join(File.dirname(__FILE__), 'merb')
23
58
  Dir.entries(lib).sort.each {|fn| require File.join(lib, fn) if fn =~ /\.rb$/}
@@ -1,9 +1,9 @@
1
1
  class Class # :nodoc:
2
- def inheritable_reader(*syms)
2
+ def meta_reader(*syms)
3
3
  syms.each do |sym|
4
4
  class_eval <<-EOS
5
5
  def self.#{sym}
6
- read_inheritable_attribute(:#{sym})
6
+ read_meta_attribute(:#{sym})
7
7
  end
8
8
 
9
9
  def #{sym}
@@ -13,11 +13,11 @@ class Class # :nodoc:
13
13
  end
14
14
  end
15
15
 
16
- def inheritable_writer(*syms)
16
+ def meta_writer(*syms)
17
17
  syms.each do |sym|
18
18
  class_eval <<-EOS
19
19
  def self.#{sym}=(obj)
20
- write_inheritable_attribute(:#{sym}, obj)
20
+ write_meta_attribute(:#{sym}, obj)
21
21
  end
22
22
 
23
23
  def #{sym}=(obj)
@@ -27,39 +27,38 @@ class Class # :nodoc:
27
27
  end
28
28
  end
29
29
 
30
-
31
- def inheritable_accessor(*syms)
32
- inheritable_reader(*syms)
33
- inheritable_writer(*syms)
30
+ def meta_accessor(*syms)
31
+ meta_reader(*syms)
32
+ meta_writer(*syms)
34
33
  end
35
34
 
36
- def inheritable_attributes
37
- @inheritable_attributes ||= {}
35
+ def meta_attributes
36
+ @meta_attributes ||= {}
38
37
  end
39
38
 
40
- def write_inheritable_attribute(key, value)
41
- inheritable_attributes[key] = value
39
+ def write_meta_attribute(key, value)
40
+ meta_attributes[key] = value
42
41
  end
43
42
 
44
- def read_inheritable_attribute(key)
45
- inheritable_attributes[key]
43
+ def read_meta_attribute(key)
44
+ meta_attributes[key]
46
45
  end
47
46
 
48
- def reset_inheritable_attributes
49
- inheritable_attributes.clear
47
+ def reset_meta_attributes
48
+ meta_attributes.clear
50
49
  end
51
50
 
52
51
  private
53
- def inherited_with_inheritable_attributes(child)
54
- inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
52
+ def inherited_with_meta_attributes(child)
53
+ inherited_without_meta_attributes(child) if respond_to?(:inherited_without_meta_attributes)
55
54
 
56
- new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
55
+ new_meta_attributes = meta_attributes.inject({}) do |memo, (key, value)|
57
56
  memo.update(key => (value.dup rescue value))
58
57
  end
59
58
 
60
- child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
59
+ child.instance_variable_set('@meta_attributes', new_meta_attributes)
61
60
  end
62
61
 
63
- alias inherited_without_inheritable_attributes inherited
64
- alias inherited inherited_with_inheritable_attributes
62
+ alias inherited_without_meta_attributes inherited
63
+ alias inherited inherited_with_meta_attributes
65
64
  end
@@ -1,5 +1,7 @@
1
1
  require File.dirname(__FILE__)+'/mixins/controller_mixin'
2
2
  require File.dirname(__FILE__)+'/mixins/render_mixin'
3
+ require File.dirname(__FILE__)+'/mixins/javascript_mixin'
4
+ require File.dirname(__FILE__)+'/mixins/responder_mixin'
3
5
 
4
6
  module Merb
5
7
 
@@ -10,30 +12,36 @@ module Merb
10
12
  # to your controller via params. It also parses the ?query=string and
11
13
  # puts that into params as well.
12
14
  class Controller
13
- include ::ControllerMixin
14
- include ::RenderMixin
15
+ include Merb::ControllerMixin
16
+ include Merb::RenderMixin
17
+ include Merb::JavascriptMixin
18
+ include Merb::ResponderMixin
15
19
 
16
20
  if Merb::Server.config[:session]
17
- require File.dirname(__FILE__)+"/session/merb_session"
21
+ require "drb"
22
+ DRb.start_service('druby://localhost:0')
23
+ Merb.const_set :DRbSession, DRbObject.new(nil, "druby://#{Merb::Server.config[:host]}:#{Merb::Server.config[:session]}")
24
+ require File.dirname(__FILE__)+"/session/merb_drb_session"
18
25
  include ::Merb::SessionMixin
19
- puts "session mixed in"
26
+ puts "drb session mixed in"
20
27
  end
21
28
 
22
- attr_accessor :status
29
+ attr_accessor :status, :body
23
30
 
24
31
  # parses the http request into params, headers and cookies
25
32
  # that you can use in your controller classes. Also handles
26
33
  # file uploads by writing a tempfile and passing a reference
27
34
  # in params.
28
- def initialize(req, env, args, method=(env['REQUEST_METHOD']||"GET")) #:nodoc:
35
+ def initialize(req, env, args, method=(env['REQUEST_METHOD']||'GET'))
29
36
  env = MerbHash[env.to_hash]
30
- @layout = 'application'
31
- @status, @method, @env, @headers, @root = 200, method.downcase, env,
32
- {'Content-Type'=>'text/html'}, env['SCRIPT_NAME'].sub(/\/$/,'')
37
+ @layout = :application
38
+ @status, @method, @env, @headers, @root = 200, method.downcase.to_sym, env,
39
+ {'Content-Type' =>'text/html'}, env['SCRIPT_NAME'].sub(/\/$/,'')
33
40
  @k = query_parse(env['HTTP_COOKIE'], ';,')
34
41
  qs = query_parse(env['QUERY_STRING'])
42
+ #puts req.read; req.rewind
35
43
  @in = req
36
- if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n.match(env['CONTENT_TYPE'])
44
+ if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n =~ (env['CONTENT_TYPE'])
37
45
  b = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/
38
46
  until @in.eof?
39
47
  fh=MerbHash[]
@@ -65,21 +73,39 @@ module Merb
65
73
  qs[fn]=fh if fn
66
74
  fh[:tempfile].rewind if fh.is_a?MerbHash
67
75
  end
68
- elsif @method == "post"
69
- qs.merge!(query_parse(@in.read))
76
+ elsif @method == :post
77
+ if ['application/json', 'text/x-json'].include?(env['CONTENT_TYPE'])
78
+ MERB_LOGGER.info("JSON Request")
79
+ json = JSON.parse(@in.read || "") || {}
80
+ json = MerbHash.new(json) if json.is_a? Hash
81
+ qs.merge!(json)
82
+ else
83
+ qs.merge!(query_parse(@in.read))
84
+ end
70
85
  end
71
86
  @cookies, @params = @k.dup, qs.dup.merge(args)
87
+ @cookies.merge!(:sess_id => @params.delete(:sess_id)) if @params.has_key?:sess_id
72
88
  MERB_LOGGER.info("Params: #{params.inspect}")
73
89
  end
74
90
 
75
- def dispatch(action=nil)
91
+ def dispatch(action=:to_s)
92
+ start = Time.now
76
93
  setup_session if respond_to?:setup_session
77
- call_filters(before_filters)
78
- res = send(action || :to_s)
94
+ if catch(:halt) { call_filters(before_filters) }
95
+ @body = send(action)
96
+ else
97
+ @body = filters_halted
98
+ end
79
99
  finalize_session if respond_to?:finalize_session
80
- res
100
+ MERB_LOGGER.info("Time spent in #{action} action: #{Time.now - start} seconds")
81
101
  end
82
-
102
+
103
+ # override this method on your controller classes to specialize
104
+ # the output when the filter chain is halted.
105
+ def filters_halted
106
+ "<html><body><h1>Filter Chain Halted!</h1></body></html>"
107
+ end
108
+
83
109
  # accessor for @params. Please use params and
84
110
  # never @params directly.
85
111
  def params
@@ -98,28 +124,70 @@ module Merb
98
124
  @headers
99
125
  end
100
126
 
101
- inheritable_accessor :before_filters
127
+ # meta_accessor sets up a class instance variable that can
128
+ # be unique for each class but also inherits the meta attrs
129
+ # from its superclasses. Since @@class variables are almost
130
+ # global vars within an inheritance tree
131
+ meta_accessor :before_filters
102
132
 
103
133
  def call_filters(filter_set)
104
- (filter_set || []).each do |filter|
134
+ (filter_set || []).each do |(filter, rule)|
135
+ ok = false
136
+ if rule.has_key?(:include)
137
+ if rule[:include].include?(params[:action].intern)
138
+ ok = true
139
+ end
140
+ elsif rule.has_key?(:exclude)
141
+ if !rule[:exclude].include?(params[:action].intern)
142
+ ok = true
143
+ end
144
+ else
145
+ ok = true
146
+ end
105
147
  case filter
106
- when Symbol
107
- send(filter)
148
+ when Symbol, String
149
+ send(filter) if ok
108
150
  when Proc
109
- filter.call(self)
110
- else
111
- raise(
112
- MerbControllerError,
113
- 'filters needs to be either a Symbol or a Proc'
114
- )
115
- end
151
+ filter.call(self) if ok
152
+ end
153
+ end
154
+ end
155
+
156
+ # #before is a class method that allows you to specify before
157
+ # filters in your controllers. Filters can either before a symbol
158
+ # or string that corresponds to a method name or a proc object.
159
+ # if it is a method name that method will be called and if it
160
+ # is a proc it will be called with an argument of self. When
161
+ # you use a proc as a filter it needs to take one parameter.
162
+ def self.before(filter, opts={})
163
+ raise(ArgumentError,
164
+ "You can specify either :include or :exclude but
165
+ not both at the same time for the same filter."
166
+ ) if opts.has_key?(:include) && opts.has_key?(:exclude)
167
+
168
+ if opts[:include] && opts[:include].is_a?(Symbol)
169
+ opts[:include] = [opts[:include]]
170
+ end
171
+ if opts[:exclude] && opts[:exclude].is_a?(Symbol)
172
+ opts[:exclude] = [opts[:exclude]]
173
+ end
174
+
175
+ case filter
176
+ when Symbol, String, Proc
177
+ (self.before_filters ||= []) << [filter, opts]
178
+ else
179
+ raise(MerbControllerError,
180
+ 'filters need to be either a Symbol, String or a Proc'
181
+ )
116
182
  end
117
- end
118
-
119
- def self.before(filter)
120
- (self.before_filters ||= []) << filter
121
183
  end
122
184
 
185
+ if Merb::Server.config[:basic_auth]
186
+ require File.dirname(__FILE__)+"/mixins/basic_authentication_mixin"
187
+ include ::Merb::Authentication
188
+ puts "Basic Authentication mixed in"
189
+ end
190
+
123
191
  end
124
192
 
125
193
  end
@@ -129,7 +197,7 @@ class Noroutefound < Merb::Controller
129
197
  # match any defined routes.
130
198
  def method_missing
131
199
  @status = 404
132
- "<html><body><h1>No Matching Route</h1></body></html>"
200
+ "<html><body><h1>No Matching Route!</h1></body></html>"
133
201
  end
134
202
 
135
203
  end