File Coverage

lib/Graph/Convert.pm
Criterion Covered Total %
statement 101 104 97.1
branch 33 38 86.8
condition 4 11 36.3
subroutine 8 9 88.8
pod 4 4 100.0
total 150 166 90.3


line stmt bran cond sub pod time code
1             ############################################################################
2             # Convert between Graph::Easy and Graph.
3             #
4             #############################################################################
5              
6             package Graph::Convert;
7              
8 4     4   143217 use 5.008001;
  4         15  
  4         225  
9 4     4   8066 use Graph::Easy;
  4         649220  
  4         167  
10 4     4   5247 use Graph;
  4         663910  
  4         183  
11              
12             $VERSION = '0.09';
13              
14 4     4   38 use strict;
  4         7  
  4         5857  
15              
16             #############################################################################
17             # conversion
18              
19             sub _add_basics
20             {
21             # Add the graph and class attributes from $in to $out
22             # Add all the nodes
23             # Add the groups as pseudo_attributes to the graph (so we can recover them)
24 15     15   31 my ($self, $in, $out) = @_;
25              
26             # add the graph attributes
27 15         28 my $att = $in->{att};
28              
29 15         48 for my $class (keys %$att)
30             {
31 6         23 my $c = $att->{$class};
32 6         16 for my $attr (keys %$c)
33             {
34 4         26 $out->set_graph_attribute($class.'_'.$attr, $c->{$attr});
35             }
36             }
37              
38             # add all nodes (sorted by ID so we can workaround the bug in Graph
39             # for undirected graphs)
40 15         119 for my $n (sort { $a->{id} <=> $b->{id} } $in->nodes())
  17         273  
41             {
42             # the node name is unique, so we can use it as the "vertex id"
43 30         2032 $out->add_vertex($n->{name});
44 30         1551 my $attr = $n->raw_attributes();
45             # store also the node's group
46 30         528 my $ng = $n->group();
47 30 100       142 if (defined $ng)
48             {
49 2         8 $attr->{group} = $ng->name();
50             }
51 30         121 $out->set_vertex_attributes($n->{name}, $attr);
52             }
53              
54             # add all groups as a special attribute list
55 15         1223 for my $g ($in->groups())
56             {
57 6         55 my $attr = $g->raw_attributes();
58             # "group_" is already used by the class attribute
59 6         111 my $prefix = 'grp_' . $g->id() . '_';
60             # store the group name, too
61 6         64 $out->set_graph_attribute($prefix.'name', $g->name());
62 6         124 my $group_group = $g->group();
63 6 100       21 if (defined $group_group)
64             {
65 1         5 $out->set_graph_attribute($prefix.'group', $group_group->name());
66             }
67 6         29 for my $k (keys %$attr)
68             {
69 5         22 $out->set_graph_attribute($prefix.$k, $attr->{$k});
70             }
71             }
72              
73 15         116 $out;
74             }
75              
76             #############################################################################
77             # from Graph::Easy to Graph:
78              
79             sub as_graph
80             {
81             # convert a Graph::Easy object to a Graph object
82 15     15 1 51325 my ($self, $in, $opt) = @_;
83              
84 15 50 33     187 $self->error(
85             "as_graph needs a Graph::Easy object, but got '". ref($in). "'" )
86             unless ref($in) && $in->isa('Graph::Easy');
87            
88 15 100       57 $opt = {} unless defined $opt;
89 15 100       80 $opt->{undirected} = 1 if $in->attribute('type') eq 'undirected';
90              
91 15 100       1235 return $self->as_multiedged_graph($in, $opt) unless $in->is_simple();
92              
93 8         224 my $out = Graph->new( %$opt );
94              
95 8         1697 $self->_add_basics($in,$out);
96              
97             # add all edges
98 8         37 for my $e ($in->edges())
99             {
100 8         115 my $from = $e->{from}->{name}; my $to = $e->{to}->{name};
  8         21  
101 8 100       30 if ($opt->{undirected})
102             {
103             # swap the arguments to avoid creating a spurious edge
104 3 100       12 ($from,$to) = ($to,$from) if $e->{to}->{id} < $e->{from}->{id};
105             }
106 8         45 my $edge = $out->add_edge($from,$to);
107 8         1351 my $attr = $e->raw_attributes();
108 8         180 $out->set_edge_attributes($from, $to, $attr);
109             }
110              
111 8         4836 $out;
112             }
113              
114             sub as_undirected_graph
115             {
116             # convert a Graph::Easy object to an undirected Graph object
117 0     0 1 0 my ($self, $in, $opt) = @_;
118              
119 0         0 $opt->{undirected} = 1;
120 0         0 $self->as_graph($in,$opt);
121             }
122              
123             sub as_multiedged_graph
124             {
125 7     7 1 237 my ($self, $in, $opt) = @_;
126              
127 7 50 33     59 $self->error(
128             "as_multiedged_graph needs a Graph::Easy object, but got '". ref($in). "'" )
129             unless ref($in) && $in->isa('Graph::Easy');
130              
131 7 50       24 $opt = {} unless defined $opt;
132 7         19 $opt->{multiedged} = 1;
133 7         55 my $out = Graph->new( %$opt );
134              
135 7         1522 $self->_add_basics($in,$out);
136              
137             # add all edges
138 7         27 for my $e ($in->edges())
139             {
140             # Adding an edge more than once will result in a new ID
141 14         2334 my $from = $e->{from}->{name}; my $to = $e->{to}->{name};
  14         26  
142 14 100       53 if ($opt->{undirected})
143             {
144             # swap the arguments to avoid creating a spurious edge
145 2 50       10 ($from,$to) = ($to,$from) if $e->{to}->{id} < $e->{from}->{id};
146             }
147 14         64 my $id = $out->add_edge_get_id($from,$to);
148 14         2883 my $attr = $e->raw_attributes();
149 14         289 $out->set_edge_attributes_by_id($from, $to, $id, $attr);
150             }
151              
152 7         2093 $out;
153             }
154              
155             #############################################################################
156             # from Graph to Graph::Easy:
157              
158             sub as_graph_easy
159             {
160             # convert a Graph object to a Graph::Easy object
161 15     15 1 22807 my ($self,$in) = @_;
162            
163 15 50 33     179 $self->error(
164             "as_graph_easy needs a Graph object, but got '". ref($in). "'" )
165             unless ref($in) && $in->isa('Graph');
166            
167 15         79 my $out = Graph::Easy->new();
168              
169 15         1536 my $group_ids = {};
170             # restore the graph attributes (and create all the group objects)
171 15         92 my $att = $in->get_graph_attributes();
172 15         186 for my $key (keys %$att)
173             {
174 15 100       163 if ($key =~ /^grp_([0-9]+)_([A-Za-z_-]+)/)
175             {
176 11         31 my ($id,$a) = ($1,$2);
177             # create the group unless we already created it
178 11 100       57 if (!exists $group_ids->{$id})
179             {
180 6   50     24 my $group_name = $att->{"grp_${id}_name"} || 'unknown group name';
181 6         22 $group_ids->{$id} = $out->add_group( $group_name );
182             }
183 11         345 my $grp = $group_ids->{$id};
184             # set the attribute on the appropriate group object
185 11 100       41 $grp->set_attribute($a, $att->{$key}) unless $a eq 'name';
186             }
187 15 100       547 next unless $key =~ /^((graph|(node|edge|group))(\.\w+)?)_(.+)/;
188              
189 4         11 my $class = $1; my $name = $5;
  4         12  
190              
191 4         19 $out->set_attribute($1,$5, $att->{$key});
192             }
193              
194 15         416 for my $n ($in->vertices())
195             {
196 30         1441 my $node = $out->add_node($n);
197 30         1621 my $attr = $in->get_vertex_attributes($n);
198 30         2573 $node->set_attributes($attr);
199             }
200              
201 15 100       142 if ($in->is_multiedged())
202             {
203             # for multiedged graphs:
204 8         75 for my $e ($in->unique_edges())
205             {
206             # get all the IDs in case of the edge existing more than once:
207 8         320 my @ids = $in->get_multiedge_ids($e->[0], $e->[1]);
208 8         1256 for my $id (@ids)
209             {
210 15         790 my $edge = $out->add_edge($e->[0],$e->[1]);
211 15         1215 my $attr = $in->get_edge_attributes_by_id($e->[0], $e->[1], $id);
212 15         6159 $edge->set_attributes($attr);
213             }
214             }
215             }
216             else
217             {
218             # for simple graphs
219 7         66 for my $e ($in->edges())
220             {
221 7         334 my $edge = $out->add_edge($e->[0],$e->[1]);
222 7         1091 my $attr = $in->get_edge_attributes($e->[0], $e->[1]);
223 7         2238 $edge->set_attributes($attr);
224             }
225             }
226 15 100       1513 $out->set_attribute('type','undirected') if $in->is_undirected();
227              
228 15         754 $out;
229             }
230              
231             1;
232             __END__