解析任意 Ruby 代码以创建传递给特定方法的所有调用的列表参数

Parsing arbitrary Ruby code to create a list arguments passed to all invocations of a particular method

提问人:Andy 提问时间:3/1/2023 最后编辑:Andy 更新时间:3/2/2023 访问量:39

问:

我有一个继承的代码库,类似于以下简单示例:

request_handling_helper_methods.rb

def send_response(response_code)
  # create and post a response using response_code
  true
end

def handle_common_domain_errors(request)
  return send_response('E22') if request.contains('foo')
  # other checks that send different responses
  nil
end

def handle_unrelated_thing(request)
  return send_response('E777') if request.green?
end

handle_request.rb

require 'request_handling_helper_methods.rb'

def handle_request_type_1(request)
  return send_response('E1200') if request.not_type_1?

  return send_response('E88') if Date.today.is_tuesday?
  
  raise if handle_common_domain_errors(request)

  send_response('I100')
end

maintainance_scripts/response_code_analysis.rb

def all_response_codes_for_request(type)
  # ***THIS IS WHAT I AM UNSURE OF HOW TO POPULATE***
  # parse handle_request_type_#{type}
  # and return a list of all possible response codes
end

我希望解析 handle_request_type_1 中的代码并提取为所有方法调用传入的参数。all_response_codes_for_requestsend_response

该方法的预期输出为 。请注意,“E777”不应在列表中,因为该方法不是在方法中调用的。all_response_codes_for_request(1)['E22', 'E1200', 'E88', 'I100']handle_unrelated_thinghandle_request_type_1

如果我从头开始,知道从一开始就列出每种请求类型的所有可能代码的要求,我会考虑创建一个包含一些请求类型、方法名称和响应代码的 YAML/JSON 文件,但这是一个继承的代码库,包含 200 多种请求类型和大约 5,000 个或更多代码(定期添加新的请求类型和代码), 我想解析代码/进行静态分析以找出所有可能的代码。

对 的调用任意嵌套在其他方法中,跨多个文件。send_response

我知道一个名为“ruby2ruby”的宝石可以解析 ruby 代码,但这是否是解决这个问题的一部分,我不确定。

Ruby 解析 元编程

评论

0赞 Dave Newton 3/2/2023
这将是一场艰难的锄头。除了挂在请求之外的功能块之外,您还有基于请求内容的决策点。如果一切都基于可能的条件,那么您可以使用它来至少收集这些条件的列表,但是......耶,好玩。send_response
0赞 Dave Newton 3/2/2023
老实说,手动操作或使用测试套件可能更容易。
1赞 Dave Newton 3/2/2023
因为肯定有一个测试套件。
0赞 Andy 3/2/2023
感谢您的评论。有一些测试,但遗憾的是,并非所有情况下都适合所有请求!希望有人有答案,但至少扩大测试范围至少会用一块石头杀死 2 只鸟。
0赞 engineersmnky 3/2/2023
哦不。。。。好吧,一个功能强大但肮脏的解决方案是将所有文件都装进去,然后读取每个文件的每一行并提取代码,例如 可能有效?获取所有代码;但是,将其与方法定义对齐将很棘手。Dir.glob('path/**/*.rb').flat_map {|f| File.foreach(f).filter_map {|line| line.match(/send_response[\s\(]+?['"](.*?)['"]/)&.captures}}

答: 暂无答案