manveru-ramaze 2008.09 → 2008.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/examples/app/rapaste/model/paste.rb +3 -0
  2. data/examples/app/rapaste/start.rb +1 -1
  3. data/examples/app/rapaste/view/view.xhtml +3 -0
  4. data/examples/helpers/httpdigest.rb +68 -10
  5. data/lib/proto/controller/init.rb +2 -1
  6. data/lib/proto/model/init.rb +3 -3
  7. data/lib/proto/start.rb +4 -0
  8. data/lib/ramaze/adapter/base.rb +2 -2
  9. data/lib/ramaze/contrib.rb +1 -1
  10. data/lib/ramaze/controller/resolve.rb +8 -3
  11. data/lib/ramaze/controller.rb +3 -0
  12. data/lib/ramaze/current/request.rb +2 -4
  13. data/lib/ramaze/dispatcher/action.rb +2 -2
  14. data/lib/ramaze/dispatcher/file.rb +2 -1
  15. data/lib/ramaze/dispatcher.rb +1 -1
  16. data/lib/ramaze/helper/formatting.rb +1 -1
  17. data/lib/ramaze/helper/httpdigest.rb +64 -24
  18. data/lib/ramaze/helper/paginate.rb +2 -3
  19. data/lib/ramaze/helper/partial.rb +1 -1
  20. data/lib/ramaze/helper/user.rb +4 -4
  21. data/lib/ramaze/helper.rb +3 -2
  22. data/lib/ramaze/log/rotatinginformer.rb +168 -0
  23. data/lib/ramaze/option/holder.rb +3 -3
  24. data/lib/ramaze/snippets/divide.rb +2 -0
  25. data/lib/ramaze/snippets/numeric/time.rb +1 -1
  26. data/lib/ramaze/snippets/object/acquire.rb +3 -6
  27. data/lib/ramaze/snippets/ordered_set.rb +21 -14
  28. data/lib/ramaze/snippets/ramaze/deprecated.rb +2 -1
  29. data/lib/ramaze/tool/localize.rb +8 -4
  30. data/lib/ramaze/tool/mime.rb +1 -1
  31. data/lib/ramaze/tool/project_creator.rb +2 -1
  32. data/lib/ramaze/version.rb +1 -1
  33. data/lib/ramaze.rb +2 -0
  34. data/rake_tasks/coverage.rake +4 -5
  35. data/rake_tasks/spec.rake +6 -6
  36. data/ramaze.gemspec +2 -1
  37. data/spec/contrib/profiling.rb +2 -2
  38. metadata +3 -2
  39. data/lib/ramaze/contrib/auto_params/get_args.rb +0 -58
  40. data/lib/ramaze/contrib/auto_params.rb +0 -135
  41. data/spec/contrib/auto_params.rb +0 -121
  42. data/spec/snippets/divide.rb +0 -19
  43. data/spec/snippets/object/acquire.rb +0 -71
@@ -27,6 +27,9 @@ class Paste < Sequel::Model(:paste)
27
27
 
28
28
  def uv(text, style = STYLE, lines = true)
29
29
  Uv.parse(text, "xhtml", syntax, lines, style)
30
+ rescue ArgumentError => ex
31
+ Ramaze::Log::error(ex)
32
+ "<pre>#{text}</pre>"
30
33
  end
31
34
 
32
35
  def syntax_name
@@ -22,4 +22,4 @@ DB = Sequel.connect("sqlite://#{DB_FILE}")
22
22
  require 'model/paste'
23
23
  require 'controller/paste'
24
24
 
25
- Ramaze.start
25
+ Ramaze.start :adapter => :mongrel, :port => 9952
@@ -1,6 +1,9 @@
1
1
  #{@pager}
2
2
  <script type="text/javascript" src="/js/jquery.js"></script>
3
3
  <script type="text/javascript">
