如何从多个文件中提取代码片段的特定部分,这些文件在不同文件中可能不同

How do I extract just a specific portion of a code snippet from multiple files, that may be different in different files

所以我正在做的是迭代各种版本的代码片段(例如 Rails 中的 Associations.rb)。

我想做的只是提取一小段代码,例如 has_many 方法:

  def has_many(name, scope = nil, options = {}, &extension)
    reflection = Builder::HasMany.build(self, name, scope, options, &extension)
    Reflection.add_reflection self, name, reflection
  end

起初我只想在整个文件中搜索字符串 def has_many,然后保存该字符串和 end 之间的所有内容。一个明显的问题是,这个文件的不同版本可以在方法中有多个 end 字符串。

例如,无论我为上面的代码片段想出什么,也应该适用于 this one too:

  def has_many(association_id, options = {})
    validate_options([ :foreign_key, :class_name, :exclusively_dependent, :dependent, :conditions, :order, :finder_sql ], options.keys)
    association_name, association_class_name, association_class_primary_key_name =
          associate_identification(association_id, options[:class_name], options[:foreign_key])

    require_association_class(association_class_name)

    if options[:dependent] and options[:exclusively_dependent]
      raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options.  You may specify one or the other.' # ' ruby-mode
    elsif options[:dependent]
      module_eval "before_destroy '#{association_name}.each { |o| o.destroy }'"
    elsif options[:exclusively_dependent]
      module_eval "before_destroy { |record| #{association_class_name}.delete_all(%(#{association_class_primary_key_name} = '\#{record.id}')) }"
    end

    define_method(association_name) do |*params|
      force_reload = params.first unless params.empty?
      association = instance_variable_get("@#{association_name}")
      if association.nil?
        association = HasManyAssociation.new(self,
          association_name, association_class_name,
          association_class_primary_key_name, options)
        instance_variable_set("@#{association_name}", association)
      end
      association.reload if force_reload
      association
    end

    # deprecated api
    deprecated_collection_count_method(association_name)
    deprecated_add_association_relation(association_name)
    deprecated_remove_association_relation(association_name)
    deprecated_has_collection_method(association_name)
    deprecated_find_in_collection_method(association_name)
    deprecated_find_all_in_collection_method(association_name)
    deprecated_create_method(association_name)
    deprecated_build_method(association_name)
  end

假设每个值都存储为 text 在我的数据库的某个列中。

我该如何处理这个问题,使用 Ruby 的字符串方法还是我应该用另一种方式处理这个问题?

编辑 1

请注意,此问题具体涉及通过使用 Regex 进行字符串操作,而无需解析器。

如前所述,这应该使用像 Ripper.

这样的解析器来完成

但是,为了回答是否可以使用字符串方法来完成,我会将语法与正则表达式匹配,前提是:

  • 您可以依靠缩进,即字符串在 "def" 之前和 "end".
  • 之前具有完全相同的字符
  • 中间没有多行字符串可以模拟具有相同缩进的 "end"。这包括多字节字符串、HEREDOC、%{ } 等。

代码

regex = /^
        (\s*)              # matches the indentation (we'll backreference later)
        def\ +has_many\b   # literal "def has_many" with a word boundary
        (?:.*+\n)*?        # match whole lines - as few as possible
                         # matches the same indentation as the def line
        end\b              # literal "end"
        /x

subject = %q|
  def has_many(name, scope = nil, options = {}, &extension)
      if association.nil?
        instance_variable_set("@#{association_name}", association)
      end
  end|


#Print matched text
puts subject.to_enum(:scan,regex).map {$&}

ideone demo


正则表达式依赖于:

  1. 使用组 (\s*)
  2. 捕获空格(缩进)
  3. 后跟文字 def has_many
  4. 然后它使用 (?:.*+\n)*? 尽可能少的行。
    注意 .*+\n 匹配整行
    (?:..)*? 重复 0 次或更多次。另外,最后的?使得重复lazy(尽可能少)。
    它将消耗行直到它符合以下条件...
  5. </code>是一个<strong><a href="http://www.regular-expressions.info/backref.html" rel="nofollow">backreference</a></strong>,存储了<strong>(1)</strong>中匹配的文本,即准确与第一行相同的缩进。</li> <li>后面显然是<code>end


测试在 Rubular