manveru-ramaze 2008.12 → 2009.01

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.
@@ -0,0 +1,24 @@
1
+ # General Apache options
2
+ Options +FollowSymLinks +ExecCGI
3
+ AddHandler cgi-script cgi rb
4
+ <IfModule mod_fastcgi.c>
5
+ AddHandler fastcgi-script fcgi
6
+ </IfModule>
7
+ <IfModule mod_fcgid.c>
8
+ AddHandler fcgid-script fcgi
9
+ </IfModule>
10
+
11
+ # Redirect all requests not available on the filesystem to Ramaze.
12
+
13
+ RewriteEngine On
14
+ RewriteCond %{REQUEST_FILENAME} !-f
15
+ RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
16
+
17
+ # In case Ramaze experiences terminal errors.
18
+ # Instead of displaying this message you can supply a
19
+ # file here which will be rendered instead.
20
+ #
21
+ # Example:
22
+ # ErrorDocument 500 /500.html
23
+
24
+ ErrorDocument 500 "<h2>Application error</h2>Ramaze failed to start properly"
@@ -49,8 +49,8 @@ module Ramaze
49
49
  # true.
50
50
 
51
51
  def cached_render
52
- if Global.file_cache
53
- cached_render_file
52
+ if cache_root = Global.file_cache
53
+ cached_render_file(cache_root)
54
54
  else
55
55
  cached_render_memory
56
56
  end
@@ -59,12 +59,13 @@ module Ramaze
59
59
  # Uses files in the Global.public_root to provide a static ressource on
60
60
  # next request and returns the rendered action
61
61
 
62
- def cached_render_file
62
+ def cached_render_file(cache_root)
63
63
  rendered = uncached_render
64
64
 
65
- global_epath = Global.public_root/self.controller.mapping/extended_path
65
+ cr = cache_root.respond_to?(:to_str) ? cache_root.to_str : Global.public_root
66
+ global_epath = File.join(cr, self.controller.mapping, extended_path)
66
67
  FileUtils.mkdir_p(File.dirname(global_epath))
67
- File.open(global_epath, 'w+') {|fp| fp.print(rendered) }
68
+ File.open(global_epath, 'w+'){|fp| fp.print(rendered) }
68
69
 
69
70
  rendered
70
71
  end
@@ -16,7 +16,7 @@ module Ramaze
16
16
  # instead, in either case with path as argument.
17
17
 
18
18
  def resolve(path, routed = false)
19
- @routed = routed
19
+ Thread.current[:routed] = routed
20
20
 
21
21
  FILTER.each do |filter|
22
22
  answer = if filter.respond_to?(:call)
@@ -90,7 +90,7 @@ module Ramaze
90
90
  end
91
91
  end
92
92
 
93
- if !@routed and new_path = Route.resolve(path)
93
+ if !Thread.current[:routed] and new_path = Route.resolve(path)
94
94
  Log.dev("Routing from `#{path}' to `#{new_path}'")
95
95
  return resolve(new_path, true)
96
96
  end
@@ -196,9 +196,9 @@ module Ramaze
196
196
  # Example:
197
197
  # request.params
198
198
  # # => {'name' => 'jason', 'age' => '45', 'job' => 'lumberjack'}
199
- # request.sub('name')
199
+ # request.subset('name')
200
200
  # # => {'name' => 'jason'}
201
- # request.sub(:name, :job)
201
+ # request.subset(:name, :job)
202
202
  # # => {'name' => 'jason', 'job' => 'lumberjack'}
203
203
 
204
204
  def subset(*keys)
@@ -0,0 +1,43 @@
1
+ require 'benchmark'
2
+
3
+ module Ramaze
4
+ module Helper
5
+
6
+ # Little helper to give you a hand when benching parts of actions
7
+
8
+ module Bench
9
+
10
+ # Will first run an empty loop to determine the overhead it imposes, then
11
+ # goes on to yield your block +iterations+ times.
12
+ #
13
+ # The last yielded return value will be returned upon completion of the
14
+ # benchmark and the result of the benchmark itself will be sent to
15
+ # Log.info
16
+ #
17
+ # Example:
18
+ #
19
+ # class MainController < Ramaze::Controller
20
+ # def index
21
+ # @users = bench{ User.all }
22
+ # @tags = bench{ Article.tags }
23
+ # end
24
+ # end
25
+ #
26
+ # This will show something like following in your log:
27
+ # [..] INFO Bench ./start.rb:3:in `index': 0.121163845062256
28
+ # [..] INFO Bench ./start.rb:4:in `index': 2.234987235098341
29
+ #
30
+ # So now we know that the Article.tags call takes the most time and
31
+ # should be improved.
32
+
33
+ def bench(iterations = 1)
34
+ result = nil
35
+ from = caller[0]
36
+ delta = Benchmark.realtime{ iterations.times{ nil }}
37
+ taken = Benchmark.realtime{ iterations.times{ result = yield }}
38
+ Log.info "Bench #{from}: #{taken - delta}"
39
+ return result
40
+ end
41
+ end
42
+ end
43
+ end
@@ -15,7 +15,7 @@ module Ramaze
15
15
  def markaby(ivs = {}, helpers = nil, &block)
16
16
  builder = ::Markaby::Builder
17
17
  builder.extend(Ramaze::Helper::Methods)
18
- builder.send(:helper, :link)
18
+ builder.send(:helper, :redirect, :link, :sendfile, :flash, :cgi, :partial)
19
19
 
20
20
  iv_hash = {}
21
21
  instance_variables.each do |iv|
@@ -165,7 +165,7 @@ 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::Request.current.request_path
168
+ name = Ramaze::Request.current.path_info
169
169
  hash[:href] = R(name, params)
170
170
 
