Ruby I / O:Rails rake任务试图找到并替换某些代码行,但却没有

时间:2012-07-18 13:42:14

标签: ruby-on-rails ruby

我正在开展一项rake任务,可以更改某些页面的元标记。这些标签在控制器中定义。 rake任务是打开控制器文件,在其中找到包含短语“@meta_tag”的任何行,然后按照replace_line(line)方法重写该行。当我运行rake任务时,我没有收到任何错误,但它也没有进行任何更改。

我认为我的问题出在'r +'行。我是否需要在一行中打开文件并在另一行代码中写入?

require 'rake'
namespace :meta_tags do
  desc 'changes the meta tags'
  task :update => :environment do 

    regex = /@meta_tag/
    found = false
    file = File.open('app/controllers/site_controller.rb', 'r+')
    file.each_line do |line|
      replace_line(line) if(found)
      found = true if(line =~ regex)
    end
  end

  def replace_line(line)
    meta_tags = MetaTag.all.map { |tag| tag["tag"] }
    new_tag = meta_tags.sample(1)[0]
    line = "@meta_tag = #{new_tag}"
  end
end

如果你看到我做错了什么,请告诉我。

1 个答案:

答案 0 :(得分:1)

嗯,你实际上并没有在任何地方写入文件。 each_line正如它所说的那样,它遍历文件中的每一行(实际上它会读取直到有换行符然后将此行生成到您提供的块)。

但是现在只使用file.write并不是一个好主意,因为 inplace 文件写入不能像您期望的那样工作。因为文件是基于字节/字符的,所以替换行必须与旧文件一样长。

所以你应该选择正常使用的阅读然后写的做法。此外,您当前的代码会改变后的行 @meta_tag发生,但您的问题表明这不是什么 你要。 以下是适用于您的情况的示例:

require 'rake'
namespace :meta_tags do
  desc 'changes the meta tags'
    task :update => :environment do 

    regex = /@meta_tag/
    # only 'r' since you will only read the file,
    # although you could use 'r+' and just change the lineno
    # back to 0 when finished reading...
    file = File.open('app/controllers/site_controller.rb', 'r')
    lines = []
    file.each_line do |line|
      # i don't think you need the found variable,
      # it is simple if-then/else
      (line =~ regex) ? (lines << replace_line(line)) : (lines << line)
    end
    file.close
    file = File.open('app/controllers/site_controller.rb', 'w')
    # you could also join the array beforehand,
    # and use one big write-operation,
    # i don't know which approach would be faster...
    lines.each{|line| file.write line} 
    file.close
  end

  def replace_line(line)
    meta_tags = MetaTag.all.map { |tag| tag["tag"] }
    new_tag = meta_tags.sample(1)[0]
    line = "@meta_tag = #{new_tag}\n" # added the newline
  end
end