rake的import
设Rakefile如下
desc 'default task'
task default: [:print]
desc 'print task'
task :print do
puts 'hello'
end
require 'trace_tree'
binding.trace_tree do
import 'dep.rb'
end
dep.rb文件如下
puts caller
运行一下
$ rake Object#block in <top (required)=""> /home/z/test_rails/rk/Rakefile:10 └─Object#import $GemPath0/gems/rake-12.0.0/lib/rake/dsl_definition.rb:182 └─Array#each $GemPath0/gems/rake-12.0.0/lib/rake/dsl_definition.rb:183 └─Object#block in import $GemPath0/gems/rake-12.0.0/lib/rake/dsl_definition.rb:183 ├─Rake.application $GemPath0/gems/rake-12.0.0/lib/rake/rake_module.rb:7 └─Rake::Application#add_import $GemPath0/gems/rake-12.0.0/lib/rake/application.rb:754 /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/rake_module.rb:28:in `load' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/rake_module.rb:28:in `load_rakefile' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/default_loader.rb:10:in `load' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:765:in `load_imports' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:695:in `raw_load_rakefile' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:96:in `block in load_rakefile' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:178:in `standard_exception_handling' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:95:in `load_rakefile' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:79:in `block in run' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:178:in `standard_exception_handling' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:77:in `run' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)="">' /home/z/.rbenv/versions/2.4.0/bin/rake:22:in `load' /home/z/.rbenv/versions/2.4.0/bin/rake:22:in `</top></top>
' hello
用源码来看,import只是将文件名暂存起来
def add_import(fn)
@pending_imports << fn
end
然后,在读完整个rakefile(即做完task、import等等)之后,运行任务之前,才加载这些要import的文件,所以即使importee依赖importor中的某些东西(例如importor中定义的方法),import语句也不必写在被依赖之物的后面
def load_imports
while fn = @pending_imports.shift
next if @imported.member?(fn)
fn_task = lookup(fn) and fn_task.invoke
ext = File.extname(fn)
loader = @loaders[ext] || @default_loader
loader.load(fn)
if fn_task = lookup(fn) and fn_task.needed?
fn_task.reenable
fn_task.invoke
loader.load(fn)
end
@imported << fn
end
end
而Rake Task Management Essentials一书中的例子
task 'dep.rb' do
sh %Q{echo "puts 'Hello, from the dep.rb'" > dep.rb}
end
task :hello => 'dep.rb'
import 'dep.rb'
运行时输出
$ rake hello
echo "puts 'Hello, from the dep.rb'" > dep.rb
Hello, from the dep.rb
echo "puts 'Hello, from the dep.rb'" > dep.rb
Hello, from the dep.rb
与书中只输出一次echo...Hello不符,是因为有两次fn_task.invoke。这里的机制主要是lookup然后invoke,如果import的参数恰好是之前定义过的task,则会先调用一下这个task
# rake-12.0.0/lib/rake/task_manager.rb
def lookup(task_name, initial_scope=nil)
initial_scope ||= @scope
task_name = task_name.to_s
if task_name =~ /^rake:/
scopes = Scope.make
task_name = task_name.sub(/^rake:/, "")
elsif task_name =~ /^(\^+)/
scopes = initial_scope.trim($1.size)
task_name = task_name.sub(/^(\^+)/, "")
else
scopes = initial_scope
end
lookup_in_scope(task_name, scopes)
end
def lookup_in_scope(name, scope)
loop do
tn = scope.path_with_task_name(name)
task = @tasks[tn]
return task if task
break if scope.empty?
scope = scope.tail
end
nil
end
不过还是没明白书中举这例子有何意义