4
+ $(function() {
5
+ $('#paste_body').dblclick(function(){ $('.line-numbers').toggle() });
6
+ });
4
7
  function change_style(name){
5
8
  $('link')[1].href = '/css/' + name + '.css';
6
9
  $('pre')[0].className = name;
@@ -4,12 +4,61 @@ require 'ramaze'
4
4
  REALM = 'ramaze authentication required'
5
5
 
6
6
  class MainController < Ramaze::Controller
7
+
8
+ helper :httpdigest
9
+
7
10
  def index
8
11
  %|
12
+ <p><a href="#{Rs(:eyes_only)}">eyes only</a></p>
9
13
  <p><a href="#{R(SecretController,'/')}">secret area</a></p>
10
- <p><a href="#{R(GuestController,'/')}">guest area</a> password must be the same as username</p>
14
+ <p><a href="#{R(GuestController,'/')}">guest area</a> username is <em>guest</em> password is <em>access</em></p>
11
15
  |
12
16
  end
17
+
18
+ def eyes_only
19
+ httpdigest('eyes only',REALM) do |username|
20
+ password = username.reverse
21
+ MD5.hexdigest([username,REALM,password].join(':'))
22
+ end
23
+ "Shhhh don't tell anyone"
24
+ end
25
+
26
+ end
27
+
28
+ class LoginController < Ramaze::Controller
29
+ map '/login'
30
+
31
+ helper :httpdigest
32
+
33
+ def index
34
+ @username ||= session[:username]
35
+ @username ||= httpdigest('login area',REALM)
36
+ "Hi there #@username!"
37
+ end
38
+
39
+ def login
40
+ %|<form action="#{Rs(:post)}" method="post"><input type="text" name="username"/><input type="password" name="password"/><input type="submit"/></form>|
41
+ end
42
+
43
+ def post
44
+ username = request.params["username"]
45
+ password = request.params["password"]
46
+ if password == "entry"
47
+ session[:username] = username
48
+ destination = session[ :redirect_after_login ]
49
+ session.delete( :redirect_after_login )
50
+ redirect destination
51
+ end
52
+ redirect Rs(:login)
53
+ end
54
+
55
+ protected
56
+
57
+ def httpdigest_failure
58
+ session[ :redirect_after_login ] = Rs(Ramaze::Action.current.method)
59
+ redirect Rs(:login)
60
+ end
61
+
13
62
  end
14
63
 
15
64
  class SecretController < Ramaze::Controller
@@ -17,17 +66,22 @@ class SecretController < Ramaze::Controller
17
66
  helper :aspect
18
67
  helper :httpdigest
19
68
 
69
+ USERS = { 'admin' => 'secret', 'root' => 'password' }
70
+
20
71
  before_all do
21
- @username = httpdigest('secret area',REALM) do |username|
22
- { 'admin' => MD5.hexdigest("admin:#{REALM}:secret"),
23
- 'root' => MD5.hexdigest("root:#{REALM}:access"),
24
- }[ username ]
25
- end
72
+ @username = httpdigest('secret area',REALM)
26
73
  end
27
74
 
28
75
  def index
29
76
  "Hello <em>#@username</em>, welcome to SECRET world"
30
77
  end
78
+
79
+ protected
80
+
81
+ def httpdigest_lookup_plaintext_password username
82
+ USERS[ username ]
83
+ end
84
+
31
85
  end
32
86
 
33
87
  class GuestController < Ramaze::Controller
@@ -36,15 +90,19 @@ class GuestController < Ramaze::Controller
36
90
  helper :httpdigest
37
91
 
38
92
  before_all do
39
- @username = httpdigest('guest area',REALM) do |username|
40
- username_used = username
41
- MD5.hexdigest([username,REALM,username].join(':'))
42
- end
93
+ @username = httpdigest('guest area',REALM)
43
94
  end
44
95
 
45
96
  def index
46
97
  "Hello <em>#@username</em>, welcome to GUEST world."
47
98
  end
99
+
100
+ protected
101
+
102
+ def httpdigest_lookup_password username
103
+ return "b71f15b2f6dd4834224fbe02169ed94c" if username == "guest"
104
+ end
105
+
48
106
  end
49
107
 
50
108
  Ramaze.start
@@ -7,4 +7,5 @@ class Controller < Ramaze::Controller
7
7
  engine :Ezamar
8
8
  end
9
9
 
10
- acquire __DIR__/"*.rb"
10
+ # Here go your requires for subclasses of Controller:
11
+ require 'controller/main'
@@ -1,4 +1,4 @@
1
- # Here goes your database connection and options
1
+ # Here goes your database connection and options:
2
2
 
3
- # Require all models in '/model/*.rb'
4
- acquire __DIR__/"*.rb"
3
+ # Here go your requires for models:
4
+ # require 'model/user'
data/lib/proto/start.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  require 'rubygems'
2
2
  require 'ramaze'
3
3
 
4
+ # Add directory start.rb is in to the load path, so you can run the app from
5
+ # any other working path
6
+ $LOAD_PATH.unshift(__DIR__)
7
+
4
8
  # Initialize controllers and models
5
9
  require 'controller/init'
6
10
  require 'model/init'
@@ -11,8 +11,8 @@ module Ramaze
11
11
  # Rack::Deflater,
12
12
  Ramaze::Reloader,
13
13
  Ramaze::Current,
14
- Ramaze::Dispatcher,
15
- ]
14
+ Ramaze::Dispatcher
15
+ ] unless defined? MIDDLEWARE
16
16
 
