Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

David Savoir
David Savoir
6,172 Points

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

I'm still attempting to solve caesar's cipher , but somehow am getting an error on the following block of code

def caesar_cipher(string, interval)
  cipherlist = []

  cipherlist = string.split()
  #Iterate over every word (loop)
  cipherlist.each do |word|
    word.split("").each do |letter|
      puts("Printing original letter #{letter}")
      if letter == letter.upcase
        newword = upcase_cipher(word, letter, interval)
      else
        if letter == [a-z]
          newword += downcase_cipher(word, letter, interval)
        else 
          newword+= letter
          puts newword
        end
      end
    end
end
end 

And the error is referring to the assignments of the respective functions' return to the variable newword: undefined method `+' for nil:NilClass (NoMethodError)

Any idea what I'm doing wrong here ?

Thanks in advance,

David

7 Answers

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

OK, I have a partial solution: your scopes are wrong. You have to change all instances of variables arraycounter, counter and newword into @arraycounter, @counter and @newword. You will get a result, no errors, but the result won't be what you were looking for. And I still don't know what this should do: if letter == [a-z]

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

Which line throws the error? Maybe this should have a space before the +: newword+= letter.

David Savoir
David Savoir
6,172 Points

Here's the entire code:

def downcase_cipher(word, letter, interval)
  arraycounter = 0 
  counter = 0 
  newword = ""
  if letter.ord() + interval > 122 
    resultant = (letter.ord()+interval) - 122
    newletter = (97 + resultant).chr
    newword += newletter
    counter += 1
    if word.length == counter
      cipherlist[arraycounter] = newword
      puts ("This is word number: #{arraycounter} #{cipherlist[arraycounter]}")
      newword = ""
      arraycounter += 1
      counter = 0
    end
  else
    newletter = (letter.ord + interval).chr
    puts ("Printing newletter #{newletter}")
    newword += newletter
    puts ("Printing newword #{newword}")
    counter += 1
    if word.length == counter
      cipherlist[arraycounter] = newword
      puts ("This is word number: #{arraycounter} #{cipherlist[arraycounter]}")
      newword = ""
      arraycounter += 1
      counter = 0
    end
  end
  return newletter     
end
def upcase_cipher(word, letter, interval)
  if letter.ord() + interval > 90 
    arraycounter = 0 
    counter = 0 
    newword = ""
    resultant = (letter.ord()+interval) - 90
    newletter = (65 + resultant).chr
    newword += newletter
    counter += 1
    if word.length == counter
      cipherlist[arraycounter] = newword
      puts ("This is word number: #{arraycounter} #{cipherlist[arraycounter]}")
      newword = ""
      arraycounter += 1
      counter = 0
    end
  else
    newletter = (letter.ord + interval).chr
    puts ("Printing newletter #{newletter}")
    newword += newletter
    puts ("Printing newword #{newword}")
    counter += 1
    if word.length == counter
      cipherlist[arraycounter] = newword
      puts ("This is word number: #{arraycounter} #{cipherlist[arraycounter]}")
      newword = ""
      arraycounter += 1
      counter = 0
    end
  end
  return newletter
end
def caesar_cipher(string, interval)
  cipherlist = []

  cipherlist = string.split()
  #Iterate over every word (loop)
  cipherlist.each do |word|
    word.split("").each do |letter|
      puts("Printing original letter #{letter}")
      if letter == letter.upcase
        newword = upcase_cipher(word, letter, interval)
      else
        if letter == [a-z]
          newword += downcase_cipher(word, letter, interval)
        else 
          newword+= letter
          puts newword
        end
      end
    end
end
end  

caesar_cipher("What a string!", 5)

Here's the full error message:

*Printing original letter W
Printing original letter h
/home/ubuntu/workspace/caesar_cypher.rb:76:in block (2 levels) in caesar_cipher': undefined local variable or methoda' for main:Object (NameError)
from /home/ubuntu/workspace/caesar_cypher.rb:71:in each' from /home/ubuntu/workspace/caesar_cypher.rb:71:inblock in caesar_cipher'
from /home/ubuntu/workspace/caesar_cypher.rb:70:in each' from /home/ubuntu/workspace/caesar_cypher.rb:70:incaesar_cipher'
from /home/ubuntu/workspace/caesar_cypher.rb:87:in `<main>' *

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

OK, so first you have to deal with line 76:

if letter == [a-z]

Right now they seem to be names of variables that have no value. You probably want to put them in quotes, do an .ord method to convert them into numbers and then back again into a character.

In line 79, you are trying to operate on a value that is nil. + is a method, it adds stuff. But nil is not a numerical and it's not a string value, so it doesn't know what to do with it. You could do something like this:

newword = ""
newword += letter

But then it will give you an error in line 52 and then some more errors along the way (including the error in variable counter - it also has a nil value and you're trying to add something to it).

You have to go through your whole code again and follow the values of each variable along the way.

David Savoir
David Savoir
6,172 Points

Thanks ! Care to elaborate on the scope part though ? I am not using classes here, but is ruby assuming that I am ?

Thanks in advance.

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

You're defining three separate methods:

def downcase_cipher, def upcase_cipher and def caesar_cipher

You define the variables I mentioned in the first method and they are local variables (no @), so their scope is only limited to that single method. Other methods have no idea what these variables are.

David Savoir
David Savoir
6,172 Points

Makes sense! Thanks!

David Savoir
David Savoir
6,172 Points

Actually the if letter = [a-z] part was supposed to be a regex.

I turned it into this:

if letter == /^[a-z]*$/

I also found a thread referring to using the .tr method on stackoverflow, but I decided to try and stay with what I know for now :-)