def add_edge(edge, opts = {})
      raise Abuelo::Exceptions::EdgeAlreadyExistsError if has_edge?(edge)

      @edges[edge.node_1] ||= {}
      @edges[edge.node_1][edge.node_2] = edge

      if undirected? && !opts[:symmetric]
        add_edge(edge.symmetric, symmetric: true)
      end

      self
    end
def add_edge(edge, opts = {})
      raise Abuelo::Exceptions::EdgeAlreadyExistsError if has_edge?(edge)

      @edges[edge.node_1] ||= {}
      @edges[edge.node_1][edge.node_2] = edge

      if undirected? && !opts[:symmetric]
        add_edge(edge.symmetric, symmetric: true)
      end

      self
    end
Adds an edge to the graph.
 Auto-adds the symmetric counterpart if graph is undirected.

 @param [Abuelo::Edge] edge to add

 @return [Abuelo::Graph] the graph

 @raise [Abuelo::Exceptions::EdgeAlreadyExistsError] if the edge is
   already contained in the graph