17
17
  def self.middleware(mws = MIDDLEWARE)
18
18
  if @middleware and trait[:previous] == mws
@@ -49,7 +49,7 @@ module Ramaze
49
49
  const.startup if const.respond_to?(:startup)
50
50
  Log.dev "Loaded contrib: #{const}"
51
51
  rescue NameError
52
- files = Dir["{contrib,#{BASEDIR/:ramaze/:contrib}}/#{name}.{so,bundle,rb}"]
52
+ files = Dir["{contrib,#{BASEDIR}/ramaze/contrib}/#{name}.{so,bundle,rb}"]
53
53
  raise LoadError, "#{mod_name} not found" unless files.any?
54
54
  require(files.first) ? retry : raise
55
55
  end
@@ -136,10 +136,15 @@ module Ramaze
136
136
 
137
137
  def resolve_template(path)
138
138
  path = path.to_s
139
- path_converted = path.split('__').inject{|s,v| s/v}
139
+ path_converted = path.split('__').inject{|s,v| File.join(s, v) }
140
140
  possible_paths = [path, path_converted].compact
141
141
 
142
- paths = template_paths.map{|pa| possible_paths.map{|a| pa/a } }.flatten.uniq
142
+ paths = template_paths.map{|pa|
143
+ possible_paths.map{|a|
144
+ File.join(pa, a)
145
+ }
146
+ }.flatten.uniq
147
+
143
148
  glob = "{#{paths.join(',')}}.{#{extension_order.join(',')}}"
144
149
 
145
150
  Dir[glob].first
@@ -153,7 +158,7 @@ module Ramaze
153
158
  if paths = view_root
154
159
  paths
155
160
  else
156
- view_root(Global.view_root / Global.mapping.invert[self])
161
+ view_root(File.join(Global.view_root, Global.mapping.invert[self]))
157
162
  end
158
163
  end
159
164
 
@@ -71,9 +71,12 @@ module Ramaze
71
71
 
72
72
  def mapping
73
73
  global_mapping = Global.mapping.invert[self]
74
+
74
75
  return global_mapping if global_mapping
76
+
75
77
  if ancestral_trait[:automap] && self.to_s !~ /#<Class:/
76
78
  name = self.to_s.gsub('Controller', '').gsub('::', '/').clone
79
+ return if name.empty?
77
80
  name == 'Main' ? '/' : "/#{name.snake_case}"
78
81
  end
79
82
  end
@@ -59,10 +59,8 @@ module Ramaze
59
59
  end
60
60
 
61
61
  def [](key, *rest)
62
- value = params[key.to_s]
63
- return value if rest.empty?
64
- keys = rest.flatten.map{|k| k.to_s}
65
- Array[value, *params.values_at(*keys)]
62
+ return params[key.to_s] if rest.empty?
63
+ [key, *rest].map{|k| params[k.to_s] }
66
64
  end
