Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Static Analysis ใน Ruby: ดึง Methods และ Parameters ด้วย Parser Gem

สมมติอยาก parse source code หา methods ทั้งหมด define ที่ไหน และรับ arguments อะไร ทำไง?

ความคิดแรกอาจเป็น regexp... แต่มีวิธีดีกว่าไหม?

เชี่ยวชาญ Static Analysis ใน Ruby: ดึง Methods และ Parameters ด้วย Parser Gem

มี! Static analysis คือเทคนิคใช้ตอนต้องดึงข้อมูลจาก source code เอง ทำโดยแปลง source code เป็น tokens (parsing)

มาเริ่มเลย!

Using the Parser Gem

Ruby มี parser ใน standard library ชื่อ Ripper แต่ output ยากต่อการใช้งาน ผมชอบ parser gem รูบิคอปใช้ gem นี้ทำ magic

Gem นี้มี binary ใช้ parse code โดยตรงดู parse tree ได้

ตัวอย่าง:

ruby-parse -e '%w(hello world).map { |c| c.upcase }'

Output 长得像这样:

(block (send (array (str "hello") (str "world")) :map) (args (arg :c)) (send (lvar :c) :upcase))

มีประโยชน์ตอนพยายามเข้าใจ Ruby parse code บางอย่าง แต่ถ้าอยากสร้าง analysis tools เอง ต้อง read source file, parse, แล้ว traverse generated tree

ตัวอย่าง:

require 'parser/current'
code = File.read('app.rb')
parsed_code = Parser::CurrentRuby.parse(code)

Parser คืน AST (Abstract Syntax Tree) ของโค้ด อย่าตื่นตระหนกชื่อ มันง่ายกว่าที่คิด 🙂

Traversing The AST

ตอนมี parsed code ด้วย parser gem ต้อง traverse AST ที่ได้ สร้าง class inherit จาก AST::Processor

ตัวอย่าง:

class Processor < AST::Processor
end

Instantiate class เรียก .process method:

ast = Processor.new
ast.process(parsed_code)

Define on_ methods ตรงกับ node names ใน AST หา methods ที่ต้อง define 加上 handler_missing method ใน Processor class ต้องมี on_begin method ด้วย

class Processor < AST::Processor
  def on_begin(node)
    node.children.each { |c| process(c) }
  end
  def handler_missing(node)
    puts "missing #{node.type}"
  end
end

ตอนนี้เราที่ไหน: มี Ruby AST และ basic processor รันโค้ดจะเห็น node types ของ AST

ตอนนี้: Implement on_ methods ที่อยากใช้ เช่นอยากได้ instance method names กับ line numbers:

def on_def(node)
  line_num = node.loc.line
  method_name = node.children[0]
  puts "Found #{method_name} at line #{line_num}"
end

รันโปรแกรมตอนนี้ควรพิมพ์ method names ทั้งหมดที่เจอ

สรุป

สร้าง Ruby static analysis tool ไมายากเท่าที่คิด ถ้าอยากตัวอย่างสมบูรณ์กว่านี้ดู class_indexer gem ของผม ตอนนี้ถึงคุณสร้าง tools ของตัวเอง!

แชร์โพสต์นี้ ถ้าชอบ! 🙂