Kleinen Grammatikfehler behoben.
[kivitendo-erp.git] / SL / MoreCommon.pm
1 package SL::MoreCommon;
2
3 require Exporter;
4 @ISA = qw(Exporter);
5
6 @EXPORT    = qw(save_form restore_form compare_numbers any cross);
7 @EXPORT_OK = qw(ary_union ary_intersect ary_diff);
8
9 use YAML;
10
11 use SL::AM;
12
13 sub save_form {
14   $main::lxdebug->enter_sub();
15
16   my @dont_dump_keys = @_;
17   my %not_dumped_values;
18
19   foreach my $key (@dont_dump_keys) {
20     $not_dumped_values{$key} = $main::form->{$key};
21     delete $main::form->{$key};
22   }
23
24   my $old_form = YAML::Dump($main::form);
25   $old_form =~ s|!|!:|g;
26   $old_form =~ s|\n|!n|g;
27   $old_form =~ s|\r|!r|g;
28
29   map { $main::form->{$_} = $not_dumped_values{$_} } keys %not_dumped_values;
30
31   $main::lxdebug->leave_sub();
32
33   return $old_form;
34 }
35
36 sub restore_form {
37   $main::lxdebug->enter_sub();
38
39   my ($old_form, $no_delete, @keep_vars) = @_;
40
41   my $form          = $main::form;
42   my %keep_vars_map = map { $_ => 1 } @keep_vars;
43
44   map { delete $form->{$_} if (!$keep_vars_map{$_}); } keys %{$form} unless ($no_delete);
45
46   $old_form =~ s|!r|\r|g;
47   $old_form =~ s|!n|\n|g;
48   $old_form =~ s|![!:]|!|g;
49
50   my $new_form = YAML::Load($old_form);
51   map { $form->{$_} = $new_form->{$_} if (!$keep_vars_map{$_}) } keys %{ $new_form };
52
53   $main::lxdebug->leave_sub();
54 }
55
56 sub compare_numbers {
57   $main::lxdebug->enter_sub();
58
59   my $a      = shift;
60   my $a_unit = shift;
61   my $b      = shift;
62   my $b_unit = shift;
63
64   $main::all_units ||= AM->retrieve_units(\%main::myconfig, $main::form);
65   my $units          = $main::all_units;
66
67   if (!$units->{$a_unit} || !$units->{$b_unit} || ($units->{$a_unit}->{base_unit} ne $units->{$b_unit}->{base_unit})) {
68     $main::lxdebug->leave_sub();
69     return undef;
70   }
71
72   $a *= $units->{$a_unit}->{factor};
73   $b *= $units->{$b_unit}->{factor};
74
75   $main::lxdebug->leave_sub();
76
77   return $a <=> $b;
78 }
79
80 sub any (&@) {
81   my $f = shift;
82   return if ! @_;
83   for (@_) {
84     return 1 if $f->();
85   }
86   return 0;
87 }
88
89 =item cross BLOCK ARRAY ARRAY
90
91 Evaluates BLOCK for each combination of elements in ARRAY1 and ARRAY2
92 and returns a new list consisting of BLOCK's return values.
93 The two elements are set to $a and $b.
94 Note that those two are aliases to the original value so changing them
95 will modify the input arrays.
96
97   # append each to each
98   @a = qw/a b c/;
99   @b = qw/1 2 3/;
100   @x = cross { "$a$b" } @a, @b;
101   # returns a1, a2, a3, b1, b2, b3, c1, c2, c3
102
103 As cross expects an array but returns a list it is not directly chainable
104 at the moment. This will be corrected in the future.
105
106 =cut
107 sub cross(&\@\@) {
108   my $op = shift;
109   use vars qw/@A @B/;
110   local (*A, *B) = @_;    # syms for caller's input arrays
111
112   # Localise $a, $b
113   my ($caller_a, $caller_b) = do {
114     my $pkg = caller();
115     no strict 'refs';
116     \*{$pkg.'::a'}, \*{$pkg.'::b'};
117   };
118
119   local(*$caller_a, *$caller_b);
120
121   # This map expression is also the return value.
122   map { my $a_index = $_;
123     map { my $b_index = $_;
124       # assign to $a, $b as refs to caller's array elements
125       (*$caller_a, *$caller_b) = \($A[$a_index], $B[$b_index]);
126       $op->();    # perform the transformation
127     }  0 .. $#B;
128   }  0 .. $#A;
129 }
130
131 sub _ary_calc_union_intersect {
132   my ($a, $b) = @_;
133
134   my %count = ();
135
136   foreach my $e (@$a, @$b) { $count{$e}++ }
137
138   my @union = ();
139   my @isect = ();
140   foreach my $e (keys %count) {
141     push @union, $e;
142     push @isect, $e if $count{$e} == 2;
143   }
144
145   return (\@union, \@isect);
146 }
147
148 sub ary_union {
149   return @{ (_ary_calc_union_intersect @_)[0] };
150 }
151
152 sub ary_intersect {
153   return @{ (_ary_calc_union_intersect @_)[1] };
154 }
155
156 sub ary_diff {
157   my ($a, $b) = @_;
158   my %in_b    = map { $_ => 1 } @$b;
159   return grep { !$in_b{$_} } @$a;
160 }
161
162 1;