class IMAPProcessor::Learn
IMAPLearn flags messages per-folder based on what you've flagged before.
aka part three of my Plan for Total Email Domination.
Constants
- BLAND_KEYWORD
IMAP keyword for bland messages
- LEARN_KEYWORD
IMAP keyword for learned messages
- TASTY_KEYWORD
IMAP keyword for tasty messages
Public Class Methods
new(options)
click to toggle source
Creates a new IMAPLearn from options
.
Options include:
+:Threshold+:: Tastiness threshold for flagging
and all options from IMAPClient
Calls superclass method
IMAPProcessor::Client::new
# File lib/imap_processor/learn.rb, line 63 def initialize(options) super @db_root = File.join '~', '.imap_learn', "#{options[:User]}@#{options[:Host]}:#{options[:Port]}" @db_root = File.expand_path @db_root @threshold = options[:Threshold] @classifiers = Hash.new do |h,k| filter_db = File.join @db_root, "#{k}.db" FileUtils.mkdir_p File.dirname(filter_db) h[k] = RBayes.new filter_db end @unlearned_flagged = [] @tasty_unflagged = [] @bland_flagged = [] @tasty_unlearned = [] @bland_unlearned = [] @noop = false end
process_args(args)
click to toggle source
Handles processing of args
.
Calls superclass method
IMAPProcessor::process_args
# File lib/imap_processor/learn.rb, line 42 def self.process_args(args) @@options[:Threshold] = [0.85, 'Tastiness threshold not set'] super __FILE__, args, {} do |opts, options| opts.on("-t", "--threshold THRESHOLD", "Flag messages more tasty than THRESHOLD", "Default: #{options[:Threshold].inspect}", "Options file name: Threshold", Float) do |threshold| options[:Threshold] = threshold end end end
Public Instance Methods
run()
click to toggle source
Flags tasty messages from all selected mailboxes.
# File lib/imap_processor/learn.rb, line 90 def run log "Flagging tasty messages" message_count = 0 mailboxes = find_mailboxes mailboxes.each do |mailbox| @mailbox = mailbox @imap.select @mailbox log "Selected #{@mailbox}" message_count += process_unlearned_flagged message_count += process_tasty_unflagged message_count += process_bland_flagged message_count += process_unlearned end log "Done. Found #{message_count} messages in #{mailboxes.length} mailboxes" end
Private Instance Methods
bland_flagged_in_curr()
click to toggle source
Returns an Array of tasty message sequence numbers that should be marked as tasty.
# File lib/imap_processor/learn.rb, line 149 def bland_flagged_in_curr log "Finding messages re-marked tasty" @bland_flagged = @imap.search [ 'FLAGGED', 'KEYWORD', BLAND_KEYWORD ] update_db @bland_flagged, :remove_bland, :add_tasty @bland_flagged.length end
chunk(messages, size = 20) { |chunk| ... }
click to toggle source
# File lib/imap_processor/learn.rb, line 189 def chunk(messages, size = 20) messages = messages.dup until messages.empty? do chunk = messages.slice! 0, size yield chunk end end
classify(text)
click to toggle source
Returns true if text
is “tasty”
# File lib/imap_processor/learn.rb, line 201 def classify(text) rating = @classifiers[@mailbox].rate text rating > @threshold end
tasty_unflagged_in_curr()
click to toggle source
Returns an Array of message sequence numbers that should be marked as bland.
# File lib/imap_processor/learn.rb, line 132 def tasty_unflagged_in_curr log "Finding messages re-marked bland" @bland_flagged = @imap.search [ 'NOT', 'FLAGGED', 'KEYWORD', TASTY_KEYWORD ] update_db @tasty_unflagged, :remove_tasty, :add_bland @bland_flagged.length end
unlearned_flagged_in_curr()
click to toggle source
Returns an Array of tasty message sequence numbers.
# File lib/imap_processor/learn.rb, line 115 def unlearned_flagged_in_curr log "Finding unlearned, flagged messages" @unlearned_flagged = @imap.search [ 'FLAGGED', 'NOT', 'KEYWORD', LEARN_KEYWORD ] update_db @unlearned_flagged, :add_tasty @unlearned_flagged.length end
unlearned_in_curr()
click to toggle source
Returns two Arrays, one of tasty message sequence numbers and one of bland message sequence numbers.
# File lib/imap_processor/learn.rb, line 165 def unlearned_in_curr log "Learning new, unmarked messages" unlearned = @imap.search [ 'NOT', 'KEYWORD', LEARN_KEYWORD ] tasty = [] bland = [] chunk unlearned do |messages| bodies = @imap.fetch messages, 'RFC822' bodies.each do |body| text = body.attr['RFC822'] bucket = classify(text) ? tasty : bland bucket << body.seqno end end update_db tasty, :add_tasty update_db bland, :add_bland tasty.length + bland.length end
update_db(messages, *actions)
click to toggle source
# File lib/imap_processor/learn.rb, line 206 def update_db(messages, *actions) chunk messages do |chunk| bodies = @imap.fetch chunk, 'RFC822' bodies.each do |body| text = body.attr['RFC822'] actions.each do |action| @classifiers[@mailbox].update_db_with text, action case action when :add_bland then @imap.store body.seqno, '+FLAG.SILENT', [LEARN_KEYWORD, BLAND_KEYWORD] when :add_tasty then @imap.store body.seqno, '+FLAG.SILENT', [:Flagged, LEARN_KEYWORD, TASTY_KEYWORD] when :remove_bland then @imap.store body.seqno, '-FLAG.SILENT', [BLAND_KEYWORD] when :remove_tasty then @imap.store body.seqno, '-FLAG.SILENT', [TASTY_KEYWORD] end end end end end