376
|
1 package IMPL::Web::Resources::StringMap;
|
|
2 use strict;
|
|
3
|
|
4 use IMPL::Const qw(:prop);
|
|
5 use IMPL::declare {
|
|
6 require => {
|
|
7 Exception => 'IMPL::Exception',
|
|
8 IOException => '-IMPL::IOException',
|
|
9 ArgException => '-IMPL::InvalidArgumentException'
|
|
10 },
|
|
11 props => [
|
|
12 _data => PROP_RW,
|
|
13 _parent => PROP_RW
|
|
14 ]
|
|
15 };
|
|
16
|
|
17 sub CTOR {
|
|
18 my ($this,$data,$parent) = @_;
|
|
19
|
|
20 die ArgException->new( data => 'A hash reference is required' )
|
|
21 unless ref($data) eq 'HASH';
|
|
22
|
|
23 die ArgException->new( data => 'A hash must contain either scalars or subs')
|
377
|
24 if ref($_) && ref($_) ne 'CODE', values %$data;
|
376
|
25
|
|
26 $this->_data($data);
|
|
27 $this->_parent($parent);
|
|
28 }
|
|
29
|
|
30 sub GetString {
|
|
31 my ($this,$id,$args) = @_;
|
|
32
|
|
33 if(my $format = $this->_data->{$id}) {
|
|
34 return $this->FormatString($format,$args);
|
|
35 } else {
|
377
|
36 return $this->_parent? $this->_parent->GetString($id,$args) : "[ $id ]";
|
376
|
37 }
|
|
38
|
|
39 }
|
|
40
|
377
|
41 sub AddFormat {
|
|
42 my ($this,$id,$format) = @_;
|
|
43
|
|
44 die ArgException->new( id => 'A format id is required' )
|
|
45 unless $id;
|
|
46
|
|
47 die ArgException->new( format => 'A format must be a scalar or a sub' )
|
|
48 if ref($format) and ref($format) ne 'CODE';
|
|
49
|
|
50 $this->_data->{$id} = $format;
|
|
51 }
|
|
52
|
376
|
53 sub FormatString {
|
|
54 my ($self,$text,$args) = @_;
|
|
55
|
|
56 $args ||= {};
|
|
57 $resolver ||= \&_defaultResolver;
|
|
58 $text ||= '';
|
|
59
|
|
60 $string =~ s/%(\w+(?:\.\w+)*)%/$self->GetValue($args,$1,"\[$1\]")/ge;
|
|
61
|
|
62 return $string;
|
|
63
|
|
64 }
|
|
65
|
|
66 sub GetValue {
|
|
67 my ($self,$obj,$path,$default) = @_;
|
|
68
|
|
69 foreach my $chunk (split /\./,$path) {
|
|
70 return $default unless $obj;
|
|
71 if (ref $obj eq 'HASH') {
|
|
72 $obj = $obj->{$chunk};
|
|
73 } else {
|
|
74 $obj = $self->Resolve($obj,$chunk);
|
|
75 }
|
|
76 }
|
|
77 return $obj||'<undef>';
|
|
78 }
|
|
79
|
|
80 sub Resolve {
|
|
81 my ($self,$obj,$prop) = @_;
|
|
82
|
|
83 return ( eval { $obj->can($prop) } ? $obj->$prop() : undef );
|
|
84 }
|
|
85
|
|
86 sub _LoadMap {
|
|
87 my ($self,$file,$parent) = @_;
|
|
88
|
|
89 my $data = do $file;
|
|
90 my $e = $@;
|
|
91 die Exception->new("Failed to load file '$file'", $e) if $e;
|
|
92 die IOException->new("Failed to load file '$file'", $!) if not defined $data and $!;
|
|
93 die Exception->new("Failed to load file '$file'", "A hash data is expected") unless ref($data) eq 'HASH';
|
|
94
|
|
95 return $self->new($data,$parent);
|
|
96 }
|
|
97
|
|
98 1;
|
|
99
|
|
100 __END__
|
|
101
|
|
102 =pod
|
|
103
|
|
104 =head1 NAME
|
|
105
|
|
106 C<IMPL::Web::Resources::StringMap>
|
|
107
|
|
108 =head1 SYNOPSIS
|
|
109
|
|
110 =begin code
|
|
111
|
377
|
112 use IMPL::require {
|
|
113 StringMap => 'IMPL::Resources::StringMap'
|
|
114 };
|
|
115
|
|
116 my $data = {
|
376
|
117 TitleLabel => 'Search results',
|
|
118 ViewLabel => 'View %name%', # same as sub { $_[0]->Format('View %name%',$_[1]) }
|
|
119 ResultsCountLabel => sub {
|
|
120 my ($self,$args) = @_;
|
|
121
|
|
122 $args ||= {};
|
|
123
|
|
124 if (not $args->{count}) {
|
|
125 return "No items found";
|
|
126 } elsif($args->{count} == 1) {
|
|
127 return "Found one item";
|
|
128 } else {
|
377
|
129 return $self->Format('Found %count% items', $args);
|
376
|
130 }
|
|
131 }
|
|
132 }
|
|
133
|
377
|
134 my $def = StringMap->new({
|
|
135 ResultsCountLabel => 'Found %count% items'
|
|
136 });
|
|
137
|
|
138 my $map = StringMap->new($data, $def);
|
|
139
|
|
140 print $map->GetString('TitleLabel');
|
|
141 print $map->GetString(ResultsCountLabel => { count => 0 }); # will print "No items found"
|
|
142
|
|
143
|
376
|
144 =end code
|
|
145
|
|
146 =head1 DESCRIPTION
|
|
147
|
377
|
148 =head1 MEMBERS
|
376
|
149
|
|
150 =cut |