undefined method [] for nil:NilClass (NoMethodError) in ruby... Why? - ruby-on-rails

Here's my code:
begin
items = CSV.read('somefile.csv')
linesAmount = CSV.readlines('somefile.csv').size
counter = 1
while linesAmount >= counter do
fullrow = items[counter]
firstitem = fullrow[0] #This is the line that my code doesn't like.
puts firstitem
counter = counter + 1
end
end
For some ruby doesn't like that one line, where I have firstitem = fullrow[0]. It throws me the undefined method [] error. BUT, in the console, I can still see it printing the firstitem... So it still prints it, but yet throws an error? What's going on?
However, if I take the first three lines in the while loop OUTSIDE of the while loop, and comment out everything in the loop other than the counter line, then I don't get any error. So if that firstitem line appears outside the while loop, the code thinks it's all fine.
Edit: I know that the arrays start from 0, but I specifically wanted counter to not care about the very first line. I forgot to mention that, sorry.
Edit2: Thank you everyone, I solved it by adding -1 after linesAmount, and it works!

Looks like you have an off by one error, you are reading past the end of the items array. If there are 10 lines in the CSV file, the lines will be an array with indexes from 0 to 9, not 1 to 10.
Change your while to look like this
counter = 0
while counter < linesAmount
...
end
However a better approach overall would be to just do the following
CSV.readlines('somefile.csv').each do |line|
puts line
end

CSV.read and CSV.readlines return arrays. If your array contains two values, then size returns 2. But the indexes you need to call are items[0] and items[1]. Therefore this line
items[counter]
throws an error.
Change the line to
items[counter - 1]
and it should work.
Furthermore you can improve your code by using Ruby idioms:
begin
items = CSV.read('somefile.csv')
items.each do |item|
puts item[0]
end
end

Related

How to wait for all Concurrent::Promise in an array to finish/resolve

#some_instance_var = Concurrent::Hash.new
(0...some.length).each do |idx|
fetch_requests[idx] = Concurrent::Promise.execute do
response = HTTP.get(EXTDATA_URL)
if response.status.success?
... # update #some_instance_var
end
# We're going to disregard GET failures here.
puts "I'm here"
end
end
Concurrent::Promise.all?(fetch_requests).execute.wait # let threads finish gathering all of the unique posts first
puts "how am i out already"
When I run this, the bottom line prints first, so it's not doing what I want of waiting for all the threads in the array to finish its work first, hence I keep getting an empty #some_instance_var to work with below this code. What am I writing wrong?
Never mind, I fixed this. That setup is correct, I just had to use the splat operator * for my fetch_requests array inside the all?().
Concurrent::Promise.all?(*fetch_requests).execute.wait
I guess it wanted multiple args instead of one array.

undefined method `click' for "2":String, Rails error when using Mechanize

class ScraperController < ApplicationController
def show
mechanize = Mechanize.new
website = mechanize.get('https://website.com/')
$max = 2
$counter = 0
$link_to_click = 2
#names = []
while $counter <= $max do
#names.push(website.css('.memName').text.strip)
website.link_with(:text => '2').text.strip.click
$link_to_click += 1
$counter += 1
end
end
end
I am trying to scrape 20 items off of each page and then click on the link at the bottom (1, 2, 3, 4, 5, etc.). However, I get the error as seen in the title which tells me that I cannot click the string. So it recognizes that the button '2' exists but will tell me if cannot click it. Ideally, once this is sorted out, I wanted to the use the $link_to_click variable as a way to replace the '2' so that it will increment each time but it always comes back as nil. I have also changed it to .to_s with the same result.
If I remove the click all together, it will scrape the same page 3 times instead of moving onto the next page. I have also removed the text.strip part before the .click and it will do the same thing. I have tried many variations but have had no luck.
I would really appreciate any advice you could offer.
I ended up reviewing the articles I was referencing to solve this and came to this conclusion.
I changed the website_link to website = website.link_with(:text => $link_to_click.to_s).click (because it only worked as a string) and it printed out the first page, second and each one thereafter.
These are the articles that I was referencing to learn how to do this.
http://docs.seattlerb.org/mechanize/GUIDE_rdoc.html
and
https://readysteadycode.com/howto-scrape-websites-with-ruby-and-mechanize

Filling Lua table not going as expected

I am coding a little something in Lua and I've encountered a very frustrating bug/mistake in my code.
network = {}
network.neurons = {}
for i=1,4 do
network.neurons[20000] = {}
network.neurons[20000][i] = NewNeuron()
print(network.neurons[20000][i])
end
The NewNeuron() function creates a new object with some variables. The print() inside this for loop returns the table with the correct variables as expected. The problem comes when I try to use this print again in this loop:
for i=1,4 do
print(network.neurons[20000][i])
end
The print then writes 4 console lines as follows:
(no return)
(no return)
(no return)
*neuron info that should be printed*
It looks as if only the last of the 4 objects exists after I exit the creation loop. Why is this? What am I doing wrong?
You are assigning an entirely new table inside the loop when creating a NewNeuron. The declaration should be outside:
network = {}
network.neurons = {}
network.neurons[20000] = {}
for i=1,4 do
network.neurons[20000][i] = NewNeuron()
print(network.neurons[20000][i])
end

ruby on rails select a variable name using loop

There's a similar answer but it won't apply to me, but maybe will help someone: here
So, I have a loop and need to input a value into each of 20 variables, called product1, product2, ... , product20.
Im using nokogiri to change the values from a page, and manually it works:
li.content = #site.product1
li = #doc.css('li')[1]
But to avoid code repetition and also I have more cases like that one in my app im trying to make a loop, but it won't work since now.
What it need to do:
(1..20).each do |i|
li = #doc.css('li')[i]
li.content = #site.producti
end
Thanks
TRy
(0...20).each do |i|
li = #doc.css('li')[i]
li.content = #site.send("product#{i}")
end

I was making an app and while i was running the code, this showed up: `main.lua`: 290: attempt to index field(a nil value)

I was making an app and while i was running the code, this showed up:
main.lua: 290: attempt to index field(a nil value)
function check()
print('check game over')
for i = 1, Balls.numChildren do
print(i)
if (Balls[i].y > display.contentHeight) then -- LINE 290
display.remove(Balls[i])
Balls[i] = nil
if (tonumber(ballRemain.text) <= 0) then
alert('lose')
end
end
end
end
I checked a couple of times and still couldn't find what's going on. Someone told me that it could be because I didn't remove an event listener, but I'm not sure. Anyone have any ideas?
check looks like a function that is called multiple times. It can set Balls[i] to nil for arbitrary values of i. Presumably Balls has a number of slots that may or may not contain an object. So, change line 290 to check if the slot is occupied before attempting to do anything with the object:
if (Balls[i] and Balls[i].y > display.contentHeight) then -- LINE 290
Ok, i tried print statement and looked at the corona simulator output this is what i got:
Check game over
1
2
Check game over
1
2
and this goes on until it reaches Runtime error and main.lua: 290: attempt to index field(a nil value)

Resources