SharKCS11 SharKCS11 - 7 months ago 25
Ruby Question

Undefined method `-@' when trying to push a string into array

I am trying to create a ruby script to help me run some C++ tests on a linux terminal. I am a total beginner when it comes to Ruby, and am running into a few problems.
I have defined a global variable array called "tfailed", but get this error when I try pushing into it:

mscr.rb:18:in `runTest': undefined method `-@' for ["Card_test_all"]:Array (NoMethodError)


The offending bit of code is here:

$trun=0;
$tpassed=0;
$tfailed=Array.new;

def runTest(testname)
puts "Running #{testname}";
if system("make " + testname + ".exe > /dev/null") then
puts "#{testname} compiled correctly.";
end
succ=system("./"+testname+".exe > /dev/null");
$trun=$trun+1;- #typo was here
if(succ)
$tpassed=$tpassed+1;
puts (testname + " successfully run.");
else
puts (testname + " unsuccessfully run.");
$tfailed << testname; #LINE 18 here
end
puts "-------------------------------";
end


If the C++ program doesn't run successfully, the name of the test should be pushed into the array. In this case, the function called was

runTest("Card_test_all");


The code should be pushing the string "Card_test_all" into the $tfailed array, but it gives me the above error instead. Any help or ideas on how to fix this would be appreciated.

Edit: Added the line number that causes the problem. Also, thanks to the commentors below for the ruby style/syntax advice.

Edit 2: The typo I edited out in my first change actually was the problem all along. I'm an idiot. Thanks for the help though.

Answer

Leaving stylistic concerns like the global variables and unnecessary semicolons aside, the root of your problem is the - at the end of line 11. This is because in Ruby, any syntactically valid piece chunk of code evaluates to a value that can be used for further operations, in addition to having whatever effect it has. Mind, some things, like puts evaluate to nil, which you can't do a ton with (puts is simply a method call, and it evaluates to nil because the method returns nil).

In particular, an if ... else ... end block evaluates to whatever the last line of the executed code evaluates to. So, rather than saying

if a == 1
  x = "foo"
else
  x = "bar"
end

you can perfectly legitimately write

x = if a == 1
      "foo"
    else
      "bar"
    end

The if evaluates to "bar", so x becomes "bar".

So, your second if statement looks like this:

if(succ)
  $tpassed=$tpassed+1;
  puts (testname + " successfully run.");
else
  puts (testname + "  unsuccessfully run.");
  $tfailed << testname;
end

Since succ is false, the else branch is evaluated:

puts (testname + " unsuccessfully run.");
$tfailed << testname;

The last line here is $tfailed << testname. $tfailed is an Array, and the << method on Array modifies the array in question and then returns it. So, when succ is false, the whole if statement evaluates to the array saved in $tfailed.

Now, Ruby statements can wrap into more than one line if you want them to. If you had written

x = 
if(succ)
  $tpassed=$tpassed+1;
  puts (testname + " successfully run.");
else
  puts (testname + "  unsuccessfully run.");
  $tfailed << testname;
end

then you'd have set the variable x equal to $tfailed. However, you wrote, effectively,

-
if(succ)
  $tpassed=$tpassed+1;
  puts (testname + " successfully run.");
else
  puts (testname + "  unsuccessfully run.");
  $tfailed << testname;
end

That's trying to find -$tfailed, that is, negative $tfailed. The unary prefix minus 'negative' operator is denoted as -@ to distinguish it from the binary infix minus 'subtraction' operator -, and can be defined on any class if you like. Array, however, does not define a unary minus operator. So, it's a NoMethodErorr: undefined method-@' for ["Card_test_all"]:Array.

EDIT: Whoops, while I was typing my answer the question was edited and the - on line 11 is no longer there. Are you sure the code as written still raises the stated exception?