File Coverage

blib/lib/MPGA.pm
Criterion Covered Total %
statement 37 37 100.0
branch 22 24 91.6
condition n/a
subroutine 5 5 100.0
pod 0 3 0.0
total 64 69 92.7


line stmt bran cond sub pod time code
1             package MPGA;
2              
3 3     3   419818 use strict;
  3         7  
  3         132  
4 3     3   18 use warnings;
  3         27  
  3         2811  
5              
6             require Exporter;
7              
8             our @ISA = qw(Exporter);
9              
10             # Items to export into callers namespace by default. Note: do not export
11             # names by default without a very good reason. Use EXPORT_OK instead.
12             # Do not simply export all your public functions/methods/constants.
13              
14             # This allows declaration use MPGA ':all';
15             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
16             # will save memory.
17             our %EXPORT_TAGS = ( 'all' => [ qw(
18            
19             ) ] );
20              
21             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
22              
23             our @EXPORT = qw(
24             flow step chunk
25             );
26              
27             our $VERSION = '0.08';
28              
29              
30             # функция flow() принимает только ссылку на массив,
31             # который переворачивается и разбирается с конца функцией step()
32             # пока не опустошится
33             #
34             sub flow {
35 10     10 0 258800 my $flow = shift;
36              
37 10 100       61 return if !$flow;
38 8 100       32 return if ref( $flow ) ne 'ARRAY';
39              
40 3         12 @$flow = reverse @$flow;
41              
42 3         10 while(scalar @$flow) {
43 6         13 step( $flow );
44             }
45              
46 3         7 return;
47             }
48              
49              
50             # функция step() принимает только ссылку на массив,
51             # который парсится с конца с помощью вызова функции chunk()
52             # в поисках первой ссылки на функцию.
53             # эта функция заносится в переменную $fun и будет исполняться, а все переменные
54             # найденные до этой функции заносятся в массив @$args. таким образом
55             # $flow становится короче.
56             #
57             # step() принимает уже перевернутый поток
58             #
59             # исполняемая функция $fun принимает три аргумента:
60             # - $fun - сама эта функция
61             # - $args - аргументы
62             # - $flow - остаток потока
63             #
64             # функция $fun может модифицировать любые свои аргументы
65             # - модифицировать первый аргумент - ссылку на саму себя в принципе можно, но не нужно
66             # функция передается сама себе для того чтобы в случае необходимости она могла
67             # рекурсивно возвратить саму себя в поток @$flow
68             # - второй аргумент - массив аргументов @$args - может относиться к этой функции или
69             # к другой, которая идет дальше по потоку, если функция $fun принимает аргументы,
70             # то массив @$args должен быть модифицирован
71             # в обязательном порядке, аргументы которые функция $fun принимает идут в конце
72             # массива @$args и должны быть получены функцией $fun с помощью pop(@$args)
73             # - третий аргумент - поток $flow - тоже может быть модифицирован с целью изменить поток
74             # выполнения программы, но так как считается, рядовая функция не должна знать слишком много,
75             # то она может модифицировать этот поток только в плане прекращения потока в случае ошибки
76             # из этого следует, что если исполняемая функция $fun захочет вообще
77             # прервать исполнение потока $flow, то она должна обнулить @$flow
78             # и вернуть undef, т.е. выполнить такой код
79             # @$flow = ();
80             # return;
81             # возможно обнуление flow надо будет сделать в анонимной функции, тогда в ней обязательно
82             # надо определить flow из аргументов в начале функции:
83             # my ( $self, $args, $flow ) = @_;
84             #
85             #
86             # исполняемая функция $fun может вернуть
87             # - ссылку на массив - в этом случае этот массив должен быть перевернут
88             # и занесен в конец остатка потока $flow
89             # - ссылка на хэш - в этом случае возврат трактуется как объект, который
90             # должен быть занесен в конец остатка потока $flow
91             # - скаляр - в этом случае возврат трактуется как скаляр, который
92             # должен быть занесен в конец остатка потока $flow
93             # - undef - в этом случае поток $flow не меняется
94             # - во всех других случаях $flow не меняется
95             #
96             # после выполнения функции $fun список аргументов @$args может быть не пустым, в
97             # таком случае он должен быть перевернут и добавлен в поток @$flow после добавления
98             # туда результатов работы $fun
99             #
100             # также надо взять за правило, что функция $fun должна возвращать что-то только
101             # тогда, когда она хочет что-то добавить в поток исполнения
102             # она может вернуть
103             # - ссылку на массив - return [...]; тогда этот массив будет инвертирован и добавлен в поток
104             # - ссылку на хэш - return {...}; добавляется в поток
105             # - скаляр - return $scalar; добавляется в поток
106             # - undef - return; - основной случай, ничего не добавляется в поток
107             #
108             sub step {
109 26     26 0 229316 my $flow = shift;
110              
111 26 100       86 return if !$flow;
112 24 100       77 return if ref($flow) ne 'ARRAY';
113              
114 19 50       45 if(scalar @$flow) {
115 19         44 my ($fun, $args) = chunk($flow);
116 19 100       53 if ($fun) {
117 15         77 my $res = $fun->($fun, $args, $flow);
118              
119 15 100       137 if( defined $res ) { # $fun вернула что-то определённое, НЕ undef
120 9 100       25 if( ref( $res ) eq 'ARRAY' ) { # $fun вернула ссылку на массив
121 4 50       42 push(@$flow, reverse @$res) if scalar @$res;
122             }
123             else {
124 5         10 push @$flow, $res;
125             }
126             }
127              
128 15 100       37 if (scalar @$args) {
129 13         42 push @$flow, reverse @$args;
130             }
131             }
132             }
133              
134 19         42 return;
135             }
136              
137              
138             # функция chunk() принимает только ссылку на массив,
139             # в котором ищет первую с конца ссылку на функцию, всё, что не является ссылкой на функцию
140             # считается аргументом функции и попадает в массив аргментов.
141             # возвращает массив из двух элементов ( fun, [args] )
142             #
143             sub chunk {
144 31     31 0 223971 my $flow = shift;
145              
146 31 100       113 return if ref( $flow ) ne 'ARRAY';
147              
148 25         79 my ($fun, $args);
149              
150 25         61 while(scalar @$flow) {
151 84         158 my $item = pop @$flow;
152 84 100       197 if( ref $item ne 'CODE' ) {
153 66         162 push @$args, $item;
154             }
155             else {
156 18         28 $fun = $item;
157 18         44 last;
158             }
159             }
160              
161 25         106 return $fun, $args;
162             }
163              
164              
165             # Preloaded methods go here.
166              
167             1;
168             __END__