merb-core 0.9.13 → 1.0

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 (90) hide show
  1. data/Rakefile +5 -3
  2. data/lib/merb-core.rb +84 -41
  3. data/lib/merb-core/bootloader.rb +71 -60
  4. data/lib/merb-core/config.rb +31 -17
  5. data/lib/merb-core/controller/abstract_controller.rb +35 -35
  6. data/lib/merb-core/controller/exceptions.rb +14 -9
  7. data/lib/merb-core/controller/merb_controller.rb +22 -20
  8. data/lib/merb-core/controller/mime.rb +5 -5
  9. data/lib/merb-core/controller/mixins/authentication.rb +11 -8
  10. data/lib/merb-core/controller/mixins/conditional_get.rb +7 -7
  11. data/lib/merb-core/controller/mixins/controller.rb +15 -15
  12. data/lib/merb-core/controller/mixins/render.rb +16 -16
  13. data/lib/merb-core/controller/mixins/responder.rb +23 -23
  14. data/lib/merb-core/controller/template.rb +17 -17
  15. data/lib/merb-core/core_ext/hash.rb +2 -2
  16. data/lib/merb-core/core_ext/kernel.rb +19 -18
  17. data/lib/merb-core/dispatch/cookies.rb +13 -0
  18. data/lib/merb-core/dispatch/default_exception/default_exception.rb +12 -1
  19. data/lib/merb-core/dispatch/dispatcher.rb +6 -5
  20. data/lib/merb-core/dispatch/request.rb +56 -52
  21. data/lib/merb-core/dispatch/request_parsers.rb +7 -7
  22. data/lib/merb-core/dispatch/router.rb +14 -14
  23. data/lib/merb-core/dispatch/router/behavior.rb +31 -31
  24. data/lib/merb-core/dispatch/router/cached_proc.rb +13 -1
  25. data/lib/merb-core/dispatch/router/resources.rb +9 -9
  26. data/lib/merb-core/dispatch/router/route.rb +60 -7
  27. data/lib/merb-core/dispatch/session.rb +21 -15
  28. data/lib/merb-core/dispatch/session/container.rb +10 -8
  29. data/lib/merb-core/dispatch/session/cookie.rb +12 -11
  30. data/lib/merb-core/dispatch/session/memcached.rb +4 -2
  31. data/lib/merb-core/dispatch/session/memory.rb +8 -6
  32. data/lib/merb-core/dispatch/session/store_container.rb +6 -5
  33. data/lib/merb-core/dispatch/worker.rb +28 -10
  34. data/lib/merb-core/gem_ext/erubis.rb +4 -2
  35. data/lib/merb-core/logger.rb +3 -22
  36. data/lib/merb-core/plugins.rb +5 -5
  37. data/lib/merb-core/rack.rb +1 -1
  38. data/lib/merb-core/rack/adapter.rb +5 -1
  39. data/lib/merb-core/rack/adapter/abstract.rb +15 -10
  40. data/lib/merb-core/rack/adapter/ebb.rb +4 -2
  41. data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -1
  42. data/lib/merb-core/rack/adapter/fcgi.rb +3 -1
  43. data/lib/merb-core/rack/adapter/irb.rb +10 -1
  44. data/lib/merb-core/rack/adapter/mongrel.rb +5 -2
  45. data/lib/merb-core/rack/adapter/runner.rb +3 -1
  46. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +2 -1
  47. data/lib/merb-core/rack/adapter/thin.rb +4 -1
  48. data/lib/merb-core/rack/adapter/thin_turbo.rb +1 -0
  49. data/lib/merb-core/rack/adapter/webrick.rb +8 -34
  50. data/lib/merb-core/rack/application.rb +2 -2
  51. data/lib/merb-core/rack/handler/mongrel.rb +7 -0
  52. data/lib/merb-core/rack/helpers.rb +1 -1
  53. data/lib/merb-core/rack/middleware.rb +7 -1
  54. data/lib/merb-core/rack/middleware/conditional_get.rb +3 -0
  55. data/lib/merb-core/rack/middleware/content_length.rb +2 -0
  56. data/lib/merb-core/rack/middleware/path_prefix.rb +4 -0
  57. data/lib/merb-core/rack/middleware/profiler.rb +3 -1
  58. data/lib/merb-core/rack/middleware/static.rb +7 -1
  59. data/lib/merb-core/rack/middleware/tracer.rb +1 -0
  60. data/lib/merb-core/rack/stream_wrapper.rb +35 -30
  61. data/lib/merb-core/server.rb +17 -16
  62. data/lib/merb-core/tasks/gem_management.rb +1 -1
  63. data/lib/merb-core/tasks/merb.rb +3 -1
  64. data/lib/merb-core/tasks/merb_rake_helper.rb +1 -1
  65. data/lib/merb-core/test.rb +8 -8
  66. data/lib/merb-core/test/helpers.rb +1 -1
  67. data/lib/merb-core/test/helpers/cookie_jar.rb +16 -2
  68. data/lib/merb-core/test/helpers/mock_request_helper.rb +13 -13
  69. data/lib/merb-core/test/helpers/request_helper.rb +1 -1
  70. data/lib/merb-core/test/helpers/route_helper.rb +2 -2
  71. data/lib/merb-core/test/matchers.rb +3 -3
  72. data/lib/merb-core/test/matchers/request_matchers.rb +1 -1
  73. data/lib/merb-core/test/run_spec.rb +1 -1
  74. data/lib/merb-core/test/tasks/spectasks.rb +1 -1
  75. data/lib/merb-core/test/test_ext/hpricot.rb +1 -1
  76. data/lib/merb-core/test/test_ext/rspec.rb +2 -2
  77. data/lib/merb-core/test/test_ext/string.rb +1 -1
  78. data/lib/merb-core/version.rb +1 -1
  79. metadata +8 -22
  80. data/lib/merb-core/test/matchers/view_matchers.rb +0 -231
  81. data/lib/merb-core/test/webrat.rb +0 -37
  82. data/lib/merb-core/vendor/nokogiri/css.rb +0 -6
  83. data/lib/merb-core/vendor/nokogiri/css/generated_parser.rb +0 -653
  84. data/lib/merb-core/vendor/nokogiri/css/generated_tokenizer.rb +0 -159
  85. data/lib/merb-core/vendor/nokogiri/css/node.rb +0 -95
  86. data/lib/merb-core/vendor/nokogiri/css/parser.rb +0 -24
  87. data/lib/merb-core/vendor/nokogiri/css/parser.y +0 -198
  88. data/lib/merb-core/vendor/nokogiri/css/tokenizer.rb +0 -9
  89. data/lib/merb-core/vendor/nokogiri/css/tokenizer.rex +0 -63
  90. data/lib/merb-core/vendor/nokogiri/css/xpath_visitor.rb +0 -159
