comparison Lib/IMPL/Web/Handler/TTView.pm @ 205:891c04080658

IMPL::Web::View fixed template selection, release candidate
author sergey
date Thu, 03 May 2012 01:00:02 +0400
parents d63f9a92d6d4
children c8fe3f84feba
comparison
equal deleted inserted replaced
204:d63f9a92d6d4 205:891c04080658
2 use strict; 2 use strict;
3 3
4 use List::Util qw(first); 4 use List::Util qw(first);
5 use IMPL::lang qw(:declare :constants); 5 use IMPL::lang qw(:declare :constants);
6 use IMPL::declare { 6 use IMPL::declare {
7 require => {
8 Factory => 'IMPL::Object::Factory'
9 },
7 base => { 10 base => {
8 'IMPL::Object' => undef, 11 'IMPL::Object' => undef,
9 'IMPL::Object::Autofill' => '@_', 12 'IMPL::Object::Autofill' => '@_',
10 'IMPL::Object::Serializable' => undef 13 'IMPL::Object::Serializable' => undef
11 } 14 }
30 sub Invoke { 33 sub Invoke {
31 my ($this,$action,$next) = @_; 34 my ($this,$action,$next) = @_;
32 35
33 my $result = $next ? $next->($action) : undef; 36 my $result = $next ? $next->($action) : undef;
34 37
38 my $vars = {
39 data => $result,
40 action => $action,
41 app => $action->application,
42 LoadFactory => sub {
43 my $class = shift;
44
45 my $module = $class;
46
47 $module =~ s/::/\//g;
48 $module .= ".pm";
49
50 require $module;
51 return Factory->new($class);
52 }
53 };
54
35 my $doc = $this->loader->document( 55 my $doc = $this->loader->document(
36 $this->SelectView($action,ref $result), 56 $this->SelectView($action,ref $result),
37 { 57 $vars
38 data => $result,
39 action => $action,
40 app => $action->application
41 }
42 ); 58 );
43 59
44 my $hout = $action->response->streamBody; 60 my $hout = $action->response->streamBody;
45 61
46 print $hout $doc->Render(); 62 print $hout $doc->Render($vars);
47 } 63 }
48 64
49 sub SelectView { 65 sub SelectView {
50 my ($this,$action,$class) = @_; 66 my ($this,$action,$class) = @_;
51 67
52 my @path = split /\//, $action->query->path_info(), -1; 68 my @path = split /\//, $action->query->path_info(), -1;
53 69
70 shift @path; # remove always empty leading segment
71
54 my $last = pop @path; 72 my $last = pop @path;
55 $last =~ s/\.\w+$//; 73 $last =~ s/\.\w+$//;
56 $last = $this->indexResource; 74 $last ||= $this->indexResource;
57 push @path,$last; 75 push @path,$last;
58 76
59 $this->BuildCache unless $this->_selectorsCache; 77 $this->BuildCache unless $this->_selectorsCache;
60 my $cache = $this->_selectorsCache; 78 my $cache = $this->_selectorsCache;
61 79
80 @path = reverse @path;
81
62 foreach my $subclass ( $class ? (_GetHierarchy($class), '-default') : '-plain') { 82 foreach my $subclass ( $class ? (_GetHierarchy($class), '-default') : '-plain') {
63 my @results; 83 my @results;
64 push @results, { data => $this->_classTemplates->{$subclass} } if $this->_classTemplates->{$subclass}; 84 push @results, { result => $this->_classTemplates->{$subclass}, level => 0 } if $this->_classTemplates->{$subclass};
65 my $alternatives = [ { selectors => $cache->{$subclass}, immediate => 1 } ]; 85 if ($cache->{$subclass}) {
66 $alternatives = $this->MatchAlternatives($_,$alternatives,\@results) foreach @path; 86 my $alternatives = [ { selector => $cache->{$subclass}, immediate => 1 } ];
87 $alternatives = $this->MatchAlternatives($_,$alternatives,\@results) foreach @path;
88 }
67 89
68 if (@results) { 90 if (@results) {
69 return shift sort { $b->{level} <=> $a->{level} } @results; 91 @results = sort { $b->{level} <=> $a->{level} } @results;
92 return (shift @results)->{result};
70 } 93 }
71 } 94 }
72 95
73 return $this->defaultDocument; 96 return $this->defaultDocument;
74 } 97 }
75 98
76 sub _GetHierarchy { 99 sub _GetHierarchy {
77 my ($class) = @_; 100 my ($class) = @_;
78 return unless $class; 101 return unless $class;
98 my @path = split(/\s+/,$path); 121 my @path = split(/\s+/,$path);
99 122
100 my $class; 123 my $class;
101 124
102 # if this selector has a class part 125 # if this selector has a class part
103 if ($path[$#path-1] =~ m/^\@(.*)/) { 126 if ($path[$#path] =~ m/^\@(.*)/) {
104 $class = $1; 127 $class = $1;
105 shift @path; 128 pop @path;
106 } else { 129 } else {
107 $class = '-default'; 130 $class = '-default';
108 } 131 }
109 132
110 #if this selector has a path 133 #if this selector has a path
131 } 154 }
132 155
133 sub MatchAlternatives { 156 sub MatchAlternatives {
134 my ($this,$segment,$alternatives,$results) = @_; 157 my ($this,$segment,$alternatives,$results) = @_;
135 158
136 warn "alternatives: ", scalar @$alternatives,", segment: $segment";
137
138 my @next; 159 my @next;
139 160
140 foreach my $alt (@$alternatives) { 161 foreach my $alt (@$alternatives) {
141 while (my ($selector,$match) = each %{$alt->{selector}} ) { 162 while (my ($selector,$match) = each %{$alt->{selector}} ) {
142 warn $selector; 163
143
144 warn "\timmediate" if $alt->{immediate};
145 warn "\thas children" if $match->{next};
146 164
147 my $context = { 165 my $context = {
148 vars => \%{ $alt->{vars} || {} }, 166 vars => \%{ $alt->{vars} || {} },
149 selector => $match->{next} 167 selector => $match->{next}
150 }; 168 };
153 $context->{immediate} = 1; 171 $context->{immediate} = 1;
154 } 172 }
155 173
156 if (my ($name,$rx) = ($selector =~ m/^\{(?:(\w+)\:)?(.*)\}$/) ) { 174 if (my ($name,$rx) = ($selector =~ m/^\{(?:(\w+)\:)?(.*)\}$/) ) {
157 #this is a regexp 175 #this is a regexp
158 warn "\tregexp: [$name] $rx";
159 176
160 if ( my @captures = ($segment =~ m/($rx)/) ) { 177 if ( my @captures = ($segment =~ m/($rx)/) ) {
161 $context->{success} = 1; 178 $context->{success} = 1;
162 179
163 warn "\t",join(',',@captures);
164
165 if ($name) { 180 if ($name) {
166 $context->{vars}->{$name} = \@captures; 181 $context->{vars}->{$name} = \@captures;
167 } 182 }
168 } 183 }
169 } else { 184 } else {
173 } 188 }
174 } 189 }
175 190
176 # test if there were a match 191 # test if there were a match
177 if (delete $context->{success}) { 192 if (delete $context->{success}) {
178 warn "\tmatch";
179 if (my $data = $match->{data}) { 193 if (my $data = $match->{data}) {
180 # interpolate data 194 # interpolate data
181 $data =~ s/{(\w+)(?:\:(\d+))?}/ 195 $data =~ s/{(\w+)(?:\:(\d+))?}/
182 my ($name,$index) = ($1,$2 || 0); 196 my ($name,$index) = ($1,$2 || 0);
183 197
188 } 202 }
189 /gex; 203 /gex;
190 204
191 push @$results, { level => $match->{level}, result => $data }; 205 push @$results, { level => $match->{level}, result => $data };
192 } 206 }
193 warn "\tnext" if $context->{selector};
194 push @next, $context if $context->{selector}; 207 push @next, $context if $context->{selector};
195 } else { 208 } else {
196 #repeat current alternative if it's not required to be immediate 209 #repeat current alternative if it's not required to be immediate
197 push @next, { 210 push @next, {
198 selector => { $selector, $match }, 211 selector => { $selector, $match },
200 } unless $alt->{immediate}; 213 } unless $alt->{immediate};
201 } 214 }
202 } 215 }
203 } 216 }
204 217
205 warn "end, next trip: ",scalar @next, " alternatives";
206
207 return \@next; 218 return \@next;
208 } 219 }
209 220
210 1; 221 1;
211 222