]> mj.ucw.cz Git - moe.git/blob - sherlock/perl/Object.pm
Added parts of libsh from Sherlock v3.12.2.
[moe.git] / sherlock / perl / Object.pm
1 #       Perl module for manipulating Sherlock objects
2 #
3 #       (c) 2007 Martin Mares <mj@ucw.cz>
4 #
5 #       This software may be freely distributed and used according to the terms
6 #       of the GNU Lesser General Public License.
7
8 =head1 NAME
9
10 Sherlock::Object -- Manipulation with Sherlock objects
11
12 =head1 DESCRIPTION
13
14 This module offers a simple interface to Sherlock objects. See F<doc/objects>
15 for a description of how the object system works.
16
17 =head1 METHODS
18
19 =over
20
21 =item B<new()>
22
23 Creates a new empty object.
24
25 =item B<< new(I<name> => I<value>, ...) >>
26
27 Creates a new object with some attributes initialized.
28
29 =item B<< set(I<name> => I<value>, ...) >>
30
31 Sets given attributes to specified values. If any of the attributes already
32 exists, the old value is replaced by the new one.
33
34 The value can be:
35
36 =over
37
38 =item *
39
40 a number
41
42 =item *
43
44 a string
45
46 =item *
47
48 a reference to an array of values, which creates a multi-valued attribute.
49
50 =item *
51
52 a reference to another object, which created a nested object. In this case
53 (and only in this case), the name of the attribute must start with C<(>.
54
55 =back
56
57 =item B<< unset(I<name>, ...) >>
58
59 Removes given attributes.
60
61 =item B<< add(I<name> => I<value>, ...) >>
62
63 Sets given attributes to specified values. If any of the attributes already
64 exists, the new value is added to the original one, creating a multi-valued
65 attribute.
66
67 The repertoir of values is the same as in the C<set> method except for references
68 to arrays, which are not allowed.
69
70 =item B<< get(I<name>) >>
71
72 Gets the value of the given attribute or C<undef> if it does not exist.
73 If the attribute is multi-valued, the first value is returned.
74
75 =item B<< getarray(I<name>) >>
76
77 Gets all values of the given attribute as an array or an empty array if the
78 attribute does not exist.
79
80 =item B<< get_attrs() >>
81
82 Get an array of names of all attributes present in the object.
83
84 =item B<< read(I<handle>) >>
85
86 Reads a textual representation of an object from the given handle and adds it
87 to the object it is invoked on. The effect is the same as calling the C<add>
88 method on all read attributes.
89
90 Returns 1 if the object has been read successfully, 0 if the input
91 stream ended before an object started or C<undef> if the input was
92 malformed.
93
94 =item B<< read(I<handle>, raw => 1) >>
95
96 Reads an object as above, but add a special attribute called C<< RAW >>, which will
97 contain the raw form of the object.
98
99 =item B<< write(I<handle>) >>
100
101 Writes a textual representation of the object to the given handle.
102
103 =item B<< write_indented(I<handle>, [I<base_indent>]) >>
104
105 Writes an indented textual representation of the object to the given handle.
106 The I<base_indent> will be prepended to all printed lines, each nested level
107 will get one tab character more.
108
109 This is intended for debugging dumps and the output cannot be read back by any
110 of the Sherlock libraries.
111
112 =back
113
114 =head1 AUTHOR
115
116 Martin Mares <mj@ucw.cz>
117
118 =cut
119
120 package Sherlock::Object;
121
122 use strict;
123 use warnings;
124
125 sub new($@) {
126         my $self = { };
127         bless $self;
128         shift @_;
129         if (@_) {
130                 $self->set(@_);
131         }
132         return $self;
133 }
134
135 sub set($@) {
136         my $self = shift @_;
137         my $attr;
138         while (defined($attr = shift @_)) {
139                 $self->{$attr} = shift @_;
140         }
141 }
142
143 sub unset($@) {
144         my $self = shift @_;
145         foreach my $attr (@_) {
146                 delete $self->{$attr};
147         }
148 }
149
150 sub add($@) {
151         my $self = shift @_;
152         my $attr;
153         while (defined($attr = shift @_)) {
154                 my $val = shift @_;
155                 if (!exists $self->{$attr}) {
156                         $self->{$attr} = $val;
157                 } elsif (ref $self->{$attr} eq "ARRAY") {
158                         push @{$self->{$attr}}, $val;
159                 } else {
160                         $self->{$attr} = [ $self->{$attr}, $val ];
161                 }
162         }
163 }
164
165 sub get($$) {
166         my ($self, $attr) = @_;
167         if (!exists $self->{$attr}) {
168                 return undef;
169         } elsif (ref $self->{$attr} eq "ARRAY") {
170                 return $self->{$attr}->[0];
171         } else {
172                 return $self->{$attr};
173         }
174 }
175
176 sub getarray($$) {
177         my ($self, $attr) = @_;
178         if (!exists $self->{$attr}) {
179                 return ();
180         } elsif (ref $self->{$attr} eq "ARRAY") {
181                 return @{$self->{$attr}};
182         } else {
183                 return ( $self->{$attr} );
184         }
185 }
186
187 sub get_attrs($) {
188         my ($self) = @_;
189         return keys %$self;
190 }
191
192 sub read($$@) {
193         my $self = shift @_;
194         my $fh = shift @_;
195         my %opts = @_;
196         my @stack = ();
197         my $read_something = 0;
198         my $obj = $self;
199         my $raw;
200         if ($opts{raw}) {
201                 $raw = $obj->{"RAW"} = [];
202         }
203         while (<$fh>) {
204                 chomp;
205                 /^$/ && last;
206                 my ($a, $v) = /^(.)(.*)$/ or return undef;
207                 push @$raw, $_ if $raw;
208                 if ($a eq "(") {
209                         $a = "$a$v";
210                         my $new = new Sherlock::Object;
211                         $obj->add($a, $new);
212                         push @stack, $obj;
213                         $obj = $new;
214                 } elsif ($a eq ")") {
215                         @stack or return undef;
216                         $obj = pop @stack;
217                 } else {
218                         $obj->add($a, $v);
219                 }
220                 $read_something = 1;
221         }
222         @stack and return undef;
223         return $read_something;
224 }
225
226 sub write($$) {
227         my ($self, $fh) = @_;
228         foreach my $a (keys %$self) {
229                 my $vals = $self->{$a};
230                 ref $vals eq "ARRAY" or $vals = [$vals];
231                 foreach my $v (@{$vals}) {
232                         if (ref $v eq "") {
233                                 print $fh $a, $v, "\n";
234                         } elsif (ref $v eq "Sherlock::Object") {
235                                 print $fh $a, "\n";
236                                 $v->write($fh);
237                                 print $fh ")\n";
238                         } else {
239                                 die;
240                         }
241                 }
242         }
243 }
244
245 sub write_indented($$$) {
246         my ($self, $fh, $indent) = @_;
247         defined $indent or $indent = "";
248         foreach my $a (sort keys %$self) {
249                 my $vals = $self->{$a};
250                 ref $vals eq "ARRAY" or $vals = [$vals];
251                 foreach my $v (@{$vals}) {
252                         if (ref $v eq "") {
253                                 print $fh $indent, $a, $v, "\n";
254                         } elsif (ref $v eq "Sherlock::Object") {
255                                 print $fh $indent, $a, "\n";
256                                 $v->write_indented($fh, $indent . "\t");
257                                 print $fh $indent, ")\n";
258                         } else {
259                                 die;
260                         }
261                 }
262         }
263 }
264
265 1;  # OK