Dragons and factorials (keyboard input)

I'm getting keyboard input successfully, but I'm getting a string. I
need to convert it to a number. But ruby is a dynamic language?
What's happening please?

(Did I mention that this list is awesome?)

Here's what I have:

C:\code>
C:\code>
C:\code>dir
Volume in drive C has no label.
Volume Serial Number is 0491-510F

Directory of C:\code

11/03/2007 12:15 PM <DIR> .
11/03/2007 12:15 PM <DIR> ..
11/03/2007 11:42 AM 827 Creature.rb
11/03/2007 11:35 AM 122 doFactorial.rb
11/03/2007 11:58 AM 449 Dragon.rb
11/03/2007 11:34 AM 114 factorial.rb
11/03/2007 11:32 AM 353 Hello.rb
11/03/2007 12:17 PM 71 input.rb
11/03/2007 12:25 PM 283 makeDragon.rb
               7 File(s) 2,219 bytes
               2 Dir(s) 28,967,956,480 bytes free

C:\code>
C:\code>type Dragon.rb
require 'Creature'

class Dragon < Creature
        life 1340 # tough scales
        strength 451 # bristling veins
        charisma 1020 # toothy smile
        weapon 939 # fire breath

        def toString()

                print "\n\n\nThis Dragon\n"
                print "-------------------"

                print "\nLife:\t\t"
                print life

                print "\nStrength:\t"
                print strength

                print "\nCharisma:\t"
                print charisma

                print "\nWeapon:\t\t"
                print weapon
                print "\n\n\n\n"
        end
end
C:\code>
C:\code>type Creature.rb
# The guts of life force within Dwemthy's Array
class Creature
# Get a metaclass for this class
def self.metaclass; class << self; self; end; end
# Advanced metaprogramming code for nice, clean traits
def self.traits( *arr )
return @traits if arr.empty?
# 1. Set up accessors for each variable
attr_accessor *arr
# 2. Add a new class method to for each trait.
arr.each do |a|
metaclass.instance_eval do
define_method( a ) do |val|
@traits ||= {}
@traits ||= {}
@traits[a] = val
end
end
end
# 3. For each monster, the `initialize' method
# should use the default number for each trait.
class_eval do
define_method( :initialize ) do
self.class.traits.each do |k,v|
instance_variable_set("@#{k}", v)
end
end
end
end
# Creature attributes are read-only
traits :life, :strength, :charisma, :weapon
end
C:\code>
C:\code>type factorial.rb
def fact(n)
        if n <= 1
                1
        else
                n * fact(n - 1)
        end
end
C:\code>
C:\code>type makeDragon.rb
require 'Dragon'
require 'factorial'

aDragon = Dragon.new

aDragon.toString

number=0
print "\n\n\nthe Dragon will calculate a factorial now."
puts "\nenter an integer "
number=gets

# print "\n\n\n" + number + "\n\n"

print "Dragon replies\n\n"
print fact(number)
C:\code>
C:\code>
C:\code>makeDragon.rb

This Dragon

···

-------------------
Life: 1340
Strength: 451
Charisma: 1020
Weapon: 939

the Dragon will calculate a factorial now.
enter an integer
9
Dragon replies

./factorial.rb:2:in `<=': comparison of String with 1 failed
(ArgumentError)
        from ./factorial.rb:2:in `fact'
        from C:/code/makeDragon.rb:16

C:\code>
C:\code>

thanks,

Thufir

C:\code>type makeDragon.rb
require 'Dragon'
require 'factorial'

aDragon = Dragon.new

aDragon.toString

number=0
print "\n\n\nthe Dragon will calculate a factorial now."
puts "\nenter an integer "
number=gets

Add number = number.to_i or number = Integer(number)

gets returns a string, so you need to convert it to an integer.

# print "\n\n\n" + number + "\n\n"

print "Dragon replies\n\n"
print fact(number)

Aditya

···

On Sat, 3 Nov 2007, Thufir wrote:

I googled, didn't find the answer, posted, googled more, found the
answer:

C:\code>
C:\code>
C:\code>
C:\code>
C:\code>type makeDragon.rb
require 'Dragon'
require 'factorial'

aDragon = Dragon.new

aDragon.toString

number=0
print "\n\n\nthe Dragon will calculate a factorial now."
puts "\nenter an integer "
#number=gets
number = gets.chomp.to_i

# print "\n\n\n" + number + "\n\n"