67
65
 
68
66
  def to_ivs(*args)
@@ -11,9 +11,9 @@ module Ramaze
11
11
 
12
12
  # The response is passed to each filter by sending .call(response) to it.
13
13
 
14
- FILTER = OrderedSet.new(
14
+ FILTER = OrderedSet[
15
15
  # Ramaze::Tool::Localize,
16
- ) unless defined?(FILTER)
16
+ ] unless defined?(FILTER)
17
17
 
18
18
  class << self
19
19
  include Trinity
@@ -64,7 +64,8 @@ module Ramaze
64
64
  joined = ::File.join(Global.public_root, path)
65
65
 
66
66
  if ::File.directory?(joined)
67
- Dir[joined/"{#{INDICES.join(',')}}"].first || joined
67
+ glob = ::File.join(joined, "{#{INDICES.join(',')}}")
68
+ Dir[glob].first || joined
68
69
  else
69
70
  joined
70
71
  end
@@ -20,7 +20,7 @@ module Ramaze
20
20
  end
21
21
 
22
22
  # requests are passed to every
23
- FILTER = OrderedSet[ Dispatcher::File, Dispatcher::Action, ]
23
+ FILTER = OrderedSet[ Dispatcher::File, Dispatcher::Action ]
24
24
 
25
25
  # Response codes to cache the output of for repeated requests.
26
26
  trait :shielded => [ STATUS_CODE["Not Found"] ]
@@ -148,7 +148,7 @@ module Ramaze
148
148
  diff = max - min
149
149
 
150
150
  tags.uniq.each do |tag|
151
- count = tags.count(tag)
151
+ count = tags.respond_to?(:count) ? tags.count(tag) : tags.select{|t| t==tag }.size
152
152
  result[tag] = ((count / total) * diff) + min
153
153
  end
154
154
 
@@ -4,45 +4,85 @@ require 'md5'
4
4
  module Ramaze
5
5
  module Helper
6
6
  module HttpDigest
7
+
8
+ UUID_GENERATOR = UUID.new
9
+
10
+ SESSION_NONCE = 'httpdigest_authentication_nonce'
11
+ SESSION_OPAQUE = 'httpdigest_authentication_opaque'
12
+
13
+ def httpdigest_logout
14
+ session.delete( SESSION_NONCE )
15
+ session.delete( SESSION_OPAQUE )
16
+ end
17
+
18
+ def httpdigest_headers uid, realm
19
+ session[ SESSION_NONCE ] = UUID_GENERATOR.generate
20
+ session[ SESSION_OPAQUE ][ realm ][ uid ] = UUID_GENERATOR.generate
21
+ response['WWW-Authenticate'] =
22
+ %|Digest realm="#{realm}",| +
23
+ %|qop="auth,auth-int",| +
24
+ %|nonce="#{session[SESSION_NONCE]}",| +
25
+ %|opaque="#{session[SESSION_OPAQUE][realm][uid]}"|
26
+ end
27
+
7
28
  def httpdigest(uid, realm)
8
- session_opaque = "authentication_digest_opaque_#{uid}"
9
- session_nonce = "authentication_digest_nonce"
29
+ session[ SESSION_OPAQUE ] ||= {}
30
+ session[ SESSION_OPAQUE ][ realm ] ||= {}
31
+
32
+ if request.env['HTTP_AUTHORIZATION']
10
33
 
11
- session[session_opaque] ||= UUID.new
34
+ authorized = false
12
35
 
13
- authorized = false
36
+ if session[ SESSION_NONCE ] and session[ SESSION_OPAQUE ][ realm ][ uid ]
14
37
 
15
- if session[session_nonce] and request.env['HTTP_AUTHORIZATION']
38
+ auth_split = request.env['HTTP_AUTHORIZATION'].split
39
+ authentication_type = auth_split[0]
40
+ authorization = Rack::Auth::Digest::Params.parse( auth_split[1..-1].join(' ') )
16
41
 