@@ -5,7 +5,9 @@ module Merb
5
5
  cattr_accessor :subclasses
6
6
  self.subclasses = []
7
7
 
8
+ # :api: private
8
9
  attr_reader :session_id
10
+ # :api: private
9
11
  attr_accessor :needs_new_cookie
10
12
 
11
13
  class << self
@@ -21,7 +23,7 @@ module Merb
21
23
  # ==== Returns
22
24
  # SessionContainer:: The new session.
23
25
  #
24
- # @api private
26
+ # :api: private
25
27
  def generate
26
28
  end
27
29
 
@@ -34,7 +36,7 @@ module Merb
34
36
  # ==== Returns
35
37
  # SessionContainer:: a SessionContainer.
36
38
  #
37
- # @api private
39
+ # :api: private
38
40
  def setup(request)
39
41
  end
40
42
 
@@ -43,7 +45,7 @@ module Merb
43
45
  # ==== Parameters
44
46
  # session_id<String>:: A unique identifier for this session.
45
47
  #
46
- # @api private
48
+ # :api: private
47
49
  def initialize(session_id)
48
50
  @_destroy = false
49
51
  self.session_id = session_id
@@ -54,7 +56,7 @@ module Merb
54
56
  # Recreates the cookie with the default expiration time. Useful during log
