Vargrantfile - Ruby - unexpected end of file - ruby

I am new to ruby. I was trying to modify existing Vargrantfile which is of ruby syntax.
I have below
def has_program(program)
ENV['PATH'].split(File::PATH_SEPARATOR).any? do |directory|
File.executable?(File.join(directory, program.to_s))
end
end
is_exist = has_program("some-command")
puts is_exist
$my_script = %{
if is_exist == false
if ! some-command status; then
#Do some staff
fi
end
# do some staff
}
Vagrant.configure("2") do |config|
node.vm.provision "shell", inline: $my_script
end
Then while running vagrant up --provision I am getting below error
syntax error: unexpected end of file
Can you please let me know what error I am doing?
With regards,
-M-

This is a syntax error but not one in your Ruby code as such. It's an unfinished statement in the shell code that you're executing from the Ruby script.
This can happen if you leave a block unclosed. The parser expects to find its end but encounters the end of the script instead.
Let's look at the part where you're executing a shell command
$my_script = %{
if is_exist == false
if ! some-command status; then
#Do some staff
fi
end
# do some staff
}
Now, let's strip the Ruby parts you have around it. The assignment $my_script = is still Ruby code. The part in curly braces is a string literal in the % notation that you later execute as a shell script using Vagrant's inline... However, it appears that you're switching back to Ruby syntax before ending the string literal.
What the interpreter parses as a shell script is this part:
if is_exist == false
if ! some-command status; then
#Do some staff
fi
end
# do some staff
Notice that the whole outer if expression uses Ruby's if syntax. It's not a valid shell command, hence the error.
I'm not sure what the semantics of this expression are in your case but you need to convert it to a shell if or move it outside the string literal you're passing to Vagrant using the inline option. On a side note, the logic inside seems strange. You're calling some-command if has_program("some-command") returns false. But that's a separate story :)

Related

How to pass array as an argument to a Ruby function from command line?

I want to call Ruby function from command line with array as an argument.
Script name is test.rb
In below code Environments are like test,dev,uat.', am passing as ['test','dev','uat']
I have tried as below:
ruby -r "./test.rb" -e "start_services '['dev','test','uat']','developer','welcome123'"
def start_services(environments,node_user_name,node_password)
environments.each do |env|
puts env
end
puts node_user_name
puts node_password
end
Output:
-e:1: syntax error, unexpected tIDENTIFIER, expecting end-of-input start_services '['dev','test','uat']','developer',' ^
You clearly want to pass an array as the first parameter into start_services method, so you should do it like this:
$ ruby -r "./test.rb" -e "start_services ['dev','test','uat'],'developer','welcome123'"
# output:
dev
test
uat
developer
welcome123
What you've been trying so far was attempt to pass '[\'dev\',\'test\',\'uat\']' string, which was malformed, because you didn't escape ' characters.
Don't pass your credentials as arguments, any user on your system would be able to see them.
Instead, you could save them as environment variables or in a config file.
if ARGV.size == 0
puts "Here's how to launch this script : ruby #{__FILE__} env_name1 env_name2 ..."
exit
end
# Define those environment variables before launching the script.
# Alternative : write credentials in a json or yml file.
node_username = ENV["NODE_USERNAME"]
node_password = ENV["NODE_PASSWORD"]
ARGV.each do |env|
puts "Launching environment #{env}"
end

File.exist? always returns false even when file does exist

I have a program that tries to open a file:
Dir.chdir(File.dirname(__FILE__))
puts "Enter file name: ";
relPath = gets;
absPath = Dir.pwd << "/" << relPath;
if File.exist?(absPath) then
puts "File exists";
file = File.open(absPath, "r");
other code...
else
puts "File does not exist";
end
It always prints "File does not exist" even when the current directory exists and the file also exists. The file and script are in the same directory.
I am running it on Mac OS X Yosemite (10.10.3) and Ruby 2.2.0p0.
I can't explain why (albeit I have strong belief that it's for some whitespace characters) but with this little contribution it works ok.
Dir.chdir(File.dirname(__FILE__))
print "Enter file name:";
relPath = gets.chomp; #intuitively used this, and it wroked fine
absPath = File.expand_path(relPath) #used builtin function expand_path instead of string concatenation
puts absPath
puts File.file?(absPath)
if File.exist?(absPath) then
puts "File exists";
puts File.ctime(absPath) #attempting a dummy operation :)
else
puts "File does not exist";
end
runnning code
$ ls -a anal*
analyzer.rb
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
ziya#ziya:~/Desktop/code/ruby$ ruby fileexists.rb
Enter file name:analyzer.rb
/home/ziya/Desktop/code/ruby/analyzer.rb #as a result of puts absPath
true #File.file?(absPath) => true
File exists
2015-06-11 12:48:31 +0500
That code has syntax error ("if" doesnt need "then"), and you dont have to put ";" after each line.
try
Dir.chdir(File.dirname(__FILE__))
puts "Enter file name: "
relPath = gets
absPath = "#{Dir.pwd}/#{relPath.chop}"
if File.exist?(absPath)
puts "File exists"
file = File.open(absPath, "r")
else
puts "File does not exist"
end
remember that gets will add a new line character so you will need to do a chomp, and that way to concatenate string won't work on ruby.
Your code is not idiomatic Ruby. I'd write it something like this untested code:
Dir.chdir(File.dirname(__FILE__))
puts 'Enter file name: '
rel_path = gets.chomp
abs_path = File.absolute_path(rel_path)
if File.exist?(abs_path)
puts 'File exists'
File.foreach(abs_path) do |line|
# process the line
end
else
puts 'File does not exist'
end
While Ruby supports the use of ;, they're for use when we absolutely must provide multiple commands on one line. The ONLY time I can think of needing that is when using Ruby to execute single-line commands at the command-line. In normal scripts I've never needed ; between statements.
then is used with if when we're using a single line if expression, however, we have trailing if which removes the need for then. For instance, these accomplish the same thing but the second is idiomatic, shorter, less verbose and easier to read:
if true then a = 1 end
a = 1 if true
See "What is the difference between "if" statements with "then" at the end?" for more information.
Instead of relPath and absPath we use snake_case for variables, so use rel_path and abs_path. It_is_a_readability AndMaintenanceThing.
File.absolute_path(rel_path) is a good way to take the starting directory and return the absolute path given a relative directory.
File.foreach is a very fast way to read a file, faster than slurping it using something like File.read. It is also scalable whereas File.read is not.

