| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Kwiki::GDGraphGenerator; |
|
2
|
1
|
|
|
1
|
|
45010
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
40
|
|
|
3
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
30
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
595
|
use Kwiki::Plugin '-Base'; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
use Kwiki::Installer '-base'; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = "0.04"; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
const class_title => 'Kwiki graphs'; |
|
11
|
|
|
|
|
|
|
const class_id => 'graphgenerator'; |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub register { |
|
14
|
|
|
|
|
|
|
my $registry = shift; |
|
15
|
|
|
|
|
|
|
$registry->add( wafl => graph => 'Kwiki::GDGraphGenerator::Wafl' ); |
|
16
|
|
|
|
|
|
|
} |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package Kwiki::GDGraphGenerator::Wafl; |
|
19
|
|
|
|
|
|
|
use Spiffy '-Base'; |
|
20
|
|
|
|
|
|
|
use base 'Spoon::Formatter::WaflBlock'; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
field 'config'; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub to_html { |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# parse the config, make sure options are there |
|
27
|
|
|
|
|
|
|
require YAML; |
|
28
|
|
|
|
|
|
|
$self->config( eval { YAML::Load( $self->block_text ) } ); |
|
29
|
|
|
|
|
|
|
return $self->error("make sure your YAML is correct") if $@; |
|
30
|
|
|
|
|
|
|
return $self->error("graph config isn't a hash") |
|
31
|
|
|
|
|
|
|
unless $self->config && ref $self->config eq 'HASH'; |
|
32
|
|
|
|
|
|
|
foreach (qw( id data type )) { |
|
33
|
|
|
|
|
|
|
return $self->error("graph config must specify '$_'") |
|
34
|
|
|
|
|
|
|
unless exists $self->config->{$_}; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# check to see if the graph exists -- if not, create it |
|
38
|
|
|
|
|
|
|
my $error = $self->generate_image |
|
39
|
|
|
|
|
|
|
unless -e $self->checksum_path |
|
40
|
|
|
|
|
|
|
&& io( $self->checksum_path )->assert->scalar eq $self->checksum; |
|
41
|
|
|
|
|
|
|
return $self->error($error) if $error; |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# return a simple link |
|
44
|
|
|
|
|
|
|
$self->hub->template->process( 'graphgenerator_inline.html', |
|
45
|
|
|
|
|
|
|
src => $self->image_path ); |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub error { |
|
49
|
|
|
|
|
|
|
$self->hub->template->process( 'graphgenerator_error.html', |
|
50
|
|
|
|
|
|
|
msg => "Couldn't create graph: " . shift ); |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub checksum { |
|
54
|
|
|
|
|
|
|
require Data::Dumper; |
|
55
|
|
|
|
|
|
|
require Digest::MD5; |
|
56
|
|
|
|
|
|
|
my $d = new Data::Dumper( [ $self->config ] ); |
|
57
|
|
|
|
|
|
|
Digest::MD5::md5_hex( $d->Sortkeys(1)->Indent(0)->Dump ); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub image_path { |
|
61
|
|
|
|
|
|
|
$self->hub->cgi->button; |
|
62
|
|
|
|
|
|
|
$self->hub->graphgenerator->plugin_directory . '/' |
|
63
|
|
|
|
|
|
|
. $self->hub->pages->current->id . '.' |
|
64
|
|
|
|
|
|
|
. $self->config->{id} . '.png'; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub checksum_path { |
|
68
|
|
|
|
|
|
|
$self->image_path . '.config.md5'; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub generate_image { |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# load config, put things in variables and strip out |
|
74
|
|
|
|
|
|
|
# options we're not going to give to set() |
|
75
|
|
|
|
|
|
|
# (NOTE: width and height are read-only) |
|
76
|
|
|
|
|
|
|
my %config = %{ $self->config }; |
|
77
|
|
|
|
|
|
|
my ( $type, $width, $height, $data ) |
|
78
|
|
|
|
|
|
|
= @config{qw( type width height data )}; |
|
79
|
|
|
|
|
|
|
delete @config{qw( type width height data id )}; |
|
80
|
|
|
|
|
|
|
$width ||= 300; |
|
81
|
|
|
|
|
|
|
$height ||= 300; |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# check for keys we don't allow |
|
84
|
|
|
|
|
|
|
foreach my $key (qw( logo )) { |
|
85
|
|
|
|
|
|
|
return "specifying $key is not permitted" if $config{$key}; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# create a new graph object |
|
89
|
|
|
|
|
|
|
require GD::Graph; |
|
90
|
|
|
|
|
|
|
my $class = "GD::Graph::$type"; |
|
91
|
|
|
|
|
|
|
eval "require $class;"; |
|
92
|
|
|
|
|
|
|
return "couldn't create new $class" if $@; |
|
93
|
|
|
|
|
|
|
my $graph = $class->new( $width, $height ); |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# set the options and plot the data |
|
96
|
|
|
|
|
|
|
$graph->set(%config) |
|
97
|
|
|
|
|
|
|
or return "couldn't use config: " . $graph->error; |
|
98
|
|
|
|
|
|
|
my $gd = $graph->plot($data) |
|
99
|
|
|
|
|
|
|
or return "couldn't plot graph: " . $graph->error; |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# save to the files |
|
102
|
|
|
|
|
|
|
io( $self->image_path ) < $gd->png; |
|
103
|
|
|
|
|
|
|
io( $self->checksum_path ) < $self->checksum; |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# undef means no error |
|
106
|
|
|
|
|
|
|
return; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
package Kwiki::GDGraphGenerator; |
|
110
|
|
|
|
|
|
|
1; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
__DATA__ |