# Initial stages of scripting

**URL:** <https://www.ruby-forum.com/t/initial-stages-of-scripting/137024>\
**Category:** Ruby\
**Created:** [May 8, 2008, 12:28pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024 "2008-05-08T12:28:11Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 12:28pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/1 "2008-05-08T12:28:11Z")

</div>

Hi there,  
I’m a relative newbie when it comes to scripting in ruby however, for a  
year 11 project at school, it is necesary for me to program a maths  
utilit which requests a user - elementary school aged - to add to  
numbers together to reach an answer. I’ve effected some coding however,  
I’m a little stumpt as to why the aplet is not correctly parsing through  
the loops.  
===script extract starts==  
question = 1  
unless question == 20  
score = 0  
number\_of\_questions = 0  
num1 = rand(20)  
num2 = rand(20)  
correct\_answer = num1 + num2  
puts(“What is #{num1} + #{num2}/?”)  
user\_answer = gets.chomp!.to\_i  
unless user\_answer == correct\_answer  
puts(“Sorry, that is not correct. Please try again.”)  
user\_answer = gets.chomp!.to\_i  
end  
score += 1  
number\_of\_questions += 1  
question += 1  
puts(“Well done! That is correct.\nYou have answered #{score} out of  
#{number\_of\_questions} questions correctly.”)  
end  
exit  
===script extract ends===  
Cheers,  
Hayden

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 12:42pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/2 "2008-05-08T12:42:21Z")

</div>

On Thu, 2008-05-08 at 19:27 +0900, Hayden Smith wrote:

> puts(“What is #{num1} + #{num2}/?”)  
> exit  
> ===script extract ends===

What loops? I don’t see any loops in there at all. I see two  
conditionals (“unless question == 20” and “unless user\_answer ==  
correct\_answer”) but no loops.

That might be a clue.

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 12:48pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/3 "2008-05-08T12:48:02Z")

</div>

I dont want to go through it all, so just a few hints:

puts(“What is #{num1} + #{num2}/?”)

No need for the () here.  
Also the / before the ? seems confusing. Maybe omit it.

The  
exit  
also seems superfluous. Maybe omit it.

My favourite loop in ruby is this:

loop {

# do something here… alter condition, and then finally

break if condition  
}

But maybe you meant to use a while  
I personally think “until” is not a good name for use here.

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 1:08pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/4 "2008-05-08T13:08:52Z")

</div>

On 8 May 2008, at 11:27, Hayden Smith wrote:

> score = 0  
> score += 1  
> number\_of\_questions += 1  
> question += 1  
> puts(“Well done! That is correct.\nYou have answered #{score} out of  
> #{number\_of\_questions} questions correctly.”)  
> end  
> exit

Hi Hayden,

I hope the following answers are helpful. The idiom that you’d be  
looking to use in your code would be:

score = 0  
1…20.each do |question|  
# do stuff  
end

where you keep track of the score yourself as part of do stuff.  
Although I prefer the form:

1…20.inject(0) |sum, question|  
# do stuff  
sum += some\_condition ? 1 : 0  
end

but that requires that the last expression in the block be the one  
that increments the sum variable. Extra marks if you can write the  
block without using any local variables 😉

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 1:33pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/5 "2008-05-08T13:33:39Z")

</div>

On 8 May 2008, at 12:07, Eleanor McHugh wrote:

> 1…20.inject(0) |sum, question|  
> # do stuff  
> sum += some\_condition ? 1 : 0  
> end

which of course should be:

1…20.inject(0) |sum, question|  
#do stuff  
sum + (some\_condition ? 1 : 0)  
end

as the whole point of inject is that it does the assignment for you…  
I really must stick to this rule of no coding before my second cup of  
tea of the day 😉

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 1:35pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/6 "2008-05-08T13:35:27Z")

</div>

My apologies for misuse of terminology: Those two conditionals are the  
particular elements that I speak of.  
----- Original Message -----  
From: Michael T. Richter  
To: ruby-talk ML  
Sent: Thursday, May 08, 2008 8:41 PM  
Subject: Re: initial stages of scripting

On Thu, 2008-05-08 at 19:27 +0900, Hayden Smith wrote:  
Hi there,  
I’m a relative newbie when it comes to scripting in ruby however, for a  
year 11 project at school, it is necesary for me to program a maths  
utilit which requests a user - elementary school aged - to add to  
numbers together to reach an answer. I’ve effected some coding however,  
I’m a little stumpt as to why the aplet is not correctly parsing through  
the loops.  
===script extract starts==  
question = 1  
unless question == 20  
score = 0  
number\_of\_questions = 0  
num1 = rand(20)  
num2 = rand(20)  
correct\_answer = num1 + num2  
puts(“What is #{num1} + #{num2}/?”)  
user\_answer = gets.chomp!.to\_i  
unless user\_answer == correct\_answer  
puts(“Sorry, that is not correct. Please try again.”)  
user\_answer = gets.chomp!.to\_i  
end  
score += 1  
number\_of\_questions += 1  
question += 1  
puts(“Well done! That is correct.\nYou have answered #{score} out of  
#{number\_of\_questions} questions correctly.”)  
end  
exit  
===script extract ends===

What loops? I don’t see any loops in there at all. I see two  
conditionals (“unless question == 20” and “unless user\_answer ==  
correct\_answer”) but no loops.

That might be a clue.

```
    --
    Michael T. Richter <removed_email_address@domain.invalid> (GoogleTalk: 

```

removed\_email\_address@domain.invalid)  
The only reason some people get lost in thought is because it’s  
unfamiliar territory. (Paul Fix)

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 1:37pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/7 "2008-05-08T13:37:52Z")

</div>

Hi Ellie,  
Thanks for the suggestions, but as is evident from this code - I believe

- I  
am a relative newbie and therefore, the logic behind this - at this  
point -  
is beyond me. Oh well, back to the bottom of the class for me.  
Cheers  
----- Original Message -----  
From: “Eleanor McHugh” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
To: “ruby-talk ML” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Sent: Thursday, May 08, 2008 9:07 PM  
Subject: Re: initial stages of scripting

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 1:41pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/8 "2008-05-08T13:41:58Z")

