Ruby File.open not creating file - ruby

I'm trying to create and write to a new file using
#logFile = File.open("C:\Users\---\Desktop\mylog.log", "w+")
And nothing happens. My program uses
#logFile.write ("Hello")
#logFile.flush
And this line seems to be running ok (no crashes or anything)
But i can't see any newly created file.
What am i missing out here?

Your backslashes are escaped, in a string enclosed with double quotes you need to double them, or just use the Unix notation.
So "C:\\Users\\---\\Desktop\\mylog.log"
or "C:/Users/---/Desktop/mylog.log"
or 'C:\Users\---\Desktop\mylog.log'
Paths in Ruby are safest in Unix notation, so even when you use backslashes for ease of copying you are better to convert them to Unix formatting.
like this 'C:\Users\---\Desktop\mylog.log'.gsub('\\','/')
The double backslash is also needed here, the ' and \ need to be escaped using single quotes.
Another tip not relevant tot the question but very handy: use the block method to open a file so that it is clear when the file is closed, see this example
File.open(path, 'w') do |file|
file.puts "Hello"
end
The file is closed after the end.
For logging though, take a look at logger, once you used it you won't stop using it.

You should always use path = File.join("C:","Program Files","Blah")
To ensure it works on any architecture.

Related

Dynamically generating the filename for svn status output

