Looking for advice on how to fix this error and refactor this code to improve it.
require 'mechanize'
require 'pry'
require 'pp'
module Mymodule
class WebBot
agent = Mechanize.new { |agent|
agent.user_agent_alias = 'Windows Chrome'
}
def form(response)
require "addressable/uri"
require "addressable/template"
template = Addressable::Template.new("http://www.domain.com/{?query*}")
url = template.expand({"query" => response}).to_s
page = agent.get(url)
end
def get_products
products = []
page.search("datatable").search('tr').each do |row|
begin
product = row.search('td')[1].text
rescue => e
p e.message
end
products << product
end
products
end
end
end
response = {size: "SM", color: "BLUE"}
t = Mymodule::WebBot.new
t.form(response)
t.get_products
NameError: undefined local variable or method `agent'
Ruby has a naming convention. agent
is a local variable in the class scope. To make it visible to other methods you should make it a class variable by naming it @@agent
, and it'll be shared among all the objects of WebBot
. The preferred way though is to make it an instance variable by naming it @agent
. Every object of WebBot
will have its own @agent
. But you should put it in initialize
, initialize
will be invoked when you create a new object with new
class WebBot
def initialize
@agent = Mechanize.new do |a|
a.user_agent_alias = 'Windows Chrome'
end
end
.....
And the same error will occur to page
. You defined it in form
as a local variable. When form
finishes execution, it'll be deleted. You should make it an instance variable. Fortunately, you don't have to put it in initialize
. You can define it here in form
. And the object will have its own @page
after invoking form
. Do this in form
:
def form(response)
require "addressable/uri"
require "addressable/template"
template = Addressable::Template.new("http://www.domain.com/{?query*}")
url = template.expand({"query" => response}).to_s
@page = agent.get(url)
end
And remember to change every occurrence of page
and agent
to @page
and @agent
. In your get_products
for example:
def get_products
products = []
@page.search("datatable").search('tr').each do |row|
.....
These changes will resolve the name errors. Refactoring is another story btw.