如何从多个文件中提取代码片段的特定部分,这些文件在不同文件中可能不同
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 {$&}
正则表达式依赖于:
- 使用组
(\s*)
、 捕获空格(缩进)
- 后跟文字
def has_many
。
- 然后它使用
(?:.*+\n)*?
尽可能少的行。
注意 .*+\n
匹配整行
(?:
..)*?
重复 0 次或更多次。另外,最后的?
使得重复lazy(尽可能少)。
它将消耗行直到它符合以下条件...
</code>是一个<strong><a href="http://www.regular-expressions.info/backref.html" rel="nofollow">backreference</a></strong>,存储了<strong>(1)</strong>中匹配的文本,即准确与第一行相同的缩进。</li>
<li>后面显然是<code>end
。
测试在 Rubular
所以我正在做的是迭代各种版本的代码片段(例如 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 {$&}
正则表达式依赖于:
- 使用组
(\s*)
、 捕获空格(缩进)
- 后跟文字
def has_many
。 - 然后它使用
(?:.*+\n)*?
尽可能少的行。
注意.*+\n
匹配整行
(?:
..)*?
重复 0 次或更多次。另外,最后的?
使得重复lazy(尽可能少)。
它将消耗行直到它符合以下条件... </code>是一个<strong><a href="http://www.regular-expressions.info/backref.html" rel="nofollow">backreference</a></strong>,存储了<strong>(1)</strong>中匹配的文本,即准确与第一行相同的缩进。</li> <li>后面显然是<code>end
。
测试在 Rubular