Undefined method `+' for nil:NilClass (NoMethodError)

Hello, I'm just setting out on Ruby and my first little program is
generating an error (in the line @allwords = @allwords +
aword.reverse.capitalize + " ")

I'm trying to reverse a name, so it someone enters 'Fred' is will supply
'Derf' and if they enter 'Fred Smith' it will supply 'Derf Htims'

Here's the code in full:

class Jumbler
  #attr_accessor :fullname
  def initialize(fullname)
    @fullname = fullname
  end

  def jumblename
    #if there is more than one word, reverse each one
    if @fullname.split(" ").length > 1
      @fullname = @fullname.split(" ")
      @fullname.each do |aword|
        @allwords = @allwords + aword.reverse.capitalize + " "
      end
      return @allwords
    else
      #just send back the single word
      return @fullname.reverse.capitalize
    end
  end
end

puts "Please enter your name:"
$stdout.flush
yourname = gets.chomp

jumbleyou = Jumbler.new(yourname)
puts jumbleyou.jumblename

I'm not sure if instance variables that are private to the object should
appear in the initialization method (or whether they need to be denoted
with '@' but that doesn't seen to fix the problem anyway). It seems to
me that the error is because I'm trying to use 'reverse' or 'capitalize'
on a 'nil' value but I can't see why that's happening.

Guidance appreciated, sorry if my code is offensive! :smiley:

Paul

···

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

Paul Robinson wrote in post #1137092:

  def jumblename
    #if there is more than one word, reverse each one
    if @fullname.split(" ").length > 1
      @fullname = @fullname.split(" ")
      @fullname.each do |aword|
        @allwords = @allwords + aword.reverse.capitalize + " "
      end

@allwords is no initialised, so @allwords + a...try to addition
something to nil

this is perhaps more rubysh :slight_smile:

       @allwords = @fullname.split(" ").map {|w|
                  w.reverse.capitalize
                 }.join(" ")

···

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

Thank you both, that explains it. I hadn't come across the .map method,
it looks very handy!

Should all variables within an object be prefixed with '@' even if they
are private to it's methods? In this case it doesn't seem to make any
difference whether I use 'allwords' or '@allwords'.

Thanks for the help, Ruby has been a revelation so far!

Paul

···

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

This code is the reason for your error
@allwords = @allwords + aword.reverse.capitalize + " "

Since @allwords has no value in it, by default that instance variable is
initialized to nil. Thus creating this error. You need to add @allwords =
"" before the loop.

@allwords = ""
@fullname.each do |aword|
        @allwords = @allwords + aword.reverse.capitalize + " "
end

There is a simpler method to do the same thing
without initializing @allwords

return @fullname.map { |word| word.reverse.capitalize }.join(' ' )

the above could would yeild the same result.

···

On Wed, Feb 19, 2014 at 1:19 AM, Paul Robinson <lists@ruby-forum.com> wrote:

Hello, I'm just setting out on Ruby and my first little program is
generating an error (in the line @allwords = @allwords +
aword.reverse.capitalize + " ")

I'm trying to reverse a name, so it someone enters 'Fred' is will supply
'Derf' and if they enter 'Fred Smith' it will supply 'Derf Htims'

Here's the code in full:

class Jumbler
  #attr_accessor :fullname
  def initialize(fullname)
    @fullname = fullname
  end

  def jumblename
    #if there is more than one word, reverse each one
    if @fullname.split(" ").length > 1
      @fullname = @fullname.split(" ")
      @fullname.each do |aword|
        @allwords = @allwords + aword.reverse.capitalize + " "
      end
      return @allwords
    else
      #just send back the single word
      return @fullname.reverse.capitalize
    end
  end
end

puts "Please enter your name:"
$stdout.flush
yourname = gets.chomp

jumbleyou = Jumbler.new(yourname)
puts jumbleyou.jumblename

I'm not sure if instance variables that are private to the object should
appear in the initialization method (or whether they need to be denoted
with '@' but that doesn't seen to fix the problem anyway). It seems to
me that the error is because I'm trying to use 'reverse' or 'capitalize'
on a 'nil' value but I can't see why that's happening.

Guidance appreciated, sorry if my code is offensive! :smiley:

Paul

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

--
Harisankar P S
https://twitter.com/coder_hsps | http://tech.hsps.in

Thank you Regis & Jesus. I should have made the question clearer but,
yes, I meant variables that are local/private to the method in which
they appear.

Paul

···

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

Hmmm, I was reading this page about 'require'...

http://rubylearning.com/satishtalim/including_other_files_in_ruby.html

... and noticed that @engine_state isn't initialised but the program
still works, presumably because 'nil' is considered to be 'not true' in
this case?

It also has the '@' prefix even though it's not accessible outside the
start_engine method.

Would it be better practice to add

@engine_state = false

to the initialize method or just remove the '@'? I realise this is a
trivial example but I'd like to pick up good habits from the start :smiley:

Paul

···

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

Great thank you both (again!). I'm ok with variable scope and object
orientation in general (Java etc) but this is a rather different!

Paul

···

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

Thanks Marcus.

Paul

···

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

Paul Robinson wrote in post #1137106:

Should all variables within an object be prefixed with '@' even if they
are private to it's methods?

yes !

In this case it doesn't seem to make any difference whether I use > 'allwords'

or '@allwords'

without @ , ruby look for a method named 'allwords'
It will found it if you have defined
   attr_accessor :allwords

this call will create this 2 methods:
   def allwords() @allwords end
   def allwords=(v) @allwords=v end

I do not know why, but theses accessors are not accessible
in constructor code.

···

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

Paul Robinson wrote in post #1137260:

Would it be better practice to add
@engine_state = false
to the initialize method or just remove the '@'?

aïe aïe aïe...

@var : is variable object instance, value is maintains with object life
var : method variable , value is lost after each methode evaluation
var=(); var() : method call, if set/return a @var, value are persisted

···

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

Hmmm, I was reading this page about 'require'...

Learn How to Blog and Build Websites for Profit!

... and noticed that @engine_state isn't initialised but the program
still works, presumably because 'nil' is considered to be 'not true' in
this case?

This is exactly the case.

It also has the '@' prefix even though it's not accessible outside the
start_engine method.

This is not true. Precisely due to having the '@' prefix it is
accesible in other methods of the same class.
If you modify the example like this:

class MotorCycle
  def initialize(make, color)
    # Instance variables
    @make = make
    @color = color
  end
  def engine_status
    @engine_state
  end
  def start_engine
    if @engine_state
      puts 'Engine is already Running'
    else
      @engine_state = true
      puts 'Engine Idle'
    end
  end
end

You could do:

m = MotorCycle.new("honda", "red")
puts m.engine_status #=> nil
m.start_engine
puts m.engine_status #=> true

Would it be better practice to add

@engine_state = false

to the initialize method

It depends. In this example, it might make sense and make everything
clearer. If the engine_state is better defined as always being true or
false, it would be better to initialize it to false in the
constructor, I agree.

or just remove the '@'?

This will impact the function of the variable. If you remove the @,
then it's simple local variable within the method. With the @, it's an
instance variable that lives as long as the object to which it
belongs.

I realise this is a
trivial example but I'd like to pick up good habits from the start :smiley:

That's a good thing, and I think you should read a little bit about
instance variables and object oriented programming in general to have
a clear understanding on the implications of being a local variable vs
an instance variable.

Jesus.

···

On Wed, Feb 19, 2014 at 7:27 PM, Paul Robinson <lists@ruby-forum.com> wrote:

Not only "in this case".
In Ruby, exactly two things are considered false: `false' and `nil'.

Regards,
Marcus

···

Am 19.02.2014 19:27, schrieb Paul Robinson:

... and noticed that @engine_state isn't initialised but the program
still works, presumably because 'nil' is considered to be 'not true' in
this case?

--
GitHub: stomar (Marcus Stollsteimer) · GitHub
PGP: 0x6B3A101A

Paul Robinson wrote in post #1137106:

Should all variables within an object be prefixed with '@' even if they
are private to it's methods?

yes !

The answer to the question I think he is asking should be: no !
I am in the assumption that when you mean "private to it's methods"
you mean variables that are local to a method, that are not used in
any other method in the class. In this case, if you don't use the @
prefix, Ruby will understand that this is a local variable, or a
method if it hasn't found an assignment previously:

allwords = ""

As soon as the parser sees this, from this point on allwords is
considered a local variable.

In this case it doesn't seem to make any difference whether I use > 'allwords'

or '@allwords'

without @ , ruby look for a method named 'allwords'

or a local variable, if it has been previously assigned.

Jesus.

···

On Tue, Feb 18, 2014 at 10:50 PM, Regis d'Aubarede <lists@ruby-forum.com> wrote: