Gem Rails 项目 Gem 依赖的社交关系网络关系图及其生成

suffering · 发布于 2015年7月15日 · 最后由 adamshen 回复于 2015年9月12日 · 3489 次阅读
709
本帖已被设为精华帖!

自己做的小玩具, 以及做小玩具的思路:).

WHAT

Rails 4.2.1 初始化项目gem依赖关系图:

原图(上传至ruby-china.org的图会被压缩): http://gemrelationship.zhuboliu.me/gem_relationship.png (帖出来后才发现这张图神似欧亚大陆, 连澳大利亚都有~)

WHY?

在阅读Rails源码时, 我脑子里总是冒出这样的念头:"卧操!这是什么鬼!?这方法是哪里来的!? 自定义的!? 来自父类!? 来自include/extend的模块!? 来自第三方gem!? 哪一个?". 如果是项目内引用定义的, 倒是很好查找. 但是, 如果是来自第三方项目, 那来自哪些? 这样的阅读体验无疑让人很痛苦.

换个思路, 用社交关系网络的概念来生成图, 让各种依赖关系一目了然.

IDEAS

rails 依赖许多gem. 现在, rails 的主要模块本身就被拆成了数个独立的gem. 我们可以理解为rails依赖这些gem. 同时, 这些gem又依赖于其他的gem. 拨出萝卜带出泥, 不胜期烦.

从社交关系的角度来看问题, 我们作如下两点设定:

  1. 一个项目是一个社交圈
  2. 项目中运行的每一个gem, 即为圈子内的一个独立的用户.
  3. 如果 gemA 依赖于 gemB , 即 gemA 关注了gemB, 换而言之 gemA 是 gemB 的粉丝. 即画一个gemA指向gemB的有向箭头指向.

最终生成的图, 通过看线条与箭头, 我们可以清楚地看到哪些 Gem 受欢迎(大批的粉丝).

有了思路, 接下来就要考虑如何实现的问题了.

HOW?

  1. 用户(gem)列表数据, 即图内的节点.
  2. 用户(gem)关系数据, 即节点间的有向线段.
  3. 数据可视化方案. 即展示方案, 或者说绘图方案. 错综复杂的关系如何布局与绘图非常重要.

问题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)可以很好地解决这个问题.

取数据, 生成Graphviz有效的文件

创建一个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!

再来一个 web 版的吧.

google的结果是arborjs勉强可以干这事儿, 而且arborjs语法类似Graphviz的语法. 使用源码中的demo,复制一份json文件, 将生成的.gv的主内容帖进, hack一下, 测试, 发布:

在线演示地址: http://gemrelationship.zhuboliu.me 在线站点支持节点拖曳. 支持在线编辑, 可以考虑直接在项目要目录下生成的文件帖到右边的框内, 实时生成关系图.

如果你需要使用此演示站的功能生成自己的ruby项目, 请确保项目使用bundlerGemfile.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

后续开发意见征集

  • 有必要做成一个gem吗? 添加command line, 在ruby项目下运行即直接生成相应关系图.
  • 或者, 做成engine, 在开发模式下, 随时可能通过链接进入到一个页面看到指向关系图? 类似http://localhost:3000/rails/info的功能.
  • 在前两者的基础上做些 option 定制, 可以手动选定中心结点? 或者为结点加上链接, 可直接点到相应gem的官方文档页去?
  • 其他

请有好的意见 @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/

共收到 20 条回复
25
reyesyang · #1 · 2015年7月15日

赞,ActiveSupport 好火。哈哈

709
suffering · #2 · 2015年7月15日

#1楼 @reyesyang , ActiveSupport 就是一大堆扩展, 连 KernelObject都没放过. 很多时候, Rails 的源码里蹦出来一个不知根脚的方法都是出自ActiveSupport.

13051
ftandy · #3 · 2015年7月15日

太nice

8
hooopo · #4 · 2015年7月16日 3 个赞

bundle viz 吧,还带group信息...

709
suffering · #5 · 2015年7月16日

bundle viz是个好东西啊, 都不知道有这个命令. 愚蠢地重造了轮子了.

1286
easyhappy · #6 · 2015年7月16日

这个 coooooool

96
femto · #7 · 2015年7月16日

@suffering 挺好,bundle viz在我rails项目下面会报错, NoMethodError: undefined method `runtime_dependencies' for nil:NilClass, 试了一下,在middleman项目下挺好的。

4755
martin91 · #8 · 2015年7月16日

#5楼 @suffering 赞一个,千万不要因为造了轮子而觉得不好,要知道,不是每一个人都拥有造轮子的能力,造轮子的过程本身就是学习!

709
suffering · #9 · 2015年7月16日
1342
ywjno · #10 · 2015年7月16日

轮子还是要造的,F1赛车用的轮子跟空客 A380 的轮子能是一样的东西么

4755
martin91 · #11 · 2015年7月16日

#9楼 @suffering 我也一直对关系图生成比较感兴趣,请问 Graphviz 是只要你提供必要的数据,节点布局跟线条那些都是它负责的吗?开发者只需要保证输入的数据是吧?

709
suffering · #12 · 2015年7月16日

#11楼 @martin91 ,是的. 节点线条都是它负责. 当然, 你也可以自己选择控制每一个节点. 包括节点的形状, 线条的颜色, 粗细, 虚线还是实线, 有无箭头等等. 这个帖子里的没有作任何相关的设定. 只声明了节点与关系. Graphviz自动用默认设置生成了整张图.

709
suffering · #13 · 2015年7月16日

#11楼 @martin91 , 这里有一个Graphviz的ruby gem工具: https://github.com/glejeune/Ruby-Graphviz, 有兴趣可以研究一下.

4755
martin91 · #14 · 2015年7月16日

#12楼 @suffering 好的,谢谢,明白了

96
boyishwei · #15 · 2015年7月16日

可以参考java, groovy界的gradle, 可以将所有的依赖生成一个dependency tree, 一目了然~

17915
caiqinghua · #16 · 2015年7月17日

#5楼 @suffering 造轮子,说明有研究精神。现在拿来主义居多,造轮子的少了

8229
scott1743 · #17 · 2015年7月19日

ios端mark

1770
playmonkey · #18 · 2015年7月20日

自己项目跑了一下bundle viz ,关系多得无法直视啊!~~

15420
pathbox · #19 · 2015年7月24日

已经眼花

20859
adamshen · #20 · 2015年9月12日

确实麻烦,我一般用RubyMine直接Go to define

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册