File Coverage

blib/lib/Chemistry/Obj.pm
Criterion Covered Total %
statement 59 73 80.8
branch 12 16 75.0
condition 1 6 16.6
subroutine 16 19 84.2
pod 4 12 33.3
total 92 126 73.0


line stmt bran cond sub pod time code
1             package Chemistry::Obj;
2             $VERSION = 0.37;
3             # $Id: Obj.pm,v 1.30 2009/05/10 19:37:58 itubert Exp $
4 18     18   28754 use 5.006;
  18         76  
  18         859  
5              
6 18     18   117 use strict;
  18         32  
  18         870  
7 18     18   94 use Carp;
  18         111  
  18         6676  
8              
9             =head1 NAME
10              
11             Chemistry::Obj - Abstract chemistry object
12              
13             =head1 SYNOPSIS
14              
15             package MyObj;
16             use base "Chemistry::Obj";
17             Chemistry::Obj::accessor('color', 'flavor');
18              
19             package main;
20             my $obj = MyObj->new(name => 'bob', color => 'red');
21             $obj->attr(size => 42);
22             $obj->color('blue');
23             my $color = $obj->color;
24             my $size = $obj->attr('size');
25              
26             =head1 DESCRIPTION
27              
28             This module implements some generic methods that are used by L,
29             L, L, L, etc.
30              
31             =head2 Common Attributes
32              
33             There are some common attributes that may be found in molecules, bonds, and
34             atoms, such as id, name, and type. They are all accessed through the methods of
35             the same name. For example, to get the id, call C<< $obj->id >>; to set the id,
36             call C<< $obj->id('new_id') >>.
37              
38             =over 4
39              
40             =item id
41              
42             Objects should have a unique ID. The user has the responsibility for uniqueness
43             if he assigns ids; otherwise a unique ID is assigned sequentially.
44              
45             =item name
46              
47             An arbitrary name for an object. The name doesn't need to be unique.
48              
49             =item type
50              
51             The interpretation of this attribute is not specified here, but it's typically
52             used for bond orders and atom types.
53              
54             =item attr
55              
56             A space where the user can store any kind of information about the object. The
57             accessor method for attr expects the attribute name as the first parameter, and
58             (optionally) the new value as the second parameter. It can also take a hash or
59             hashref with several attributes. Examples:
60              
61             $color = $obj->attr('color');
62             $obj->attr(color => 'red');
63             $obj->attr(color => 'red', flavor => 'cherry');
64             $obj->attr({color => 'red', flavor => 'cherry'});
65              
66             =cut
67              
68             sub attr {
69 16     16 1 57 my $self = shift;
70 16         26 my ($attr) = @_;
71 16 100       676 if (ref $attr eq 'HASH') {
    100          
    100          
72 1         6 $self->{attr} = { %$attr };
73             } elsif (@_ == 1) {
74 7         103 return $self->{attr}{$attr};
75             } elsif (@_ == 0) {
76 2         3 return {%{$self->{attr}}};
  2         12  
77             } else {
78 6         19 while (@_ > 1) {
79 7         10 $attr = shift;
80 7         51 $self->{attr}{$attr} = shift;
81             }
82             }
83 7         17 $self;
84             }
85              
86             =back
87              
88             =head1 OTHER METHODS
89              
90             =over
91              
92             =item $obj->del_attr($attr_name)
93              
94             Delete an attribute.
95              
96             =cut
97              
98             sub del_attr {
99 1     1 1 516 my $self = shift;
100 1         1 my $attr = shift;
101 1         4 delete $self->{attr}{$attr};
102             }
103              
104             # A generic class attribute set/get method generator
105             sub accessor {
106 135     135 0 945 my $pkg = caller;
107 18     18   134 no strict 'refs';
  18         35  
  18         9013  
108 135         319 for my $attribute (@_) {
109 212         1713 *{"${pkg}::$attribute"} =
110             sub {
111 963     963   3187 my $self = shift;
112 963 100       6006 return $self->{$attribute} unless @_;
113 162         1835 $self->{$attribute} = shift;
114 162         556 return $self;
115 212         962 };
116             }
117             }
118              
119             sub print_attr {
120 0     0 0 0 my $self = shift;
121 0         0 my ($indent) = @_;
122 0         0 my $ret = '';
123            
124 0         0 for my $attr (keys %{$self->{attr}}) {
  0         0  
125 0         0 $ret .= "$attr: ".$self->attr($attr)."\n";
126             }
127 0 0       0 $ret and $ret =~ s/^/" "x$indent/gem;
  0         0  
128 0         0 $ret;
129             }
130              
131             my $N = 0; # atom ID counter
132 26     26 0 297 sub nextID { "obj".++$N; }
133 0     0 0 0 sub reset_id { $N = 0; }
134              
135             =item $class->new(name => value, name => value...)
136              
137             Generic object constructor. It will automatically call each "name" method with
138             the parameter "value". For example,
139              
140             $bob = Chemistry::Obj->new(name => 'bob', attr => {size => 42});
141              
142             is equivalent to
143              
144             $bob = Chemistry::Obj->new;
145             $bob->name('bob');
146             $bob->attr({size => 42});
147              
148             =cut
149              
150             sub new {
151 26     26 1 1327 my $class = shift;
152 26         110 my %args = @_;
153 26   33     417 my $self = bless {
154             id => $class->nextID,
155             #$class->default_args,
156             }, ref $class || $class;
157 26         200 $self->$_($args{$_}) for (keys %args);
158 26         123 return $self;
159             }
160              
161             #sub default_args { (id => shift->nextID) }
162              
163             =back
164              
165             =head1 OPERATOR OVERLOADING
166              
167             Chemistry::Obj overloads a couple of operators for convenience.
168              
169             =over
170              
171             =cut
172              
173             use overload
174 18         181 '""' => "stringify",
175             'cmp' => "obj_cmp",
176             '0+', => "as_number",
177             fallback => 1,
178 18     18   32784 ;
  18         12278  
