added _class_to_attribute_name method
[catagits/Reaction.git] / lib / Reaction / UI / LayoutSet.pm
CommitLineData
7adfd53f 1package Reaction::UI::LayoutSet;
2
3use Reaction::Class;
4use File::Spec;
5
6class LayoutSet which {
7
f2fef590 8 has 'layouts' => (is => 'ro', default => sub { {} });
7adfd53f 9
10 has 'name' => (is => 'ro', required => 1);
11
12 has 'source_file' => (is => 'rw', lazy_fail => 1);
1c41e332 13
e22de101 14 has 'file_extension'=> (isa => 'Str', is => 'rw', lazy_build => 1);
15
aa8c0c90 16 has 'widget_class' => (
17 is => 'rw', lazy_fail => 1, predicate => 'has_widget_class'
18 );
19
1c41e332 20 has 'widget_type' => (is => 'rw', lazy_build => 1);
21
aa8c0c90 22 has 'super' => (is => 'rw', predicate => 'has_super');
f2fef590 23
89939ff9 24 implements _build_file_extension => as { 'html' };
7adfd53f 25
26 implements 'BUILD' => as {
27 my ($self, $args) = @_;
28 my @path = @{$args->{search_path}||[]};
29 confess "No search_path provided" unless @path;
aa8c0c90 30 confess "No view object provided" unless $args->{view};
7adfd53f 31 my $found;
e22de101 32 my $ext = $self->file_extension;
7adfd53f 33 SEARCH: foreach my $path (@path) {
e22de101 34 my $cand = $path->file($self->name . ".${ext}");
35 #print STDERR $cand,"\n";
7adfd53f 36 if ($cand->stat) {
aa8c0c90 37 $self->_load_file($cand, $args);
7adfd53f 38 $found = 1;
39 last SEARCH;
40 }
41 }
42 confess "Unable to load file for LayoutSet ".$self->name unless $found;
aa8c0c90 43 unless ($self->has_widget_class) {
44 $self->widget_class($args->{view}->widget_class_for($self));
45 }
f2fef590 46 };
47
48 implements 'widget_order_for' => as {
49 my ($self, $name) = @_;
aa8c0c90 50 return (
51 ($self->has_layout($name)
52 ? ([ $self->widget_class, $self ]) #;
53 : ()),
54 ($self->has_super
55 ? ($self->super->widget_order_for($name))
56 : ()),
57 );
7adfd53f 58 };
59
aa8c0c90 60 implements 'layout_names' => as {
61 my ($self) = @_;
62 my %seen;
63 return [
64 grep { !$seen{$_}++ }
65 keys %{shift->layouts},
66 ($self->has_super
67 ? (@{$self->super->layout_names})
68 : ())
69 ];
70 };
f2fef590 71
72 implements 'has_layout' => as { exists $_[0]->layouts->{$_[1]} };
73
7adfd53f 74 implements '_load_file' => as {
aa8c0c90 75 my ($self, $file, $build_args) = @_;
7adfd53f 76 my $data = $file->slurp;
f2fef590 77 my $layouts = $self->layouts;
78 # cheesy match for "=for layout name ... =something"
7adfd53f 79 # final split group also handles last in file, (?==) is lookahead
f2fef590 80 # assertion for '=' so "=for layout name1 ... =for layout name2"
81 # doesn't have the match pos go past the latter = and lose name2
aa8c0c90 82 while ($data =~ m/=(.*?)\n(.*?)(?:\n(?==)|$)/sg) {
83 my ($data, $text) = ($1, $2);
aa8c0c90 84 if ($data =~ /^for layout (\S+)/) {
85 my $fname = $1;
cf272446 86 $text =~ s/^(?:\s*\r?\n)+//; #remove leading empty lines
87 $text =~ s/[\s\r\n]+$//; #remove trailing whitespace
88 $layouts->{$fname} = $text;
aa8c0c90 89 } elsif ($data =~ /^extends (\S+)/) {
90 my $super_name = $1;
91 $self->super($build_args->{view}->create_layout_set($super_name))
1c41e332 92 } elsif ($data =~ /^widget (\S+)/) {
93 my $widget_type = $1;
94 $self->widget_type($1);
aa8c0c90 95 } elsif ($data =~ /^cut/) {
96 # no-op
97 } else {
98 confess "Unparseable directive ${data}";
99 }
7adfd53f 100 }
101 $self->source_file($file);
102 };
103
1c41e332 104 implements '_build_widget_type' => as {
7adfd53f 105 my ($self) = @_;
6ab43711 106 my $widget = join('', map { ucfirst($_) } split('_', $self->name));
107 $widget = join('::', map { ucfirst($_) } split('/', $widget));
108
e22de101 109 #print STDERR "--- ", $self->name, " maps to widget $widget \n";
6ab43711 110
111 return $widget;
7adfd53f 112 };
7b78a39d 113
7adfd53f 114};
115
1161;