File Coverage

blib/lib/App/Chart/LatestHandler.pm
Criterion Covered Total %
statement 21 23 91.3
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 29 31 93.5


line stmt bran cond sub pod time code
1             # Latest quotes download handlers.
2              
3             # Copyright 2007, 2008, 2009, 2010, 2011, 2014, 2016, 2017 Kevin Ryde
4              
5             # This file is part of Chart.
6             #
7             # Chart is free software; you can redistribute it and/or modify it under the
8             # terms of the GNU General Public License as published by the Free Software
9             # Foundation; either version 3, or (at your option) any later version.
10             #
11             # Chart is distributed in the hope that it will be useful, but WITHOUT ANY
12             # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13             # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14             # details.
15             #
16             # You should have received a copy of the GNU General Public License along
17             # with Chart. If not, see <http://www.gnu.org/licenses/>.
18              
19             package App::Chart::LatestHandler;
20 1     1   392 use 5.010;
  1         3  
21 1     1   5 use strict;
  1         1  
  1         17  
22 1     1   4 use warnings;
  1         2  
  1         20  
23 1     1   4 use Carp;
  1         2  
  1         44  
24 1     1   294 use Encode;
  1         10820  
  1         57  
25 1     1   234 use Encode::Locale; # for coding system "locale"
  1         2305  
  1         33  
26 1     1   5 use List::Util;
  1         2  
  1         45  
27             # use Locale::TextDomain ('App-Chart');
28              
29 1     1   302 use App::Chart;
  0            
  0            
30             use App::Chart::Database;
31             use App::Chart::Download;
32             use App::Chart::Sympred;
33              
34             # uncomment this to run the ### lines
35             # use Smart::Comments;
36              
37             our @handler_list = ();
38              
39             sub new {
40             my $class = shift;
41             my $self = bless ({ @_ }, $class);
42             App::Chart::Sympred::validate ($self->{'pred'});
43             push @handler_list, $self;
44             # highest priority first, and 'stable' for order added among equal
45             use sort 'stable'; # lexical in 5.10
46             @handler_list = sort { ($b->{'priority'} || 0) <=> ($a->{'priority'} || 0) }
47             @handler_list;
48             return $self;
49             }
50              
51             sub handler_for_symbol {
52             if (@_ != 2) { croak "wrong number of arguments"; }
53             my ($class, $symbol) = @_;
54             App::Chart::symbol_setups ($symbol);
55             return List::Util::first { $_->{'pred'}->match($symbol) } @handler_list;
56             }
57              
58             sub download {
59             my ($class, $orig_symbol_list, $orig_extra_list) = @_;
60             $orig_extra_list ||= [];
61             ### LatestHandler download()
62             ### $orig_symbol_list
63             ### $orig_extra_list
64              
65             my (@symbol_list, @extra_list);
66             {
67             # delete duplicates and any extra_list already in symbol_list
68             my %hash;
69             @symbol_list = grep {!$hash{$_}++} @$orig_symbol_list;
70             @extra_list = grep {!$hash{$_}++} @$orig_extra_list;
71             }
72              
73             foreach my $symbol (@symbol_list, @extra_list) {
74             App::Chart::symbol_setups ($symbol);
75             }
76              
77             while (@symbol_list) {
78             ### LatestHandler considering: "@symbol_list"
79             my @this_list = (shift @symbol_list);
80              
81             my $handler = $class->handler_for_symbol ($this_list[0]);
82             if (! $handler) {
83             print "No latest handler for \"",$this_list[0],"\"\n";
84             next;
85             }
86             my $pred = $handler->{'pred'};
87             my $max_symbols = $handler->{'max_symbols'} || 1_000_000;
88              
89             foreach my $list (\@symbol_list, \@extra_list) {
90             for (my $i = 0; @this_list < $max_symbols && $i < @$list; ) {
91             my $symbol = $list->[$i];
92             if ($pred->match ($symbol)) {
93             push @this_list, $symbol;
94             splice @$list, $i,1;
95             } else {
96             $i++;
97             }
98             }
99             }
100              
101             my $proc = $handler->{'proc'};
102             my $trace;
103             unless (do {
104             local $SIG{'__DIE__'} =
105             (# $App::Chart::option{'verbose'} &&
106             eval { require Devel::StackTrace; 1 }
107             ? sub {
108             { local $@; $trace = Devel::StackTrace->new; }
109             die $@;
110             }
111             : $SIG{'__DIE__'});
112             eval { $proc->(\@this_list); 1 };
113             }) {
114             my $err = $@;
115             unless (utf8::is_utf8($err)) { $err = Encode::decode('locale',$err); }
116             say "Latest download error: ", $err;
117             if (defined $trace) {
118             say $trace->as_string;
119             }
120             }
121             }
122             }
123              
124             sub expand_arguments {
125             my ($args) = @_;
126             my @symbol_list = ();
127             foreach my $arg (@$args) {
128             if (ref $arg) {
129             push @symbol_list, $arg->symbols;
130             } else {
131             push @symbol_list, App::Chart::Download::symbol_glob ($arg);
132             }
133             }
134             return @symbol_list;
135             }
136              
137             sub command_line_download {
138             my ($class, $args) = @_;
139             my @symbol_list = expand_arguments ($args);
140             $class->download (\@symbol_list, []);
141             }
142              
143              
144              
145             1;
146             __END__
147              
148             =for stopwords intraday undef
149              
150             =head1 NAME
151              
152             App::Chart::LatestHandler -- latest quotes download handler object
153              
154             =head1 SYNOPSIS
155              
156             use App::Chart::LatestHandler;
157              
158             =head1 FUNCTIONS
159              
160             =over 4
161              
162             =item C<< App::Chart::LatestHandler->new (...) >>
163              
164             Create and register a new intraday image handler. The return is a new
165             C<App::Chart::LatestHandler> object, though usually this is not of interest
166             (only all the handlers later with C<handlers_for_symbol> below).
167              
168             my $pred = App::Chart::Sympred::Suffix->new ('.NZ');
169              
170             App::Chart::LatestHandler->new
171             (pred => $pred,
172             proc => \&latest_download);
173              
174             =item C<< App::Chart::LatestHandler->handler_for_symbol ($symbol) >>
175              
176             Return the C<App::Chart::LatestHandler> object which handles C<$symbol>, or
177             return undef if none.
178              
179             =item C<< App::Chart::LatestHandler->download ($symbol_list, $extra_list) >>
180              
181              
182             =back