这条新线来自哪里?

时间:2010-07-02 17:36:14

标签: ruby regex rake

我正在使用rake脚本来标记我的.NET项目中的AssemblyInfo.cs文件,但是引入了一个幻像回车(或换行符等),它正在打破编译。获取版本号的方法是:

def get_version()
  version = ''
  IO.popen("#{SVNVERSION_APPLICATION} #{build_info.root_dir}") do |output|
    output.readlines.each do |line|
      version << line.gsub(/\:.*/, '')
    end
  end
  result = version
end

如果有更好的方法,请告诉我。我在这里大部分都在修补(这实际上是我曾经做过的第一个Ruby,所以请耐心等待)。正如你所看到的(我的正则表达式技能从未真正成为忍者级别)我只是试图摆脱第一个冒号以及它之后的一切。 Svnversion返回“64:67M”之类的内容,我只对第一个数字感兴趣。

然后我将文件标记为:

contents = contents.gsub(/AssemblyVersion\(\"([\d.*]*)\"\)/, "AssemblyVersion(\"#{helper.build_info.build_number_template}\")")

当然,围绕这些位的代码更多。这只是正在发生的事情。基本上,在任务中,我调用get_version将版本号存储在辅助对象上,该对象稍后用于将AssemblyInfo.cs文件读入“内容”的方法中,并进行替换并将其写回。

除了输出中的幻影换行符外,一切正常:

[assembly: AssemblyVersion("1.1.0.62
")]
[assembly: AssemblyFileVersion("1.1.0.62
")]

我已经尝试添加另一个.gsub来尝试过滤掉\ n和\ r,没有运气,我已经尝试过.chomp等等。似乎总是将新行放在生成的文件中。

我错过了一些明显的东西吗?

[编辑以回应第一个回答:]

以下是编辑AssemblyInfo.cs文件的方法:

def replace_assembly_strings(file_path, helper)

    if not (File.exists?(file_path) || File.writable?(file_path))
      raise "the file_path \"#{file_path}\" can not be written to.  Does it exist?"
    end

    path = Pathname.new(file_path)
    contents = path.read
    puts "AssemblyVersion(\"#{helper.build_info.build_number_template}\")"
    contents = contents.gsub(/AssemblyVersion\(\"([\d.*]*)\"\)/, "AssemblyVersion(\"#{helper.build_info.build_number_template}\")")
    contents = contents.gsub(/AssemblyFileVersion\(\"([\d.*]*)\"\)/, "AssemblyFileVersion(\"#{helper.build_info.build_number_template}\")")
    contents = contents.gsub(/AssemblyCompany\(\"(.*)\"\)/, "AssemblyCompany(\"#{helper.build_info.company}\")")
    contents = contents.gsub(/AssemblyCopyright\(\"(.*)\"\)/, "AssemblyCopyright(\"#{helper.build_info.copyright}\")")

    File.open(file_path, 'w') {|f| f.write(contents)}

  end

puts行输出AssemblyVersion("1.1.0.62")但结果文件显示AssemblyVersion("1.1.0.>")

2 个答案:

答案 0 :(得分:1)

Readlines不会隐含地从行尾删除换行符。通常人们会选择chomp!在结果上。您可以使用p方法(或调试器,我猜)计算这样的事情,在调用gsub之前添加p line。然后你应该看到(除非我非常错误)您的版本实际上看起来像"64:67M\n"但是,您有一个更简单的解决方案,String#to_i会将字符串转换为int,直到找到非数字。所以"64:67M".to_i # => 64"64:67M\n".to_i # => 64这使您无需成为正则表达式忍者,并解决了换行问题。

答案 1 :(得分:1)

这并没有真正解决你的问题,这里有一点重构第二种方法,使它看起来更像是惯用的红宝石。我知道我在学习语言时用同样的方式编写了它,但是有很多东西使得这个函数看起来像C#或用ruby编写的java。

def replace_assembly_strings path, helper
  raise %{the path "#{path}" can not be written to.  Does it exist?} unless File.exists?(path) or File.writable?(path)

  file = Pathname.new(path).read

  methods = {/(AssemblyVersion\(\")[\d.*]*(\"\))/      => helper.build_info.build_number_template, 
             /(AssemblyFileVersion\(\")[\d.*]*(\"\))/  => helper.build_info.build_number_template, 
             /(AssemblyCopyright\(\").*(\"\))/         => helper.build_info.copyright,
             /(AssemblyCompany\(\").*(\"\))/           => helper.build_info.company}

  methods.keys.each do |regex| 
    file.gsub! regex, "\1#{methods[regex]}\2"
  end

  File.open(path, 'w') {|f| f.write(file)}
end

ruby​​代码中涉及很多个人风格,这就是我的方式。在我学习的时候,这种事情对我来说是纯金,所以我将逐步详细说明为什么我改变了我所改变的东西。

所以,从顶部开始:)

首先,我从方法签名中删除了parens。作为一般惯例,除非你需要,否则你不应该使用parens,因为过多的标点符号往往会使内容难以阅读。同样从file_path转到路径,这只是一个简洁的事情(和个人品味)

接下来,您永远不会在ruby中看到if not,始终使用unless。需要一点时间来习惯,但读取时需要做的布尔代数越少越好。删除了一些parens(与第一次相同的推理),并将||切换为or

说到and/or vs &&/||,我更喜欢前者(回到标点符号)。话虽如此,由于运算符优先级的不同,使用该表单可能会发生相当大的问题。假设你有类似的东西

def foo bar
  'foobar!' if bar
end

foobar = foo false || true
# foobar == 'foobar!'

首先发生的事情是false || true评估到true,然后true会传递到foo。如果我们走另一条路

foobar = foo false or true
# foobar == true ????

首先,false将传递给foofoo将返回nilnil在布尔表达式中被视为false,因此nil or true最终会评估为true

正如您所看到的,这可能导致真正奇怪的错误。因此,很多rubyists只使用&amp;&amp; / ||完全形成。就个人而言,我只是试着记住这个问题,因为我真的喜欢和/或更好。

在guard子句的最后一点,我交换了%{...}语法的引号。有一种绝对疯狂的方法可以在ruby中创建字符串文字。因此,总有办法避免不得不逃避你的报价。

接下来的改变只是简洁的名义。一般来说,我尽量减少我使用的变量,尽管这也是一种风格。

下一次变化是最大的。

我做的第一件事就是改变你所有的正则表达式,在我们希望保持不变的开始和结束位置周围进行分组(()),并删除我们想要改变的东西的分组。我这样做是因为使用gsub,我们可以获得对另一方的组匹配的引用(\1是第一组,\2第二组)。在减少噪音方面,这有很大帮助,正则表达已经足够难以阅读; - )

接下来,我试图解决你基本上是以蛮力的方式将相同的操作应用于四件事。当你发现自己这样做时,如果你将操作与想要操作的操作分开,通常会使事情变得更加清晰。这里的另一个考虑因素是我们正在处理适度长的正则表达式,这些正则表达式本身很难全部阅读。

将这些内容放入正则表达式的哈希值中,并将其替换为更清晰的内容。所以现在我们可以遍历那个哈希并进行替换。

您可能会注意到我已将gsub更改为gsub!,并取消了作业。一般而言,以!结尾的方法将是不以!结尾的方法的变体,但在某种程度上您必须更加注意使用它。在这种情况下,gsub返回带有替换的新字符串,gsub!进行替换。这里的另一点是,在ruby中,字符串是可变的,这是与C#的细微差别,但允许像现场替换这样的事情。

一般来说,大多数差异可归结为三件事; DRY(不要重复自己)在ruby中进一步使用它然后它在C#中,除非你需要,否则不要使用标点符号,并且通过尽可能少打字(在降低可读性之前)来处理语言的简洁性< / p>

如果您有任何意见/问题,请告诉我,祝您在进一步的红宝石冒险中好运:)