diff options
Diffstat (limited to 'lib/GitHub/Collector/Role/Graph')
| -rw-r--r-- | lib/GitHub/Collector/Role/Graph/Edges.pm | 13 | ||||
| -rw-r--r-- | lib/GitHub/Collector/Role/Graph/Gexf.pm | 47 | ||||
| -rw-r--r-- | lib/GitHub/Collector/Role/Graph/Neighbors.pm | 128 | ||||
| -rw-r--r-- | lib/GitHub/Collector/Role/Graph/Nodes.pm | 13 | ||||
| -rw-r--r-- | lib/GitHub/Collector/Role/Graph/Query.pm | 45 | ||||
| -rw-r--r-- | lib/GitHub/Collector/Role/Graph/Search.pm | 19 |
6 files changed, 265 insertions, 0 deletions
diff --git a/lib/GitHub/Collector/Role/Graph/Edges.pm b/lib/GitHub/Collector/Role/Graph/Edges.pm new file mode 100644 index 0000000..bea5914 --- /dev/null +++ b/lib/GitHub/Collector/Role/Graph/Edges.pm @@ -0,0 +1,13 @@ +package GitHub::Collector::Role::Graph::Edges; + +use Moose::Role; + +has edges => ( + is => 'rw', + isa => 'HashRef', + lazy => 1, + default => sub { {} }, + auto_deref => 1, +); + +1; diff --git a/lib/GitHub/Collector/Role/Graph/Gexf.pm b/lib/GitHub/Collector/Role/Graph/Gexf.pm new file mode 100644 index 0000000..ab83dd4 --- /dev/null +++ b/lib/GitHub/Collector/Role/Graph/Gexf.pm @@ -0,0 +1,47 @@ +package GitHub::Collector::Role::Graph::Gexf; + +use Moose::Role; +use Graph::GEXF; + +has output => ( + is => 'ro', + isa => 'Int', + predicate => 'should_export', +); + +sub export { + my ($self, ) = @_; + + my $gexf = Graph::GEXF->new(); + $gexf->add_node_attribute( name => 'string' ); + $gexf->add_node_attribute( lang => 'string' ); + $gexf->add_node_attribute( size => 'int' ); + $gexf->add_node_attribute( country => 'string' ); + $gexf->add_node_attribute( indegree => 'int' ); + + my $nodes = {}; + foreach my $node ( keys %{ $self->nodes } ) { + my $n = $gexf->add_node( $self->nodes->{$node}->{id} ); + $n->label($node); + $n->attribute( name => $node ); + $n->attribute( size => $self->nodes->{$node}->{size} ); + $n->attribute( lang => $self->nodes->{$node}->{language} || '' ); + $n->attribute( country => $self->nodes->{$node}->{country} || '' ); + $n->attribute( indegree => $self->nodes->{$node}->{indegree} ); + $nodes->{$node} = $n; + } + + foreach my $edge (keys %{$self->edges}){ + $nodes->{ $self->edges->{$edge}->{sourceId} }->link_to( + { + target => $self->edges->{$edge}->{targetId}, + weight => $self->edges->{$edge}->{weight} + } + ); + } + + my $xml = $gexf->to_xml(); + print $xml; +} + +1; diff --git a/lib/GitHub/Collector/Role/Graph/Neighbors.pm b/lib/GitHub/Collector/Role/Graph/Neighbors.pm new file mode 100644 index 0000000..627de94 --- /dev/null +++ b/lib/GitHub/Collector/Role/Graph/Neighbors.pm @@ -0,0 +1,128 @@ +package GitHub::Collector::Role::Graph::Neighbors; + +use Moose::Role; +with qw(GitHub::Collector::Role::Languages); + +sub neighbors { + my ( $self, $name, $with_connections ) = @_; + + $self->_neighbors($name); + + if ($with_connections) { + foreach my $id ( keys %{ $self->edges } ) { + $self->_connections( $id, $name ); + } + } +} + +sub _neighbors { + my ( $self, $name ) = @_; + + if ( !defined $self->nodes->{$name} ) { + $self->_create_node($name); + } + + $self->_fetch_edges_from($name); + $self->_fetch_edges_to($name); +} + +sub _connections { + my ( $self, $id, $name ) = @_; + + if ( $self->edges->{$id}->{sourceId} eq $name ) { + $self->_neighbors( $self->edges->{$id}->{targetId} ); + } + else { + $self->_neighbors( $self->edges->{$id}->{sourceId} ); + } +} + +sub remove_leaves { + my $self = shift; + + foreach my $id ( keys %{$self->nodes} ) { + if ( $self->nodes->{$id}->{size} < 2 ) { + delete $self->nodes->{$id}; + } + } + + foreach my $id ( keys %{$self->edges} ) { + unless ( $self->nodes->{ $self->edges->{$id}->{sourceId} } + && $self->nodes->{ $self->edges->{$id}->{targetId} } ) + { + delete $self->edges->{ $id }; + } + } +} + +sub _fetch_edges_from { + my ( $self, $name ) = @_; + + my $connections = $self->db_edges->find( { source => $name } ); + + while ( my $edge = $connections->next ) { + my $edge_id = $edge->{source} . $edge->{target}; + + if ( !defined $self->edges->{$edge_id} ) { + $self->edges->{$edge_id} = { + id => $edge_id, + targetId => $edge->{target}, + sourceId => $name, + weight => $edge->{weight}, + }; + + $self->nodes->{$name}->{size}++; + + if ( defined $self->nodes->{ $edge->{target} } ) { + $self->nodes->{ $edge->{target} }->{size}++; + } + else { + $self->_create_node( $edge->{target}, 1 ); + } + } + } +} + +sub _fetch_edges_to { + my ($self, $name) = @_; + my $connections = $self->db_edges->find( { target => $name } ); + while ( my $edge = $connections->next ) { + my $edge_id = $edge->{source} . $edge->{target}; + + if ( !defined $self->edges->{$edge_id} ) { + $self->edges->{$edge_id} = { + id => $edge_id, + targetId => $name, + sourceId => $edge->{source}, + weight => $edge->{weight}, + }; + + $self->nodes->{$name}->{size}++; + + if ( defined $self->nodes->{ $edge->{source} } ) { + $self->nodes->{ $edge->{source} }->{size}++; + } + else { + $self->_create_node( $edge->{source}, 1 ); + } + } + } +} + +sub _create_node { + my ( $self, $login, $size ) = @_; + + $size ||= 0; + + my $info = $self->db_profiles->find_one( { login => $login } ); + $self->nodes->{$login} = { + id => $login, + label => $login, + size => $size, + language => $self->map_languages($info->{language}), + country => $info->{country} || '', + indegree => $info->{indegree}, + }; +} + +1; diff --git a/lib/GitHub/Collector/Role/Graph/Nodes.pm b/lib/GitHub/Collector/Role/Graph/Nodes.pm new file mode 100644 index 0000000..5109e9a --- /dev/null +++ b/lib/GitHub/Collector/Role/Graph/Nodes.pm @@ -0,0 +1,13 @@ +package GitHub::Collector::Role::Graph::Nodes; + +use Moose::Role; + +has nodes => ( + is => 'rw', + isa => 'HashRef', + lazy => 1, + default => sub { {} }, + auto_deref => 1, +); + +1; diff --git a/lib/GitHub/Collector/Role/Graph/Query.pm b/lib/GitHub/Collector/Role/Graph/Query.pm new file mode 100644 index 0000000..d3ab7f0 --- /dev/null +++ b/lib/GitHub/Collector/Role/Graph/Query.pm @@ -0,0 +1,45 @@ +package GitHub::Collector::Role::Graph::Query; + +use Moose::Role; + +has language => ( + is => 'rw', + isa => 'Str', + predicate => 'has_language', +); + +has location => ( + is => 'rw', + isa => 'Str', + predicate => 'has_location', +); + +has company => ( + is => 'ro', + isa => 'Str', + predicate => 'has_company', +); + +has country => ( + is => 'ro', + isa => 'Str', + predicate => 'has_country', +); + + +sub build_query { + my $self = shift; + + my $search = {}; + + foreach my $attr (qw/language location company country/) { + my $predicate = "has_$attr"; + if ( $self->$predicate ) { + $search->{$attr} = $self->$attr; + } + } + + return $search; +} + +1; diff --git a/lib/GitHub/Collector/Role/Graph/Search.pm b/lib/GitHub/Collector/Role/Graph/Search.pm new file mode 100644 index 0000000..fbd0d07 --- /dev/null +++ b/lib/GitHub/Collector/Role/Graph/Search.pm @@ -0,0 +1,19 @@ +package GitHub::Collector::Role::Graph::Search; + +use Moose::Role; + +sub build_from_query { + my ($self, $search) = @_; + + $search ||= $self->build_query(); + + my $profiles = $self->db_profiles->find($search); + + while ( my $profile = $profiles->next ) { + $self->neighbors( $profile->{login}, 0 ); + } + + $self->remove_leaves(); +} + +1; |