answer=fact(number)
print "Dragon replies\n\n"
print answer
#print fact(number)
C:\code>
C:\code>makeDragon.rb

This Dragon

···

-------------------
Life: 1340
Strength: 451
Charisma: 1020
Weapon: 939

the Dragon will calculate a factorial now.
enter an integer
11
Dragon replies

39916800
C:\code>

A bit chagrined,

Thufir

ps: I'm thinking about class, inheritance and so forth. I'm going to
review another thread where I was asking about the ruby equivalent to
"static class methods" for, specifically, the factorial which I want
ensure cannot be instantiated. I know it's an object, because
everything's an object in Ruby, but have to think about that one.

I think I also want to make some private methods, and a friend was
suggesting to insert some error if the Dragon has low intelligence! :slight_smile:

Thufir wrote:

I'm getting keyboard input successfully, but I'm getting a string. I
need to convert it to a number. But ruby is a dynamic language?
What's happening please?

<snip -- too much to read through>

Look at this and see if it helps:

print "Enter an integer: "
str_int = gets

print "Enter a float: "
str_float = gets

the_int = str_int.to_i
the_float = str_float.to_f

puts the_int + the_float

···

--
Posted via http://www.ruby-forum.com/\.

Others have already answered your question, and it appears you figured it out or yourself, too.

Ruby does not perform coercion on strings. Perl allows you to do this ...

1 + "2" #=> 3

However, Matz decided to make type coercion the responsibility of the programmer and not the programming language. Whenever input is read (from a file or the command line) it is returned as a string. It is up to your program to convert that string into an Integer, a Float, and imaginary number, etc. In ruby you would need to write ...

1 + Integer("2") #=> 3
1 + "2".to_i #=> 3
1 + "2" #=> raises an error

You can write your own coerce method for the string class, if you are so inclined, in order to make ruby strings behave like Perl strings.

class String
   def coerce( other )
     case other
     when Integer: [other, Integer(self)]
     when Float: [other, Float(self)]
     else raise TypeError, "can't coerce into '#{other.class.name}'" end
   end
end

WIth a coerce method defined for String, you can now write the following in Ruby ...

1 + "2" #=> 3

Blessings,
TwP

···

On Nov 3, 2007, at 1:35 PM, Thufir wrote:

I'm getting keyboard input successfully, but I'm getting a string. I
need to convert it to a number. But ruby is a dynamic language?
What's happening please?

Might I recommend that you read a book about Ruby and/ or programming (I think Ruby). In either case, reading Chris Pine's "How to Program" will give you all that you need to know about walking - and I think you'll be able to run after that.

Things like to_i and to_s, etc. are quite elementary to any language and are covered in detail in books about the language.

Cheers,
Mohit.
11/4/2007 | 4:08 AM.

Thufir wrote:

···

I googled, didn't find the answer, posted, googled more, found the
answer:

C:\code>
C:\code>type makeDragon.rb
require 'Dragon'
require 'factorial'

aDragon = Dragon.new

aDragon.toString

number=0
print "\n\n\nthe Dragon will calculate a factorial now."
puts "\nenter an integer "
#number=gets
number = gets.chomp.to_i

# print "\n\n\n" + number + "\n\n"

answer=fact(number)
print "Dragon replies\n\n"
print answer
#print fact(number)
C:\code>
C:\code>makeDragon.rb

This Dragon
-------------------
Life: 1340
Strength: 451
Charisma: 1020
Weapon: 939

the Dragon will calculate a factorial now.
enter an integer
11
Dragon replies

39916800
C:\code>

A bit chagrined,

Thufir

ps: I'm thinking about class, inheritance and so forth. I'm going to
review another thread where I was asking about the ruby equivalent to
"static class methods" for, specifically, the factorial which I want
ensure cannot be instantiated. I know it's an object, because
everything's an object in Ruby, but have to think about that one.

I think I also want to make some private methods, and a friend was
suggesting to insert some error if the Dragon has low intelligence! :slight_smile:

Thufir wrote:

I googled, didn't find the answer, posted, googled more, found the
answer:

number = gets.chomp.to_i

------------------------------------------------------------ String#to_i
     str.to_i(base=10) => integer

···

------------------------------------------------------------------------
     Returns the result of interpreting ***leading characters*** in
_str_ as
     an integer... .Extraneous characters
     past the end of a valid number are ****ignored***.

     If there is not a valid
     number at the start of _str_, +0+ is returned. This method never
     raises an exception.