17
- auth_split = request.env['HTTP_AUTHORIZATION'].split
18
- authentication_type = auth_split[0]
19
- authorization = Rack::Auth::Digest::Params.parse( auth_split[1..-1].join(' ') )
20
- digest_response, username, nonce, nc, cnonce, qop =
21
- authorization.values_at(*%w[response username nonce nc cnonce qop])
42
+ digest_response, username, nonce, nc, cnonce, qop, opaque =
43
+ authorization.values_at(*%w[response username nonce nc cnonce qop opaque])
22
44
 
23
- if authentication_type == 'Digest'
24
- if nonce == session[session_nonce]
25
- ha1 = yield(username)
26
- ha2 = MD5.hexdigest("#{request.request_method}:#{request.fullpath}")
27
- md5 = MD5.hexdigest([ha1, nonce, nc, cnonce, qop, ha2].join(':'))
45
+ if authentication_type == 'Digest'
46
+ if nonce == session[SESSION_NONCE] and opaque == session[SESSION_OPAQUE][realm][uid]
47
+ h1 = nil
48
+ if respond_to?( :httpdigest_lookup_password )
49
+ ha1 = httpdigest_lookup_password( username )
50
+ else
51
+ if respond_to?( :httpdigest_lookup_plaintext_password )
52
+ ha1 = MD5.hexdigest( "#{username}:#{realm}:#{httpdigest_lookup_plaintext_password( username )}" )
53
+ else
54
+ if block_given?
55
+ ha1 = yield( username )
56
+ else
57
+ raise "No password lookup handler found"
58
+ end
59
+ end
60
+ end
61
+ ha2 = MD5.hexdigest([request.request_method,request.fullpath].join(':'))
62
+ md5 = MD5.hexdigest([ha1, nonce, nc, cnonce, qop, ha2].join(':'))
28
63
 
29
- authorized = digest_response == md5
64
+ authorized = digest_response == md5
65
+ end
30
66
  end
67
+
68
+ end
69
+
70
+ unless authorized
71
+ httpdigest_headers( uid, realm )
72
+ respond('Unauthorized', 401)
31
73
  end
32
- end
33
74
 
34
- unless authorized
35
- session[session_nonce] = UUID.new
36
- response['WWW-Authenticate'] =
37
- %|Digest realm="#{realm}",| +
38
- %|qop="auth,auth-int",| +
39
- %|nonce="#{session[session_nonce]}",| +
40
- %|opaque="#{session[session_opaque]}"|
75
+ else
76
+
77
+ httpdigest_headers( uid, realm )
78
+ httpdigest_failure if respond_to?( :httpdigest_failure )
41
79
  respond('Unauthorized', 401)
80
+
42
81
  end
43
82
 
44
83
  authorization["username"]
45
84
  end
85
+
46
86
  end
47
87
  end
48
88
  end
@@ -165,9 +165,8 @@ module Ramaze
165
165
  text = h(text.to_s)
166
166
 
167
167
  params = Ramaze::Request.current.params.merge(@var.to_s => n)
168
- name = Ramaze::Action.stack.first.name
169
- name = '/' if name == 'index' # make nicer...
170
- hash[:href] = Rs(name, params)
168
+ name = Ramaze::Request.current.request_path
169
+ hash[:href] = R(name, params)
171
170
 
172
171
  g.a(hash){ text }
173
172
  end
@@ -69,7 +69,7 @@ module Ramaze
69
69
  else
70
70
  roots = [options[:controller].template_paths].flatten
71
71
 
72
- if (files = Dir["{#{roots.join(',')}}"/"{#{file},#{file}.*}"]).any?
72
+ if (files = Dir[File.join("{#{roots.join(',')}}","{#{file},#{file}.*}")]).any?
73
73
  options[:template] = files.first.squeeze '/'
74
74
  else
75
75
  Log.warn "render_template: #{file} does not exist in the following directories: #{roots.join(',')}."
@@ -8,10 +8,10 @@ module Ramaze
8
8
  #
9
9
  # class MainController < Ramaze::Controller
10
10
  # def index
11
- # if user?
12
- # A('login', :href => Rs(:login))
13
- # else
11
+ # if logged_in?
14
12
  # "Hello #{user.name}"