55
57
  # in for pushing back the expiration date.
56
58
  #
57
- # @api private
59
+ # :api: private
58
60
  def session_id=(sid)
59
61
  self.needs_new_cookie = (@session_id && @session_id != sid)
60
62
  @session_id = sid
@@ -68,13 +70,13 @@ module Merb
68
70
  # ==== Parameters
69
71
  # request<Merb::Request>:: The Merb::Request that came in from Rack.
70
72
  #
71
- # @api private
73
+ # :api: private
72
74
  def finalize(request)
73
75
  end
74
76
 
75
77
  # Destroy the current session - clears data and removes session cookie.
76
78
  #
77
- # @api private
79
+ # :api: private
78
80
  def clear!
79
81
  @_destroy = true
80
82
  self.clear
@@ -82,9 +84,9 @@ module Merb
82
84
 
83
85
  # Regenerate the session_id.
84
86
  #
85
- # @api private
87
+ # :api: private
86
88
  def regenerate
87
89
  end
88
90
 
89
91
  end
90
- end
92
+ end
@@ -14,7 +14,7 @@ module Merb
14
14
  #
15
15
  # To use Cookie Sessions, set in config/merb.yml
16
16
  # :session_secret_key - your secret digest key
17
- # :session_store: cookie
17
+ # :session_store - cookie
18
18
  class CookieSession < SessionContainer
19
19
  # TODO (maybe):
20
20
  # include request ip address
@@ -30,6 +30,7 @@ module Merb
30
30
  MAX = 4096
31
31
  DIGEST = OpenSSL::Digest::Digest.new('SHA1') # or MD5, RIPEMD160, SHA256?
32
32
 
33
+ # :api: private
33
34
  attr_accessor :_original_session_data
34
35
 
35
36
  # The session store type
@@ -41,7 +42,7 @@ module Merb
41
42
  # ==== Returns
42
43
  # SessionContainer:: The new session.
43
44
  #
44
- # @api private
45
+ # :api: private
45
46
  def generate
46
47
  self.new(Merb::SessionMixin.rand_uuid, "", Merb::Request._session_secret_key)
47
48
  end
@@ -55,7 +56,7 @@ module Merb
55
56
  # SessionContainer:: a SessionContainer. If no sessions were found,
56
57
  # a new SessionContainer will be generated.
57
58
  #
58
- # @api private
59
+ # :api: private
59
60
  def setup(request)
60
61
  session = self.new(Merb::SessionMixin.rand_uuid,
61
62
  request.session_cookie_value, request._session_secret_key)
@@ -73,7 +74,7 @@ module Merb
73
74
  # ==== Raises
74
75
  # ArgumentError:: blank or insufficiently long secret.
75
76
  #
76
- # @api private
77
+ # :api: private
77
78
  def initialize(session_id, cookie, secret)
78
79
  super session_id
79
80
  if secret.blank? || secret.length < 16
@@ -93,7 +94,7 @@ module Merb
93
94
  # ==== Parameters
94
95
  # request<Merb::Request>:: request object created from Rack environment.
95
96
  #
96
- # @api private
97
+ # :api: private
97
98
  def finalize(request)
98
99
  if @_destroy
99
100
  request.destroy_session_cookie
@@ -104,7 +105,7 @@ module Merb
104
105
 
105
106
  # Regenerate the session_id.
106
107
  #
107
- # @api private
108
+ # :api: private
108
109
  def regenerate
109
110
  self.session_id = Merb::SessionMixin.rand_uuid
110
111
  end
@@ -122,7 +123,7 @@ module Merb
122
123
  # choose to marshal it, which would make it persist
