Filename | /var/www/foswikidev/core/lib/Foswiki/Contrib/MailerContrib/Subscription.pm |
Statements | Executed 383 statements in 2.53ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
62 | 1 | 1 | 1.58ms | 1.58ms | new | Foswiki::Contrib::MailerContrib::Subscription::
1 | 1 | 1 | 17µs | 31µs | BEGIN@15 | Foswiki::Contrib::MailerContrib::Subscription::
1 | 1 | 1 | 10µs | 40µs | BEGIN@17 | Foswiki::Contrib::MailerContrib::Subscription::
1 | 1 | 1 | 9µs | 14µs | BEGIN@16 | Foswiki::Contrib::MailerContrib::Subscription::
1 | 1 | 1 | 9µs | 44µs | BEGIN@20 | Foswiki::Contrib::MailerContrib::Subscription::
1 | 1 | 1 | 9µs | 37µs | BEGIN@23 | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | _sameTopics | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | covers | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | equals | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | filterExact | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | getMode | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | matches | Foswiki::Contrib::MailerContrib::Subscription::
0 | 0 | 0 | 0s | 0s | stringify | Foswiki::Contrib::MailerContrib::Subscription::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Contrib::MailerContrib::Subscription | ||||
6 | Object that represents a subscription to notification on a set of pages. | ||||
7 | A subscription is expressed as a set of page specs (each of which may | ||||
8 | contain wildcards) and a depth of children of matching pages that the | ||||
9 | user is subscribed to. | ||||
10 | |||||
11 | =cut | ||||
12 | |||||
13 | package Foswiki::Contrib::MailerContrib::Subscription; | ||||
14 | |||||
15 | 2 | 32µs | 2 | 44µs | # spent 31µs (17+14) within Foswiki::Contrib::MailerContrib::Subscription::BEGIN@15 which was called:
# once (17µs+14µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@23 at line 15 # spent 31µs making 1 call to Foswiki::Contrib::MailerContrib::Subscription::BEGIN@15
# spent 14µs making 1 call to strict::import |
16 | 2 | 24µs | 2 | 18µs | # spent 14µs (9+4) within Foswiki::Contrib::MailerContrib::Subscription::BEGIN@16 which was called:
# once (9µs+4µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@23 at line 16 # spent 14µs making 1 call to Foswiki::Contrib::MailerContrib::Subscription::BEGIN@16
# spent 4µs making 1 call to warnings::import |
17 | 2 | 31µs | 2 | 69µs | # spent 40µs (10+30) within Foswiki::Contrib::MailerContrib::Subscription::BEGIN@17 which was called:
# once (10µs+30µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@23 at line 17 # spent 40µs making 1 call to Foswiki::Contrib::MailerContrib::Subscription::BEGIN@17
# spent 30µs making 1 call to Exporter::import |
18 | |||||
19 | # Always mail out this subscription, even if there have been no changes | ||||
20 | 2 | 31µs | 2 | 78µs | # spent 44µs (9+34) within Foswiki::Contrib::MailerContrib::Subscription::BEGIN@20 which was called:
# once (9µs+34µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@23 at line 20 # spent 44µs making 1 call to Foswiki::Contrib::MailerContrib::Subscription::BEGIN@20
# spent 34µs making 1 call to constant::import |
21 | |||||
22 | # Always mail out the full topic, not just the changes | ||||
23 | 2 | 729µs | 2 | 65µs | # spent 37µs (9+28) within Foswiki::Contrib::MailerContrib::Subscription::BEGIN@23 which was called:
# once (9µs+28µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@23 at line 23 # spent 37µs making 1 call to Foswiki::Contrib::MailerContrib::Subscription::BEGIN@23
# spent 28µs making 1 call to constant::import |
24 | |||||
25 | # in the page spec these correspond as follows: | ||||
26 | # ? = FULL_TOPIC | ||||
27 | # ! = FULL_TOPIC | ALWAYS | ||||
28 | |||||
29 | =begin TML | ||||
30 | |||||
31 | ---++ ClassMethod new($pages, $childDepth, $options) | ||||
32 | * =$pages= - Wildcarded expression matching subscribed pages. | ||||
33 | * =$childDepth= - Depth of children of $topic to notify changes | ||||
34 | for. Defaults to 0 | ||||
35 | * =$options= - bitmask of Foswiki::Contrib::MailerContrib::Subscription options | ||||
36 | Create a new subscription. | ||||
37 | |||||
38 | =cut | ||||
39 | |||||
40 | # spent 1.58ms within Foswiki::Contrib::MailerContrib::Subscription::new which was called 62 times, avg 26µs/call:
# 62 times (1.58ms+0s) by Foswiki::Contrib::MailerContrib::WebNotify::subscribe at line 158 of /var/www/foswikidev/core/lib/Foswiki/Contrib/MailerContrib/WebNotify.pm, avg 26µs/call | ||||
41 | 62 | 39µs | my ( $class, $topics, $depth, $opts ) = @_; | ||
42 | |||||
43 | ASSERT( defined($opts) && $opts =~ /^\d*$/ ) if DEBUG; | ||||
44 | |||||
45 | 62 | 13µs | my $tre = $topics; | ||
46 | 62 | 121µs | $tre =~ s/ +/|/g; # space means alternate | ||
47 | 62 | 59µs | $tre =~ s/\*/\.\*\?/g; # convert wildcards to perl RE syntax | ||
48 | 62 | 1.27ms | my $this = bless( | ||
49 | { | ||||
50 | topics => [ split( /\s+/, $topics ) ], | ||||
51 | depth => $depth || 0, | ||||
52 | options => $opts || 0, | ||||
53 | topicsRE => qr/^(?:$tre)$/ | ||||
54 | }, | ||||
55 | $class | ||||
56 | ); | ||||
57 | 62 | 179µs | return $this; | ||
58 | } | ||||
59 | |||||
60 | =begin TML | ||||
61 | |||||
62 | ---++ stringify() -> string | ||||
63 | Return a string representation of this object, in Web<nop>Notify format. | ||||
64 | |||||
65 | =cut | ||||
66 | |||||
67 | sub stringify { | ||||
68 | my $this = shift; | ||||
69 | my $record = join( | ||||
70 | ' ', | ||||
71 | map { | ||||
72 | |||||
73 | # Protect single and double quotes in topic names | ||||
74 | ( $_ =~ /'/ ) ? "\"$_\"" : ( ( $_ =~ /"/ ) ? "'$_'" : $_ ); | ||||
75 | } @{ $this->{topics} } | ||||
76 | ); | ||||
77 | $record .= $this->getMode(); | ||||
78 | $record .= " ($this->{depth})" if ( $this->{depth} ); | ||||
79 | return $record; | ||||
80 | } | ||||
81 | |||||
82 | =begin TML | ||||
83 | |||||
84 | ---++ ObjectMethod matches($topic, $db, $depth) -> boolean | ||||
85 | * =$topic= - Topic names we are checking (may be an array ref) | ||||
86 | * =$db= - Foswiki::Contrib::MailerContrib::UpData database of parent names | ||||
87 | * =$depth= - If non-zero, check if the parent of the given topic matches as well. undef = 0. | ||||
88 | Check if we match this topic. Recurses up the parenthood tree seeing if | ||||
89 | this is a child of a parent that matches within the depth range. | ||||
90 | |||||
91 | TODO: '*' should match alot of things.. | ||||
92 | |||||
93 | =cut | ||||
94 | |||||
95 | sub matches { | ||||
96 | my ( $this, $topics, $db, $depth ) = @_; | ||||
97 | |||||
98 | return 0 unless ($topics); | ||||
99 | |||||
100 | unless ( ref $topics ) { | ||||
101 | $topics = [$topics]; | ||||
102 | } | ||||
103 | |||||
104 | foreach my $topic (@$topics) { | ||||
105 | return 1 if ( $topic =~ $this->{topicsRE} ); | ||||
106 | |||||
107 | $depth = $this->{depth} unless defined($depth); | ||||
108 | $depth ||= 0; | ||||
109 | |||||
110 | if ( $depth && $db ) { | ||||
111 | my $parent = $db->getParent($topic); | ||||
112 | $parent =~ s/^.*\.//; | ||||
113 | return $this->matches( $parent, $db, $depth - 1 ) if ($parent); | ||||
114 | } | ||||
115 | } | ||||
116 | |||||
117 | return 0; | ||||
118 | } | ||||
119 | |||||
120 | =begin TML | ||||
121 | |||||
122 | ---++ ObjectMethod covers($other, $db) -> $boolean | ||||
123 | * =$other= - Other subscription object we are checking | ||||
124 | * =$db= - Foswiki::Contrib::MailerContrib::UpData database of parent names | ||||
125 | Return true if this subscription already covers all the topics | ||||
126 | specified by another subscription. Thus: | ||||
127 | * AA;B _covers_ AB, AxB | ||||
128 | * AA; _covers_ AA;B | ||||
129 | * A;B _does not cover_ AA; | ||||
130 | |||||
131 | =cut | ||||
132 | |||||
133 | sub covers { | ||||
134 | my ( $this, $tother, $db ) = @_; | ||||
135 | |||||
136 | # Does the mode cover the other subscription? | ||||
137 | # ALWAYS covers (ALWAYS and not ALWAYS). | ||||
138 | # FULL_TOPIC covers (FULL_TOPIC and not FULL_TOPIC) | ||||
139 | return 0 | ||||
140 | unless ( $this->{options} & $tother->{options} ) == $tother->{options}; | ||||
141 | |||||
142 | # A * always covers if the options match | ||||
143 | foreach my $t ( @{ $this->{topics} } ) { | ||||
144 | return 1 if ( $t eq '*' ); | ||||
145 | } | ||||
146 | |||||
147 | # do they match without taking into account the depth? | ||||
148 | return 0 unless ( $this->matches( $tother->{topics}, undef, 0 ) ); | ||||
149 | |||||
150 | # if we have a depth and they don't, that's already catered for | ||||
151 | # by the matches test above | ||||
152 | |||||
153 | # if we don't have a depth and they do, then we might be covered | ||||
154 | # by them, but that's irrelevant | ||||
155 | |||||
156 | # if we have a depth and they have a depth, then there is coverage | ||||
157 | # if our depth is >= their depth | ||||
158 | return 0 unless ( $this->{depth} >= $tother->{depth} ); | ||||
159 | |||||
160 | return 1; | ||||
161 | } | ||||
162 | |||||
163 | =begin TML | ||||
164 | |||||
165 | ---++ ObjectMethod filterExact( \@pages ) -> $boolean | ||||
166 | If this subscription has an exact (string) match to any of the page expressions passed, | ||||
167 | remove it and return true. | ||||
168 | * \@pages - list of page expressions to filter | ||||
169 | |||||
170 | =cut | ||||
171 | |||||
172 | sub filterExact { | ||||
173 | my ( $this, $pages ) = @_; | ||||
174 | my $removed = 0; | ||||
175 | KNOWN: | ||||
176 | for ( my $i = $#{ $this->{topics} } ; $i >= 0 ; $i-- ) { | ||||
177 | foreach my $j ( @{$pages} ) { | ||||
178 | if ( $j eq $this->{topics}[$i] ) { | ||||
179 | splice( @{ $this->{topics} }, $i, 1 ); | ||||
180 | $removed = 1; | ||||
181 | next KNOWN; | ||||
182 | } | ||||
183 | } | ||||
184 | } | ||||
185 | return $removed; | ||||
186 | } | ||||
187 | |||||
188 | =begin TML | ||||
189 | |||||
190 | ---++ ObjectMethod getMode() -> $mode | ||||
191 | Get the newsletter mode of this subscription ('', '?' or '!') as | ||||
192 | specified in WebNotify. | ||||
193 | |||||
194 | =cut | ||||
195 | |||||
196 | sub getMode { | ||||
197 | my $this = shift; | ||||
198 | |||||
199 | if ( $this->{options} & FULL_TOPIC ) { | ||||
200 | return '!' | ||||
201 | if ( $this->{options} & ALWAYS ); | ||||
202 | return '?'; | ||||
203 | } | ||||
204 | return ''; | ||||
205 | } | ||||
206 | |||||
207 | sub _sameTopics { | ||||
208 | my ( $a, $b ) = @_; | ||||
209 | my @aa = sort @$a; | ||||
210 | my @bb = sort @$b; | ||||
211 | my $i = scalar(@aa); | ||||
212 | return 0 unless scalar(@bb) == $i; | ||||
213 | while ($i) { | ||||
214 | $i--; | ||||
215 | return 0 unless $aa[$i] eq $bb[$i]; | ||||
216 | } | ||||
217 | return 1; | ||||
218 | } | ||||
219 | |||||
220 | =begin TML | ||||
221 | |||||
222 | ---++ ObjectMethod equals($other) -> $boolean | ||||
223 | Compare two subscriptions. | ||||
224 | |||||
225 | =cut | ||||
226 | |||||
227 | sub equals { | ||||
228 | my ( $this, $tother ) = @_; | ||||
229 | return 0 unless ( $this->{options} eq $tother->{options} ); | ||||
230 | return 0 unless ( $this->{depth} == $tother->{depth} ); | ||||
231 | return 0 unless ( _sameTopics( $this->{topics}, $tother->{topics} ) ); | ||||
232 | } | ||||
233 | |||||
234 | 1 | 2µs | 1; | ||
235 | __END__ |