13
+ # else
14
+ # A('login', :href => Rs(:login))
15
15
  # end
16
16
  # end
17
17
  #
@@ -77,7 +77,7 @@ module Ramaze
77
77
  elsif _model.respond_to?(:authenticate)
78
78
  _model.authenticate(creds)
79
79
  else
80
- Log.warn("Helper::User has no callback and %p doesn't respond to #authenticate" % _model)
80
+ Log.warn("Helper::User has no callback and there is no %p::authenticate" % _model)
81
81
  nil
82
82
  end
83
83
  end
data/lib/ramaze/helper.rb CHANGED
@@ -12,8 +12,9 @@ module Ramaze
12
12
  module Helper
13
13
  LOOKUP = Set.new
14
14
  PATH = ['']
15
+ path = File.expand_path("#{BASEDIR}/../spec/ramaze/helper/")
15
16
  trait :ignore => [
16
- /#{Regexp.escape(File.expand_path(BASEDIR/'../spec/ramaze/helper/'))}\//
17
+ /#{Regexp.escape(path)}\//
17
18
  ]
18
19
 
19
20
  module Methods
@@ -61,7 +62,7 @@ module Ramaze
61
62
  end
62
63
 
63
64
  def require_helper(name)
64
- paths = (PATH + [Global.root, BASEDIR/:ramaze]).join(',')
65
+ paths = (PATH + [Global.root, "#{BASEDIR}/ramaze"]).join(',')
65
66
  glob = "{#{paths}}/helper/#{name}.{so,bundle,rb}"
66
67
  files = Dir[glob]
67
68
  ignore = Helper.trait[:ignore]
