class EmailGraph::InteractionGraph

Directed graph of identities and their relationships, created by parsing messages.

Public Class Methods

new(messages: [], email_processor: nil) click to toggle source

@param messages [Array<#from, to, cc, bcc, date>] optional

message-like objects. See {#add_message} for specification.

@param email_processor [Proc] block that should return a processed email

when passed an unprocessed one. Defaults to #default_email_processor; pass
+Proc.new{ |e| e }+ for no processing.
Calls superclass method EmailGraph::DirectedGraph::new
# File lib/email_graph/interaction_graph.rb, line 12
def initialize(messages: [], email_processor: nil)
  super()
  @email_processor = email_processor || default_email_processor

  messages.each{ |m| add_message(m) }
end

Public Instance Methods

add_message(m, email_processor: nil) click to toggle source

Adds a message to the graph.

@param m [#from, to, cc, bcc, date] message-like object. Field methods

should return an array of objects that respond to #name and #email;
#date should return an instance of +Time+.

@param email_processor [Proc] block that should return a processed email

when passed an unprocessed one. Pass +Proc.new{ |e| e }+ for no processing.

@return m param

# File lib/email_graph/interaction_graph.rb, line 27
def add_message(m, email_processor: nil)
  email_processor ||= @email_processor

  # Fields are in prioritized order (e.g., if in 'to', don't process again in 'cc')
  to_emails = []
  [:to, :cc, :bcc].each do |field|
    addresses = m.send(field) || []
    addresses.each do |a|
      to = email_processor.call(a.email)
      unless to_emails.include?(to)
        from ||= email_processor.call(m.from.first.email)
         
        add_interaction(from, to, m.date)
         
        to_emails << to
      end
    end
  end

  m
end
default_email_processor() click to toggle source
# File lib/email_graph/interaction_graph.rb, line 68
def default_email_processor
  Proc.new do |email| 
    begin
      Normailize::EmailAddress.new(email).normalized_address
    rescue ArgumentError
      # Chokes on emails like "twitter-confirmation-blah=gmail.com@postmaster.twitter.com"
      email.downcase
    end
  end
end
to_mutual_graph(&edge_filter) click to toggle source

Converts graph into an undirected one, where edges are mutual relationships.

The optional edge_filter is used for determining the mutual relationship threshold based on the edge pair. It should take an edge and its inverse as arguments and return true if a MutualRelationship should be created.

# File lib/email_graph/interaction_graph.rb, line 54
def to_mutual_graph(&edge_filter)
  edge_filter ||= Proc.new{ |e, e_inverse| e && e_inverse }

  edge_factory = Proc.new do |e, e_inverse|
    if edge_filter.call(e, e_inverse)
      MutualRelationship.new(e.from, e.to).tap do |r|
        r.interactions.push(*(e.interactions + e_inverse.interactions))
      end
    end
  end

  to_undirected(&edge_factory)
end

Private Instance Methods

add_interaction(from, to, date) click to toggle source
# File lib/email_graph/interaction_graph.rb, line 81
def add_interaction(from, to, date)
  r = add_edge(InteractionRelationship.new(from, to))
  r.add_interaction(date)
end