This is a follow up question to: ruby variable scoping across classes. The solution makes sense to me conceptually, but I can't get it to work. Thought maybe with more code someone could help me.
I have a class Login that declares a new IMAP class, authenticates, and picks a mailbox.
I then am trying to create a separate class that will "do stuff" in the mailbox. For example, calculate the number of emails received. The problem is that the @imap
instance of Net::IMAP
doesn't pass from the Login class to the Stat class -- I'm getting no method errors for imap.search in the new class. I don't want to re-log in and re-authenticate each time I need to "do some stuff" with the mailbox. I'm trying to implement the solution in the other thread, but can't seem to get it to work.
Here's the Login
class:
class Login
def initialize(user, domain, pass)
@username = user
@domain = domain
@pass = pass
#check if gmail or other domain
gmail_test = @domain.include? "gmail.com"
if gmail_test == true
@imap = Net::IMAP.new('imap.gmail.com',993,true,nil,false)
@imap.login(@username + "@" + @domain, @pass)
else
@imap = Net::IMAP.new("mail." + @domain)
@imap.authenticate('LOGIN', @username + "@" + @domain, @pass)
end
return self
end
#enable mailbox select
def mailbox(box)
@mailbox = box
@mailbox_array = @imap.list('','*').collect{ |mailbox| mailbox.name } #create array of mailboxes
@matching_mailbox = @mailbox_array.grep(/#{@mailbox}/i) #search for mailbox along list
if @matching_mailbox.empty? == true #if no results open INBOX
@mailbox = "INBOX"
@imap.examine(@mailbox)
else
@imap.examine(@matching_mailbox.first.to_s) #if multiple results, select first and examine
@mailbox = @matching_mailbox.first.to_s
end
return self
end
end
I want to be able to say:
Login.new("user", "domain", "pass").mailbox("in")
and then something like:
class Stat
def received_today()
#emails received today
@today = Date.today
@received_today = @imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
puts @domain + " " + @mailbox.to_s + ": " + @received_today + " -- Today\n\n" #(" + @today.strftime("%d-%b-%Y") + ")
end
end
And be able to call
Stat.new.received_today
and have it not throw a "no method search" error. Again, the other question contains pseudo_code and a high level explanation of how to use an accessor method to do this, but I can't implement it regardless of how many hours I've tried (been up all night)...
All I can think is that I am doing this wrong at a high level, and the stat calculation needs to be a method for the Login class, not a separate class. I really wanted to make it a separate class, however, so I could more easily compartmentalize... Thanks!
OK --- After much head banging on the wall, I got this to work.
Added these three methods to class Login:
def get_imap
@imap
end
def get_domain
@domain
end
def get_mailbox
@mailbox
end
Changed class Stat to:
class Stat
def received_today(login)
#emails received today
@today = Date.today
@received_today = login.get_imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
# puts @received_today
puts login.get_domain + " " + login.get_mailbox.to_s + ": " + @received_today + " -- Today\n\n"
end
end
Now this actually works, and doesn't say undefined method search
or imap
:
b = Login.new("user", "domain", "pass").mailbox("box")
c = Stat.new
c.received_today(b)
I'm pretty sure there is a way to use attr_accessor to do this as well, but couldn't figure out the syntax. Anyway, this works and enables me to use the @imap var from class Login in class Stat so I can write methods to "do_stuff" with it. Thanks for the help and please don't hesitate to tell me this is horrible Ruby or not best practices. I'd love to hear the Ruby way to accomplish this.
Edit for attr_accessor
or attr_reader
use:
Just add it to class Login and then can say login.imap.search#stuff
in class Stat
with no problem.