--Boundary-00bCzH1xO4iXhVUU
Content-Type: Multipart/Mixed;
  boundaryoundary-00bCzH1xO4iXhVUU"

--Boundary-00bCzH1xO4iXhVUU
Content-Type: text/plain;
  charsetso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Monday 03 March 2008, August0866 wrote:
> Hi All,
>
> I am not a programmer, yet.  I am trying ruby on for size, most things
> fit ok, but Classes are puzzling me.
>
> <code>
> class Roll
>          def Roll(base,range)
>            @basee
>            @range
nge
>           @roll  ase+random(range)
>          end
> end
>
> class Stats
>     def power
>      @powerll.new(10,8)
>      end
>     def speed
>       @speedll.new(10,8)
>      end
>     def smarts
>      @smartsll.new(10,8)
>     end
> end
>
> class Attribs < Stats
>    def acc
>       @acc75*self.power+(self.speed/self.smarts)
>    end
>     def  health
>     @health  elf.power*(self.smarts/self.speed)
>   end
>  end
> class Npc < Attribs
>   def name(name)
>  @name
me
> end
> end
>
> joec.new
> joe.name('Joe')
> #puts joe.name.to_s+'  ame'
> puts joe.power.to_s+'  ower'
> puts joe.smarts.to_s+'  marts'
> puts joe.speed.to_s+'  peed'
> puts joe.health.to_s+'  ealth'
> puts joe.acc+'  cc'
> puts joe
> puts '
> puts 'Calculations'
> puts   0.75*joe.power+(joe.speed/joe.smarts)
> </code>
>
> OK, so why is this broken?

There are many reasons your code doesn't work. Let's see what happens running
it in ruby (by the way, when asking for help about a piece of code which
produces an error, it's better to also show the error message):

* FIRST TRY:
./prova.rb:13:in `initialize': wrong number of arguments (2 for 0)
(ArgumentError)

This means that some initialize method is called with 2 arguments, when it
should receive no argument on line 11. The line in question is:

@power  oll.new(10, 8)

Apparently, there's no call to initialize here. What you're trying to do in
this line, is to create an instance of class Roll, calling Roll.new. For most
classes, the 'new' method first creates a new object, then calls its
'initialize' method, which, as the name implies, is used to perform
initialization on the object (for example, giving starting values to instance
variables). Since you didn't define an initialize method for class Roll, it
uses the one defined for the parent class, which is Object.
The initialize method defined for class Object takes no argument, so you get
an error.

Looking at the definition of class Roll, i see you defined a method called
Roll, which takes two arguments and sets instance variables, just like
initialize should do. I guess you thought that method would have been called
by new. Let's rename it to initialize and see if it solves the problem.

* SECOND TRY:
./prova.rb:5:in `initialize': undefined method `random' for #<Roll:0xb7c10c70
@range@base> (NoMethodError)

This is easy: you're calling a method named 'random', which doesn't exist.
The method which generates a random number in ruby is called rand, so we'll
replace random with rand
 
* THIRD TRY:
./prova.rb:26:in `health': undefined method `/' for #<Roll:0xb7beeb34
@range@base, @roll> (NoMethodError)
        from ./prova.rb:41

Now, ruby hits an error while calling the health method: in particular, in
line 26 there's a call to a method '/' which is undefined. Line 26 is:

@health   self.power*(self.smarts/self.speed)

In ruby, operators such as +, -, * and / are simply methods, so that when you
write, for example 2 + 3, ruby calls the '+' method of the object 2 passing
it the object 3 as argument. In your code, you're dividing self.smarts by
self.speed, which are both of class Roll. Class Roll doesn't have a method
called '/', so you get the error.

This problem could be solved defining a sensible / method for class Roll, or,
more simply, by defining a method which allows to get the value of the
variable @roll of an instance of roll (which is a number), and use that
instead of the instance of Roll itself. It may be worth asking whether class
Roll really needs to exist. If you won't require the @base and @range values
somewhere else, then it would be much easier to replace the whole class with
a method such as this:

def roll(base, range)
  base + rand(range)
end

At any rate, let's assume that Roll needs to be a class and add a method
which allows to extract the @roll instance variable. We could define it by
hand, but ruby does it automatically if we add this line inside class Roll:

attr_reader :roll

This generates a method called roll which returns @roll.

Then, we need to replace speed and smarts and power with speed.roll,
smarts.roll and power.roll in lines 24, 26 and 47 (we would get an analogous
problem with the acc method if we leaved it as it is).

* FOURTH TRY
#<Roll:0xb7cd0b60>   power
#<Roll:0xb7cd0afc>   smarts
#<Roll:0xb7cd0aac>   speed
0   health
./prova.rb:43:in `+': String can't be coerced into Float (TypeError)
        from ./prova.rb:43

Before looking at the error, there are two things to notice: first, power,
smarts and speed aren't numbers but instances of class Roll. If this isn't
what you expected, then most likely you should replace class Roll with the
method roll as I mentioned above. Second, health is 0 (of course, this will
depend on the random number which have been generated). Since both
smarts.roll and speed.roll are integers, the division will return 0 if the
divider is greater than the divisor. To avoid this, add a call to to_f to one
of the operands. to_f will convert the integer to a float, so the division
will use decimals.

Looking at the error, it simply means that, in line 43, we're trying to add a
number with a string. The reason is simply that you forget to call the to_s
method on joe.acc as you did for the other ones.

* FIFTH TRY
#<Roll:0xb7c79af4>   power
#<Roll:0xb7c79a90>   smarts
#<Roll:0xb7c79a40>   speed
10   health
10.75   acc
#<Npc:0xb7c79b6c>
Calculations
11.5

Now, it works. 

Attached, you'll find a copy of the code with all the modifications I spoke
about.

I hope this helps

Stefano


--Boundary-00bCzH1xO4iXhVUU
Content-Type: application/x-ruby;
  name
ode.rb" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename
ode.rb" #!/usr/bin/env ruby class Roll attr_reader :roll def initialize(base,range) @basee @range nge @roll base+rand(range) end end class Stats def power @powerll.new(10,8) end def speed @speedll.new(10,8) end def smarts @smartsll.new(10,8) end end class Attribs < Stats def acc @acc75*self.power.roll+(self.speed.roll.to_f / self.smarts.roll) end def health @health self.power.roll*(self.smarts.roll.to_f / self.speed.roll) end end class Npc < Attribs def name(name) @name me end end joec.new joe.name('Joe') #puts joe.name.to_s+' name' puts joe.power.to_s+' power' puts joe.smarts.to_s+' smarts' puts joe.speed.to_s+' speed' puts joe.health.to_s+' health' puts joe.acc.to_s+' acc' puts joe puts ' puts 'Calculations' puts 0.75*joe.power.roll+(joe.speed.roll.to_f / joe.smarts.roll) --Boundary-00bCzH1xO4iXhVUU-- --Boundary-00bCzH1xO4iXhVUU--