Pistos-ramaze 2008.09 → 2008.12
Sign up to get free protection for your applications and to get access to all the features.
- data/benchmark/run.rb +1 -1
- data/examples/app/blog/spec/blog.rb +2 -2
- data/examples/app/rapaste/spec/rapaste.rb +1 -1
- data/examples/app/rapaste/start.rb +2 -2
- data/examples/app/rapaste/view/view.xhtml +3 -0
- data/examples/app/todolist/spec/todolist.rb +1 -1
- data/examples/app/whywiki/spec/whywiki.rb +1 -1
- data/examples/app/wikore/spec/wikore.rb +1 -1
- data/examples/app/wikore/src/model.rb +1 -1
- data/examples/app/wiktacular/spec/wiktacular.rb +1 -1
- data/examples/app/wiktacular/src/model.rb +1 -1
- data/examples/basic/partial.rb +28 -0
- data/examples/helpers/httpdigest.rb +68 -10
- data/examples/misc/ramaise.rb +2 -2
- data/examples/templates/template_amrita2.rb +1 -1
- data/examples/templates/template_erubis.rb +1 -1
- data/examples/templates/template_ezamar.rb +1 -1
- data/examples/templates/template_haml.rb +2 -2
- data/examples/templates/template_liquid.rb +1 -1
- data/examples/templates/template_markaby.rb +2 -2
- data/examples/templates/template_nagoro.rb +1 -1
- data/examples/templates/template_redcloth.rb +1 -1
- data/examples/templates/template_remarkably.rb +2 -2
- data/examples/templates/template_tenjin.rb +1 -1
- data/examples/templates/template_xslt.rb +1 -1
- data/lib/proto/controller/init.rb +2 -1
- data/lib/proto/model/init.rb +3 -3
- data/lib/proto/public/dispatch.fcgi +2 -2
- data/lib/proto/spec/main.rb +3 -3
- data/lib/proto/start.rb +4 -0
- data/lib/ramaze/action/render.rb +6 -5
- data/lib/ramaze/action.rb +7 -1
- data/lib/ramaze/cache/file.rb +71 -0
- data/lib/ramaze/cache.rb +1 -0
- data/lib/ramaze/contrib/email.rb +2 -0
- data/lib/ramaze/contrib/facebook.rb +2 -2
- data/lib/ramaze/contrib/file_cache.rb +2 -64
- data/lib/ramaze/contrib/sequel/image.rb +1 -1
- data/lib/ramaze/contrib.rb +1 -1
- data/lib/ramaze/controller/resolve.rb +8 -3
- data/lib/ramaze/controller.rb +9 -1
- data/lib/ramaze/current/request.rb +85 -68
- data/lib/ramaze/current/session/hash.rb +7 -11
- data/lib/ramaze/current/session.rb +3 -5
- data/lib/ramaze/dispatcher/action.rb +2 -0
- data/lib/ramaze/dispatcher/file.rb +6 -1
- data/lib/ramaze/helper/aspect.rb +2 -2
- data/lib/ramaze/helper/form.rb +5 -2
- data/lib/ramaze/helper/formatting.rb +4 -0
- data/lib/ramaze/helper/gravatar.rb +18 -1
- data/lib/ramaze/helper/httpdigest.rb +57 -28
- data/lib/ramaze/helper/maruku.rb +2 -0
- data/lib/ramaze/helper/paginate.rb +2 -3
- data/lib/ramaze/helper/partial.rb +1 -1
- data/lib/ramaze/helper/redirect.rb +22 -4
- data/lib/ramaze/helper/user.rb +4 -4
- data/lib/ramaze/helper.rb +12 -4
- data/lib/ramaze/log/rotatinginformer.rb +168 -0
- data/lib/ramaze/option/holder.rb +3 -3
- data/lib/ramaze/option.rb +1 -1
- data/lib/ramaze/reloader/watch_inotify.rb +85 -0
- data/lib/ramaze/reloader/watch_stat.rb +58 -0
- data/lib/ramaze/reloader.rb +25 -41
- data/lib/ramaze/snippets/divide.rb +2 -0
- data/lib/ramaze/snippets/numeric/time.rb +1 -1
- data/lib/ramaze/snippets/object/__dir__.rb +3 -3
- data/lib/ramaze/snippets/object/acquire.rb +3 -6
- data/lib/ramaze/snippets/ramaze/acquire.rb +31 -0
- data/lib/ramaze/snippets/ramaze/deprecated.rb +2 -1
- data/lib/ramaze/spec/helper/mock_http.rb +6 -5
- data/lib/ramaze/template/ezamar/render_partial.rb +8 -0
- data/lib/ramaze/tool/mime.rb +1 -1
- data/lib/ramaze/tool/project_creator.rb +2 -1
- data/lib/ramaze/version.rb +1 -1
- data/lib/ramaze.rb +6 -0
- data/rake_tasks/coverage.rake +4 -5
- data/rake_tasks/spec.rake +6 -6
- data/ramaze.gemspec +769 -756
- data/spec/contrib/profiling.rb +2 -2
- data/spec/ramaze/action/file_cache.rb +1 -1
- data/spec/ramaze/action/layout.rb +1 -1
- data/spec/ramaze/controller/actionless_templates.rb +1 -1
- data/spec/ramaze/controller/resolve.rb +1 -1
- data/spec/ramaze/controller/template_resolving.rb +1 -1
- data/spec/ramaze/dispatcher/directory.rb +3 -3
- data/spec/ramaze/helper/aspect.rb +1 -1
- data/spec/ramaze/helper/partial.rb +1 -1
- data/spec/ramaze/localize.rb +1 -1
- data/spec/ramaze/rewrite.rb +1 -1
- data/spec/ramaze/template/amrita2.rb +1 -1
- data/spec/ramaze/template/erubis.rb +1 -1
- data/spec/ramaze/template/ezamar.rb +1 -1
- data/spec/ramaze/template/haml.rb +2 -2
- data/spec/ramaze/template/nagoro.rb +1 -1
- data/spec/ramaze/template/redcloth.rb +1 -1
- data/spec/ramaze/template/sass.rb +1 -1
- data/spec/ramaze/template/tenjin.rb +1 -1
- data/spec/ramaze/template.rb +3 -3
- data/spec/snippets/object/__dir__.rb +6 -0
- data/spec/snippets/{object → ramaze}/acquire.rb +24 -18
- metadata +15 -12
- data/lib/ramaze/contrib/auto_params/get_args.rb +0 -58
- data/lib/ramaze/contrib/auto_params.rb +0 -135
- data/spec/contrib/auto_params.rb +0 -121
- data/spec/snippets/divide.rb +0 -19
@@ -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(',')}}"
|
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(',')}."
|
@@ -59,7 +59,7 @@ module Ramaze
|
|
59
59
|
def raw_redirect(target, opts = {})
|
60
60
|
target = target.to_s
|
61
61
|
header = {'Location' => target}
|
62
|
-
status = opts[:status] ||
|
62
|
+
status = opts[:status] || 302 # Found
|
63
63
|
body = %{You are being redirected, please follow <a href="#{target}">this link to: #{target}</a>!}
|
64
64
|
|
65
65
|
Log.info("Redirect to '#{target}'")
|
@@ -72,10 +72,28 @@ module Ramaze
|
|
72
72
|
request[:redirected]
|
73
73
|
end
|
74
74
|
|
75
|
-
#
|
75
|
+
# Redirect to the location the browser says it's coming from.
|
76
|
+
# If the current address is the same as the referrer or no referrer exists
|
77
|
+
# yet, we will redirect to +fallback+.
|
78
|
+
#
|
79
|
+
# NOTE:
|
80
|
+
# * In some cases this may result in a double redirect, given that the
|
81
|
+
# request query parameters may change order. We don't have a nice way
|
82
|
+
# of handling that yet, but it should be very, very rare
|
83
|
+
|
84
|
+
def redirect_referer(fallback = R(:/))
|
85
|
+
if referer = request.referer and url = request.url
|
86
|
+
referer_uri = URI(referer)
|
87
|
+
request_uri = URI(url)
|
76
88
|
|
77
|
-
|
78
|
-
|
89
|
+
if referer_uri == request_uri
|
90
|
+
redirect fallback
|
91
|
+
else
|
92
|
+
redirect referer
|
93
|
+
end
|
94
|
+
else
|
95
|
+
redirect fallback
|
96
|
+
end
|
79
97
|
end
|
80
98
|
alias redirect_referrer redirect_referer
|
81
99
|
end
|
data/lib/ramaze/helper/user.rb
CHANGED
@@ -8,10 +8,10 @@ module Ramaze
|
|
8
8
|
#
|
9
9
|
# class MainController < Ramaze::Controller
|
10
10
|
# def index
|
11
|
-
# if
|
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
|
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(
|
17
|
+
/#{Regexp.escape(path)}\//
|
17
18
|
]
|
18
19
|
|
19
20
|
module Methods
|
@@ -44,7 +45,7 @@ module Ramaze
|
|
44
45
|
if require_helper(name)
|
45
46
|
redo
|
46
47
|
else
|
47
|
-
raise LoadError, "#{name} not found"
|
48
|
+
raise LoadError, "helper #{name} not found"
|
48
49
|
end
|
49
50
|
end
|
50
51
|
end
|
@@ -52,6 +53,8 @@ module Ramaze
|
|
52
53
|
|
53
54
|
private
|
54
55
|
|
56
|
+
# returns the Ramaze::Helper::Name Module Constant if exists.
|
57
|
+
|
55
58
|
def find_helper(name)
|
56
59
|
name = name.to_s.camel_case
|
57
60
|
ramaze_helper_consts = ::Ramaze::Helper.constants.grep(/^#{name}$/i)
|
@@ -60,16 +63,21 @@ module Ramaze
|
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
66
|
+
# Loads helper from /lib/ramaze/helper/name.(so, bundle, rb)
|
67
|
+
# raises LoadError if helper not found.
|
68
|
+
|
63
69
|
def require_helper(name)
|
64
|
-
paths = (PATH + [Global.root, BASEDIR
|
70
|
+
paths = (PATH + [Global.root, "#{BASEDIR}/ramaze"]).join(',')
|
65
71
|
glob = "{#{paths}}/helper/#{name}.{so,bundle,rb}"
|
66
72
|
files = Dir[glob]
|
67
73
|
ignore = Helper.trait[:ignore]
|
68
74
|
files.reject!{|f| ignore.any?{|i| f =~ i }}
|
69
|
-
raise LoadError, "#{name} not found" unless file = files.first
|
75
|
+
raise LoadError, "file for #{name} not found" unless file = files.first
|
70
76
|
require(file)
|
71
77
|
end
|
72
78
|
|
79
|
+
# injects the helper via include and extend, takes Constant as argument.
|
80
|
+
|
73
81
|
def use_helper(mod)
|
74
82
|
include mod
|
75
83
|
extend mod
|
@@ -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
|
data/lib/ramaze/option/holder.rb
CHANGED
@@ -78,7 +78,7 @@ module Ramaze
|
|
78
78
|
# currently set one.
|
79
79
|
def public_root
|
80
80
|
[ @public_root,
|
81
|
-
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
|
94
|
-
root
|
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
|
|
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 "
|
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",
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Ramaze
|
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
|
+
|
15
|
+
class WatchInotify
|
16
|
+
POLL_INTERVAL = 2 # seconds
|
17
|
+
NOTIFY_MASK = RInotify::MODIFY | RInotify::IN_ONESHOT
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@watcher = RInotify.new
|
21
|
+
@changed = Queue.new
|
22
|
+
@watcher_thread = start_watcher
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(cooldown)
|
26
|
+
yield
|
27
|
+
end
|
28
|
+
|
29
|
+
# TODO: define a finalizer to cleanup? -- reloader never calls #close
|
30
|
+
|
31
|
+
def start_watcher
|
32
|
+
Thread.new{ loop{ watcher_cycle }}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Not much work here, we just have to empty the event queue and push the
|
36
|
+
# descriptors for reloading on next request.
|
37
|
+
def watcher_cycle
|
38
|
+
return unless @watcher.wait_for_events(POLL_INTERVAL)
|
39
|
+
|
40
|
+
@watcher.each_event do |event|
|
41
|
+
@changed.push(event.watch_descriptor)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def watch(file)
|
46
|
+
return if @watcher.watch_descriptors.has_value?(file)
|
47
|
+
return unless File.exist?(file)
|
48
|
+
|
49
|
+
@watcher.add_watch(file, NOTIFY_MASK)
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
retry
|
52
|
+
end
|
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
|
+
|
58
|
+
def remove_watch(file)
|
59
|
+
@watcher.rm_watch(file)
|
60
|
+
end
|
61
|
+
|
62
|
+
def close
|
63
|
+
@watcher_thread.terminate
|
64
|
+
@watcher.close
|
65
|
+
true
|
66
|
+
end
|
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.
|
75
|
+
def changed_files
|
76
|
+
until @changed.empty?
|
77
|
+
descriptor = @changed.shift
|
78
|
+
file = @watcher.watch_descriptors.delete(descriptor)
|
79
|
+
watch(file)
|
80
|
+
yield(file)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Ramaze
|
2
|
+
class Reloader
|
3
|
+
class WatchStat
|
4
|
+
def initialize
|
5
|
+
# @files[file_path] = stat
|
6
|
+
@files = {}
|
7
|
+
@last = Time.now
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(cooldown)
|
11
|
+
if cooldown and Time.now > @last + cooldown
|
12
|
+
yield
|
13
|
+
@last = Time.now
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# start watching a file for changes
|
18
|
+
# true if succeeded, false if failure
|
19
|
+
def watch(file)
|
20
|
+
return true if watching?(file) # if already watching
|
21
|
+
if stat = safe_stat(file)
|
22
|
+
@files[file] = stat
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def watching?(file)
|
27
|
+
@files.has_key?(file)
|
28
|
+
end
|
29
|
+
|
30
|
+
# stop watching a file for changes
|
31
|
+
def remove_watch(file)
|
32
|
+
@files.delete(file)
|
33
|
+
end
|
34
|
+
|
35
|
+
# no need for cleanup
|
36
|
+
def close
|
37
|
+
end
|
38
|
+
|
39
|
+
# return files changed since last call
|
40
|
+
def changed_files
|
41
|
+
@files.each do |file, stat|
|
42
|
+
if new_stat = safe_stat(file)
|
43
|
+
if new_stat.mtime > stat.mtime
|
44
|
+
@files[file] = new_stat
|
45
|
+
yield(file)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def safe_stat(file)
|
52
|
+
File.stat(file)
|
53
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/ramaze/reloader.rb
CHANGED
@@ -11,9 +11,7 @@ module Ramaze
|
|
11
11
|
# Reloader::Hooks module or include your own module to override the hooks.
|
12
12
|
# You also might have to set the Log constant.
|
13
13
|
#
|
14
|
-
#
|
15
|
-
# any file will only be checked once and there will only be made one system
|
16
|
-
# call stat(2).
|
14
|
+
# Currently, it uses RInotify if available and falls back to using File.stat.
|
17
15
|
#
|
18
16
|
# Please note that this will not reload files in the background, it does so
|
19
17
|
# only when actively called
|
@@ -47,11 +45,21 @@ module Ramaze
|
|
47
45
|
:control => nil, # lambda{ cycle },
|
48
46
|
}
|
49
47
|
|
48
|
+
begin
|
49
|
+
gem 'RInotify', '>=0.9' # is older version ok?
|
50
|
+
require 'rinotify'
|
51
|
+
require 'ramaze/reloader/watch_inotify'
|
52
|
+
Watcher = WatchInotify
|
53
|
+
rescue LoadError
|
54
|
+
# stat always available
|
55
|
+
require 'ramaze/reloader/watch_stat'
|
56
|
+
Watcher = WatchStat
|
57
|
+
end
|
58
|
+
|
50
59
|
def initialize(app)
|
51
60
|
@app = app
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@cache = {}
|
61
|
+
@files = {}
|
62
|
+
@watcher = Watcher.new
|
55
63
|
options_reload
|
56
64
|
end
|
57
65
|
|
@@ -63,7 +71,7 @@ module Ramaze
|
|
63
71
|
def call(env)
|
64
72
|
options_reload
|
65
73
|
|
66
|
-
|
74
|
+
@watcher.call(@cooldown) do
|
67
75
|
if @control
|
68
76
|
instance_eval(&@control)
|
69
77
|
elsif @thread
|
@@ -71,8 +79,6 @@ module Ramaze
|
|
71
79
|
else
|
72
80
|
cycle
|
73
81
|
end
|
74
|
-
|
75
|
-
@last = Time.now
|
76
82
|
end
|
77
83
|
|
78
84
|
@app.call(env)
|
@@ -81,16 +87,8 @@ module Ramaze
|
|
81
87
|
def cycle
|
82
88
|
before_cycle
|
83
89
|
|
84
|
-
rotation
|
85
|
-
|
86
|
-
if mtime > (@mtimes[file] ||= mtime)
|
87
|
-
safe_load(file)
|
88
|
-
@mtimes[file] = mtime
|
89
|
-
end
|
90
|
-
else
|
91
|
-
@cache.delete(file)
|
92
|
-
end
|
93
|
-
end
|
90
|
+
rotation{|file| @watcher.watch(file) }
|
91
|
+
@watcher.changed_files{|f| safe_load(f) }
|
94
92
|
|
95
93
|
after_cycle
|
96
94
|
end
|
@@ -111,37 +109,23 @@ module Ramaze
|
|
111
109
|
|
112
110
|
files.each do |file|
|
113
111
|
next if file =~ @ignore
|
114
|
-
path
|
115
|
-
|
116
|
-
|
117
|
-
@cache[file] = path
|
118
|
-
yield(path, stat)
|
119
|
-
else
|
120
|
-
# Quite harmless, we just couldn't figure out path for #{file}
|
112
|
+
if not @files.has_key?(file) and path = figure_path(file, paths)
|
113
|
+
@files[file] = path
|
114
|
+
yield path
|
121
115
|
end
|
122
116
|
end
|
123
117
|
end
|
124
118
|
|
125
119
|
def figure_path(file, paths)
|
126
|
-
if
|
127
|
-
|
128
|
-
return cached, stat if stat.file?
|
129
|
-
elsif Pathname.new(file).absolute?
|
130
|
-
stat = File.stat(file)
|
131
|
-
return file, stat if stat.file? # do directories really end up in $" ?
|
120
|
+
if Pathname.new(file).absolute?
|
121
|
+
return File.exist?(file) ? file : nil
|
132
122
|
end
|
133
123
|
|
134
124
|
paths.each do |possible_path|
|
135
|
-
|
136
|
-
|
137
|
-
begin
|
138
|
-
stat = File.stat(path)
|
139
|
-
return path, stat if stat.file?
|
140
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
141
|
-
end
|
125
|
+
full_path = File.join(possible_path, file)
|
126
|
+
return full_path if File.exist?(full_path)
|
142
127
|
end
|
143
|
-
|
144
|
-
return nil
|
128
|
+
nil
|
145
129
|
end
|
146
130
|
|
147
131
|
|
@@ -6,6 +6,7 @@ class String
|
|
6
6
|
# Usage:
|
7
7
|
# 'a' / 'b' # => 'a/b'
|
8
8
|
def / obj
|
9
|
+
Ramaze.deprecated('String#/', 'File::join')
|
9
10
|
File.join(self, obj.to_s)
|
10
11
|
end
|
11
12
|
end
|
@@ -15,6 +16,7 @@ class Symbol
|
|
15
16
|
# Usage:
|
16
17
|
# :dir/:file # => 'dir/file'
|
17
18
|
def / obj
|
19
|
+
Ramaze.deprecated('Symbol#/', 'File::join(sym.to_s)')
|
18
20
|
self.to_s / obj
|
19
21
|
end
|
20
22
|
end
|
@@ -16,11 +16,11 @@ module Ramaze
|
|
16
16
|
# This method is convenience for the
|
17
17
|
# File.expand_path(File.dirname(__FILE__))
|
18
18
|
# idiom.
|
19
|
-
#
|
20
19
|
|
21
|
-
def __DIR__()
|
20
|
+
def __DIR__(*args)
|
22
21
|
filename = caller[0][/^(.*):/, 1]
|
23
|
-
File.expand_path(File.dirname(filename))
|
22
|
+
dir = File.expand_path(File.dirname(filename))
|
23
|
+
::File.expand_path(::File.join(dir, *args.map{|a| a.to_s}))
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -27,12 +27,9 @@ module Ramaze
|
|
27
27
|
# # require 'src/foo.rb' and 'src/bar.so' and 'src/foobar/baz.rb'
|
28
28
|
# acquire 'src/*', 'src/foobar/*'
|
29
29
|
|
30
|
-
def acquire
|
31
|
-
|
32
|
-
|
33
|
-
require file if file =~ /\.(rb|so)$/
|
34
|
-
end
|
35
|
-
end
|
30
|
+
def acquire(*globs)
|
31
|
+
Ramaze.deprecated('Object#acquire', 'Ramaze::acquire')
|
32
|
+
Ramaze.acquire(*globs)
|
36
33
|
end
|
37
34
|
end
|
38
35
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
3
|
+
|
4
|
+
module Ramaze
|
5
|
+
# Require all .rb and .so files on the given globs, utilizes Dir::[].
|
6
|
+
#
|
7
|
+
# Examples:
|
8
|
+
# # Given following directory structure:
|
9
|
+
# # src/foo.rb
|
10
|
+
# # src/bar.so
|
11
|
+
# # src/foo.yaml
|
12
|
+
# # src/foobar/baz.rb
|
13
|
+
# # src/foobar/README
|
14
|
+
#
|
15
|
+
# # requires all files in 'src':
|
16
|
+
# Ramaze.acquire 'src/*'
|
17
|
+
#
|
18
|
+
# # requires all files in 'src' recursive:
|
19
|
+
# Ramaze.acquire 'src/**/*'
|
20
|
+
#
|
21
|
+
# # require 'src/foo.rb' and 'src/bar.so' and 'src/foobar/baz.rb'
|
22
|
+
# Ramaze.acquire 'src/*', 'src/foobar/*'
|
23
|
+
|
24
|
+
def self.acquire(*globs)
|
25
|
+
globs.flatten.each do |glob|
|
26
|
+
Dir[glob].each do |file|
|
27
|
+
require file if file =~ /\.(rb|so)$/
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -6,7 +6,8 @@ module Ramaze
|
|
6
6
|
def self.deprecated(from, to = nil)
|
7
7
|
message = "%s is deprecated"
|
8
8
|
message << ", use %s instead" unless to.nil?
|
9
|
-
|
9
|
+
message << " - from: %p"
|
10
|
+
Log.warn(message % [from, to, caller[1]])
|
10
11
|
end
|
11
12
|
|
12
13
|
def self.const_missing(name)
|