Errors in my ruby script - ruby

I am getting an error I don't understand. It runs how I intended but throws an error at the end. I am still new to ruby but I know it has something to do with my for loops.
This is my code
nums = Array.new(24){Array.new(80){'X'}}
system('cls')
for i in 0..24
for j in 0..79
print nums[i][j]
end
end
And this is the error messages
K:/Ruby 2/RubyInvaders.rb:5:in block (2 levels) in <main>': undefined method `[]' for nil:NilClass (NoMethodError)
from K:/Ruby 2/RubyInvaders.rb:4:in each'
from K:/Ruby 2/RubyInvaders.rb:4:in block in <main>'
from K:/Ruby 2/RubyInvaders.rb:3:in each'
from K:/Ruby 2/RubyInvaders.rb:3:in <main>'
Its ok to offer better ways to do this but I would also like to understand why I am getting this error

You are creating an array with 24 elements and then a loop with 25 iterations. When you try to print the 25th iteration of that loop, the array position doesn't exist. If you change for i in 0..24 to for i in 0..23, the error should be addressed:
nums = Array.new(24){Array.new(80){'X'}}
system('cls')
for i in 0..23
for j in 0..79
print nums[i][j]
end
end
To amplify on Jon's comment, ruby ranges created with the ... operator are exclusive and won't use the highest specified value (as opposed to the .. operator, which is inclusive).
And--while your approach to looping is valid--it's not idiomatic for ruby. Something like this would be more common:
nums = Array.new(24){Array.new(80){'X'}}
system('cls')
(0..23).each do |i|
(0..79).each do |j|
print nums[i][j]
end
end

When i is 24, nums[i] is nil, and you are calling [] on it.

Related

Ruby Unidentified Method for nil No Method Error

