NoMethodError: undefined method `+' for nil:NilClass - ruby

I tried googling and looking through stackoverflow and still couldnt figure out why does it not work. Essentially, this line of code reads in a file.txt and loop through the line of instructions on the text file
# Load instruction in an array
File.open('file.txt').each do |line|
line_num += 1
array.to_a.push line.split(" ")
end
# Loop through the array of Instructions
array.each do |line|
instruction = line[0]
value = line[1].to_i
This is the error that I got
NoMethodError: undefined method `+' for nil:NilClass
method block in <main> in VirtualMemory.rb at line 3
method each in VirtualMemory.rb at line 2
method <main> in VirtualMemory.rb at line 2

line_num += 1
is equivalent to
line_num = line_num + 1
Since line_num is not defined, it is nil -- the fix would be to initialize it as 0 before opening the file, or you could do something like:
array = File.open('file.txt').each.map{ |line| line.split(" ")}

You have to initialize your variables.
line_num += 1
Unless line_num is previously defined this will fail, it's basically the same thing as line_num = nil + 1
This will also fail if you haven't previously defined array, and if you had, then there'd be no point calling to_a.
array.to_a.push line.split(" ")

Related

Ruby want to read file line by line and get the particular part out using gsub

I am writing a code to read a text file or csv file line by line which contain url and i want out the id of each url and print or store in text file but when i do i get an error when i use a loop before loop i am able to get it printed line by line. Can any one help me in this.
Below is the my code sample.
line_num=0
File.open('/Users/divyanshu/python_imdb/channels/url.txt').each do |line|
video_links = "#{line_num += 1} #{line}"
# puts video_links
for video_link in video_links
video_lin = video_link.gsub('https://www.youtube.com/watch?v=', '')
video_di = video_lin.gsub('?utm_source=komparify&utm_campaign=site&utm_medium=detailpage', '')
puts video_di
end
This the error I'm getting
Traceback (most recent call last):
2: from /Users/divyanshu/python_imdb/url_validation.rb:6:in `<main>'
1: from /Users/divyanshu/python_imdb/url_validation.rb:6:in `each'
/Users/divyanshu/python_imdb/url_validation.rb:10:in `block in <main>': undefined method `each' for #<String:0x00007fef3d0907c0> (NoMethodError)
and if I run only this part of code its working fine.
line_num=0
File.open('/Users/divyanshu/python_imdb/channels/url.txt').each do |line|
video_links = "#{line_num += 1} #{line}"
puts video_links
end
Strings Don't Normally #respond_to? :each
The stack trace tells you everything you need to know:
undefined method `each' for #String:0x00007fef3d0907c0 (NoMethodError)
Even assuming that /channels / with a trailing space is a valid portion of the file path, File#open returns a File object rather than a collection of lines. As written, video_links is a String, not a collection such as a Hash or Array, and there's no String#each method. Since for-in loops are syntatic sugar for #each, the object can't respond to the method.
Depending on whether you want to slurp the whole file into an array of lines, or operate linewise, you should use one of the following alternative methods:
File#each_line, inhereted from IO. For example:
File.open("path/to/file").each_line
File#readlines, also inherited from IO. For example:
File.readlines("path/to/file")
Adding on to the answer by #Todd. There is one more issue in your code snippet as I mentioned in my comment. the video_links variable is of class String.
It will contain only the last line of file
You can not iterate over it
For example, a file.txt as below:
one
two
three
four
And code:
File.open('file.txt').each do |line|
var = line
end
puts var
#=> "four"
So, working with your example, you should define your variable video_links as an (empty) Array and append the lines of file to iterate.
Example:
video_links = []
lines_in_file = File.readlines('/Users/divyanshu/python_imdb/channels/url.txt')
lines_in_file.each do |line|
video_links.append line
end
video_links.each do |video_link|
video_lin = video_link.gsub('https://www.youtube.com/watch?v=', '')
video_di = video_lin.gsub('?utm_source=komparify&utm_campaign=site&utm_medium=detailpage', '')
puts video_di
end

undefined method: nil:NilClass

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

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.

Error comparing strings?

When I run the following code where str is of type string:
def self.split(str)
array = Array.new
for i in 0..str.length-1
if str[i].casecmp('a') == 0 || str[i].casecmp(':') == 0
...
end
end
array
end
if __FILE__ == $PROGRAM_NAME
count = 0;
File.readlines('C:/Users/JRQuick/Desktop/while1.test').each do |line|
line = line.strip()
count = count + 1
#CHECKS IF LINE IS COMMENT
if (line.include? '//').equal? false
#CHECKS IF EMPTY LINE
if (line.gsub(" ", "").length != 0)
array = split(line)
print array
end
end
end
end
end
This error appears:
`block in split': undefined method `[]' for nil:NilClass (NoMethodError)
The error us thrown on the 4th line above, which is the if statement found in split().
I have tried equals() and matches() for string comparison but they throw the same error. I have also tried eql?() which throws no error but does not correctly compare string, always returns false, even when should return true.
Along with the above I have made sure str[i] is never nil, and even tried str[i].to_s