171
171
  g.a(hash){ text }
data/lib/ramaze/option.rb CHANGED
@@ -78,7 +78,7 @@ module Ramaze
78
78
  o "Turn on customized error pages. Use Rack::ShowException otherwise.",
79
79
  :error_page, true, :cli => true
80
80
 
81
- o "Caching actions to the filesystem in Global.public_root",
81
+ o "Cache actions to filesystem, uses String as directory name or Global.public_root if other truism",
82
82
  :file_cache, false, :cli => false
83
83
 
84
84
  o "Specify what IP Ramaze will respond to - 0.0.0.0 for all",
@@ -1,57 +1,62 @@
1
1
  module Ramaze
2
2
  class Reloader
3
+ # TODO:
4
+ # * There seems to be a problem somewhere that I couldn't identify yet, a
5
+ # file has to be modified twice initially to make it show up as
6
+ # modified here, subsequent changes work just fine.
7
+ # The only workaround I could find right now would be to read/write
8
+ # every single file, but that would be unexpected, irresponsible, and
9
+ # error-prone.
10
+ #
11
+ # NOTE:
12
+ # * I have changed from using a Mutex to using a Queue, which uses a
13
+ # Mutex internally.
14
+
3
15
  class WatchInotify
4
16
  POLL_INTERVAL = 2 # seconds
17
+ NOTIFY_MASK = RInotify::MODIFY | RInotify::IN_ONESHOT
5
18
 
6
19
  def initialize
7
20
  @watcher = RInotify.new
8
- @changed = []
9
- @mutex = Mutex.new
21
+ @changed = Queue.new
10
22
  @watcher_thread = start_watcher
11
23
  end
12
24
 
13
25
  def call(cooldown)
14
- yield if @changed.any?
26
+ yield
15
27
  end
16
28
 
17
29
  # TODO: define a finalizer to cleanup? -- reloader never calls #close
18
30
 
19
31
  def start_watcher
20
- Thread.new do
21
- loop do
22
- watcher_cycle
23
- sleep POLL_INTERVAL
24
- end
25
- end
32
+ Thread.new{ loop{ watcher_cycle }}
26
33
  end
27
34
 
35
+ # Not much work here, we just have to empty the event queue and push the
36
+ # descriptors for reloading on next request.
28
37
  def watcher_cycle
29
- return unless @watcher.wait_for_events(0)
30
- changed_descriptors = []
38
+ return unless @watcher.wait_for_events(POLL_INTERVAL)
31
39
 
32
40
  @watcher.each_event do |event|
33
- changed_descriptors << event.watch_descriptor
34
- end
35
-
36
- @mutex.synchronize do
37
- changed_descriptors.each do |descriptor|
38
- @changed << @watcher.watch_descriptors[descriptor]
39
- end
41
+ @changed.push(event.watch_descriptor)
40
42
  end
41
43
  end
42
44
 
43
45
  def watch(file)
44
- return false if @watcher.watch_descriptors.has_value?(file)
45
- return false unless File.exist?(file)
46
+ return if @watcher.watch_descriptors.has_value?(file)
47
+ return unless File.exist?(file)
46
48
 
47
- @mutex.synchronize{ @watcher.add_watch(file, RInotify::MODIFY) }
48
-
49
- true
49
+ @watcher.add_watch(file, NOTIFY_MASK)
50
+ rescue Errno::ENOENT
51
+ retry
50
52
  end
51
53
 
54
+ # FIXME:
55
+ # Seems like this won't work due to some bug in the rinotify library.
56
+ # Would be cool if someone could make a FFI version.
57
+
52
58
  def remove_watch(file)
53
- @mutex.synchronize{ @watcher.rm_watch(file) }
54
- true
59
+ @watcher.rm_watch(file)
55
60
  end
56
61
 
57
62
  def close
@@ -60,13 +65,20 @@ module Ramaze
60
65
  true
61
66
  end
62
67
 
68
+ # NOTE:
69
+ # We have to add the changed file again after we got a notification, I
70
+ # have no idea why, but using IN_ONESHOT should make sure that there is
71
+ # no memory leak in the C level even if we add a file again.
72
+ # There is a memory leak however in the watch_descriptors hash, since
73
+ # rinotify won't synchronize the contents properly and will only add to
74
+ # the hash, so we have to clean up ourselves.
63
75
  def changed_files
64
- @mutex.synchronize do
65
- @tmp = @changed
66
- @changed = []
76
+ until @changed.empty?
77
+ descriptor = @changed.shift
78
+ file = @watcher.watch_descriptors.delete(descriptor)
79
+ watch(file)
80
+ yield(file)
67
81
  end
68
- @tmp.uniq!
69
- @tmp
70
82
  end
71
83
  end
72
84
  end
@@ -38,18 +38,14 @@ module Ramaze
38
38
 
39
39
  # return files changed since last call
40
40
  def changed_files
41
- changed = []
42
-
43
41
  @files.each do |file, stat|
44
42
  if new_stat = safe_stat(file)
45
43
  if new_stat.mtime > stat.mtime
46
- changed << file
47
44
  @files[file] = new_stat
45
+ yield(file)
48
46
  end
49
47
  end
50
48
  end
51
-
52
- changed
53
49
  end
54
50
 
55
51
  def safe_stat(file)
@@ -88,7 +88,7 @@ module Ramaze
88
88
  before_cycle
89
89
 
90
90
  rotation{|file| @watcher.watch(file) }
91
- @watcher.changed_files.each{|f| safe_load(f) }
91
+ @watcher.changed_files{|f| safe_load(f) }
92
92
 
93
93
  after_cycle
94
94
  end
@@ -2,5 +2,5 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
- VERSION = "2008.10"
5
+ VERSION = "2009.01"
6
6
  end