undefined method: nil:NilClass - ruby

Can someone help explain why the following code produces a:
5.times do
star_count = star_count + 1
puts "*" * star_count
end
#=> NoMethodError: undefined method `+' for nil:NilClass
The desired effect of the code is the following image below:
*
**
***
****
*****
Sorry for including the asterisk triangle as code ... was not outputting right so that was the only solution I could think of. Treating the triangle as an image did not work either.

start_count must be initialized to 0 before the loop in this case.
Anyway, there is more idiomatic in Ruby:
5.times do |index|
puts '*' * (index + 1)
end

You can also use upto instead of times to start from another index than zero.
1.upto(5) do |index|
puts '*' * index
end

Related

Why am I getting a "no method" error for a simple matrix add operation in Ruby? Many essentially identical lines in my other programs

Here's the error statement:
EvoWithout.rb:53:in `block (2 levels) in ': undefined method `+' for nil:NilClass (NoMethodError)
Here's line 53:
if behavior[i,0] > Thrsh && s == 0 then animal[i,0]+= 5 end
Here's the relevant code:
situation= Matrix[ [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1],
[1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1],
[1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
[1,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1] ]
# Build brain with $Behavmax rows of 0,1's
brain = Matrix.build(10,16) { 1 }
for i in (0..$Behavmax)
for j in (0..$Stimmax)
if rand(4) < 1.1 then brain[i,j] = 0 end
end # j
end #i
stimulus=Matrix.column_vector([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
behavior=Matrix.row_vector([0,0,0,0,0,0,0,0,0,0])
animal=Matrix.row_vector([20,20,20,20,20,20,20,20,20,20]) # to hold value of fitness
# BEGIN MAIN PROGRAM
# Noise=20
# Go through once presenting 1 situation after another
for s in (0..4)
for j in (0..$Stimmax)
stimulus[j,0] = situation[s,j]
end # for j
# GENERATE BEHAVIOR
behavior=brain*stimulus
for i in (0..$Behavmax) #fire iff stimulus pattern matches detector
if behavior[i,0] > Thrsh && s == 0 then animal[i,0]+= 5 end
#if behavior[i,0] > Thrsh && s != 0 then print "Behavior#{i}=#{behavior[i,0]} and s=#{s} " end
end # for i
puts
end # for s
An important skill to learn is to read error messages and warnings. In your title, you ask:
Why am I getting a “no method” error for a simple matrix add operation in Ruby?
But, that's not what the error message is saying!
You don't get a NoMethodError for a matrix add operation (Matrix#+). If you were, the error message would say something like:
EvoWithout.rb:53:in `block (2 levels) in ': undefined method `+' for animal:Matrix (NoMethodError)
Note that the error message would say (bold emphasis mine) "undefined method `+' for animal:Matrix" (which would be wrong, because Matrix#+ exists). However, that's not what your error message is saying. Your error message says (bold emphasis mine):
undefined method `+' for nil:NilClass
Which is correct, because NilClass does, in fact, not have a + method, and neither do its superclasses Object, Kernel, and BasicObject.
So, you are looking in the wrong place: your problem is not with the matrix add operation, your problem is that your matrix index operation returns nil.
And the reason for that is rather simple: you animal matrix contains only a single row, but you are iterating over $Behavmax + 1 rows. So, as soon as $Behavmax is greater than zero, you will index into the second row of animal, which doesn't exist. Therefore, it will return nil, and your addition will fail.
Remember that a ω= b for any operator ω and arbitrary expressions a and b is equivalent to a = a ω b with a only evaluated once, so
animal[i,0]+= 5
is roughly equivalent to:
__temp__ = animal[i, 0]
animal[i, 0] = __temp__ + 5
And if i is anything other than 0, __temp__ will be nil, because there is only one row in animal.

Ruby Error: wrong number of arguments (given 4, expected 0) (ArgumentError)

I am a ruby beginner and I am trying to make a method called print that prints all the elements in a given array. I want my code to get an undefined local variable error.
This is what I got from Youtube. This gives an undefined local variable error.
movies = ["good","bad"]
def good_movies
movies.each do |movies|
puts "I like #{movie}"
end
end
good_movies
I am using interactive Ruby. This is my version.
numbers = [1,2,3]
def print
numbers.each do |number|
puts "#{number}"
end
end
print
I am getting an error: (irb):2:in `print': wrong number of arguments (given 4, expected 0) (ArgumentError). Why am I getting this, not the undefined local variable error?
What is going on?
You have to pass an argument 'numbers" to the print method.
numbers = [1,2,3]
def print(nums)
nums.each do |number|
puts number
end
end
And then:
print(numbers)

Error using yield in Ruby

I am new to ruby and am trying to learn how yield works. I am using yield in the following way to read characters in a file with help of a function. The return value of this function is input to another function which extracts words based on spaces. However, I am getting the following error while execution:
in `block (2 levels) in getchars': no block given (yield) (LocalJumpError)
Here is the code snippet generating error:
def getchars(file)
IO.readlines(file).each {|line| line.each_char {|chrc| yield chrc }}
end
Can someone please help me understand what am I doing wrong? Thanks.
Addition:
This is how I make call:
def getwords(file)
#st_char = true
getchars(file).each {|c|
if #st_char == true
#word = ""
if c.match(/^[[:alnum:]]+$/)
#word = c
#st_char = false
end
else
if c.match(/^[[:alnum:]]+$/)
#word = #word + c
else
#st_char = true
yield #word
end
end
}
end
You need to pass a code block to getchars for it to yield to.
something like,
getchars("example.txt") {|char| puts char}
Then inside your get chars, it will yield each char one at a time to the supplied code block - which simply puts them out.
I think the error message is pretty clear: getchars tries to yield to a block, but whoever called getchars didnt' pass a block.
In line 2 of getwords, you call getchars without passing a block. You need to pass a block to getchars, so it has something to yield to.
file_as_string = File.read("greetings.txt") # => "hey hello hola vanakam"
array_of_words_after_splitting_by_spaces = file_as_string.split(" ") # => ["hey", "hello", "hola", "vanakam"]
Warning: Please don't use such variable names, just used it to explicitly see whats happening

Getting (NoMethodError) as if object has not been created

I'm having difficulty running the following. I get the following error
"': undefined method `name' for nil:NilClass (NoMethodError)"
at the
puts shopper[i].name
line
As if sometimes the object hasn't been created by the time it gets to that line
(0 .. 9).each do |i|
shopper[i] = Shopper.new("Shopper Number-#{i}")
(0 .. 19).each do |j|
r = rand(0 .. (k-1))
if shopper[i].unsuccessful_shopping_trip == true
puts "#{shopper[i].name} has failed to buy 3 times and has decided to go home"
i += 1
break
else
if shopper[i].add_product(shop.remove_product_bought_by_shopper(r)) == false
puts "#{shopper[i].name} has tried to buy #{(shop.products[r]).name} but it is sold out"
j -= 1
else
puts "#{shopper[i].name} has bought #{(shop.products[r]).name}"
end
end
end
puts shopper[i].name
puts shopper[i].shopping_list
total_shopper_net += shopper[i].total_net_value
total_shopper_gross += shopper[i].how_much_spent
total_shopper_product_count += shopper[i].total_product_count
end
Can anyone explain this?
You are manually incrementing i within the each iterator. Any subsequent reference to shopper[i] does not yet exist, since shoppers are created only at the top of the loop.

Trouble when using match on an array

What i'm trying to do is create a method that can be given an array as an argument. The array should have some numbers in it. The method will return the number of times the array includes each number inside of it. I understand that there are probably many ways to do this, but I'd appreciate it if folks could help me understand why my way is not working rather than just advising me to do something completely different.
So I start by trying this method out
def score (dice)
dice.each do |die|
x = /(die)/.match(dice.to_s).length
end
x
end
and calling it with score ([5])expecting to get an output of 1. However, I get
NoMethodError: undefined method `length' for nil:NilClass
from t2.rb:22:in `block in score'
from t2.rb:21:in `each'
from t2.rb:21:in `score'
from (irb):2
from /home/macs/.rvm/rubies/ruby-2.0.0-p247/bin/irb:13:in `<main>'
I have also tried changing the match statement slightly (getting rid of the to_s) so it is
def score (dice)
dice.each do |die|
x = /(die)/.match(dice).length
end
x
end
and calling it with score ([5]) I get
TypeError: no implicit conversion of Array into String
from t2.rb:22:in `match'
from t2.rb:22:in `block in score'
from t2.rb:21:in `each'
from t2.rb:21:in `score'
from (irb):2
from /home/macs/.rvm/rubies/ruby-2.0.0-p247/bin/irb:13:in `<main>'
Really not sure how I'm supposed to accomplish this matching.
In this line
/(die)/.match(dice.to_s).length
the method match returns nil if the argument you are passing doesn't match the regular expression, which leads to this error
nil.length
# => NoMethodError: undefined method `length' for nil:NilClass
The method will return the number of times the array includes each
number inside of it.
You can try this
a = [1,1,1,2,2,1,3]
a.uniq.map { |x| a.count(x) }
# => [4, 2, 1]
a.uniq.map { |x| {x => a.count(x)} }
# => [{1=>4}, {2=>2}, {3=>1}]
If you want to count the occurence of each elements in the array, then you can do something like this
def score (dice)
count_hash = {}
dice.uniq.each do |die|
count_hash[die] = dice.count(die)
end
count_hash
end
I'd appreciate it if folks could help me understand why my way is not working ...
/(die)/ creates a Regexp, a pattern that can be matched against a string. Your pattern matches and captures die.
Regexp#match returns a MatchData object if there was a match:
/(die)/.match('a string with die') #=> #<MatchData "die" 1:"die">
# here's the match: ^^^
or nil if there was no match:
/(die)/.match('a string with dice') #=> nil
You are not working with string but with an array of integers. You convert this array to a string using Array#to_s:
dice = [5]
dice.to_s #=> "[5]"
This string doesn't contain die and therefore match returns nil:
/(die)/.match("[5]") #=> nil
Calling nil.length then raises the NoMethodError.
Passing the array "as-is" doesn't work either, because match expects a string:
/(die)/.match([5]) #=> TypeError: no implicit conversion of Array into String
Using a Regexp is not going to work here, you'll have to approach this problem in another way.
This is probably the most rubyish way to solve the problem:
a = [1,1,1,2,2,1,3]
p Hash[a.group_by{|x|x}.map{|key, val| [key,val.size]}]
#=> {1=>4, 2=>2, 3=>1}
An example that might help you implement your logic
a = [2,3,2,8,3]
a.uniq.each {|i| print i, "=>", a.to_s.scan(/#{i}/).length, " times \n" } #=> this works but ugly.
a.uniq.each {|i| print i, "=>", a.count(i), " times \n" } #=> borrowed from one of the answers.
2=>2 times
3=>2 times
8=>1 times
You're getting errors because in both cases you are trying to match a string (5) with the wrong thing.
This tries to match die with the entire array dice converted to a string:
dice.each do |die|
x = /(die)/.match(dice.to_s).length
end
This tries to match die with the dice array itself:
dice.each do |die|
x = /(die)/.match(dice).length
end

Resources