QBoard » Statistical modeling » Stats - Conceptual » Implementing accessor methods in Ruby

Implementing accessor methods in Ruby

  • 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!

      August 23, 2021 5:00 PM IST
    0
  • Another approach that works and doesn't require defining get_var methods:

    b.instance_variable_get("@imap") # where b = class instance of login
    
      August 25, 2021 2:34 PM IST
    0
  • 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.
      August 26, 2021 5:39 PM IST
    0
  • 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.
      September 18, 2021 6:19 PM IST
    0