bin/rails stats 来自哪里
想知道rails stats干什么,于是检查下ARGV会在哪里被调用,修改bin/rails如下
class << ARGV
instance_methods.each do |m|
old_m = instance_method m
define_method m do |*args, &blk|
puts "#{m} #{caller[0]}"
old_m.bind(ARGV).call *args, &blk
end
end
end
没看出什么,再检查stats这个字符在哪被调用
(因ARGV内的字符串都被freeze了,无法重定义单例实例方法,所以另给stats字符串塞进ARGV)
ARGV[0] = "stats"
class << ARGV[0]
instance_methods.each do |m|
old_m = instance_method m
define_method m do |*args, &blk|
puts "#{m} #{caller[0]}"
old_m.bind(ARGV[0]).call *args, &blk
end
end
end
require 'rails/commands'
还是没看出什么
但细看下stats的输出,猜测可直接在源码中查找“Code LOC”在哪里出现
+----------------------+--------+--------+---------+---------+-----+-------+
| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
+----------------------+--------+--------+---------+---------+-----+-------+
| Controllers | 467 | 330 | 9 | 54 | 6 | 4 |
| Helpers | 21 | 21 | 0 | 1 | 0 | 19 |
| Jobs | 2 | 2 | 1 | 0 | 0 | 0 |
| Models | 71 | 63 | 6 | 5 | 0 | 10 |
| Mailers | 4 | 4 | 1 | 0 | 0 | 0 |
| Channels | 8 | 8 | 2 | 0 | 0 | 0 |
| Javascripts | 54 | 4 | 0 | 1 | 0 | 2 |
| Libraries | 0 | 0 | 0 | 0 | 0 | 0 |
| Tasks | 0 | 0 | 0 | 0 | 0 | 0 |
| Controller tests | 331 | 256 | 8 | 43 | 5 | 3 |
| Helper tests | 0 | 0 | 0 | 0 | 0 | 0 |
| Model tests | 66 | 41 | 5 | 3 | 0 | 11 |
| Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 |
| Integration tests | 0 | 0 | 0 | 0 | 0 | 0 |
+----------------------+--------+--------+---------+---------+-----+-------+
| Total | 1024 | 729 | 32 | 107 | 3 | 4 |
+----------------------+--------+--------+---------+---------+-----+-------+
Code LOC: 432 Test LOC: 297 Code to Test Ratio: 1:0.7
于是
$ gems git:(master) grep 'Code LOC' -rn *
railties-5.0.2/lib/rails/code_statistics.rb:110: puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
看上去应该就是这里,于是加入caller,检查哪里会生成这个CodeStatistics
class CodeStatistics
def initialize(*pairs)
puts caller
@pairs = pairs
@statistics = calculate_statistics
@total = calculate_total if pairs.length > 1
end
end
出来的调用栈如下
/home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/railties-5.0.2/lib/rails/tasks/statistics.rake:28:in `new' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/railties-5.0.2/lib/rails/tasks/statistics.rake:28:in `block in <top (required)="">' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/task.rb:250:in `block in execute' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/task.rb:250:in `each' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/task.rb:250:in `execute' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/task.rb:194:in `block in invoke_with_call_chain' /home/z/.rbenv/versions/2.4.0/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/task.rb:187:in `invoke_with_call_chain' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/task.rb:180:in `invoke' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:152:in `invoke_task' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:108:in `block (2 levels) in top_level' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:108:in `each' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:108:in `block in top_level' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:117:in `run_with_threads' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/application.rb:102:in `top_level' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/railties-5.0.2/lib/rails/commands/rake_proxy.rb:14:in `block in run_rake_task' /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/railties-5.0.2/lib/rails/commands/rake_proxy.rb:11:in `run_rake_task' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/railties-5.0.2/lib/rails/commands/commands_tasks.rb:51:in `run_command!' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/railties-5.0.2/lib/rails/commands.rb:18:in `<top (required)="">' /home/z/test_rails/depot/bin/rails:25:in `require' /home/z/test_rails/depot/bin/rails:25:in `<top (required)="">' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/client/rails.rb:28:in `load' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/client/rails.rb:28:in `call' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/client/command.rb:7:in `call' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/client.rb:30:in `run' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/bin/spring:49:in `<top (required)="">' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/binstub.rb:31:in `load' /home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/binstub.rb:31:in `<top (required)="">' /home/z/.rbenv/versions/2.4.0/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:68:in `require' /home/z/.rbenv/versions/2.4.0/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:68:in `require' /home/z/test_rails/depot/bin/spring:15:in `<top (required)="">' bin/rails:3:in `load' bin/rails:3:in `</top></top></top></top></top></top>
'
而railties-5.0.2/lib/rails/tasks/statistics.rake是这样的
STATS_DIRECTORIES = [
%w(Controllers app/controllers),
%w(Helpers app/helpers),
%w(Jobs app/jobs),
%w(Models app/models),
%w(Mailers app/mailers),
%w(Channels app/channels),
%w(Javascripts app/assets/javascripts),
%w(Libraries lib/),
%w(Tasks lib/tasks),
%w(APIs app/apis),
%w(Controller\ tests test/controllers),
%w(Helper\ tests test/helpers),
%w(Model\ tests test/models),
%w(Mailer\ tests test/mailers),
%w(Job\ tests test/jobs),
%w(Integration\ tests test/integration),
].collect do |name, dir|
[ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ]
end.select { |name, dir| File.directory?(dir) }
desc "Report code statistics (KLOCs, etc) from the application or engine"
task :stats do
require 'rails/code_statistics'
CodeStatistics.new(*STATS_DIRECTORIES).to_s
end
同时,可发现rails还定义了以下task
$ gems git:(master) tree railties-5.0.2/lib/rails/tasks/
railties-5.0.2/lib/rails/tasks/
├── annotations.rake
├── dev.rake
├── engine.rake
├── framework.rake
├── initializers.rake
├── log.rake
├── middleware.rake
├── misc.rake
├── restart.rake
├── routes.rake
├── statistics.rake
└── tmp.rake