问题
RuNubie here. I've got a class Login
that logs into gmail using the net/IMAP
library. What is happening is that I create a new instance of that class, such as:
a = Login.new("username", "gmail.com", "passw")
Then, I'm working on other classes that will do some "stuff" with the mailbox. The problem is that the @imap
variable I've defined in Login seems to have disappeared (due to scoping I assume).
This is how @imap
is declared in Login class:
@imap = Net::IMAP.new('imap.gmail.com',993,true,nil,false)
So this:
@today = Date.today
@received_today = imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
...returns an error. These are the two errors I've gotten while playing around with this. The first one is when I use imap
, the second one is when I try @imap
:
NameError: undefined local variable or method `imap' for #<Object:0x10718d2a8>
NoMethodError: undefined method `search' for nil:NilClass
What are the best practices for dealing with a situation like this? Is the only solution to define my methods that do "stuff" in the same class where I'm creating the new instance of Net::IMAP? Is declaring @imap
as a global variable $imap
a bad practice? So confused, I bet the answer is very simple and obvious too, but I'm just not seeing it. Thanks!
回答1:
This:
@received_today = imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
won't work because, well, there is no imap
in scope at that point and so you get a NameError. When you try it like this:
@received_today = @imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
You get a NoMethodError because instance variables, such as @imap
, are automatically created at first use and initialized as nil
. Your real @imap
is in another object so you can't refer to it as @imap
anywhere else.
I think you want a structure more like this:
class User
def imap
if(!@imap)
@imap = Net::IMAP.new('imap.gmail.com', 993, true, nil, false)
# and presumably an @imap.authenticate too...
end
@imap
end
end
class OtherOne
def some_method(user)
@today = Date.today
@received_today = user.imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
end
end
Keep your Net::IMAP
localized inside your User and let other objects use it by providing a simple accessor method.
Oh and that global $imap
idea, I'll just pretend I didn't see that as globals are almost always a really bad idea.
回答2:
a shorter way to define the imap variable in the User class, which is pretty much the same as what mu posted:
class User
def imap
@imap ||= Net::IMAP.new...
end
end
来源:https://stackoverflow.com/questions/9527573/ruby-variable-scoping-across-classes