</div>

Hi,  
If I were to pursue this line of logic, how would I allow the break to  
have  
two conditions to opperate on? For example, in my first nested loop, I  
wished to test for the equality of user\_answer and correct\_answer as  
well  
as - this was not included due to my ignorance - a comparison to only  
continue the loop - regardless whether the two previous were correct -  
but  
only whilst looper != 3.  
Cheers,  
Hayden  
----- Original Message -----  
From: “Marc H.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Newsgroups: comp.lang.ruby  
To: “ruby-talk ML” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Sent: Thursday, May 08, 2008 8:48 PM  
Subject: Re: initial stages of scripting

---

<div class="post-metadata">

**Author:** ![Hayden\_Smith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/cc9497/32.png) [@Hayden\_Smith](https://www.ruby-forum.com/u/Hayden_Smith)\
**Post date:** [May 8, 2008, 4:08pm UTC](https://www.ruby-forum.com/t/initial-stages-of-scripting/137024/9 "2008-05-08T16:08:27Z")

</div>

On 8 May 2008, at 12:36, Hayden Smith wrote:

> Hi Ellie,  
> Thanks for the suggestions, but as is evident from this code - I  
> believe - I am a relative newbie and therefore, the logic behind  
> this - at this point - is beyond me. Oh well, back to the bottom of  
> the class for me.  
> Cheers

Well I didn’t want to ruin your homework assignment for you so I sort  
of dodged around your actual task. Apologies if the following breaks  
that rule, but getting the hang of basic loops etc. is a fundamental  
if you want to really enjoy programming.

If I lay out your code to better reflect the logical structure it  
looks like this:

```
question = 1
unless question == 20
  score = 0
  number_of_questions = 0
  num1 = rand(20)
  num2 = rand(20)
  correct_answer = num1 + num2
  puts("What is #{num1} + #{num2}/?")
  user_answer = gets.chomp!.to_i
end
score += 1
number_of_questions += 1
question += 1
puts("Well done! That is correct.\nYou have answered #{score} out of

```

#{number\_of\_questions} questions correctly.")  
end  
exit

Clearly there’s either a fragment missing at the very start which  
would matches with the final ‘end’ statement, or else your first ‘end’  
statement is an erroneous inclusion. This is one of the reasons for  
laying out code with clear indentation - it makes the logic flow  
glaringly obvious.

It would make sense to put some kind of loop statement at the start  
otherwise there will be no repetition. With this inclusion what you  
have is a classic example of what’s known as a sentinel guarded loop.  
You have a sentinel value (in this case 20) and an accumulator  
‘question’ which changes value with each loop iteration until it  
reaches a specified value. The way in which you would handle this in a  
traditional procedural language such as BASIC would be to write a code  
fragment of this form:

FOR QUESTION = 1 TO 20  
num1 = RND(20)  
num2 = RND(20)  
correct\_answer = num1 + num2  
REM read the value from the keyboard  
REM compare the result and do some stuff  
REM etc.  
END

In Ruby it’s more natural for these kinds of problems to use a Range  
object (because Ruby is object-oriented) and then enumerate across it:

questions = 1…20 # this creates an instance of the Range 1 through  
20  
questions.each do |question|  
# actions to do for the question asked  
end

but you can also use a more procedural style:

questions = 1…20 # this creates an instance of the Range 1 through  
20  
for question in questions  
# actions to do for the question asked  
end

and either form would provide the loop that you need to ask the user  
for their answer to successive questions.

If you then study the actions that you’re taking in your code and  
consider the actual logic of what you’re trying to achieve you’ll  
notice that the score generated will be incorrect. This is where my  
suggestion of enumerating a Range object using the inject() method  
rather that each() becomes relevant:

questions = 1…20 # this creates an instance of the Range 1 through  
20  
questions.inject(0) do |sum, question|  
#do stuff  
sum + (some\_condition ? 1 : 0)  
end

The ‘sum’ parameter to the block acts as an accumulator and for each  
element in the range ‘questions’ whatever the final expression of the  
code block evaluates to will be the value stored in ‘sum’. Once all  
elements have been enumerated, the value in ‘sum’ is then returned by  
inject() as the value of the expression. So for example:

numbers = 1…20  
result = numbers.inject(0) do |sum, number|  
sum + number  
end

would set ‘result’ to 210, which is the sum of the first twenty  
integers. The way in which this then applies to your problem:

questions = 1…20 # this creates an instance of the Range 1 through  
20  
correct\_answers = questions.inject(0) do |sum, question|  
#do stuff  
sum + (condition\_for\_correct\_answer ? 1 : 0)  
end

The use of the ternary logic operator is compact but for more complex  
behaviour a clearer formulation would be:

correct\_answers = questions.inject(0) do |sum, question|  
#do stuff  
sum + if condition\_for\_correct\_answer ? then  
# print some stuff  
1  
else  
# print some other stuff  
0  
end  
end

which takes advantage of the fact that ‘if’ is also an expression and  
will return a value which can be used directly. In languages where  
‘if’ is a statement (and hence does not return a value itself) the  
logic would look more like:

correct\_answers = 0  
questions.each do |question|  
#do stuff  
if condition\_for\_correct\_answer ? then  
# print some stuff  
correct\_answers += 1  
else  
# print some other stuff  
correct\_answers += 0  
end  
end

which is also valid Ruby.

And if that’s not baffled you completely, you’ll be well on your way  
to Ruby mastery 🙂

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason
