File Coverage

blib/lib/App/RecordStream/Clumper/Options.pm
Criterion Covered Total %
statement 103 118 87.2
branch 14 20 70.0
condition n/a
subroutine 24 31 77.4
pod 0 8 0.0
total 141 177 79.6


line stmt bran cond sub pod time code
1             package App::RecordStream::Clumper::Options;
2              
3 4     4   23 use strict;
  4         8  
  4         92  
4 4     4   17 use warnings;
  4         8  
  4         89  
5              
6 4     4   1264 use App::RecordStream::Clumper::CubeKeyPerfect;
  4         12  
  4         107  
7 4     4   1334 use App::RecordStream::Clumper::KeyLRU;
  4         12  
  4         102  
8 4     4   36 use App::RecordStream::Clumper::KeyPerfect;
  4         10  
  4         72  
9 4     4   1397 use App::RecordStream::Clumper::WrappedClumperCallback;
  4         12  
  4         121  
10 4     4   30 use App::RecordStream::Clumper;
  4         9  
  4         84  
11 4     4   1541 use App::RecordStream::DomainLanguage::Library;
  4         15  
  4         134  
12 4     4   31 use App::RecordStream::DomainLanguage::Snippet;
  4         9  
  4         64  
13 4     4   17 use App::RecordStream::DomainLanguage::Valuation::KeySpec;
  4         8  
  4         50  
14 4     4   17 use App::RecordStream::DomainLanguage;
  4         7  
  4         69  
15 4     4   17 use App::RecordStream::KeyGroups;
  4         8  
  4         3308  