123
124
  # attributes like 'needs_new_cookie', which it shouldn't.
124
125
  #
125
- # @api private
126
+ # :api: private
126
127
  def to_cookie
127
128
  unless self.empty?
128
129
  data = self.serialize
@@ -143,7 +144,7 @@ module Merb
143
144
  # ==== Returns
144
145
  # String:: an HMAC digest of the cookie data.
145
146
  #
146
- # @api private
147
+ # :api: private
147
148
  def generate_digest(data)
148
149
  OpenSSL::HMAC.hexdigest(DIGEST, @secret, data)
149
150
  end
@@ -159,7 +160,7 @@ module Merb
159
160
  # ==== Returns
160
161
  # Hash:: The stored session data.
161
162
  #
162
- # @api private
163
+ # :api: private
163
164
  def unmarshal(cookie)
164
165
  if cookie.blank?
165
166
  {}
@@ -184,7 +185,7 @@ module Merb
184
185
  # ==== Returns
185
186
  # String:: Base64 encoded dump of the session hash.
186
187
  #
187
- # @api private
188
+ # :api: private
188
189
  def serialize
189
190
  Base64.encode64(Marshal.dump(self.to_hash)).chop
190
191
  end
@@ -194,7 +195,7 @@ module Merb
194
195
  # ==== Returns
195
196
  # Hash:: the session hash Base64 decoded from the data dump.
196
197
  #
197
- # @api private
198
+ # :api: private
198
199
  def unserialize(data)
199
200
  Marshal.load(Base64.decode64(data)) rescue {}
200
201
  end
@@ -37,7 +37,7 @@ module Merb
37
37
  # ==== Returns
38
38
  # ContainerSession:: The session corresponding to the ID.
39
39
  #
40
- # @api private
40
+ # :api: private
41
41
  def retrieve_session(session_id)
42
42
  get("session:#{session_id}")
43
43
  end
@@ -46,13 +46,15 @@ module Merb
46
46
  # session_id<String>:: ID of the session to set.
47
47
  # data<ContainerSession>:: The session to set.
48
48
  #
49
- # @api private
49
+ # :api: private
50
50
  def store_session(session_id, data)
51
51
  set("session:#{session_id}", data)
52
52
  end
53
53
 
54
54
  # ==== Parameters
55
55
  # session_id<String>:: ID of the session to delete.
56
+ #
57
+ # :api: private
56
58
  def delete_session(session_id)
57
59
  delete("session:#{session_id}")
58
60
  end
@@ -21,11 +21,13 @@ module Merb
21
21
  self.session_store_type = :memory
22
22
 
23
23
  # Bypass normal implicit class attribute reader - see below.
24
+ # :api: private
24
25
  def store
25
26
  self.class.store
26
27
  end
27
28
 
28
29
  # Lazy load/setup of MemorySessionStore.
30
+ # :api: private
29
31
  def self.store
30
32
  @_store ||= MemorySessionStore.new(Merb::Config[:memory_session_ttl])
31
33
  end
@@ -38,7 +40,7 @@ module Merb
38
40
  # ==== Parameters
39
41
  # ttl<Fixnum>:: Session validity time in seconds. Defaults to 1 hour.
40
42
  #
41
- # @api private
43
+ # :api: private
42
44
  def initialize(ttl=nil)
43
45
  @sessions = Hash.new
44
46
  @timestamps = Hash.new
@@ -53,7 +55,7 @@ module Merb
53
55
  # ==== Returns
54
56
  # ContainerSession:: The session corresponding to the ID.
55
57
  #
56
- # @api private
58
+ # :api: private
57
59
  def retrieve_session(session_id)
