0

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.

6
  • 1
    Well, what is the purpose of the - in $trun=$trun+1;-? Commented May 2, 2016 at 18:34
  • Why do you use global variables everywhere? Commented May 2, 2016 at 18:56
  • You'd be better off using Open3 instead of system. Someone will complain about all those unnecessary semicolons so I'll do it: you don't need semicolon terminators in Ruby. Be careful when using parentheses to call methods, m (x) and m(x) are very different things. You might want to include a bit more whitespace: $trun = 0 and $trun = $trun + 1 for example. Commented May 2, 2016 at 19:09
  • What is line 18? it looks to me like $tfailed is actually set to ["Card_test_all"] by the time your exception occurs... Commented May 2, 2016 at 19:47
  • 2
    Also, some general ruby guidelines--don't use globals, it's a bad idea. Second, get rid of all of your semi-colons, they are unnecessary. Third, get rid of your parentheses around your puts calls, they're both unnecessary and ugly. Fourth, avoid camelizing method names, camelization is usually used for classes or modules. Fifth, rather than using string concatenation with + consider using string interpolation, so you can do things like: "#{testname} successfully run." Commented May 2, 2016 at 19:50

1 Answer 1

2

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?

Sign up to request clarification or add additional context in comments.

2 Comments

Yeah, the "-" was a typo that occurred when I copied the code from my text editor into the question box. Turns out I recopied it into a different file with the typo. When I ran it, it stopped working. So your answer was correct. I'll edit my original post about that. Anyway, thanks so much for the detailed explanation. I'm obviously going to have to be a lot more careful as there's no compiler telling me when I screw up something simple like this!
@SharkCS11 Glad to help! Ruby is wonderful in many ways, my favorite language, but it definitely has some confusing areas. Also, as far as I'm concerned that error message should have stated the error was on line 11, not line 18. I may actually log that as an issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.