You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过静态分析Ruby代码提取指定方法的调用参数

静态分析Ruby代码提取指定请求处理方法的响应码

解决方案思路

  • 使用parser gem解析Ruby代码生成抽象语法树(AST),替代ruby2ruby(后者更适合代码生成而非静态分析)
  • 构建代码库内所有方法的AST映射,递归遍历目标方法及其调用的内部方法
  • 在每个方法的AST中查找send_response调用,提取响应码参数
  • 自动排除未被调用的方法中的响应码

实现步骤与代码示例

1. 安装依赖

gem install parser

2. 实现分析器(maintainance_scripts/response_code_analysis.rb)

require 'parser/current'
require 'set'

class ResponseCodeAnalyzer
  def initialize(target_files)
    @target_files = target_files
    @method_asts = {} # 存储方法名到方法体AST的映射
    parse_all_files
  end

  # 提取指定请求类型对应的所有响应码
  def all_response_codes_for_request(type)
    target_method = "handle_request_type_#{type}"
    visited = Set.new
    codes = Set.new

    crawl_method_calls(target_method, visited, codes)
    codes.to_a.sort
  end

  private

  # 解析所有目标文件,构建方法AST映射
  def parse_all_files
    @target_files.each do |file|
      ast = Parser::CurrentRuby.parse(File.read(file))
      traverse_ast_for_methods(ast)
    end
  end

  # 遍历AST,收集所有方法定义
  def traverse_ast_for_methods(node)
    return unless node.is_a?(Parser::AST::Node)

    case node.type
    when :def # 实例方法定义
      method_name = node.children[0].to_s
      @method_asts[method_name] = node.children[2]
    when :defs # 类/模块方法定义
      method_name = node.children[1].to_s
      @method_asts[method_name] = node.children[3]
    end

    node.children.each { |child| traverse_ast_for_methods(child) }
  end

  # 递归爬取方法调用链,收集响应码
  def crawl_method_calls(method_name, visited, codes)
    return if visited.include?(method_name)
    return unless @method_asts.key?(method_name)

    visited.add(method_name)
    method_body = @method_asts[method_name]

    scan_method_body(method_body, visited, codes)
  end

  # 扫描方法体AST,查找send_response调用和内部方法调用
  def scan_method_body(node, visited, codes)
    return unless node.is_a?(Parser::AST::Node)

    if node.type == :send
      _, method_sym, *args = node.children
      called_method = method_sym.to_s

      # 提取send_response的字符串响应码
      if called_method == 'send_response' && args.first&.type == :str
        codes.add(args.first.children[0])
      # 递归处理内部定义的方法调用
      elsif @method_asts.key?(called_method)
        crawl_method_calls(called_method, visited, codes)
      end
    end

    node.children.each { |child| scan_method_body(child, visited, codes) }
  end
end

# 使用示例
if __FILE__ == $0
  analyzer = ResponseCodeAnalyzer.new([
    '../request_handling_helper_methods.rb',
    '../handle_request.rb'
  ])
  puts analyzer.all_response_codes_for_request(1).inspect
end

关键注意事项

  • 方法类型覆盖:同时处理实例方法(:def节点)和类/模块方法(:defs节点),适配代码库的不同定义风格
  • 内部方法识别:只递归代码库内定义的方法,避免跟踪Ruby内置方法或第三方库方法,减少无效遍历
  • 动态场景限制:对于动态方法调用(如send("handle_#{var}")),静态分析无法完全覆盖,若代码中存在这类场景,可结合少量运行时日志补充
  • 非字符串响应码:如果响应码使用变量而非直接字符串,静态分析无法提取具体值,这种情况需要额外的数据流分析逻辑(可扩展parser的数据流分析能力)

内容的提问来源于stack exchange,提问作者Andy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 16:17:33