58
60
  @mutex.synchronize {
59
61
  @timestamps[session_id] = Time.now
@@ -65,7 +67,7 @@ module Merb
65
67
  # session_id<String>:: ID of the session to set.
66
68
  # data<ContainerSession>:: The session to set.
67
69
  #
68
- # @api private
70
+ # :api: private
69
71
  def store_session(session_id, data)
70
72
  @mutex.synchronize {
71
73
  @timestamps[session_id] = Time.now
@@ -76,7 +78,7 @@ module Merb
76
78
  # ==== Parameters
77
79
  # session_id<String>:: ID of the session to delete.
78
80
  #
79
- # @api private
81
+ # :api: private
80
82
  def delete_session(session_id)
81
83
  @mutex.synchronize {
82
84
  @timestamps.delete(session_id)
@@ -86,7 +88,7 @@ module Merb
86
88
 
87
89
  # Deletes any sessions that have reached their maximum validity.
88
90
  #
89
- # @api private
91
+ # :api: private
90
92
  def reap_expired_sessions
91
93
  @timestamps.each do |session_id,stamp|
92
94
  delete_session(session_id) if (stamp + @session_ttl) < Time.now
@@ -96,7 +98,7 @@ module Merb
96
98
 
97
99
  # Starts the timer that will eventually reap outdated sessions.
98
100
  #
99
- # @api private
101
+ # :api: private
100
102
  def start_timer
101
103
  Thread.new do
102
104
  loop {
@@ -3,6 +3,7 @@ module Merb
3
3
  class SessionStoreContainer < SessionContainer
4
4
 
5
5
  class_inheritable_accessor :store
6
+ # :api: private
6
7
  attr_accessor :_fingerprint
7
8
 
8
9
  # The class attribute :store holds a reference to an object that implements
@@ -51,7 +52,7 @@ module Merb
51
52
  # ==== Returns
52
53
  # SessionStoreContainer:: The new session.
53
54
  #
54
- # @api private
55
+ # :api: private
55
56
  def generate
56
57
  session = new(Merb::SessionMixin.rand_uuid)
57
58
  session.needs_new_cookie = true
@@ -69,7 +70,7 @@ module Merb
69
70
  # ==== Returns
70
71
  # SessionContainer:: a SessionContainer.
71
72
  #
72
- # @api private
73
+ # :api: private
73
74
  def setup(request)
74
75
  session = retrieve(request.session_id)
75
76
  request.session = session
@@ -91,7 +92,7 @@ module Merb
91
92
  # If there are persisted exceptions callbacks to execute, they all get executed
92
93
  # when Memcache library raises an exception.
93
94
  #
94
- # @api private
95
+ # :api: private
95
96
  def retrieve(session_id)
96
97
  unless session_id.blank?
97
98
  begin
@@ -130,7 +131,7 @@ module Merb
130
131
  # choose to do a full Marshal on the data, which would make it persist
131
132
  # attributes like 'needs_new_cookie', which it shouldn't.
132
133
  #
133
- # @api private
134
+ # :api: private
134
135
  def finalize(request)
135
136
  if @_destroy
136
137
  store.delete_session(self.session_id)
@@ -151,7 +152,7 @@ module Merb
151
152
 
152
153
  # Regenerate the session ID.
153
154
  #
154
- # @api private
155
+ # :api: private
155
156
  def regenerate
156
157
  store.delete_session(self.session_id)
157
158
  self.session_id = Merb::SessionMixin.rand_uuid
@@ -1,26 +1,43 @@
1
1
  module Merb
2
2
  class Worker
3
3
 
4
+ # :api: private
4
5
  attr_accessor :thread
5
6
 
6
- # ==== Returns
7
- # Merb::Worker:: instance of a worker.
8
- #
9
- # @api private
10
- def self.start
11
- new
7
+ class << self
8
+ # ==== Returns
9
+ # Merb::Worker:: instance of a worker.
10
+ #
11
+ # :api: private
12
+ def start
13
+ @worker ||= new
14
+ Merb.at_exit do
15
+ if Merb::Dispatcher.work_queue.empty?
16
+ @worker.thread.abort_on_exception = false
17
+ @worker.thread.raise
18
+ else
19
+ @worker.thread.join
20
+ end
21
+ end
22
+ @worker
23
+ end
12
24
  end
13
25
 
14
26
  # Creates a new worker thread that loops over the work queue.
15
27
  #
16
- # @api private
28
+ # :api: private
17
29
  def initialize
18
- @thread = Thread.new { loop { process_queue } }
30
+ @thread = Thread.new do
31
+ loop do
32
+ process_queue
33
+ break if Merb::Dispatcher.work_queue.empty? && Merb.exiting
34
+ end
35
+ end
19
36
  end
20
37
 
21
38
  # Processes tasks in the Merb::Dispatcher.work_queue.
22
39
  #
23
- # @api private
40
+ # :api: private
24
41
  def process_queue
25
42
  begin
26
43
  while blk = Merb::Dispatcher.work_queue.pop
@@ -31,6 +48,7 @@ module Merb
31
48
  # it's own processing
32
49
  Thread.pass
33
50
  blk.call
51
+ break if Merb::Dispatcher.work_queue.empty? && Merb.exiting
34
52
  end
35
53
  rescue Exception => e
36
54
  Merb.logger.warn! %Q!Worker Thread Crashed with Exception:\n#{Merb.exception(e)}\nRestarting Worker Thread!
@@ -39,4 +57,4 @@ module Merb
39
57
  end
40
58
 
41
59
  end
42
- end
60
+ end
@@ -3,7 +3,7 @@ module Erubis
3
3
  # This adds support for embedding the return value of a block call:
4
4
  # <%= foo do %>...<% end =%>
5
5
  #
6
- # @api private
6
+ # :api: private
7
7
  module Basic::Converter
8
8
  def convert_input(src, input)
9
9
  pat = @pattern
@@ -75,7 +75,9 @@ module Erubis
75
75
  # binding<Binding>::
76
76
  # The binding to use when evaluating the ERB tags. Defaults to the current
77
77
  # binding.
78
+ #
79
+ # :api: private
78
80
  def self.load_yaml_file(file, binding = binding)
79
81
  YAML::load(Erubis::MEruby.new(IO.read(File.expand_path(file))).result(binding))
80
82
  end
81
- end
83
+ end
@@ -1,10 +1,12 @@
1
1
  # Merb::Logger = Extlib::Logger
2
2
 
3
3
  class Merb::Logger < Extlib::Logger
4
+ # :api: public
4
5
  def verbose!(message, level = :warn)
5
6
  send("#{level}!", message) if Merb::Config[:verbose]
6
7
  end
7
8
 
9
+ # :api: public
8
10
  def verbose(message, level = :warn)
9
11
  send(level, message) if Merb::Config[:verbose]
10
12
  end
@@ -71,28 +73,6 @@ module Merb
71
73
 
72
74
  @@mutex = {}
73
75
 
74
- private
75
-
76
- # Readies a log for writing.
77
- #
78
- # ==== Parameters
79
- # log<IO, String>:: Either an IO object or a name of a logfile.
80
- def initialize_log(log)
81
- close if @log # be sure that we don't leave open files laying around.
82
-
83
- if log.respond_to?(:write)
84
- @log = log
85
- elsif File.exist?(log)
86
- @log = open(log, (File::WRONLY | File::APPEND))
87
- @log.sync = true
88
- else
89
- FileUtils.mkdir_p(File.dirname(log)) unless File.directory?(File.dirname(log))
90
- @log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
91
- @log.sync = true
92
- @log.write("#{Time.now.httpdate} #{delimiter} info #{delimiter} Logfile created\n")
93
- end
94
- end
95
-
96
76
  public
97
77
 
98
78
  # To initialize the logger you create a new object, proxies to set_log.
@@ -131,6 +111,7 @@ module Merb
131
111
  end
132
112
 
133
113
  @log = stream
114
+ @log.sync = true
134
115
  @mutex = (@@mutex[@log] ||= Mutex.new)
135
116
  end
136
117