16              
17             sub new {
18 21     21 0 77 my $class = shift;
19              
20 21         193 App::RecordStream::Clumper->load_implementations();
21              
22 21         284974 my $this = {
23             # options for old-style clumping
24             'KEY_SIZE' => undef,
25             'KEY_CUBE' => 0,
26              
27             'TBD' => [],
28              
29             # help
30             'HELP_LIST' => 0,
31             'HELP_SHOW' => 0,
32             };
33              
34 21         180 bless $this, $class;
35              
36 21         117 return $this;
37             }
38              
39             sub main_options {
40 21     21 0 55 my $this = shift;
41              
42 21         66 my $clumpers = $this->{'TBD'};
43              
44             return (
45             # old style clumping
46 10     10   16947 "key|k=s" => sub { push @$clumpers, ['KEYGROUP', $_[1]]; },
47 1     1   155 "dlkey|K=s" => sub { push @$clumpers, ['VALUATION', _build_dlkey($_[1])]; },
48             "size|sz|n=i" => \($this->{'KEY_SIZE'}),
49 0     0   0 "adjacent|1" => sub { $this->{'KEY_SIZE'} = 1; },
50             "cube" => \($this->{'KEY_CUBE'}),
51              
52             # new style clumping
53 9     9   11517 "clumper|c=s" => sub { push @$clumpers, ['CLUMPER', App::RecordStream::Clumper->make_clumper($_[1])]; },
54 0     0   0 "dlclumper|C=s" => sub { push @$clumpers, ['CLUMPER', _build_dlclumper($_[1])]; },
55 21         398 );
56             }
57              
58             sub help_options {
59 21     21 0 51 my $this = shift;
60              
61             return (
62             "list-clumpers" => \($this->{'HELP_LIST'}),
63 21         289 "show-clumper=s" => \($this->{'HELP_SHOW'}),
64             );
65             }
66              
67             sub check_options {
68 21     21 0 68 my $this = shift;
69 21         43 my $clumper_callback = shift;
70              
71 21 50       80 if($this->{'HELP_LIST'}) {
72 0     0   0 die sub { print App::RecordStream::Clumper->list_implementations(); };
  0         0  
73             }
74              
75 21 50       62 if($this->{'HELP_SHOW'}) {
76 0     0   0 die sub { App::RecordStream::Clumper->show_implementation($this->{'HELP_SHOW'}) };
  0         0  
77             }
78              
79 21         59 $this->{'CALLBACK'} = $clumper_callback;
80 21         381 $this->{'CALLBACK_COOKIE'} = undef;
81             }
82              
83             sub _build_dlkey {
84 1     1   3 my $string = shift;
85              
86 1         3 my $name;
87 1 50       8 if($string =~ s/^([^=]*)=//) {
88 1         3 $name = $1;
89             }
90             else {
91 0         0 die "Bad domain language key option (missing '=' to separate name and code): " . $string;
92             }
93              
94 1         9 return ($name, App::RecordStream::DomainLanguage::Snippet->new($string)->evaluate_as('VALUATION'));
95             }
96              
97             sub _build_dlclumper {
98 0     0   0 my $string = shift;
99              
100 0         0 return App::RecordStream::DomainLanguage::Snippet->new($string)->evaluate_as('CLUMPER');
101             }
102              
103             sub _get_cb_and_cookie {
104 159     159   259 my $this = shift;
105              
106 159         258 my $cb = $this->{'CALLBACK'};
107 159         270 my $cookie = $this->{'CALLBACK_COOKIE'};
108 159 100       373 if(!defined($cookie)) {
109 21         81 $cookie = $this->{'CALLBACK_COOKIE'} = $cb->clumper_callback_begin({});
110             }
111              
112 159         345 return ($cb, $cookie);
113             }
114              
115             sub accept_record {
116 138     138 0 257 my $this = shift;
117 138         219 my $record = shift;
118              
119 138         257 my $clumpers = $this->{'TBD'};
120 138         359 while(@$clumpers) {
121 20         40 my $clumper_tuple = pop @$clumpers;
122 20         68 my ($type, @rest) = @$clumper_tuple;
123              
124 20         43 my $cb = $this->{'CALLBACK'};
125              
126 20 100       76 if(0) {
    100          
    50          
127             }
128 0         0 elsif($type eq 'KEYGROUP') {
129 10         25 my ($group_spec) = @rest;
130              
131 10         79 my $key_groups = App::RecordStream::KeyGroups->new();
132 10         47 $key_groups->add_groups($group_spec);
133 10         39 my $keys = $key_groups->get_keyspecs($record);
134              
135 10         27 for my $spec (@$keys) {
136 12         90 $cb = $this->_wrap_key_cb($spec, App::RecordStream::DomainLanguage::Valuation::KeySpec->new($spec), $cb);
137             }
138             }
139             elsif($type eq 'VALUATION') {
140 1         4 my ($name, $val) = @rest;
141              
142 1         4 $cb = $this->_wrap_key_cb($name, $val, $cb);
143             }
144             elsif($type eq 'CLUMPER') {
145 9         16 my ($clumper) = @rest;
146              
147 9         51 $cb = App::RecordStream::Clumper::WrappedClumperCallback->new($clumper, $cb);
148             }
149             else {
150 0         0 die "Internal error";
151             }
152              
153 20         82 $this->{'CALLBACK'} = $cb;
154             }
155              
156 138         307 my ($cb, $cookie) = $this->_get_cb_and_cookie();
157              
158 138         498 $cb->clumper_callback_push_record($cookie, $record);
159              
160 138         837 return 1;
161             }
162              
163             sub _wrap_key_cb {
164 13     13   22 my $this = shift;
165 13         29 my $name = shift;
166 13         22 my $val = shift;
167 13         20 my $cb = shift;
168              
169 13         26 my $size = $this->{'KEY_SIZE'};
170 13         28 my $cube = $this->{'KEY_CUBE'};
171              
172 13         21 my $clumper;
173 13 100       40 if($cube) {
    50          
174 4 50       12 if(defined($size)) {
175 0         0 die "--cube with --size (or --adjacent) is no longer a thing (and it never made sense)";
176             }
177 4         27 $clumper = App::RecordStream::Clumper::CubeKeyPerfect->new_from_valuation($name, $val);
178             }
179             elsif(defined($size)) {
180 0         0 $clumper = App::RecordStream::Clumper::KeyLRU->new_from_valuation($name, $val, $size);
181             }
182             else {
183 9         68 $clumper = App::RecordStream::Clumper::KeyPerfect->new_from_valuation($name, $val);
184             }
185              
186 13         76 return App::RecordStream::Clumper::WrappedClumperCallback->new($clumper, $cb);
187             }
188              
189             sub stream_done {
190 21     21 0 42 my $this = shift;
191              
192 21         51 my ($cb, $cookie) = $this->_get_cb_and_cookie();
193              
194 21         82 $cb->clumper_callback_end($cookie);
195             }
196              
197             sub main_usage {
198             return (
199 0     0 0   [ 'key|-k ', 'Comma separated list of key fields. May be a key spec or key group'],
200             [ 'dlkey|-K ...', 'Specify a domain language key. See "Domain Language Integration" section in --help-more.'],
201             [ 'size|--sz|-n ', 'Number of running clumps to keep.'],
202             [ 'adjacent|-1', 'Only group together adjacent records. Avoids spooling records into memeory'],
203             [ 'cube', 'See "Cubing" section in --help-more.'],
204             [ 'clumper ...', 'Use this clumper to group records. May be specified multiple times. See --help-clumping.'],
205             [ 'dlclumper ...', 'Use this domain language clumper to group records. May be specified multiple times. See --help-clumping.'],
206             );
207             }
208              
209             sub help_usage {
210             return (
211 0     0 0   [ 'list-clumpers', 'Bail and output a list of clumpers' ],
212             [ 'show-clumper ', 'Bail and output this clumper\'s detailed usage.'],
213             );
214             }
215              
216             1;