File Coverage

blib/lib/Data/Fetch.pm
Criterion Covered Total %
statement 9 11 81.8
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 13 15 86.6


line stmt bran cond sub pod time code
1             package Data::Fetch;
2              
3             # Author Nigel Horne: njh@bandsman.co.uk
4             # Copyright (C) 2016, Nigel Horne
5              
6             # Usage is subject to licence terms.
7             # The licence terms of this software are as follows:
8             # Personal single user, single computer use: GPL2
9             # All other users (including Commercial, Charity, Educational, Government)
10             # must apply in writing for a licence for use from Nigel Horne at the
11             # above e-mail.
12              
13             # use 5.12.0; # Threads before that are apparently not good
14 1     1   138980 use 5.10.0; # Earliest version that Coro works with
  1         3  
15 1     1   4 use strict;
  1         1  
  1         41  
16 1     1   5 use warnings;
  1         12  
  1         36  
17 1     1   353 use Coro;
  0            
  0            
18             # use threads;
19              
20             =head1 NAME
21              
22             Data::Fetch - give advance warning that you'll be needing a value
23              
24             =head1 VERSION
25              
26             Version 0.04
27              
28             =cut
29              
30             our $VERSION = '0.04';
31              
32             =head1 SYNOPSIS
33              
34             Sometimes we know in advance that we'll be needing a value which is going to take a long time to compute or determine.
35             This module fetches the value in the background so that you don't need to wait so long when you need the value.
36              
37             use CalculatePi;
38             use Data::Fetch;
39             my $fetcher = Data::Fetch->new();
40             my $pi = CalculatePi->new(places => 1000000);
41             $fetcher->prime(object => $pi, message => 'as_string'); # Warn we'll run $pi->as_string() in the future
42             # Do other things
43             print $fetcher->get(object => $pi, message => 'as_string'), "\n"; # Runs $pi->as_string()
44              
45             =head1 SUBROUTINES/METHODS
46              
47             =head2 new
48              
49             Creates a Data::Fetch object. Takes no argument.
50              
51             =cut
52              
53             sub new {
54             my $proto = shift;
55             my $class = ref($proto) || $proto;
56              
57             return unless(defined($class));
58              
59             return bless { }, $class;
60             }
61              
62             =head2 prime
63              
64             Say what is is you'll be needing later.
65             Takes two mandatory parameters:
66              
67             object - the object you'll be sending the message to
68             message - the message you'll be sending
69              
70             Takes one optional parameter:
71              
72             arg - passes this argument to the message
73              
74             =cut
75              
76             sub prime {
77             my $self = shift;
78             my %args = (ref($_[0]) eq 'HASH') ? %{$_[0]} : @_;
79              
80             return unless($args{'object'} && $args{'message'});
81              
82             my $object = $args{'object'} . '->' . $args{'message'};
83             if(my $a = $args{arg}) {
84             $object .= "($a)"
85             }
86              
87             if($self->{values} && $self->{values}->{$object} && $self->{values}->{$object}->{status}) {
88             return $self;
89             }
90             # $self->{values}->{$object}->{thread} = threads->create(sub {
91             # my $o = shift;
92             # my $m = shift;
93             # if(my $a = shift) {
94             # return eval '$o->$m($a)';
95             # }
96             # return eval '$o->$m()';
97             # }, $args{'object'}, $args{'message'}, $args{'arg'});
98              
99             $self->{values}->{$object}->{status} = 'running';
100             $self->{values}->{$object}->{thread} = async {
101             my $o = $args{object};
102             my $m = $args{message};
103             if(my $a = $args{arg}) {
104             return eval '$o->$m($a)';
105             }
106             return eval '$o->$m()';
107             };
108              
109             return $self; # Easily prime lots of values in one call
110             }
111              
112             =head2 get
113              
114             Retrieve get a value you've primed. Takes two mandatory parameters:
115              
116             object - the object you'll be sending the message to
117             message - the message you'll be sending
118              
119             Takes one optional parameter:
120              
121             arg - passes this argument to the message
122              
123             =cut
124              
125             sub get {
126             my $self = shift;
127             my %args = (ref($_[0]) eq 'HASH') ? %{$_[0]} : @_;
128              
129             return unless($args{'object'} && $args{'message'});
130              
131             my $object = $args{'object'} . '->' . $args{'message'};
132             if(my $a = $args{arg}) {
133             $object .= "($a)"
134             }
135              
136             if(!defined($self->{values}->{$object}->{status})) {
137             my @call_details = caller(0);
138             die "Need to prime before getting at line ", $call_details[2], ' of ', $call_details[1];
139             }
140             if($self->{values}->{$object}->{status} eq 'complete') {
141             return $self->{values}->{$object}->{value};
142             }
143             if($self->{values}->{$object}->{status} eq 'running') {
144             my $rc = $self->{values}->{$object}->{thread}->join();
145             $self->{values}->{$object}->{status} = 'complete';
146             delete $self->{values}->{$object}->{thread};
147             # $self->{values}->{$object}->{thread} = undef; # ????
148             return $self->{values}->{$object}->{value} = $rc;
149             }
150             die 'Unknown status: ', $self->{values}->{$object}->{status};
151             }
152              
153             sub DESTROY {
154             if(defined($^V) && ($^V ge 'v5.14.0')) {
155             return if ${^GLOBAL_PHASE} eq 'DESTRUCT'; # >= 5.14.0 only
156             }
157             my $self = shift;
158              
159             return unless($self->{values});
160              
161             foreach my $o(values %{$self->{values}}) {
162             if($o->{thread}) {
163             # $o->{thread}->detach();
164             delete $o->{thread};
165             delete $o->{value};
166             }
167             }
168             }
169              
170             =head1 AUTHOR
171              
172             Nigel Horne, C<< >>
173              
174             =head1 BUGS
175              
176             Can't pass more than one argument to the message.
177              
178             I would not advise using this to call messages that change values in the object.
179              
180             Changing a value between prime and get will not necessarily get you the data you want. That's the way it works
181             and isn't going to change.
182              
183             If you change a value between two calls of get(), the earlier value is always used. This is definitely a feature
184             not a bug.
185              
186             Please report any bugs or feature requests to C,
187             or through the web interface at
188             L.
189             I will be notified, and then you'll
190             automatically be notified of progress on your bug as I make changes.
191              
192             =head1 SEE ALSO
193              
194             =head1 SUPPORT
195              
196             You can find documentation for this module with the perldoc command.
197              
198             perldoc Data::Fetch
199              
200             You can also look for information at:
201              
202             =over 4
203              
204             =item * RT: CPAN's request tracker
205              
206             L
207              
208             =item * AnnoCPAN: Annotated CPAN documentation
209              
210             L
211              
212             =item * CPAN Ratings
213              
214             L
215              
216             =item * Search CPAN
217              
218             L
219              
220             =back
221              
222             =head1 LICENSE AND COPYRIGHT
223              
224             Copyright 2016 Nigel Horne.
225              
226             This program is released under the following licence: GPL
227              
228             =cut
229              
230             1; # End of Data::Fetch