179              
180             =item ""
181              
182             The stringification operator. Stringify an object as its id. For example, If an
183             object $obj has the id 'a1', print "$obj" will print 'a1' instead of something
184             like 'Chemistry::Obj=HASH(0x810bbdc)'. If you really want to get the latter,
185             you can call C. See L for details.
186              
187             =cut
188              
189             sub stringify {
190 9     9 0 5856 my $self = shift;
191 9         38 $self->id;
192             }
193              
194             sub as_number {
195 19     19 0 547 $_[0];
196             }
197              
198             =item cmp
199              
200             Compare objects by ID. This automatically overloads C, C, C, C,
201             C, and C as well. For example, C<$obj1 eq $obj2> returns true if both
202             objects have the same id, even if they are different objects with different
203             memory addresses. In contrast, C<$obj1 == $obj2> will return true only if
204             C<$obj1> and C<$obj2> point to the same object, with the same memory address.
205              
206             =cut
207              
208             sub obj_cmp {
209 151     151 0 350 my ($a, $b) = @_;
210 18     18   8979 no warnings;
  18         41  
  18         5916  
211              
212 151         842 return $a->{id} cmp $b->{id};
213             }
214              
215             =back
216              
217             =cut
218              
219             accessor(qw(name type));
220              
221             sub id {
222 685     685 1 1315 my $self = shift;
223 685 100       3662 return $self->{id} unless @_;
224 9 100       35 if ($self->{parent}) {
225 4         8 my $new_id = shift;
226 4         9 my $old_id = $self->{id};
227 4         9 $self->{id} = $new_id;
228 4         89 $self->{parent}->_change_id($old_id, $new_id);
229             } else {
230 5         21 $self->{id} = shift;
231             }
232             }
233              
234             # this is an experimental method and shouldn't be used!
235             sub use {
236 0     0 0   my ($pack, $module, @args) = @_;
237 0   0       $pack = ref $pack || $pack;
238 0 0         my $args = @args ? "(@args)" : '';
239 0           eval "package $pack; use $module $args";
240             }
241              
242             1;
243              
244             =head1 VERSION
245              
246             0.37
247              
248             =head1 SEE ALSO
249              
250             L, L, L
251              
252             The PerlMol website L
253              
254             =head1 AUTHOR
255              
256             Ivan Tubert-Brohman Eitub@cpan.orgE
257              
258             =head1 COPYRIGHT
259              
260             Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is
261             free software; you can redistribute it and/or modify it under the same terms as
262             Perl itself.
263              
264             =cut
265