----------------------------------------------------------- String#chomp
     str.chomp(separator=$/) => new_str
------------------------------------------------------------------------
     Returns a new +String+ with the given record separator removed from
     the end of _str_ (if present)....

        "hello".chomp #=> "hello"
        "hello\n".chomp #=> "hello"
        "hello\r\n".chomp #=> "hello"
        "hello\n\r".chomp #=> "hello\n"
        "hello\r".chomp #=> "hello"
        "hello \n there".chomp #=> "hello \n there"
        "hello".chomp("llo") #=> "he"

Based on those descriptions will the result returned by

input.chomp().to_i

be any different than the result returned by:

input.to_i

??
--
Posted via http://www.ruby-forum.com/\.

[...]

WIth a coerce method defined for String, you can now write the
following in Ruby ...

1 + "2" #=> 3

[...]

In Java String is immutable partly for security reasons. I don't see
that security is a concern with Ruby, however. No?

thanks,

Thufir

···

On Nov 3, 12:59 pm, tim.pe...@gmail.com wrote:

You want to avoid method's being instantiated per object? You can
attach the method directly to a class...

class C
  def self.fact
    puts "factorial goes here"
  end
end
C.fact

...or to a module...

module M
  def fact
    puts "factorial goes here"
  end
end
include M
foo

...or to a module while preserving namespace...

module M
  def self.fact
    puts "factorial goes here"
  end
end
M::foo

For factorial, I like the Rubyish...

def fact n
  (1..n).inject { |fact, i| fact * i }
end

...unless there is some performance thing I'm not aware of (or I'm
answering the wrong question).

Todd

···

On 11/3/07, Thufir <hawat.thufir@gmail.com> wrote:

ps: I'm thinking about class, inheritance and so forth. I'm going to
review another thread where I was asking about the ruby equivalent to
"static class methods" for, specifically, the factorial which I want
ensure cannot be instantiated. I know it's an object, because
everything's an object in Ruby, but have to think about that one.

[...]

You want to avoid method's being instantiated per object? You can
attach the method directly to a class...

For instance:

C:\code>
C:\code>
C:\code>type factorial.rb
def fact(n)
        if n <= 1
                1
        else
                n * fact(n - 1)
        end
end
C:\code>
C:\code>

I think that factorial would best be a module, as module's cannot be
instantiated. However, I would also want to prevent factorial from
being extended so that nothing "from" it can be instantiated. The
idea of a factorial "object", or an object which descends from it,
strikes me as ludicrous. Is this un-ruby-ish thinking?

-Thufir

···

On Nov 6, 4:12 pm, Todd Benson <caduce...@gmail.com> wrote:

I think that factorial would best be a module, as module's cannot be
instantiated. However, I would also want to prevent factorial from
being extended so that nothing "from" it can be instantiated. The
idea of a factorial "object", or an object which descends from it,
strikes me as ludicrous. Is this un-ruby-ish thinking?

No, not really. But keep in mind you can always make a copy of a
method on the fly in Ruby (unless $SAFE level alters this behavior;
which I'm not sure of)...

module M
  def self.factorial n; (1..n).inject { |f,i| f * i }; end
end

class C; end

c.extend(M)
c.fact # will result in error, which is what you want
m = Math.method(:factorial)
m.call 3 # will result in 6
Math.method(:factorial) == Math.method(:factorial)
# will result in true
Math.method(:factorial).object_id == Math.method(:factorial).object_id
# will result in false on my machine, but that's what I expect

-Thufir

Todd

···

On Nov 6, 2007 10:55 PM, Thufir <hawat.thufir@gmail.com> wrote:

Thanks for the response, Todd. I kinda sorta follow what you were
doing, but that's good, I can come back to it later as I get better :slight_smile:

-Thufir

Well I sorta kinda screwed up. The Math in the original should be M.
I guess that's what happens when you can't cut and paste. It brings
up an interesting point for you, though. You could just add the
factorial method to the existing module Math yourself on the fly.

#reopen Math module
module Math
  def self.factorial n
    #whatever factorial technique you want here
  end
end

Todd

···

On Nov 7, 2007 3:00 PM, Thufir <hawat.thufir@gmail.com> wrote:

Thanks for the response, Todd. I kinda sorta follow what you were
doing, but that's good, I can come back to it later as I get better :slight_smile:

-Thufir