Ruby error: undefined method `[]’ for nil:NilClass

I am learning Ruby and I have a bug I cannot understand. I have a method that takes an array of strings (lines) and removes all lines up to a certain line containing a pattern.
The method looks as follows:
def removeHeaderLines(lines)
pattern = "..." # Some pattern.
# If the pattern is not there, do not drop any lines.
prefix = lines.take_while {|line| (not line.match(pattern))}
if prefix.length == lines.length then
return prefix
end
# The pattern is there: remove all line preceding it, as well as the line
# containing it.
suffix = (lines.drop_while {|line| (not line.match(pattern))}).drop(1)
return suffix
end
This works fine and the resulting strings (lines) are displayed correctly on a web page
I am generating.
Additionally, I want to remove all non-empty lines following the pattern. I have modified the method as follows:
def removeHeaderLines(lines)
pattern = "..." # Some pattern.
# If the pattern is not there, do not drop any lines.
prefix = lines.take_while {|line| (not line.match(pattern))}
if prefix.length == lines.length then
return prefix
end
# The pattern is there: remove all line preceding it, as well as the line
# containing it.
suffix = (lines.drop_while {|line| (not line.match(pattern))}).drop(1)
# Remove leading non-empty lines.
# ADDING THIS INTRODUCES A BUG.
body = suffix.drop_while {|line| (line != "")}
return body
end
Very surprisingly (at least for me) this does not work. On the generated web page, instead of the content, I see the error message: Liquid error: undefined method `[]’ for nil:NilClass.
I cannot make much sense out of this message. As far as I understand, some code calling my code has tried to access a non-array object as if it were an array. But both versions
of my method return an array of strings (both variables suffix and body are set to an array of strings), so why should there be a difference?
So, unfortunately, also due to my scarce knowledge of Ruby, I have no clue as to how to debug this problem.
Does anybody see any mistake in the above code? Alternatively, does anybody have any hints as to what can cause the error "undefined method `[]’ for nil:NilClass"?
EDIT
Additional information. I am extending code that I have not written myself (it comes from
Octopress, file plugins/include_code.rb). The original
rendering code looks like this:
def render(context)
code_dir = (context.registers[:site].config['code_dir'].sub(/^\//,'') || 'downloads/code')
code_path = (Pathname.new(context.registers[:site].source) + code_dir).expand_path
file = code_path + #file
if File.symlink?(code_path)
return "Code directory '#{code_path}' cannot be a symlink"
end
unless file.file?
return "File #{file} could not be found"
end
Dir.chdir(code_path) do
##################################
# I have replaced the line below #
##################################
code = file.read
#filetype = file.extname.sub('.','') if #filetype.nil?
title = #title ? "#{#title} (#{file.basename})" : file.basename
url = "/#{code_dir}/#{#file}"
source = "<figure class='code'><figcaption><span>#{title}</span> <a href='#{url}'>download</a></figcaption>\n"
source += " #{highlight(code, #filetype)}</figure>"
safe_wrap(source)
end
end
I have replaced the line
code = file.read
with
code = linesToString(removeHeaderLines(stringToLines(file.read)))
where the two missing methods are:
def stringToLines(string)
ar = Array.new
string.each_line {|line| ar.push(line)}
return ar
end
def linesToString(lines)
s = ""
lines.each {|line| s.concat(line)}
return s
end
I hope this helps.
EDIT 2
Thanks to Hassan's hint (use the join method) I have found the problem!
Parallel to the join method there exists a split method. So
"A\nB\n".split(/\n/)
gives
["A", "B"]
Whereas by using each_line (as I did), one gets each line with the '\n' at the end.
As a consequence
suffix.drop_while {|line| (line != "")}
drops all lines. The result was an empty string that apparently crashes the library
I am using. Thanks to Hassan for indicating a more idiomatic solution. I have now the
following:
def removeHeaderLines(code)
lines = code.split(/\r?\n/)
pat = /.../ # Some pattern.
index = lines.index {|line| line =~ pat}
lines = lines.drop(index + 1).drop_while {|line| line != ""} unless index.nil?
lines.join "\n"
end
and it works fine.
That exception occurs when you attempt to use nil like an array (or hash):
irb(main):001:0> nil[0]
NoMethodError: undefined method `[]' for nil:NilClass
from (irb):1
from /home/mslade/rubygems1.9/bin/irb:12:in `<main>'
or use a variable as an array (or hash) when it has not been initialised:
irb(main):005:0> #b[0]
NoMethodError: undefined method `[]' for nil:NilClass
from (irb):5
from /home/mslade/rubygems1.9/bin/irb:12:in `<main>'
Look for where you have neglected to initalize the array, with something like #b = []
If you are not actually using an array, then it's possible that a funciton you are calling expects one. Scan through the stak dump given, starting at the top, until it mentions a line of your code. Then investigate that line to see what you might have missed.
I don't know what cause the exception, but your code could be like this:
def remove_header_lines(lines)
pattern = /some pat/
index = lines.index {|lines| lines =~ pattern}
lines = lines.drop(index+1).drop_while {|lines| line != ""} unless index.nil?
lines.join
end

Resources