@@ -0,0 +1,168 @@
1
+ module Ramaze
2
+
3
+ module Logger
4
+
5
+ # A customized logger (based on Informer) that creates multiple log files based on time
6
+
7
+ class RotatingInformer
8
+
9
+ include Logging
10
+
11
+ attr_accessor :time_format, :log_levels
12
+ attr_reader :base_dir
13
+
14
+ # parameter for Time.now.strftime
15
+ trait :timestamp => "%Y-%m-%d %H:%M:%S"
16
+
17
+ # This is how the final output is arranged.
18
+ trait :format => "[%time] %prefix %text"
19
+
20
+ # Create a new instance of RotatingInformer.
21
+ #
22
+ # base_dir is the directory where all log files will be stored
23
+ #
24
+ # time_format is the time format used to name the log files.
25
+ # Possible formats are identical to those
26
+ # accepted by Time.strftime
27
+ #
28
+ # log_levelse is an array describing what kind of messages
29
+ # that the log receives. The array may contain
30
+ # any or all of the symbols :debug, :error, :info and/or :warn
31
+ #
32
+ # Examples:
33
+ # RotatingInformer.new('logs')
34
+ # #=> Creates logs in directory called logs.
35
+ # The generated filenames will be in the
36
+ # form YYYY-MM-DD.log
37
+ # RotatingInformer.new('logs', '%Y-%m.txt')
38
+ # #=> Creates logs in directory called logs.
39
+ # The generated filenames will be in the
40
+ # form YYYY-MM.txt
41
+ # RotatingInformer.new('logs', '%Y-%m.txt', [:error])
42
+ # #=> Creates logs in directory called logs.
43
+ # The generated filenames will be in the
44
+ # form YYYY-MM.txt. Only errors will be
45
+ # logged to the files.
46
+
47
+ def initialize(base_dir, time_format = '%Y-%m-%d.log', log_levels = [:debug, :error, :info, :warn])
48
+ # Verify and set base directory
49
+ send :base_dir=, base_dir, true
50
+
51
+ @time_format = time_format
52
+ @log_levels = log_levels
53
+
54
+ # Keep track of log shutdown (to prevent StackErrors due to recursion)
55
+ @in_shutdown = false
56
+ end
57
+
58
+ # Set the base directory for log files
59
+ #
60
+ # If this method is called with the raise_exception
61
+ # parameter set to true the method will raise an exception
62
+ # if the specified directory does not exist or is unwritable.
63
+ #
64
+ # If raise_exception is set to false, the method will just
65
+ # silently fail if the specified directory does not exist
66
+ # or is unwritable
67
+
68
+ def base_dir=(directory, raise_exception = false)
69
+ # Expand directory path
70
+ base_dir = File.expand_path(directory)
71
+ # Verify that directory path exists
72
+ if File.exist?(base_dir)
73
+ # Verify that directory path is a directory
74
+ if File.directory?(base_dir)
75
+ # Verify that directory path is writable
76
+ if File.writable?(base_dir)
77
+ @base_dir = base_dir
78
+ else
79
+ raise Exception.new("#{base_dir} is not writable") if raise_exception
80
+ end
81
+ else
82
+ raise Exception.new("#{base_dir} is not a directory") if raise_exception
83
+ end
84
+ else
85
+ raise Exception.new("#{base_dir} does not exist.") if raise_exception
86
+ end
87
+ end
88
+
89
+ # Close the file we log to if it isn't closed already.
90
+
91
+ def shutdown
92
+ if @out.respond_to?(:close)
93
+ unless @in_shutdown
94
+ @in_shutdown = true
95
+ Log.debug("close, #{@out.inspect}")
96
+ @in_shutdown = false
97
+ end
98
+ @out.close
99
+ end
100
+ end
101
+
102
+ # Integration to Logging.
103
+
104
+ def log tag, *messages
105
+
106
+ return unless @log_levels.include?(tag)
107
+
108
+ # Update current log
109
+ update_current_log
110
+
111
+ messages.flatten!
112
+
113
+ prefix = tag.to_s.upcase.ljust(5)
114
+
115
+ messages.each do |message|
116
+ @out.puts(log_interpolate(prefix, message))
117
+ end
118
+
119
+ @out.flush if @out.respond_to?(:flush)
120
+ end
121
+
122
+ # Takes the prefix (tag), text and timestamp and applies it to
123
+ # the :format trait.
124
+
125
+ def log_interpolate prefix, text, time = timestamp
126
+ message = class_trait[:format].dup
127
+
128
+ vars = { '%time' => time, '%prefix' => prefix, '%text' => text }
129
+ vars.each{|from, to| message.gsub!(from, to) }
130
+
131
+ message
132
+ end
133
+
134
+ # This uses Global.inform_timestamp or a date in the format of
135
+ # %Y-%m-%d %H:%M:%S
136
+ # # => "2007-01-19 21:09:32"
137
+
138
+ def timestamp
139
+ mask = class_trait[:timestamp]
140
+ Time.now.strftime(mask || "%Y-%m-%d %H:%M:%S")
141
+ end
142
+
143
+ # is @out closed?
144
+
145
+ def closed?
146
+ @out.respond_to?(:closed?) && @out.closed?
147
+ end
148
+
149
+ private
150
+
151
+ # Checks whether current filename is still valid.
152
+ # If not, update the current log to point at the new
153
+ # filename
154
+
155
+ def update_current_log
156
+ out = File.join(@base_dir, Time.now.strftime(@time_format))
157
+ if @out.nil? || @out.path != out
158
+ # Close old log if necessary
159
+ shutdown unless @out.nil? || closed?
160
+
161
+ # Start new log
162
+ @out = File.open(out, 'ab+')
163
+ end
164
+ end
165
+ end
166
+
167
+ end
168
+ end
@@ -78,7 +78,7 @@ module Ramaze
78
78
  # currently set one.
79
79
  def public_root
80
80
  [ @public_root,
81
- root/@public_root
81
+ File.join(root, @public_root)
82
82
  ].find{|path| File.directory?(path) } || @public_root
83
83
  end
84
84
 
@@ -90,8 +90,8 @@ module Ramaze
90
90
  # the currently set one.
91
91
  def view_root
92
92
  [ @view_root,
93
- root/@view_root,
94
- root/'template',
93
+ File.join(root, @view_root),
94
+ File.join(root, 'template'),
95
95
  ].find{|path| File.directory?(path) } || @view_root
96
96
  end
97
97