Can't get bash to loop in chef

I am trying to run a loop over array in chef (The loop contains a bash command). Anyone has any idea on this ?
symlink_db = data_bag_item(“my”_db,”my”_db)
source = symlink_db[“sourceFile”]
instances = symlink_db["Instances"].split(',') <---Instances is a comma separated string in Databag
bash "create_link" do
puts "1: #{instances}" <-------Puts all instances correctly
instances.each do |instance|
puts "2: #{instance}" <------ This prints each instance in loop correctly
code <<-EOH
echo "ln -fs #{source} #{instance}"; <----- This is printed only for last instance in the loop
EOH
end
end
Appreciate if anyone can help soon.....Thanks
You need the bash resource inside your loop:
instances.each do |instance|
bash "create_link-#{instance}" do
code <<-EOH
echo "ln -fs #{source} #{instance}"
EOH
end
end
BTW, this is not idiomatic chef. You should simply use the link resource like this:
instances.each do |instance|
link instance do
to source
end
end
An advantage of this approach is that it makes your recipe cross-platform. It's also a lot more readable.

Named groups from regular expression in case statement [duplicate]

I want to parse user input using named captures for readability.
When they type a command I want to capture some params and pass them. I'm using RegExps in a case statement and thus I can't assign the return of /pattern/.named_captures.
Here is what I would like to be able to do (for example):
while command != "quit"
print "Command: "
command = gets.chomp
case command
when /load (?<filename>\w+)/
load(filename)
end
end
named captures set local variables when this syntax.
regex-literal =~ string
Dosen't set in other syntax. # See rdoc(re.c)
regex-variable =~ string
string =~ regex
regex.match(string)
case string
when regex
else
end
I like named captures too, but I don't like this behavior.
Now, we have to use $~ in case syntax.
case string
when /(?<name>.)/
$~[:name]
else
end
This is ugly but works for me in Ruby 1.9.3:
while command != "quit"
print "Command: "
command = gets.chomp
case command
when /load (?<filename>\w+)/
load($~[:filename])
end
end
Alternatively you can use the English extension of $~, $LAST_MATCH_INFO.

Using Named Captures with regex match in Ruby's case...when?

I want to parse user input using named captures for readability.
When they type a command I want to capture some params and pass them. I'm using RegExps in a case statement and thus I can't assign the return of /pattern/.named_captures.
Here is what I would like to be able to do (for example):
while command != "quit"
print "Command: "
command = gets.chomp
case command
when /load (?<filename>\w+)/
load(filename)
end
end
named captures set local variables when this syntax.
regex-literal =~ string
Dosen't set in other syntax. # See rdoc(re.c)
regex-variable =~ string
string =~ regex
regex.match(string)
case string
when regex
else
end
I like named captures too, but I don't like this behavior.
Now, we have to use $~ in case syntax.
case string
when /(?<name>.)/
$~[:name]
else
end
This is ugly but works for me in Ruby 1.9.3:
while command != "quit"
print "Command: "
command = gets.chomp
case command
when /load (?<filename>\w+)/
load($~[:filename])
end
end
Alternatively you can use the English extension of $~, $LAST_MATCH_INFO.

Resources