]>
Dogcows Code - chaz/homebank/blob - src/HomeBank.pm
3 use warnings FATAL
=> 'all';
6 use Symbol qw
/delete_package/;
10 HomeBank - Perl plugin bindings for C<homebank>
14 # NAME: Example Plugin
18 my $self = $class->SUPER::new(@_);
22 print "Terminating...\n";
30 my ($self, $hook_id) = @_;
31 print "An unhandled hook named '$hook_id' was called.\n";
36 The C<HomeBank> class provides the infrastructure for loading plugins and handling the registration and calling of
43 Contains all of the information about each loaded perl plugin. Plugins probably shouldn't mess around with this.
51 =head2 load_plugin $filepath
53 Load a plugin with the given name. Dies if a plugin with the given name cannot be found or if the plugin couldn't
54 successfully be eval'd. L<homebank> calls this to load enabled plugins; plugins themselves probably shouldn't ever use
62 my $package = _valid_package_name
($filepath);
63 $plugins{$package} ||= {};
65 my $mtime = -M
$filepath;
66 if (defined $plugins{$package}->{mtime
} && $plugins{$package}->{mtime
} <= $mtime) {
67 warn "Already loaded $filepath";
69 delete_package
$package if exists $plugins{$package}->{mtime
};
71 open my $fh, $filepath or die "Open '$filepath' failed ($!)";
77 my $eval = qq
/# line 1 "$filepath"\npackage $package; use base 'HomeBank::Plugin'; $code/;
79 my (%plugins, $mtime, $package);
80 eval "$eval; 1" or die $@;
83 $plugins{$package}->{mtime
} = $mtime;
85 if (!exists $plugins{$package}->{instance
}) {
86 $plugins{$package}->{instance
} = $package->new or die "Plugin instantiation failed";
90 =head2 unload_plugin $filepath
92 The opposite of L<load_plugin>.
98 my $package = _valid_package_name
($filepath);
100 return unless exists $plugins{$package};
102 if ($package->can('delete_package_on_unload') && $package->delete_package_on_unload) {
103 delete $plugins{$package};
104 delete_package
$package;
106 delete $plugins{$package}->{instance
};
107 delete $plugins{$package}->{hooks
};
111 =head2 execute_action $filepath
113 Allow the plugin specified by C<$filepath> to perform an action. This is called when the plugin is "activated" by the
114 user. Most plugins should run a modal dialog to allow the user to see and edit plugin preferences.
119 my $filepath = shift;
120 my $package = _valid_package_name
($filepath);
122 return unless exists $plugins{$package};
124 my $instance = $plugins{$package}->{instance
};
125 $instance->EXECUTE if $instance && $instance->can('EXECUTE');
128 =head2 read_metadata $filepath
130 Get the metadata for a plugin without evaluating it. Plugin metadata should be in the first 100 lines of the plugin file
131 and should look something like this:
135 # ABSTRACT: This plugin does something.
136 # AUTHOR: John Doe <jdoe@acme.tld>
137 # WEBSITE: http://acme.tld/
142 my $filepath = shift;
144 my $package = _valid_package_name
($filepath);
145 $plugins{$package} ||= {};
147 return $plugins{$package}->{metadata
} if exists $plugins{$package}->{metadata
};
149 my @keywords = qw
/name version abstract author website/;
150 my $keywords = join('|', @keywords);
153 open my $fh, $filepath or die "Open '$filepath' failed ($!)";
155 for my $line (<$fh>) {
156 last if 100 < ++$count;
157 my ($key, $val) = $line =~ /^#[ \t]*($keywords)[ \t]*[=:](.*)/i;
161 $metadata->{lc $key} = $val;
166 $plugins{$package}->{metadata
} = $metadata;
169 =head2 call_hook $hook_id, ...
171 Invoke each perl plugins' hook handlers for the given hook. Additional arguments are passed through to each handler.
172 Plugins shouldn't use this.
181 for my $package (keys %plugins) {
182 my $hooks = ($plugins{$package} ||= {})->{hooks
} ||= {};
184 for my $cb (@{$hooks->{$hook} ||= []}) {
185 eval { $cb->(@_); 1 } or warn $@;
189 for my $cb (@{$hooks->{unhandled
} ||= []}) {
190 eval { $cb->($hook, @_); 1 } or warn $@;
196 =head2 register_method_hooks $plugin
198 Register hooks defined as methods that begin with `on_'.
202 sub register_method_hooks
{
204 my $package = ref $plugin;
207 my %subs = map { $_ =~ /^on_(.+)/ ? ($1 => $_) : () } keys %{"${package}::"};
210 register_hooks
($plugin, %subs);
213 =head2 register_hooks $plugin, %hooks
215 Register hooks for a plugin.
220 my ($plugin, %hooks) = @_;
221 my $package = ref $plugin;
223 my $hooks = ($plugins{$package} ||= {})->{hooks
} ||= {};
224 for my $hook (keys %hooks) {
225 if (!ref($hooks{$hook}) && defined &{"${package}::$hooks{$hook}"}) {
226 push @{$hooks->{$hook} ||= []}, sub { unshift @_, $plugin; goto &{"${package}::$hooks{$hook}"} };
227 } elsif (ref($hooks{$hook}) eq 'CODE') {
228 push @{$hooks->{$hook} ||= []}, $hooks{$hook};
230 warn "Hook callback is unusable";
235 =head2 unregister_hooks $package, [@hooks]
237 Unregister hooks for a package. If no hooks are specified, B<all> hooks will be unregistered.
241 sub unregister_hooks
{
242 my ($package, @hooks) = @_;
245 for my $hook (@hooks) {
246 (($plugins{$package} ||= {})->{hooks
} ||= {})->{$hook} = [];
249 ($plugins{$package} ||= {})->{hooks
} = {};
253 =head2 _valid_package_name $string
255 Turn a string into a valid name of a package.
259 sub _valid_package_name
{
261 $str =~ s
|.*?([^/\\]+)\
.pl
$|$1|;
262 $str =~ s
|([^A-Za-z0-9\
/_
])|sprintf("_%2x",unpack("C",$1))|eg
;
263 $str =~ s
|/(\d)|sprintf("/_
%2x",unpack("C
",$1))|eg;
265 "HomeBank
::Plugin
::$str";
269 package HomeBank::Boolean;
272 '0+' => sub { ${$_[0]} },
273 '++' => sub { $_[0] = ${$_[0]} + 1 },
274 '--' => sub { $_[0] = ${$_[0]} - 1 },
277 package Types::Serialiser::Boolean;
278 @HomeBank::Boolean::ISA = Types::Serialiser::Boolean::;
281 package HomeBank::Plugin;
284 my ($class, $self) = (shift, shift || {});
286 HomeBank::register_method_hooks($self);
291 goto &HomeBank::register_hooks;
295 goto &HomeBank::unregister_hooks;
299 package HomeBank::Transaction;
303 require DateTime::Format::Strptime;
304 my $dt = DateTime->new(shift->date);
305 $dt->set_formatter(DateTime::Format::Strptime->new(pattern => '%Y-%m-%d'));
312 Charles McGarvey <chazmcgarvey@brokenzipper.com>
314 =head1 COPYRIGHT AND LICENSE
316 This software is copyright (c) 2013 Charles McGarvey.
318 This file is part of HomeBank.
320 HomeBank is free software; you can redistribute it and/or modify
321 it under the terms of the GNU General Public License as published by
322 the Free Software Foundation; either version 2 of the License, or
323 (at your option) any later version.
325 HomeBank is distributed in the hope that it will be useful,
326 but WITHOUT ANY WARRANTY; without even the implied warranty of
327 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
328 GNU General Public License for more details.
330 You should have received a copy of the GNU General Public License
331 along with this program. If not, see <http://www.gnu.org/licenses/>.
This page took 0.059664 seconds and 5 git commands to generate.