自己做的小玩具,以及做小玩具的思路:).
原图 (上传至 ruby-china.org 的图会被压缩): http://gemrelationship.zhuboliu.me/gem_relationship.png (帖出来后才发现这张图神似欧亚大陆,连澳大利亚都有~)
在阅读 Rails 源码时,我脑子里总是冒出这样的念头:"卧操!这是什么鬼!?这方法是哪里来的!? 自定义的!? 来自父类!? 来自 include/extend 的模块!? 来自第三方 gem!? 哪一个?". 如果是项目内引用定义的,倒是很好查找。但是,如果是来自第三方项目,那来自哪些?这样的阅读体验无疑让人很痛苦。
换个思路,用社交关系网络的概念来生成图,让各种依赖关系一目了然。
rails 依赖许多 gem. 现在,rails 的主要模块本身就被拆成了数个独立的 gem. 我们可以理解为 rails 依赖这些 gem. 同时,这些 gem 又依赖于其他的 gem. 拨出萝卜带出泥,不胜期烦。
从社交关系的角度来看问题,我们作如下两点设定:
最终生成的图,通过看线条与箭头,我们可以清楚地看到哪些 Gem 受欢迎 (大批的粉丝).
有了思路,接下来就要考虑如何实现的问题了。
问题 1 和问题 2 很简单,项目内通过bundle install
生成的Gemfile.lock
提供了所有的节点与关系。
This is important: the Gemfile.lock makes your application a single package of both your own code and the third-party code it ran the last time you know for sure that everything worked. Specifying exact versions of the third-party code you depend on in your Gemfile would not provide the same guarantee, because gems usually declare a range of versions for their dependencies.
问题 3, 通过网络搜索,发现Graphviz(Graph Visualization Software) 可以很好地解决这个问题。
创建一个 Rails 原生项目,不添加任何其他 Gem.
cd to/your/path
# rails 4.2.1
rails new rgraph
cd graph
bundle install
touch graph.rb
# edit graph.rb
分析Gemfile.lock
文件,生成gem_relationshop.gv
文件。
# rails/app/root/path/graph.rb
src_box = []
File.open('gem_relationship.gv', 'w') do |t|
t.puts "digraph G {"
File.open("Gemfile.lock").each do |n|
# 通过缩进来判断指向关系.
n =~ /^( {2,})([a-zA-Z0-9_-]+)/
if $1 and $1.length == 4
@src = $2
src_box << @src
elsif $1 and $1.length == 6
@target = $2
puts @src
t.puts " \"#{@src}\" -> \"#{@target}\""
else
end
end
t.puts "}"
end
运行 script 生成源文件:
ruby graph.rb
运行 graphviz 相关命令生成图:
# 系统内必须装好 Graphviz.
dot -Tpng -o ./gem_relationship.png ./gem_relationship.gv
# open gem_relationship.png
Done!
google 的结果是arborjs勉强可以干这事儿,而且arborjs
语法类似Graphviz
的语法.
使用源码中的 demo,复制一份 json 文件,将生成的.gv
的主内容帖进,hack 一下,测试,发布:
在线演示地址:http://gemrelationship.zhuboliu.me 在线站点支持节点拖曳。支持在线编辑,可以考虑直接在项目要目录下生成的文件帖到右边的框内,实时生成关系图。
如果你需要使用此演示站的功能生成自己的 ruby 项目,请确保项目使用bundler
且Gemfile.lock
存在。
站点实时生成关系图的数据的代码略有不同,如下:
css_box = %W{NAVY BLUE AQUA TEAL OLIVE GREEN LIME ORANGE RED MAROON FUCHSIA PURPLE BLACK GRAY SILVER}
src_box = []
File.open('gem_relationship.gv', 'w') do |t|
# t.puts "digraph G {"
File.open("Gemfile.lock").each do |n|
# 通过缩进来判断指向关系.
n =~ /^( {2,})([a-zA-Z0-9_-]+)/
if $1 and $1.length == 4
@src = $2
src_box << @src
elsif $1 and $1.length == 6
@target = $2
puts @src
# t.puts " \"#{@src}\" -> \"#{@target}\""
t.puts "#{@src} -> #{@target}"
else
end
end
# t.puts "}"
# 随机生成色彩.
src_box.each do |s|
t.puts "#{s} {color:#{css_box.shuffle.first}}"
end
end
注意:不要帖入大型项目的关系数据,节点太多,结果会很难看。
railtie
, activesupport
, activepack
, rack
是真正的大 V, 粉丝无数,若要阅读 Rails 源码,从了解它们开始吧。
附上一张个人的小项目 (引入第三方 gem 若干) 的图: 原图地址:http://gemrelationship.zhuboliu.me/color.png
请有好的意见 @suffering, 谢谢。
http://bundler.io/v1.7/rationale.html#checking-your-code-into-version-control http://www.graphviz.org/ http://arborjs.org/ http://arborjs.org/docs/barnes-hut http://getspringy.com/