Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
80256abb
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
80256abb
编写于
12月 13, 2011
作者:
J
José Valim
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
FileUpdateChecker should be able to handle deleted files.
上级
1f5b9bbd
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
109 addition
and
61 deletion
+109
-61
activerecord/lib/active_record/railtie.rb
activerecord/lib/active_record/railtie.rb
+1
-2
activesupport/lib/active_support/file_update_checker.rb
activesupport/lib/active_support/file_update_checker.rb
+45
-28
activesupport/lib/active_support/i18n_railtie.rb
activesupport/lib/active_support/i18n_railtie.rb
+1
-1
activesupport/test/file_update_checker_test.rb
activesupport/test/file_update_checker_test.rb
+15
-21
railties/lib/rails/application.rb
railties/lib/rails/application.rb
+1
-1
railties/lib/rails/application/finisher.rb
railties/lib/rails/application/finisher.rb
+3
-4
railties/lib/rails/application/routes_reloader.rb
railties/lib/rails/application/routes_reloader.rb
+11
-4
railties/test/application/loading_test.rb
railties/test/application/loading_test.rb
+32
-0
未找到文件。
activerecord/lib/active_record/railtie.rb
浏览文件 @
80256abb
...
@@ -95,8 +95,7 @@ class Railtie < Rails::Railtie
...
@@ -95,8 +95,7 @@ class Railtie < Rails::Railtie
end
end
initializer
"active_record.add_watchable_files"
do
|
app
|
initializer
"active_record.add_watchable_files"
do
|
app
|
files
=
[
"
#{
app
.
root
}
/db/schema.rb"
,
"
#{
app
.
root
}
/db/structure.sql"
]
config
.
watchable_files
.
concat
[
"
#{
app
.
root
}
/db/schema.rb"
,
"
#{
app
.
root
}
/db/structure.sql"
]
config
.
watchable_files
.
concat
files
.
select
{
|
f
|
File
.
exist?
(
f
)
}
end
end
config
.
after_initialize
do
config
.
after_initialize
do
...
...
activesupport/lib/active_support/file_update_checker.rb
浏览文件 @
80256abb
...
@@ -2,10 +2,27 @@
...
@@ -2,10 +2,27 @@
require
"active_support/core_ext/array/extract_options"
require
"active_support/core_ext/array/extract_options"
module
ActiveSupport
module
ActiveSupport
# This class is responsible to track files and invoke the given block
# \FileUpdateChecker specifies the API used by Rails to watch files
# whenever one of these files are changed. For example, this class
# and control reloading. The API depends on four methods:
# is used by Rails to reload the I18n framework whenever they are
#
# changed upon a new request.
# * +initialize+ which expects two parameters and one block as
# described below;
#
# * +updated?+ which returns a boolean if there were updates in
# the filesystem or not;
#
# * +execute+ which executes the given block on initialization
# and updates the counter to the latest timestamp;
#
# * +execute_if_updated+ which just executes the block if it was updated;
#
# After initialization, a call to +execute_if_updated+ must execute
# the block only if there was really a change in the filesystem.
#
# == Examples
#
# This class is used by Rails to reload the I18n framework whenever
# they are changed upon a new request.
#
#
# i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
# i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
# I18n.reload!
# I18n.reload!
...
@@ -16,37 +33,38 @@ module ActiveSupport
...
@@ -16,37 +33,38 @@ module ActiveSupport
# end
# end
#
#
class
FileUpdateChecker
class
FileUpdateChecker
# It accepts two parameters on initialization. The first is
# It accepts two parameters on initialization. The first is an array
# the *paths* and the second is *calculate*, a boolean.
# of files and the second is an optional hash of directories. The hash must
#
# have directories as keys and the value is an array of extensions to be
# paths must be an array of file paths but can contain a hash as
# watched under that directory.
# last argument. The hash must have directories as keys and the
# value is an array of extensions to be watched under that directory.
#
#
# If *calculate* is true, the latest updated at will calculated
# This method must also receive a block that will be called once a path changes.
# on initialization, therefore, the first call to execute_if_updated
# will only evaluate the block if something really changed.
#
#
#
This method must also receive a block that will be called once a file changes.
#
== Implementation details
#
#
# This particular implementation checks for added
files
and updated files,
# This particular implementation checks for added and updated files,
# but not removed files. Directories lookup are compiled to a glob for
# but not removed files. Directories lookup are compiled to a glob for
# performance. Therefore, while someone can add new files to paths after
# performance. Therefore, while someone can add new files to the +files+
# initialization, adding new directories is not allowed. Notice that,
# array after initialization (and parts of Rails do depend on this feature),
# depending on the implementation, not even new files may be added.
# adding new directories after initialization is not allowed.
def
initialize
(
paths
,
calculate
=
false
,
&
block
)
#
@paths
=
paths
# Notice that other objects that implements FileUpdateChecker API may
@glob
=
compile_glob
(
@paths
.
extract_options!
)
# not even allow new files to be added after initialization. If this
# is the case, we recommend freezing the +files+ after initialization to
# avoid changes that won't make effect.
def
initialize
(
files
,
dirs
=
{},
&
block
)
@files
=
files
@glob
=
compile_glob
(
dirs
)
@block
=
block
@block
=
block
@updated_at
=
nil
@updated_at
=
nil
@last_update_at
=
calculate
?
updated_at
:
nil
@last_update_at
=
updated_at
end
end
# Check if any of the entries were updated. If so, the updated_at
# Check if any of the entries were updated. If so, the updated_at
# value is cached until the block is executed via +execute+ or +execute_if_updated+
# value is cached until the block is executed via +execute+ or +execute_if_updated+
def
updated?
def
updated?
current_updated_at
=
updated_at
current_updated_at
=
updated_at
if
@last_update_at
!=
current_updated_at
if
@last_update_at
<
current_updated_at
@updated_at
=
updated_at
@updated_at
=
updated_at
true
true
else
else
...
@@ -54,7 +72,7 @@ def updated?
...
@@ -54,7 +72,7 @@ def updated?
end
end
end
end
# Executes the given block
expiring any internal cache
.
# Executes the given block
and updates the counter to latest timestamp
.
def
execute
def
execute
@last_update_at
=
updated_at
@last_update_at
=
updated_at
@block
.
call
@block
.
call
...
@@ -62,8 +80,7 @@ def execute
...
@@ -62,8 +80,7 @@ def execute
@updated_at
=
nil
@updated_at
=
nil
end
end
# Execute the block given if updated. This call
# Execute the block given if updated.
# always flush the cache.
def
execute_if_updated
def
execute_if_updated
if
updated?
if
updated?
execute
execute
...
@@ -78,9 +95,9 @@ def execute_if_updated
...
@@ -78,9 +95,9 @@ def execute_if_updated
def
updated_at
#:nodoc:
def
updated_at
#:nodoc:
@updated_at
||
begin
@updated_at
||
begin
all
=
[]
all
=
[]
all
.
concat
@
paths
all
.
concat
@
files
.
select
{
|
f
|
File
.
exists?
(
f
)
}
all
.
concat
Dir
[
@glob
]
if
@glob
all
.
concat
Dir
[
@glob
]
if
@glob
all
.
map
{
|
path
|
File
.
mtime
(
path
)
}.
max
all
.
map
{
|
path
|
File
.
mtime
(
path
)
}.
max
||
Time
.
at
(
0
)
end
end
end
end
...
...
activesupport/lib/active_support/i18n_railtie.rb
浏览文件 @
80256abb
...
@@ -64,7 +64,7 @@ def self.initialize_i18n(app)
...
@@ -64,7 +64,7 @@ def self.initialize_i18n(app)
init_fallbacks
(
fallbacks
)
if
fallbacks
&&
validate_fallbacks
(
fallbacks
)
init_fallbacks
(
fallbacks
)
if
fallbacks
&&
validate_fallbacks
(
fallbacks
)
reloader_paths
.
concat
I18n
.
load_path
reloader_paths
.
concat
I18n
.
load_path
reloader
.
execute
_if_updated
reloader
.
execute
@i18n_inited
=
true
@i18n_inited
=
true
end
end
...
...
activesupport/test/file_update_checker_test.rb
浏览文件 @
80256abb
...
@@ -14,7 +14,7 @@ def setup
...
@@ -14,7 +14,7 @@ def setup
def
teardown
def
teardown
FileUtils
.
rm_rf
(
"tmp_watcher"
)
FileUtils
.
rm_rf
(
"tmp_watcher"
)
FileUtils
.
rm
(
FILES
)
FileUtils
.
rm
_rf
(
FILES
)
end
end
def
test_should_not_execute_the_block_if_no_paths_are_given
def
test_should_not_execute_the_block_if_no_paths_are_given
...
@@ -24,39 +24,33 @@ def test_should_not_execute_the_block_if_no_paths_are_given
...
@@ -24,39 +24,33 @@ def test_should_not_execute_the_block_if_no_paths_are_given
assert_equal
0
,
i
assert_equal
0
,
i
end
end
def
test_should_invoke_the_block_on_first_call_if_it_does_not_calculate_last_updated_at_on_load
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
){
i
+=
1
}
checker
.
execute_if_updated
assert_equal
1
,
i
end
def
test_should_not_invoke_the_block_on_first_call_if_it_calculates_last_updated_at_on_load
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
,
true
){
i
+=
1
}
checker
.
execute_if_updated
assert_equal
0
,
i
end
def
test_should_not_invoke_the_block_if_no_file_has_changed
def
test_should_not_invoke_the_block_if_no_file_has_changed
i
=
0
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
,
true
){
i
+=
1
}
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
){
i
+=
1
}
5
.
times
{
assert
!
checker
.
execute_if_updated
}
5
.
times
{
assert
!
checker
.
execute_if_updated
}
assert_equal
0
,
i
assert_equal
0
,
i
end
end
def
test_should_invoke_the_block_if_a_file_has_changed
def
test_should_invoke_the_block_if_a_file_has_changed
i
=
0
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
,
true
){
i
+=
1
}
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
){
i
+=
1
}
sleep
(
1
)
sleep
(
1
)
FileUtils
.
touch
(
FILES
)
FileUtils
.
touch
(
FILES
)
assert
checker
.
execute_if_updated
assert
checker
.
execute_if_updated
assert_equal
1
,
i
assert_equal
1
,
i
end
end
def
test_should_
cache_updated_result_until_flushed
def
test_should_
be_robust_enough_to_handle_deleted_files
i
=
0
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
,
true
){
i
+=
1
}
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
){
i
+=
1
}
FileUtils
.
rm
(
FILES
)
assert
!
checker
.
execute_if_updated
assert_equal
0
,
i
end
def
test_should_cache_updated_result_until_execute
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
(
FILES
){
i
+=
1
}
assert
!
checker
.
updated?
assert
!
checker
.
updated?
sleep
(
1
)
sleep
(
1
)
...
@@ -69,7 +63,7 @@ def test_should_cache_updated_result_until_flushed
...
@@ -69,7 +63,7 @@ def test_should_cache_updated_result_until_flushed
def
test_should_invoke_the_block_if_a_watched_dir_changed_its_glob
def
test_should_invoke_the_block_if_a_watched_dir_changed_its_glob
i
=
0
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
([
{
"tmp_watcher"
=>
[
:txt
]}],
true
){
i
+=
1
}
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
([
],
"tmp_watcher"
=>
[
:txt
]
){
i
+=
1
}
FileUtils
.
cd
"tmp_watcher"
do
FileUtils
.
cd
"tmp_watcher"
do
FileUtils
.
touch
(
FILES
)
FileUtils
.
touch
(
FILES
)
end
end
...
@@ -79,7 +73,7 @@ def test_should_invoke_the_block_if_a_watched_dir_changed_its_glob
...
@@ -79,7 +73,7 @@ def test_should_invoke_the_block_if_a_watched_dir_changed_its_glob
def
test_should_not_invoke_the_block_if_a_watched_dir_changed_its_glob
def
test_should_not_invoke_the_block_if_a_watched_dir_changed_its_glob
i
=
0
i
=
0
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
([
{
"tmp_watcher"
=>
:rb
}],
true
){
i
+=
1
}
checker
=
ActiveSupport
::
FileUpdateChecker
.
new
([
],
"tmp_watcher"
=>
:rb
){
i
+=
1
}
FileUtils
.
cd
"tmp_watcher"
do
FileUtils
.
cd
"tmp_watcher"
do
FileUtils
.
touch
(
FILES
)
FileUtils
.
touch
(
FILES
)
end
end
...
...
railties/lib/rails/application.rb
浏览文件 @
80256abb
...
@@ -124,7 +124,7 @@ def watchable_args
...
@@ -124,7 +124,7 @@ def watchable_args
dirs
[
path
.
to_s
]
=
[
:rb
]
dirs
[
path
.
to_s
]
=
[
:rb
]
end
end
files
<<
dirs
[
files
,
dirs
]
end
end
# Initialize the application passing the given group. By default, the
# Initialize the application passing the given group. By default, the
...
...
railties/lib/rails/application/finisher.rb
浏览文件 @
80256abb
...
@@ -64,10 +64,9 @@ module Finisher
...
@@ -64,10 +64,9 @@ module Finisher
# routes added in the hook are still loaded.
# routes added in the hook are still loaded.
initializer
:set_routes_reloader_hook
do
initializer
:set_routes_reloader_hook
do
reloader
=
routes_reloader
reloader
=
routes_reloader
hook
=
lambda
{
reloader
.
execute_if_updated
}
reloader
.
execute_if_updated
hook
.
call
self
.
reloaders
<<
reloader
self
.
reloaders
<<
reloader
ActionDispatch
::
Reloader
.
to_prepare
(
&
hook
)
ActionDispatch
::
Reloader
.
to_prepare
{
reloader
.
execute_if_updated
}
end
end
# Set app reload just after the finisher hook to ensure
# Set app reload just after the finisher hook to ensure
...
@@ -79,7 +78,7 @@ module Finisher
...
@@ -79,7 +78,7 @@ module Finisher
end
end
if
config
.
reload_classes_only_on_change
if
config
.
reload_classes_only_on_change
reloader
=
config
.
file_watcher
.
new
(
watchable_args
,
true
,
&
callback
)
reloader
=
config
.
file_watcher
.
new
(
*
watchable_args
,
&
callback
)
self
.
reloaders
<<
reloader
self
.
reloaders
<<
reloader
# We need to set a to_prepare callback regardless of the reloader result, i.e.
# We need to set a to_prepare callback regardless of the reloader result, i.e.
# models should be reloaded if any of the reloaders (i18n, routes) were updated.
# models should be reloaded if any of the reloaders (i18n, routes) were updated.
...
...
railties/lib/rails/application/routes_reloader.rb
浏览文件 @
80256abb
...
@@ -4,11 +4,10 @@ module Rails
...
@@ -4,11 +4,10 @@ module Rails
class
Application
class
Application
class
RoutesReloader
class
RoutesReloader
attr_reader
:route_sets
,
:paths
attr_reader
:route_sets
,
:paths
delegate
:execute_if_updated
,
:
updated?
,
:to
=>
:@
updater
delegate
:execute_if_updated
,
:
execute
,
:updated?
,
:to
=>
:
updater
def
initialize
(
updater
=
ActiveSupport
::
FileUpdateChecker
)
def
initialize
@paths
=
[]
@paths
=
[]
@updater
=
updater
.
new
(
paths
)
{
reload!
}
@route_sets
=
[]
@route_sets
=
[]
end
end
...
@@ -20,7 +19,15 @@ def reload!
...
@@ -20,7 +19,15 @@ def reload!
revert
revert
end
end
protected
private
def
updater
@updater
||=
begin
updater
=
ActiveSupport
::
FileUpdateChecker
.
new
(
paths
)
{
reload!
}
updater
.
execute
updater
end
end
def
clear!
def
clear!
route_sets
.
each
do
|
routes
|
route_sets
.
each
do
|
routes
|
...
...
railties/test/application/loading_test.rb
浏览文件 @
80256abb
...
@@ -175,6 +175,38 @@ def self.counter; 2; end
...
@@ -175,6 +175,38 @@ def self.counter; 2; end
assert_equal
"1"
,
last_response
.
body
assert_equal
"1"
,
last_response
.
body
end
end
test
"added files also trigger reloading"
do
add_to_config
<<-
RUBY
config.cache_classes = false
RUBY
app_file
'config/routes.rb'
,
<<-
RUBY
$counter = 0
AppTemplate::Application.routes.draw do
match '/c', :to => lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] }
end
RUBY
app_file
"app/models/user.rb"
,
<<-
MODEL
class User
$counter += 1
end
MODEL
require
'rack/test'
extend
Rack
::
Test
::
Methods
require
"
#{
rails_root
}
/config/environment"
get
"/c"
assert_equal
"1"
,
last_response
.
body
app_file
"db/schema.rb"
,
""
get
"/c"
assert_equal
"2"
,
last_response
.
body
end
protected
protected
def
setup_ar!
def
setup_ar!
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录