I have a chef-infra set-up with chef-node as a windows server. The cookbook (recipe) is trying to take the status of the svn working copy folder and write it in a file. The nomenclature of the output file is CHEFRPT_TESTREPO_ddmmyyyy hh:mm:ss.txt. However, the following code is failing to generate the desired
filename with date and time dynamically.
Following is the ruby code of the recipe:
time = Time.now
execute 'stat' do
cwd 'D:\inetpub\TEST_APP'
command 'svn status > D:\SVN_CHECKOUT\REPORTS\CHEFRPT_TESTREPO_#{time.strftime("%Y-%m-%d%H:%M:%S")}.txt'
end
Need some help regarding the variable to be appended at the end of the file to generate the filename with current date and time when it was generated.
Thank You!
You have to use double quotes " instead of your single quotes ' if you want to to interpolate code within a string with #{...}.
As you use single quotes in the command argument, this interpolation will not be performed and the string will be used as is (that is, including the #{time.stftime...} code in the string.
Your final resource should thus look like this:
time = Time.now
execute 'stat' do
cwd 'D:\inetpub\TEST_APP'
command "svn status > D:\\SVN_CHECKOUT\\REPORTS\\CHEFRPT_TESTREPO_#{time.strftime("%Y-%m-%d%H:%M:%S")}.txt"
end
See https://ruby-doc.org/core/doc/syntax/literals_rdoc.html#label-Strings for details about String literal syntax in Ruby.
This issue is coming up because file/folder names in Windows cannot have the colon (:) character. Try manually creating a file though UI or command line. Also see naming a file for the list of special characters that render the filename invalid.
Since we are creating a timestamp with time.strftime("%Y-%m-%d%H:%M:%S"), execute block is failing. Changing %H:%M:%S to some other accepted character should be enough.
Also, as #Holger Just pointed out in his answer, we need to use double quotes to interpolate the value of time.strftime.
In the example below I've used hyphen (-), i.e. %H-%M-%S:
execute 'stat' do
cwd 'D:\inetpub\TEST_APP'
command "svn status > D:\SVN_CHECKOUT\REPORTS\CHEFRPT_TESTREPO_#{time.strftime("%Y-%m-%d%H-%M-%S")}.txt"
end

change file extension with a ruby script

I'm trying to change the exstension of a file passing the arguments by console
system = "rename" , "'s/\#{ARGV[0]}$/\#{ARGV[1]}'", "*#{ARGV[1]}"
The code is correct because it works on console but when I put it in a script I have trouble with
s/\#
because it appears in pink and the console does not get it.
you don't want to send literal single quotes, so remove them.
you want to remove the backslashes so you let Ruby evaluate those expressions.
you're missing the trailing slash.
what's that equal sign doing?
did you want ARGV[0] in the last argument to rename, instead of ARGV[1]?
you want to use * wildcard, which requires a shell to expand into a list of files, which means you can't use the list form of system
Try
system "/usr/bin/rename -n 's/#{ARGV[0]}$/#{ARGV[1]}/' *#{ARGV[0]}"
Remove the -n option if it looks like you're going to rename the way you want.
And, of course, you don't need to call out to the shell for this:
Dir.glob("*#{ARGV[0]}").each {|fname|
newname = fname.sub(/#{ARGV[0]}$/, ARGV[1])
File.rename(fname, newname)
}

How to output file name inside system(git log) command in ruby script?

The problem I encounter is that I don't manage to put the name of the file inside the below screen output inside git log using pretty format flag.
An extract of my code is the following:
filename = File.basename file
system('git log --pretty=format:"%cd: (here I want the filename)"')
presented as sample.c for example.
I tried #{filename} but is interpreted as a string from the compiler and the result is the same as the input.
Thank you in advance.
It is interpreting it as a string because single quotes do now allow string interpolation.
system('git log --pretty=format:"%cd: (here I want the filename)"')
You can change this to use double quotes so you can take advantage of interpolation and escaping.
system("git log --pretty=format:\"%cd: #{filename}\"")
https://ruby-doc.org/core-2.1.1/doc/syntax/literals_rdoc.html

How to check many files exist with ruby code in windows

I want to check all file having .war extension and move them to another folder in chef-client windows but it does not work.
if !Dir.glob("C:\\tempwar\\*.war").empty?
execute 'mv-war' do
command 'move C:\tempwar\*.war C:\tomcat\webapps\ '
end
end
It's always best to build paths in ruby with ::File.join. This takes care of the path separators in a platform neutral way. Also, it's prefered to use Chef conditionals rather than wrapping things in an if. So try this:
execute 'mv-war' do
command "move #{::File.join('C:', 'tempwar', '*.war')} #{::File.join('C:', 'tomcat', 'webapps'} "
only_if { Dir.glob(::File.join('C:', 'tempwar', '*.war').empty? }
end
The backslash characters here are not being interpreted as a pathname separator. Your \t becomes a tab character, for example, and \* is just a *. Double the backslashes or use a single-quoted string and you have a fighting chance.

Single quote string interpolation to access a file in linux

How do I make the parameter file of the method sound become the file name of the .fifo >extension using single quotes? I've searched up and down, and tried many different >approaches, but I think I need a new set of eyes on this one.
def sound(file)
#cli.stream_audio('audio\file.fifo')
end
Alright so I finally got it working, might not be the correct way but this seemed to do the trick. First thing, there may have been some white space interfering with my file parameter. Then I used the File.join option that I saw posted here by a few different people.
I used a bit of each of the answers really, and this is how it came out:
def sound(file)
file = file.strip
file = File.join('audio/',"#{file}.fifo")
#cli.stream_audio(file) if File.exist? file
end
Works like a charm! :D
Ruby interpolation requires that you use double quotes.
Is there a reason you need to use single quotes?
def sound(FILE)
#cli.stream_audio("audio/#{FILE}.fifo")
end
As Charles Caldwell stated in his comment, the best way to get cross-platform file paths to work correctly would be to use File.join. Using that, your method would look like this:
def sound(FILE)
#cli.stream_audio(File.join("audio", "#{FILE}.fifo"))
end
Your problem is with your usage of file path separators. You are using a \. Whereas this may not seem like a big deal, it actually is when used in Ruby strings.
When you use \ in a single quoted string, nothing happens. It is evaluated as-is:
puts 'Hello\tWorld' #=> Hello\tWorld
Notice what happens when we use double quotes:
puts "Hello\tWorld" #=> "Hello World"
The \t got interpreted as a tab. That's because, much like how Ruby will interpolate #{} code in a double quote, it will also interpret \n or \t into a new line or tab. So when it sees "audio\file.fifo" it is actually seeing "audio" with a \f and "ile.fifo". It then determines that \f means 'form feed' and adds it to your string. Here is a list of escape sequences. It is for C++ but it works across most languages.
As #sawa pointed out, if your escape sequence does not exist (for instance \y) then it will just remove the \ and leave the 'y'.
"audio\yourfile.fifo" #=> audioyourfile.fifo
There are three possible solutions:
Use a forward slash:
"audio/#{file}.fifo"
The forward slash will be interpreted as a file path separator when passed to the system. I do most my work on Windows which uses \ but using / in my code is perfectly fine.
Use \\:
"audio\\#{file}.fifo"
Using a double \\ escapes the \ and causes it to be read as you intended it.
Use File.join:
File.join("audio", "#{file}.fifo")
This will output the parameters with whatever file separator is setup as in the File::SEPARATOR constant.

Resources