From: Stefano Crocco Date: 2007-09-20T03:22:15+09:00 Subject: Re: YAML & readlines & modify text files Alle mercoled� 19 settembre 2007, Dan George ha scritto: > On Sep 19, 5:27 pm, Stefano Crocco wrote: > > Alle mercoled� 19 settembre 2007, Dan George ha scritto: > > > > I'm not at all sure I understand correctly what you want to do. I think > > you want to replace the line under > > > > Name-line: Name01 > > > > with some text containing a string taken from the Name01 entry in the > > yaml file. Is it correct? If it isn't, then please explain better what > > you mean. Otherwise, read on. > > > > In my opinion, you're storing data in the YAML file in the wrong way, > > because, at each iteration, name contains only one pair of > > name/replacement string, which forces you to iterate over all the files > > for each document in the YAML file (and also makes the replacing code > > more complicated). I think your YAML file should contain a single hash, > > with the names as keys and the replacement strings as values: > > > > --- > > Name01: N01 > > Name02: N02 > > > > Then, you can do the following (untested) > > > > require 'yaml' > > lnk = 'blabla.something.' > > op = '&=bla' > > hash = File.open('name.yaml'){|f| YAML.load f} > > Dir.glob('**/.txt').each do |path| > > lines = File.readlines(path) > > lines.each_with_index do |line, i| > > if line.match(/Link-line/) > > match = lines[i-1].match(/Name-line:\s(.*)$/)[1] > > line.gsub!(/Link-line.*/, 'Link-line: '+ lnk+hash[match[1]]+ > > op) if match and hash.has_key?(match[1]) > > end > > end > > File.open(path,'w'){|f| f.write lines} > > end > > > > When iterating on the lines, the block is passed not only the line, but > > also the line number. This way, when you meet a Link-line line, you can > > access the corresponding name-line using its index. It then matches the > > previous line with a regexp to extract the name from it and stores the > > result in the match variable. If match is not nil (i.e if the name line > > had the expected format) and the name is included in hash, the > > replacement is performed (of course, you can skip this test if you're > > confident enough in the format of the files and in the contents of the > > yaml file) > > > > I hope this helps > > > > Stefano > > You are correct, that is what I want! > > I tryied what you suggested but I get some weird errors: > > new.rb:45: undefined method `[]' for nil:NilClass (NoMethodError) > from D:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in > `each_with_index' > from new.rb:43:in `each' > from new.rb:43:in `each_with_index' > from new.rb:43 > from new.rb:41:in `each' > from new.rb:41 > > Line 45 is: match = lines[i-1].match(/Name-line:\s(.*)$/)[1] > Line 43 is: lines.each_with_index do |line, i| > Line 41 is: Dir.glob('**/*.jad').each do |path| > > I don't get it, as far as I can tell the code is ok... I think it's because of a mistake in my code: the [1] part of line 45 shouldn't be there (it's a leftover from a previous version of the code). If I'm right, the string doesn't match the regexp, so lines[i-1].match(...) returns nil, which doesn't have a [] method, leading to the error you get. Avod to call nil.[] is the reason for the conditional at the end of the following line (note that the conditional checks that match is not nil before trying to extract an element from it), but this is useless if I call it on the line before. Removing that [1] from line 45 should solve your porblem. However, if you found this mistake, it may mean that there's something amiss in either your .txt files or your yaml file (see the end of my previous post). Stefano