manveru-ramaze 2008.09 → 2008.10

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 (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