static code analysis for ruby

34
Static Code Analysis for Ruby Richard Huang Ekohe www.ekohe.com Web Development & Graphic Design China Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

Post on 12-Sep-2014

4.433 views

Category:

Technology


9 download

DESCRIPTION

This is my presentation on Shanghai on Rails at 3.20. It introduces static code analysis for ruby, tells you a pattern to analysis ruby code and gives you some examples that how rails_best_practices analysis rails codes.

TRANSCRIPT

Page 1: Static Code Analysis For Ruby

Static Code Analysis for Ruby

Richard HuangEkohe

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

Page 2: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

有没有对 Ruby 代码进行过静态分析?

Page 3: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

案例

Page 4: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

有没有看过张文钿的演讲稿 Rails Best Practices ?

http://www.slideshare.net/ihower/rails-best-practices

Page 5: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

有没有使用过 rails_best_practices gem?http://github.com/flyerhzm/rails_best_practices

Page 6: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

静态分析 VS 动态分析• 整体 VS 局部• 粗略 VS 精确

Page 7: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

静态分析什么?源程序?

Page 8: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

抽象语法树 (AST)assign

a

*

+

*

b bc c

• a = b * c + b * c

Page 9: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

s-expression s(:class, :Student, nil, s(:scope, s(:block, s(:call, nil, :attr_accessor, s(:arglist, s(:lit, :name)) ), s(:defn, :initialize, s(:args, :name), s(:scope, s(:block, s(:iasgn, :@name, s(:lvar, :name)) ) ) ))))

class Student attr_accessor :name

def initialize(name) @name = name endend

Page 10: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

s-expressions(:defn, :output, s(:args, :arg1, :arg2), s(:scope, s(:block, s(:if, s(:call, s(:lvar, :arg1), :==, s(:arglist, s(:str, "hello")) ), s(:call, nil, :print, s(:arglist, s(:lvar, :arg1), s(:lvar, :arg2)) ), s(:call, nil, :print, s(:arglist, s(:lvar, :arg1)) ) ) ) ))

def output(arg1, arg2) if arg1 == 'hello' print arg1, arg2 else print arg1 endend

Page 11: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

s-expression 的特点• 类树(继承数组)• 结构清晰• 方便解析

Page 12: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

ruby 源代码 s-expression

ruby_parser

ruby2ruby

如何生成 s-expression

Page 13: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

如何解析 s-expression ?• Visitor Pattern

• 优点:– 数据结构与访问类分离– 方便地增加访问类

• 缺点:– 增加数据类型很麻烦– 访问类只能处理当前结点

Page 14: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

rails_best_practices 是如何做静态代码分析的?

Page 15: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

rails_best_practices

rails_best_practices

结果输出

代码检查类代码解析器

配置源代码

5. 代码检查2. 生成检查类集合

3. 分析源代码4. 生成 s-

expression

1. 读取配置

6. 显示检查结果

Page 16: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

代码解析• 解析顺序

model files

migration filescontroller files

helper filesview files

……

migration files

Page 17: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

代码解析

erb files

haml files

ruby files

src

precompiled ruby_parser s-expression

Page 18: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

代码检查s-expression

class

defn

call

Check

UseModelAssociationCheck

MoveFinderToNamedScopeCheck

if UseScopeAccessCheck

LawOfDemeterCheck

Page 19: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

代码检查• Visitor Pattern 扩展

– 不仅关注结点的类型

– 而且关注结点所在的文件

Page 20: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

rails_best_practices 做静态代码分析的一些思路

Page 21: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

ReplaceInstanceVariableWithLocalVariableCheck

# app/views/posts/_post.html.erb<%= @post.title %><%= @post.body %>

Page 22: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

ReplaceInstanceVariableWithLocalVariableCheck

# app/views/posts/_post.html.erb<%= @post.title %>

在 partial文件中任何类型为 ivar的结点都违反

ivar s(:call, s(:ivar, :@post), :title, s(:arglist))

Page 23: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

MoveFinderToNamedScopeCheck

class PostsController < ApplicationController def index @published_posts = Post.find(:all, :limit => 10, :order

=> ‘created_at desc’) endend

Page 24: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

MoveFinderToNamedScopeCheck Post.find(:all, :limit => 10, :order => ‘created_at desc’)

在 controller文件中 find, all, first, last方法带类型为 hash的参数的都违反

constfind,all,

first,last

hashs(:call, s(:const, :Post), :find, s(:arglist, s(:lit, :all), s(:hash, s(:lit, :limit), s(:lit, 10), s(:lit, :order), s(:str, "created_at desc")) ))

Page 25: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

AddModelVirtualAttributeCheck

class UsersController < ApplicationController def create @user = User.new(params[:user]) @user.first_name = params[:full_name].split(‘ ‘, 2).first @user.last_name = params[:full_name].split(‘ ‘, 2).last @user.save endend

Page 26: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

[email protected]_name = params[:full_name].split(‘ ‘, 2).firstattrassign

@user.last_name = params[:full_name].split(‘ ‘, 2).lastattrassign

@user.save

对于一个 variable,如果接收到两条不同的赋值消息,但参数的 "首部分 "是相同的,那么它就违反

mesage arguments whose message is []

mesage arguments whose message is []

Page 27: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

LawOfDemeterCheck

class Invoice < ActiveRecord::Base belongs_to :userend

<%= @invoice.user.name %>

Page 28: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

LawOfDemeterCheck

class Invoice < ActiveRecord::Base belongs_to :userend

<%= @invoice.user.name %>app/models/*.rb 必须首先被解析

如果 variable的名字和model 的 class name匹配,同时调用的消息名和 association名字相同,则违反

message

class name

association name

Page 29: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

AlwaysAddDbIndexCheck

class CreateComments < ActiveRecord::Migration def self.up create_table :comments do |t| t.string :content t.integer :post_id t.integer :user_id end endend

Page 30: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

AlwaysAddDbIndexCheckcreate_table :comments do |t| t.string :content t.integer :post_id t.integer :user_idendadd_index :comments, :post_id

db/migrations/*.rb 必须被解析两次所有 create_table中创建的外键没有出现在 add_index的参数中,那么它就违反

table name

integer with _idcolumn with _id and integerreferences

Page 31: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

AlwaysAddDbIndexCheck

What about?

[[:comments, :post_id], [:comments, :user_id]].each do |args|

add_index *argsend

Page 32: Static Code Analysis For Ruby

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

AlwaysAddDbIndexCheck

Ruby2Ruby.new.process(node)

模拟 add_index,动态处理Ruby is Powerful!

def add_index(*args) table_name, column_names = *args table_name = table_name.to_s

# call AlwaysAddDbIndexCheck methodend

Page 33: Static Code Analysis For Ruby

静态代码分析代码检查代码重构

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development

Page 34: Static Code Analysis For Ruby

Q&A

Thank you

Website: http://www.huangzhimin.com

Github: http://github.com/flyerhzm

www.ekohe.comWeb Development & Graphic DesignChina Ruby on Rails Development - Rails Consulting - Rails Services - Merb - Offshore Web Development