Expect scripting, source and return - expect

On page 35, in the book "Exploring Expect", it says "The return command can be used to make a source command return. Otherwise, source returns only after executing the last command in the file."
I don't quite understand what it's getting at. I'd like to know what this means and how this is useful.
Thank you.

an example:
main script:
puts "about to source external file"
set some_var true
source something.exp
puts "done sourcing"
something.exp
puts "in something.exp"
if {$some_var} return
puts "you won't see this if some_var is true"

Basically, when the 'return' command is encountered, 'expect' will stop processing the script further, and return to the parent script (if any) that ran it using the 'source' command. It's much like 'return' in any programming language.

Related

Nested `if` statement not evaluating the result of an operation

I am generating a file in a temp directory.
If the file to be generated is different from an already existing file, then I wan't to update it, and run a command. If it's the same, then I can do nothing.
My code looks like this:
errstatus = 0
if FileUtils.identical?('/var/tmp/newfile', '/var/tmp/originalfile')
$stderr.puts "Files are the same, nothing to do"
else
$stderr.puts "Files are different, let's update them."
if FileUtils.cp_r '/var/tmp/newfile', '/var/tmp/originalfile'
$stderr.puts "File copied successfully."
if system('systemcommand1 here')
$stderr.puts "command ran OK"
if system('systemcommand2 here')
$stderr.puts "next command ran ok"
else
$stderr.puts "command 2 failed"
errstatus = 1
end
else
$stderr.puts "command 1 failed"
errstatus = 1
end
end
end
When I run it when the files are different, I get the output:
Files are different, let's update them.
It runs with FileUtils.cp_r without any errors, but it doesn't tell that the File was copied successfully, or run the system command. I have used the same syntax to evaluate FileUtils.identical?, but it does not work for FileUtils.cp_r.
Where am I going wrong here?
FileUtils::cp_r returns nil (which in Ruby is falsy) if the copying was successful, raises an error if not. It will never return a truthy value, so making it a condition does not make sense.
Since it doesn't have an else statement right now, simply remove the if before it. If you want error handling for your cp_r, you will need to wrap it into a begin..rescue block.
Maybe it's because the if FileUtils.cp_r '/var/tmp/newfile', '/var/tmp/originalfile' doesn't have an else clause so if it returns false or throws and exception it doesn't enter the if.

How to use a conditional within a Ruby expect script

I'm playing with expect in Ruby but I'm a little lost as to how I can branch my code based on the behavior of a device I am logging into. How could I do say foo.run if I get the correct prompt below > but run foo.fail if I do not? Even further, how can I evaluate all of the text that comes back between entering the password and receiving the > prompt? Is there a way to look at all text that the device prints somehow?
def device_test(password)
$expect_verbose = true
PTY.spawn("ssh my-router") do |reader, writer, pid|
reader.expect("password:")
writer.puts(password)
reader.expect(">")
puts "logged in"
sleep(15)
end
end
It appears that the expect method can only look for a single pattern (unlike the Tcl expect library where you can look for multiple patterns simultaneously).
It looks like you'll have to pass a "timeout" parameter and check the return value:
if reader.expect(">", 2)
puts "foo.run"
else
# did not see ">" within 2 seconds
puts "foo.fail
end

Having trouble in getting input from user in Ruby

I have a method which check if the file exists, If the file does not exist then it should call another method which prompts the questions. Below is the sample code.
def readFile1()
flag = false
begin
#ssh.exec!("cd #{##home_dir}")
puts "\nChecking if file exists on #{#hostname}\n"
if #ssh.exec!("sh -c '[ -f "#{file_name}" ]; echo $?'").to_i == 0
flag = true
puts "File exists on #{#hostname}"
display()
else
puts "File does not exist. Please answer following questions."
prompt()
end
rescue => e
puts "readFile1 failed... #{e}"
end
return exists
end
def prompt()
puts "\nDo you want to enter the new file location? [y/n]"
ans = gets.chomp
puts "New location is #{ans}"
end
When I am calling readFile method, if the file does not exists, it prints Do you want to enter the new file location? [y/n] and does not wait for the user to enter the value but immediately prints the rescue block and quits. Below is the Output if file does not exists.
Checking if file exists on LNXAPP
File does not exist. Please answer following questions.
Do you want to enter the new file location? [y/n]
readFile1 failed... No such file or directory - LNXAPP
I want the user to enter the values for the questions but it's not happening.Need help in fixing this.
Your code is not ideal.
You should check if the file exists via:
if File.exist? location_of_your_file_goes_here
The begin/rescue is then not required, because
you already check before whether the file exists.
Also two spaces should be better than one tab,
at least when you display on a site such as here.
Reason is simple - it makes your code easier
to read for others.
You also don't need the flag variable if I am
right - try to omit it and use solely File.exist?
there.
Also you wrote:
"When I am calling readFile method"
But you have no method called readFile().
Your method is called readFile1().
I know that you probably know this too, but
you must be very specific so that the ruby
parser understands precisely what you mean,
and that what you describe with words also
matches to the code you use.
Another issue I see with your code is that
you do this:
return exists
but what is "exists" here? A variable?
A method? It has not been defined elsewhere
in your code.
Try to make your code as simple and as logical
as possible.

check for (the absence of) `puts` in RSpec

I am using rspec for my test in a ruby project, and I want to spec that my program should not output anything when the -q option is used. I tried:
Kernel.should_not_receive :puts
That did not result in a failed test when there was output to the console.
How do I verify the absents of text output?
puts uses $stdout internally. Due to the way it works, the easiest way to check is to simply use: $stdout.should_not_receive(:write)
Which checks nothing is written to stdout as expected.
Kernel.puts (as above) would only result in a failed test when it
is explictely called as such (e.g. Kernel.puts "Some text"), where
as most cases it's call in the scope of the current object.
The accepted answer above is incorrect. It "works" because it doesn't receive a :write message but it might have received a :puts message.
The correct line should read:
$stdout.should_not_receive(:puts)
Also you need to make sure you put the line before the code that will write to STDIO. For instance:
it "should print a copyright message" do
$stdout.should_receive(:puts).with(/copyright/i)
app = ApplicationController.new(%w[project_name])
end
it "should not print an error message" do
$stdout.should_not_receive(:puts).with(/error/i)
app = ApplicationController.new(%w[project_name])
end
That's an actual working RSpec from a project

How to create an exit message

Is there a one line function call that quits the program and displays a message? I know in Perl it's as simple as:
die("Message goes here")
I'm tired of typing this:
puts "Message goes here"
exit
The abort function does this. For example:
abort("Message goes here")
Note: the abort message will be written to STDERR as opposed to puts which will write to STDOUT.
If you want to denote an actual error in your code, you could raise a RuntimeError exception:
raise RuntimeError, 'Message goes here'
This will print a stacktrace, the type of the exception being raised and the message that you provided. Depending on your users, a stacktrace might be too scary, and the actual message might get lost in the noise. On the other hand, if you die because of an actual error, a stacktrace will give you additional information for debugging.
I got here searching for a way to execute some code whenever the program ends.
Found this:
Kernel.at_exit { puts "sayonara" }
# do whatever
# [...]
# call #exit or #abort or just let the program end
# calling #exit! will skip the call
Called multiple times will register multiple handlers.
I've never heard of such a function, but it would be trivial enough to implement...
def die(msg)
puts msg
exit
end
Then, if this is defined in some .rb file that you include in all your scripts, you are golden.... just because it's not built in doesn't mean you can't do it yourself ;-)

Resources