Get line number of beginning and end of Ruby method given a ruby file
如何在给定ruby文件的情况下找到Ruby方法的开头和结尾的行?
比如说:
1 2 3 4 5 | 1 class Home 2 def initialize(color) 3 @color = color 4 end 5 end |
给定文件
找到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | require"parser/current" def recursive_find(node, &block) return node if block.call(node) return nil unless node.respond_to?(:children) && !node.children.empty? node.children.each do |child_node| found = recursive_find(child_node, &block) return found if found end nil end src = <<END class Home def initialize(color) @color = color end end END ast = Parser::CurrentRuby.parse(src) found = recursive_find(ast) do |node| node.respond_to?(:type) && node.type == :def && node.children[0] == :initialize end puts"Start: #{found.loc.first_line}" puts"End: #{found.loc.last_line}" # => Start: 2 # End: 4 |
附:我会推荐标准库中的Ripper模块,但据我所知,没有办法从它中获得结束。
Ruby有一个
1 2 3 4 5 6 7 8 | class Home def initialize(color) @color = color end end p Home.new(1).method(:initialize).source_location # => ["test2.rb", 2] |
要找到结束,也许要寻找下一个
我假设该文件包含最多一个
唯一棘手的部分是找到包含
码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def get_start_end_offsets(fname) start = nil str = '' File.foreach(fname).with_index do |line, i| if start.nil? next unless line.lstrip.start_with?('def initialize') start = i str << line.lstrip.insert(4,'_') else str << line if line.strip =="end" begin rv = eval(str) rescue SyntaxError nil end return [start, i] unless rv.nil? end end end nil end |
例
假设我们正在搜索如下创建的文件1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | str = <<-_ class C def self.feline "cat" end def initialize(arr) @row_sums = arr.map do |row| row.reduce do |t,x| t+x end end end def speak(sound) puts sound end end _ FName = 'temp' File.write(FName, str) #=> 203 |
我们首先搜索开始的行(在去除前导空格之后)
让我们看看这是否是我们得到的。
1 2 | p get_start_end_offsets(FName) #=> [4, 10] |
说明
变量
我们现在寻找
我已将
查看此SO问题的两个答案,以了解为什么
比较缩进
如果已知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def get_start_end_offsets(fname) indent = -1 lines = File.foreach(fname).with_index.select do |line, i| cond1 = line.lstrip.start_with?('def initialize') indent = line.size - line.lstrip.size if cond1 cond2 = line.strip =="end" && line.size - line.lstrip.size == indent cond1 .. cond2 ? true : false end return nil if lines.nil? lines.map(&:last).minmax end get_start_end_offsets(FName) #=> [4, 10] |
1文件不必仅包含代码。
Ruby源只是一个文本文件。您可以使用linux命令查找方法行号
1 | grep -nrw 'def initialize' home.rb | grep -oE '[0-9]+' |