I'm attempting to run this code:
def get_linedict(filename,source)
`dwarfdump -l #{source} > dwarfline.txt`
linefile = File.new("dwarfline.txt","r")
match = false
linefile.readlines.each do |line|
puts line
if /uri:/ =~ line
file = line.match(/.*\/(.*)"/)[1]
if file == filename
match = true
end
puts file
puts match
end
end
And when I do I get the following error:
assn4.rb:12:in `block in get_linedict': undefined method `[]' for nil:NilClass (NoMethodError)
from assn4.rb:9:in `each'
from assn4.rb:9:in `get_linedict'
from assn4.rb:126:in `block in <main>'
from assn4.rb:80:in `each'
from assn4.rb:80:in `<main>'
If I change my each loop to only print the lines it's reading, it works fine. As I understand it, the error I'm getting comes from something being nil which shouldn't be, but if that error is coming from the each loop, why am I able to print out the file?
I guess you first have to ask if line.match gets something, before calling an element of the desired array.
line.match(/.*\/(.*)"/)[1]
When you call line.match(/.*\/(.*)"/) the result is nil. Then you attempt to access nil as an Array. That is when you get undefined method []' for nil:NilClass.
And as for this part of your question
but if that error is coming from the each loop, why am I able to print out the file?
The each loop is causing your code to fail and halt when the error occurs. Since you are attempting to print file after the errors, you are actually not printing out file on that iteration of the loop.
Be aware that line might not be nil. Your regular expression is probably just not covering all the cases you think it is, so one of the match calls is failing and returning nil.

When I run this, there is a something wrong in the sum+=n statement, I don't know how to fix it

class Test
def multiples
(1..1000).each do |n|
if n % 3 == 0 || n % 5 == 0
sum += n
end
puts "The sum of multiples of 3 or 5 below 1000 is #{sum}"
end
end
end
test = Test.new
test.multiples
Error:
test.rb:9:in `block in multiples': undefined method `+' for nil:NilClass (NoMethodError)
The sum of multiples of 3 or 5 below 1000 is
from test.rb:7:in `each'
from test.rb:7:in `multiples'
from test.rb:19:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'
You have not initialised sum, adding sum = 0 should fix this:
class Test
def multiples
sum = 0
(1..1000).each do |n|
if n % 3 == 0 || n % 5 == 0
sum += n
end
puts "The sum of multiples of 3 or 5 below 1000 is #{sum}"
end
end
end
test = Test.new
test.multiples
I remember when I started out in Ruby, I didn't really observe the error messages much, but you might find value in learning how to read those messages. You have:
test.rb:9:in `block in multiples': undefined method `+' for nil:NilClass (NoMethodError)
Just to dissect the obvious a little here. You get the following parts:
test.rb - Your file name
9 - The line number where things break down.
block in multiples - There's a block with an issue
inside 'multiples'
undefined method '+' - Remember that a + sign
is actually just a method name in Ruby and different methods are
available for different variable types. This is saying there's no
method by the name of + for the variable type you're calling it on.
nil - This is the variable type you just tried to call the +
method on.
By element 5 of that error message, you should be thinking "Why is sum currently nil?" And then look around your code and realize you've never declared it. Ruby doesn't know how to add something to nil, so you should immediately think about instantiating/declaring the variable 'sum' somewhere outside of the loop that it's adding things to itself.
Hopefully understanding error messages and why you had an error helps. Because if you don't understand and think through an error message, you're going to hit a road block again. It will probably be around the same time you try to create an array by shoveling something into it, instead of instantiating it first, and wonder why you get a similar error message.
Hope this helps!

Unexpected Method Call

I'm using mongomapper to store pages in a db, and I index them first. In the index method, I loop through each word, and check to see if it is already in the words hashmap. If not, I add an empty array to the hash, then push its location to the array.
def index_words
#words = self.body.split(" ")
#words.each_with_index do |word,i|
if self.words[word.stem].nil?
self.words[word.stem] = []
end
puts "Called from #{caller[0]}"
self.words[word.stem].push(i)
end
end
When I run this, I get an undefined method error, saying that self.words[word.stem] is nil. Furthermore, this method is actually being called from the loop, when it's only called once in the constructor:
def initialize(*args)
super
index_words
end
The error message is:
p = Page.new({author: 'Michael',url: 'michaelfine.me',title: 'Michael Fine',body: 'Body Text'})
called fromPage.rb:19:in `each'
NoMethodError: undefined method `push' for nil:NilClass
from Page.rb:24:in `block in index_words'
from Page.rb:19:in `each'
from Page.rb:19:in `each_with_index'
from Page.rb:19:in `index_words'
from Page.rb:14:in `initialize'
from (irb):103:in `new'
from (irb):103
from /Users/Michael/.rvm/rubies/ruby-1.9.3-p286/bin/irb:16:in `<main>'

Confusion with IRB output in Ruby when object#initialize is overloaded

What I actually trying to see when no 'initialize' method is given to an class definition then the class as you said should call the "Object#initialize",which here I tried to customize and see if it has been called or not. With that approach I reached to a conclusion(although that's wrong), when I typed "ob = A .new" that yes I can overload the Object#initialize method.But all has been ended up with the below exception. Then I thought I did something wrong in my customization.So I tried to create the object creation within an exception block and when I typed "begin" and pressed "ENTER" - i got the same error.
>> class A
>> def Object.new initialize
>> p "hi"
>> rescue
>> end
>> end
=> nil
>> begin # <~~~ Here I have pressed on ENTER
"hi" #<~~~~ How was it print out?
/usr/lib/ruby/1.9.1/irb/ruby-token.rb:94:in `Token': undefined method `set_backtrace' for "hi":String (NoMethodError)
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:348:in `block in lex_init'
from /usr/lib/ruby/1.9.1/irb/slex.rb:236:in `call'
from /usr/lib/ruby/1.9.1/irb/slex.rb:236:in `match_io'
from /usr/lib/ruby/1.9.1/irb/slex.rb:221:in `match_io'
from /usr/lib/ruby/1.9.1/irb/slex.rb:75:in `match'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:286:in `token'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:262:in `lex'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:233:in `block (2 levels) in each_top_level_statement'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
from /usr/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
from /usr/lib/ruby/1.9.1/irb.rb:70:in `block in start'
from /usr/lib/ruby/1.9.1/irb.rb:69:in `catch'
from /usr/lib/ruby/1.9.1/irb.rb:69:in `start'
from /usr/bin/irb:12:in `<main>'
#ubuntu:~$
Now my questions are -
How has the "hi" been printed?
What is the cause of the error as printed above?
If such initialize definition is not allowed,then why has the error not come after I ended with the class definition?
EDIT
As per #casper I tried below:
>> def Object.new
>> p "hi"
>> end
=> nil
>> begin
/usr/lib/ruby/1.9.1/irb/ruby-token.rb:96: stack level too deep (SystemStackError)
But here no "hi" printed back.
So what made the "hi" to print back in the first case?
What exactly are you trying to do? You just redefined Object.new, so there is no surprise you make everything go haywire.
You can basically get the same effect by just:
>> def Object.new
>> end
>> [press enter]
KABOOM
The reason "hi" is printed is that someone just called Object.new, probably the irb REPL loop, and it expected an object, but instead it gets gobledygook.
You can also try this:
def Object.new *args
p args
end
And you will see funny stuff. However you won't be able to quit irb or do anything useful with it after that. Again: you just broke Object.
To make some sense of it you should read this:
In Ruby, what's the relationship between 'new' and 'initialize'? How to return nil while initializing?
And then you can try this:
class Object
class << self
alias :old_new :new
end
end
Now you can do:
def Object.new *args
p args
old_new *args
end
This won't break new because you are still calling the old version of it. However you will now be printing out stuff every time someone calls new.

NoMethodError .to_i ruby

A basic code in ruby that isn't working for me.... The error specifies
NoMethodError (undefined method `to_i' for
row = row.split(",").map { |x| x.to_i }
EDIT:
NoMethodError (undefined method `to_i' for [["123,123,123,"]]:Array):
app/controllers/sessions_controller.rb:21:in `import'
app/controllers/sessions_controller.rb:20:in `each'
app/controllers/sessions_controller.rb:20:in `import'
app/controllers/sessions_controller.rb:17:in `each'
app/controllers/sessions_controller.rb:17:in `import'
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.7ms)
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (8.2ms)
you're receiving that error because you're calling the method .to_i on an array, which is wrong since that method is of the String class, source :http://www.ruby-doc.org/core-2.1.0/String.html#method-i-to_i
So in order to fix this we need to take that string from the array so we can turn it into an integer, remember that you started with an array containing an array, so that's why I'm calling .pop twice:
row = [["123, 123, 123"]]
string_of_numbers = row.pop.pop
string_of_numbers.split(",").map {|x| x.to_i }
If it feels too odd try to play with it on irb, that's usually how I try to sort these kinds of things out, don't forget to always refer to the official documentation

Resources