manveru-ramaze 2008.10 → 2008.12
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.
- 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/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/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/public/dispatch.fcgi +2 -2
- data/lib/proto/spec/main.rb +3 -3
- 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/controller.rb +6 -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 +4 -0
- 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/maruku.rb +2 -0
- data/lib/ramaze/helper/redirect.rb +22 -4
- data/lib/ramaze/helper.rb +9 -2
- data/lib/ramaze/reloader/watch_inotify.rb +73 -0
- data/lib/ramaze/reloader/watch_stat.rb +62 -0
- data/lib/ramaze/reloader.rb +25 -41
- data/lib/ramaze/snippets/object/__dir__.rb +3 -3
- data/lib/ramaze/snippets/ramaze/acquire.rb +31 -0
- data/lib/ramaze/spec/helper/mock_http.rb +6 -5
- data/lib/ramaze/template/ezamar/render_partial.rb +8 -0
- data/lib/ramaze.rb +4 -0
- data/ramaze.gemspec +757 -756
- data/spec/contrib/profiling.rb +1 -1
- 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/ramaze/acquire.rb +77 -0
- metadata +8 -8
@@ -28,10 +28,14 @@ module Ramaze
|
|
28
28
|
super
|
29
29
|
end
|
30
30
|
|
31
|
+
# the full request URI provided by Rack::Request e.g. http://localhost:7000/controller/action?foo=bar.xhtml
|
32
|
+
|
31
33
|
def request_uri
|
32
34
|
env['REQUEST_URI'] || path_info
|
33
35
|
end
|
34
36
|
|
37
|
+
# the IP address(s) making the request provided by Rack::Request. You shouldn't trust it
|
38
|
+
|
35
39
|
def ip
|
36
40
|
if addr = env['HTTP_X_FORWARDED_FOR']
|
37
41
|
addr.split(',').last.strip
|
@@ -47,9 +51,8 @@ module Ramaze
|
|
47
51
|
ipv6 = %w[ fc00::/7 fe80::/10 fec0::/10 ::1 ]
|
48
52
|
LOCAL = (ipv4 + ipv6).map{|a| IPAddr.new(a)} unless defined?(LOCAL)
|
49
53
|
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# ++
|
54
|
+
# returns true if the IP address making the request is from local network.
|
55
|
+
# Optional argument address can be used to check any IP address.
|
53
56
|
|
54
57
|
def local_net?(address = ip)
|
55
58
|
addr = IPAddr.new(address)
|
@@ -63,6 +66,15 @@ module Ramaze
|
|
63
66
|
[key, *rest].map{|k| params[k.to_s] }
|
64
67
|
end
|
65
68
|
|
69
|
+
# Sets any arguments passed as @instance_variables for the current action.
|
70
|
+
#
|
71
|
+
# Usage:
|
72
|
+
# request.params # => {'name' => 'manveru', 'q' => 'google', 'lang' => 'de'}
|
73
|
+
# to_ivs(:name, :q)
|
74
|
+
# @q # => 'google'
|
75
|
+
# @name # => 'manveru'
|
76
|
+
# @lang # => nil
|
77
|
+
|
66
78
|
def to_ivs(*args)
|
67
79
|
instance = Action.current.instance
|
68
80
|
args.each do |arg|
|
@@ -71,81 +83,77 @@ module Ramaze
|
|
71
83
|
end
|
72
84
|
end
|
73
85
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
@rack_params = {}
|
116
|
-
Log.error(ex)
|
117
|
-
end
|
86
|
+
# Wrapping Request#params to support a one-level hash notation.
|
87
|
+
# It doesn't support anything really fancy, so be conservative in its use.
|
88
|
+
#
|
89
|
+
# See if following provides something useful for us:
|
90
|
+
# http://redhanded.hobix.com/2006/01/25.html
|
91
|
+
#
|
92
|
+
# Example Usage:
|
93
|
+
#
|
94
|
+
# # Template:
|
95
|
+
#
|
96
|
+
# <form action="/paste">
|
97
|
+
# <input type="text" name="paste[name]" />
|
98
|
+
# <input type="text" name="paste[syntax]" />
|
99
|
+
# <input type="submit" />
|
100
|
+
# </form>
|
101
|
+
#
|
102
|
+
# # In your Controller:
|
103
|
+
#
|
104
|
+
# def paste
|
105
|
+
# name, syntax = request['paste'].values_at('name', 'syntax')
|
106
|
+
# paste = Paste.create_with(:name => name, :syntax => syntax)
|
107
|
+
# redirect '/'
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# # Or, easier:
|
111
|
+
#
|
112
|
+
# def paste
|
113
|
+
# paste = Paste.create_with(request['paste'])
|
114
|
+
# redirect '/'
|
115
|
+
# end
|
116
|
+
|
117
|
+
def params
|
118
|
+
return {} if put?
|
119
|
+
return @ramaze_params if @ramaze_params
|
120
|
+
|
121
|
+
begin
|
122
|
+
@rack_params ||= super
|
123
|
+
rescue EOFError => ex
|
124
|
+
@rack_params = {}
|
125
|
+
Log.error(ex)
|
126
|
+
end
|
118
127
|
|
119
|
-
|
128
|
+
@ramaze_params = {}
|
120
129
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
130
|
+
@rack_params.each do |key, value|
|
131
|
+
if key =~ /^(.*?)(\[.*\])/
|
132
|
+
prim, nested = $~.captures
|
133
|
+
ref = @ramaze_params
|
125
134
|
|
126
|
-
|
127
|
-
|
135
|
+
keys = nested.scan(/\[([^\]]+)\]/).flatten
|
136
|
+
keys.unshift prim
|
128
137
|
|
129
|
-
|
130
|
-
|
131
|
-
|
138
|
+
keys.each_with_index do |k, i|
|
139
|
+
if i + 1 >= keys.size
|
140
|
+
ref[k] = value
|
141
|
+
else
|
142
|
+
# in case the value is a string we cannot let it be ref next
|
143
|
+
# time, so throw it away
|
144
|
+
if ref[k].is_a?(String)
|
145
|
+
ref = ref[k] = {}
|
132
146
|
else
|
133
|
-
|
134
|
-
# time, so throw it away
|
135
|
-
if ref[k].is_a?(String)
|
136
|
-
ref = ref[k] = {}
|
137
|
-
else
|
138
|
-
ref = ref[k] ||= {}
|
139
|
-
end
|
147
|
+
ref = ref[k] ||= {}
|
140
148
|
end
|
141
149
|
end
|
142
|
-
else
|
143
|
-
@ramaze_params[key] = value
|
144
150
|
end
|
151
|
+
else
|
152
|
+
@ramaze_params[key] = value
|
145
153
|
end
|
146
|
-
|
147
|
-
@ramaze_params
|
148
154
|
end
|
155
|
+
|
156
|
+
@ramaze_params
|
149
157
|
end
|
150
158
|
|
151
159
|
# Interesting HTTP variables from env
|
@@ -156,12 +164,18 @@ module Ramaze
|
|
156
164
|
}
|
157
165
|
end
|
158
166
|
|
167
|
+
# Returns a string presentation of the request, useful for debugging
|
168
|
+
# parameters of the action.
|
169
|
+
|
159
170
|
def to_s
|
160
171
|
p, c, e = params.inspect, cookies.inspect, http_vars.inspect
|
161
172
|
%{#<Ramaze::Request params=#{p} cookies=#{c} env=#{e}>}
|
162
173
|
end
|
163
174
|
alias inspect to_s
|
164
175
|
|
176
|
+
# Pretty prints current action with parameters, cookies and
|
177
|
+
# enviroment variables.
|
178
|
+
|
165
179
|
def pretty_print pp
|
166
180
|
p, c, e = params, cookies, http_vars
|
167
181
|
pp.object_group(self){
|
@@ -198,6 +212,9 @@ module Ramaze
|
|
198
212
|
URI("#{scheme}://#{host}#{path}")
|
199
213
|
end
|
200
214
|
|
215
|
+
# Returns and array of locales from env['HTTP_ACCEPT_LANGUAGE].
|
216
|
+
# e.g. ["fi", "en", "ja", "fr", "de", "es", "it", "nl", "sv"]
|
217
|
+
|
201
218
|
def locales
|
202
219
|
env['HTTP_ACCEPT_LANGUAGE'].to_s.split(/(?:,|;q=[\d.,]+)/)
|
203
220
|
end
|
@@ -9,8 +9,8 @@ module Ramaze
|
|
9
9
|
|
10
10
|
# Sets @hash to an empty Hash
|
11
11
|
|
12
|
-
def initialize
|
13
|
-
@session =
|
12
|
+
def initialize(session)
|
13
|
+
@session = session
|
14
14
|
@hash = {}
|
15
15
|
end
|
16
16
|
|
@@ -18,11 +18,8 @@ module Ramaze
|
|
18
18
|
# Session.current.sessions if anything changes.
|
19
19
|
|
20
20
|
def method_missing(*args, &block)
|
21
|
-
old = @hash.dup
|
22
21
|
result = @hash.send(*args, &block)
|
23
|
-
|
24
|
-
Cache.sessions[@session.session_id] = self
|
25
|
-
end
|
22
|
+
Cache.sessions[@session.session_id] = self
|
26
23
|
result
|
27
24
|
end
|
28
25
|
|
@@ -48,11 +45,10 @@ module Ramaze
|
|
48
45
|
|
49
46
|
# Unmarshal cookie data to a hash and verify its integrity.
|
50
47
|
def unmarshal(cookie)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
48
|
+
return unless cookie
|
49
|
+
data, digest = cookie.split('--')
|
50
|
+
return nil unless digest == generate_digest(data)
|
51
|
+
Marshal.load(data.unpack('m').first)
|
56
52
|
end
|
57
53
|
|
58
54
|
# Generate the inline SHA512 message digest. Larger (128 bytes) than SHA256
|
@@ -96,7 +96,7 @@ module Ramaze
|
|
96
96
|
def initialize(sess_or_request = Current.request)
|
97
97
|
return unless Global.sessions
|
98
98
|
|
99
|
-
if sess_or_request.
|
99
|
+
if sess_or_request.respond_to?(:cookies)
|
100
100
|
request = sess_or_request
|
101
101
|
@session_id = request.cookies[SESSION_KEY] || Session.random_key
|
102
102
|
else
|
@@ -125,10 +125,8 @@ module Ramaze
|
|
125
125
|
# existing already, the session itself is an instance of SessionHash
|
126
126
|
|
127
127
|
def current
|
128
|
-
|
129
|
-
|
130
|
-
end
|
131
|
-
@current
|
128
|
+
return @current if @current
|
129
|
+
@current = ( sessions[session_id] ||= Session::Hash.new(self) )
|
132
130
|
end
|
133
131
|
|
134
132
|
# shortcut to Cache.sessions
|
data/lib/ramaze/helper/aspect.rb
CHANGED
@@ -76,7 +76,7 @@ module Ramaze
|
|
76
76
|
class Action
|
77
77
|
|
78
78
|
# overwrites the default Action hook and runs the neccesary blocks in its
|
79
|
-
# scope
|
79
|
+
# scope before actions are run, starting from Ramaze::Controller down the
|
80
80
|
# ancestor chain.
|
81
81
|
def before_process
|
82
82
|
common_aspect(:before)
|
@@ -84,7 +84,7 @@ module Ramaze
|
|
84
84
|
|
85
85
|
|
86
86
|
# overwrites the default Action hook and runs the neccesary blocks in its
|
87
|
-
# scope
|
87
|
+
# scope after actions are run, starting from Ramaze::Controller down the
|
88
88
|
# ancestor chain.
|
89
89
|
def after_process
|
90
90
|
common_aspect(:after)
|
data/lib/ramaze/helper/form.rb
CHANGED
@@ -219,16 +219,19 @@ module Ramaze
|
|
219
219
|
|
220
220
|
# Form for instances of the model class
|
221
221
|
class InstanceForm < Form
|
222
|
-
# <input type='text' name='name' value='value' />
|
222
|
+
# returns <input type='text' name='name' value='value' />
|
223
223
|
def field_input(name, value)
|
224
224
|
"<input type='text' name='#{name}' value='#{value}'/>"
|
225
225
|
end
|
226
226
|
|
227
|
+
# returns <textarea name='name'>#{value}</textarea>
|
228
|
+
|
227
229
|
def field_textarea(name, value)
|
228
230
|
"<textarea name='#{name}'>#{value}</textarea>"
|
229
231
|
end
|
230
232
|
|
231
|
-
# <input type="text" name="name" value="value" />
|
233
|
+
# returns <input type="text" name="name" value="value" />
|
234
|
+
|
232
235
|
def field_integer(name, value)
|
233
236
|
field_input(name, value)
|
234
237
|
end
|
@@ -111,6 +111,10 @@ module Ramaze
|
|
111
111
|
end
|
112
112
|
alias autolink auto_link
|
113
113
|
|
114
|
+
# takes a string and optional argument for outputting compliance HTML
|
115
|
+
# instead of XHTML.
|
116
|
+
# e.g nl2br "a\nb\n\c" #=> 'a<br />b<br />c'
|
117
|
+
|
114
118
|
def nl2br(string, xhtml = true)
|
115
119
|
br = xhtml ? '<br />' : '<br>'
|
116
120
|
string.gsub(/\n/, br)
|
@@ -1,12 +1,29 @@
|
|
1
1
|
module Ramaze
|
2
2
|
module Helper
|
3
3
|
module Gravatar
|
4
|
+
|
5
|
+
# fetches a gravatar from http//www.gravatar.com based on 'email'
|
6
|
+
# and 'size'. Falls back to 'fallback_path' if no gravatar is found.
|
7
|
+
# default 'fallback_path' is "/images/gravatar_default.jpg".
|
8
|
+
# example:
|
9
|
+
#
|
10
|
+
# class GravatarController < Ramaze::Controller
|
11
|
+
# helper :gravatar
|
12
|
+
#
|
13
|
+
# def index
|
14
|
+
# @gravatar_thumbnail_src = gravatar(session[:email] || 'riku@helloit.fi')
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# /view/gravatar/index.html:
|
19
|
+
# <img src="#{@gravatar_thumbnail_src}" />
|
20
|
+
|
4
21
|
def gravatar(email, size = 32, fallback_path = "/images/gravatar_default.jpg")
|
5
22
|
emailhash = Digest::MD5.hexdigest(email)
|
6
23
|
|
7
24
|
fallback = Request.current.domain
|
8
25
|
fallback.path = fallback_path
|
9
|
-
default =
|
26
|
+
default = Rack::Utils.escape(fallback.to_s)
|
10
27
|
|
11
28
|
return "http://www.gravatar.com/avatar.php?gravatar_id=#{emailhash}&default=#{default}&size=#{size}"
|
12
29
|
end
|
data/lib/ramaze/helper/maruku.rb
CHANGED
@@ -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.rb
CHANGED
@@ -45,7 +45,7 @@ module Ramaze
|
|
45
45
|
if require_helper(name)
|
46
46
|
redo
|
47
47
|
else
|
48
|
-
raise LoadError, "#{name} not found"
|
48
|
+
raise LoadError, "helper #{name} not found"
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -53,6 +53,8 @@ module Ramaze
|
|
53
53
|
|
54
54
|
private
|
55
55
|
|
56
|
+
# returns the Ramaze::Helper::Name Module Constant if exists.
|
57
|
+
|
56
58
|
def find_helper(name)
|
57
59
|
name = name.to_s.camel_case
|
58
60
|
ramaze_helper_consts = ::Ramaze::Helper.constants.grep(/^#{name}$/i)
|
@@ -61,16 +63,21 @@ module Ramaze
|
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
66
|
+
# Loads helper from /lib/ramaze/helper/name.(so, bundle, rb)
|
67
|
+
# raises LoadError if helper not found.
|
68
|
+
|
64
69
|
def require_helper(name)
|
65
70
|
paths = (PATH + [Global.root, "#{BASEDIR}/ramaze"]).join(',')
|
66
71
|
glob = "{#{paths}}/helper/#{name}.{so,bundle,rb}"
|
67
72
|
files = Dir[glob]
|
68
73
|
ignore = Helper.trait[:ignore]
|
69
74
|
files.reject!{|f| ignore.any?{|i| f =~ i }}
|
70
|
-
raise LoadError, "#{name} not found" unless file = files.first
|
75
|
+
raise LoadError, "file for #{name} not found" unless file = files.first
|
71
76
|
require(file)
|
72
77
|
end
|
73
78
|
|
79
|
+
# injects the helper via include and extend, takes Constant as argument.
|
80
|
+
|
74
81
|
def use_helper(mod)
|
75
82
|
include mod
|
76
83
|
extend mod
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Ramaze
|
2
|
+
class Reloader
|
3
|
+
class WatchInotify
|
4
|
+
POLL_INTERVAL = 2 # seconds
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@watcher = RInotify.new
|
8
|
+
@changed = []
|
9
|
+
@mutex = Mutex.new
|
10
|
+
@watcher_thread = start_watcher
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(cooldown)
|
14
|
+
yield if @changed.any?
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: define a finalizer to cleanup? -- reloader never calls #close
|
18
|
+
|
19
|
+
def start_watcher
|
20
|
+
Thread.new do
|
21
|
+
loop do
|
22
|
+
watcher_cycle
|
23
|
+
sleep POLL_INTERVAL
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def watcher_cycle
|
29
|
+
return unless @watcher.wait_for_events(0)
|
30
|
+
changed_descriptors = []
|
31
|
+
|
32
|
+
@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
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def watch(file)
|
44
|
+
return false if @watcher.watch_descriptors.has_value?(file)
|
45
|
+
return false unless File.exist?(file)
|
46
|
+
|
47
|
+
@mutex.synchronize{ @watcher.add_watch(file, RInotify::MODIFY) }
|
48
|
+
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_watch(file)
|
53
|
+
@mutex.synchronize{ @watcher.rm_watch(file) }
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def close
|
58
|
+
@watcher_thread.terminate
|
59
|
+
@watcher.close
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def changed_files
|
64
|
+
@mutex.synchronize do
|
65
|
+
@tmp = @changed
|
66
|
+
@changed = []
|
67
|
+
end
|
68
|
+
@tmp.uniq!
|
69
|
+
@tmp
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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
|
+
changed = []
|
42
|
+
|
43
|
+
@files.each do |file, stat|
|
44
|
+
if new_stat = safe_stat(file)
|
45
|
+
if new_stat.mtime > stat.mtime
|
46
|
+
changed << file
|
47
|
+
@files[file] = new_stat
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
changed
|
53
|
+
end
|
54
|
+
|
55
|
+
def safe_stat(file)
|
56
|
+
File.stat(file)
|
57
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|