AcePerl
view release on metacpan or search on metacpan
Ace/Object.pm view on Meta::CPAN
while ($obj_right->isComment) {
$current_obj->comment($obj_right) if $obj_right->isComment;
$t = $obj_right;
last unless defined($obj_right = $self->_fromRaw($raw,$row++,$col+1,$self->{'.end_row'},$db));
}
}
$current_obj->{'.right'} = $obj_right;
$self->_dirty(1) if $changed;
delete @{$self}{qw[.raw .start_row .end_row .col]};
}
sub _fromRaw {
my $pack = shift;
# this breaks inheritance...
# $pack = $pack->factory();
my ($raw,$start_row,$col,$end_row,$db) = @_;
$db = "$db" if ref $db;
return unless defined $raw->[$start_row][$col];
# HACK! Some LongText entries may begin with newlines. This is within the Acedb spec.
# Let's purge text entries of leading space and format them appropriate.
# This should probably be handled in Freesubs.xs / Ace::split
my $temp = $raw->[$start_row][$col];
# if ($temp =~ /^\?txt\?\s*\n*/) {
# $temp =~ s/^\?txt\?(\s*\\n*)/\?txt\?/;
# $temp .= '?';
# }
my ($class,$name,$ts) = Ace->split($temp);
my $self = $pack->new($class,$name,$db,!($start_row || $col));
@{$self}{qw(.raw .start_row .end_row .col db)} = ($raw,$start_row,$end_row,$col,$db);
$self->{'.timestamp'} = $ts if defined $ts;
return $self;
}
# Return partial ace subtree at indicated tag
sub _at {
my ($self,$tag) = @_;
my $pos=0;
# Removed a $` here to increase speed -- tim.cutts@incyte.com 2 Sep 1999
if ($tag=~/(.*?)\[(\d+)\]$/) {
$pos=$2;
$tag=$1;
}
my $p;
my $o = $self->right;
while ($o) {
return ($o->right($pos),$p,$self) if (lc($o) eq lc($tag));
$p = $o;
$o = $o->down;
}
return;
}
# Used to munge special data types. Right now dates are the
# only examples.
sub _ace_format {
my $self = shift;
my ($class,$name) = @_;
return undef unless defined $class && defined $name;
return $class eq 'date' ? $self->_to_ace_date($name) : $name;
}
# It's an object unless it is one of these things
sub _isObject {
return unless defined $_[0];
$_[0] !~ /^(float|int|date|tag|txt|peptide|dna|scalar|[Tt]ext|comment)$/;
}
# utility routine used to split a tag path into individual components
# allows components to contain dots.
sub _split_tags {
my $self = shift;
my $tag = shift;
$tag =~ s/\\\./$;/g; # protect backslashed dots
return map { (my $x=$_)=~s/$;/./g; $x } split(/\./,$tag);
}
1;
__END__
=head1 NAME
Ace::Object - Manipulate Ace Data Objects
=head1 SYNOPSIS
# open database connection and get an object
use Ace;
$db = Ace->connect(-host => 'beta.crbm.cnrs-mop.fr',
-port => 20000100);
$sequence = $db->fetch(Sequence => 'D12345');
# Inspect the object
$r = $sequence->at('Visible.Overlap_Right');
@row = $sequence->row;
@col = $sequence->col;
@tags = $sequence->tags;
# Explore object substructure
@more_tags = $sequence->at('Visible')->tags;
@col = $sequence->at("Visible.$more_tags[1]")->col;
# Follow a pointer into database
$r = $sequence->at('Visible.Overlap_Right')->fetch;
$next = $r->at('Visible.Overlap_left')->fetch;
# Classy way to do the same thing
$r = $sequence->Overlap_right;
$next = $sequence->Overlap_left;
# Pretty-print object
print $sequence->asString;
print $sequence->asTabs;
print $sequence->asHTML;
# Update object
$sequence->replace('Visible.Overlap_Right',$r,'M55555');
$sequence->add('Visible.Homology','GR91198');
$sequence->delete('Source.Clone','MBR122');
$sequence->commit();
# Rollback changes
$sequence->rollback()
# Get errors
print $sequence->error;
=head1 DESCRIPTION
I<Ace::Object> is the base class for objects returned from ACEDB
databases. Currently there is only one type of I<Ace::Object>, but
this may change in the future to support more interesting
object-specific behaviors.
Using the I<Ace::Object> interface, you can explore the internal
structure of an I<Ace::Object>, retrieve its content, and convert it
into various types of text representation. You can also fetch a
representation of any object as a GIF image.
If you have write access to the databases, add new data to an object,
replace existing data, or kill it entirely. You can also create a new
object de novo and write it into the database.
For information on connecting to ACEDB databases and querying them,
see L<Ace>.
=head1 ACEDB::OBJECT METHODS
The structure of an Ace::Object is very similar to that of an Acedb
object. It is a tree structure like this one (an Author object):
Thierry-Mieg J->Full_name ->Jean Thierry-Mieg
|
Laboratory->FF
|
Address->Mail->CRBM duCNRS
| | |
| | BP 5051
| | |
| | 34033 Montpellier
| | |
| | FRANCE
| |
| E_mail->mieg@kaa.cnrs-mop.fr
| |
| Phone ->33-67-613324
| |
| Fax ->33-67-521559
|
Paper->The C. elegans sequencing project
|
Genome Project Database
|
Genome Sequencing
|
How to get ACEDB for your Sun
|
ACEDB is Hungry
Each object in the tree has two pointers, a "right" pointer to the
node on its right, and a "down" pointer to the node beneath it. Right
pointers are used to store hierarchical relationships, such as
Address->Mail->E_mail, while down pointers are used to store lists,
such as the multiple papers written by the Author.
Each node in the tree has a type and a name. Types include integers,
strings, text, floating point numbers, as well as specialized
biological types, such as "dna" and "peptide." Another fundamental
type is "tag," which is a text identifier used to label portions of
the tree. Examples of tags include "Paper" and "Laboratory" in the
example above.
In addition to these built-in types, there are constructed types known
as classes. These types are specified by the data model. In the
above example, "Thierry-Mieg J" is an object of the "Author" class,
and "Genome Project Database" is an object of the "Paper" class. An
interesting feature of objects is that you can follow them into the
database, retrieving further information. For example, after
retrieving the "Genome Project Database" Paper from the Author object,
you could fetch more information about it, either by following B<its>
right pointer, or by using one of the specialized navigation routines
described below.
=head2 new() method
$object = new Ace::Object($class,$name,$database);
$object = new Ace::Object(-class=>$class,
-name=>$name,
-db=>database);
You can create a new Ace::Object from scratch by calling the new()
routine with the object's class, its identifier and a handle to the
database to create it in. The object won't actually be created in the
database until you add() one or more tags to it and commit() it (see
below). If you do not provide a database handle, the object will be
created in memory only.
Arguments can be passed positionally, or as named parameters, as shown
above.
This routine is usually used internally. See also add_row(),
add_tree(), delete() and replace() for ways to manipulate this object.
=head2 name() method
$name = $object->name();
Return the name of the Ace::Object. This happens automatically
whenever you use the object in a context that requires a string or a
number. For example:
$object = $db->fetch(Author,"Thierry-Mieg J");
print "$object did not write 'Pride and Prejudice.'\n";
=head2 class() method
$class = $object->class();
Return the class of the object. The return value may be one of
"float," "int," "date," "tag," "txt," "dna," "peptide," and "scalar."
(The last is used internally by Perl to represent objects created
programatically prior to committing them to the database.) The class
may also be a user-constructed type such as Sequence, Clone or
Author. These user-constructed types usually have an initial capital
letter.
=head2 db() method
$db = $object->db();
Return the database that the object is associated with.
=head2 isClass() method
$bool = $object->isClass();
Returns true if the object is a class (can be fetched from the
database).
=head2 isTag() method
$bool = $object->isTag();
Returns true if the object is a tag.
=head2 tags() method
@tags = $object->tags();
Return all the top-level tags in the object as a list. In the Author
example above, the returned list would be
('Full_name','Laboratory','Address','Paper').
You can fetch tags more deeply nested in the structure by navigating
inwards using the methods listed below.
=head2 right() and down() methods
$subtree = $object->right;
$subtree = $object->right($position);
$subtree = $object->down;
$subtree = $object->down($position);
B<right()> and B<down()> provide a low-level way of traversing the
tree structure by following the tree's right and down pointers.
Called without any arguments, these two methods will move one step.
Called with a numeric argument >= 0 they will move the indicated
number of steps (zero indicates no movement).
$full_name = $object->right->right;
$full_name = $object->right(2);
$city = $object->right->down->down->right->right->down->down;
$city = $object->right->down(2)->right(2)->down(2);
If $object contains the "Thierry-Mieg J" Author object, then the first
series of accesses shown above retrieves the string "Jean
Thierry-Mieg" and the second retrieves "34033 Montpellier." If the
right or bottom pointers are NULL, these methods will return undef.
In addition to being somewhat awkard, you will probably never need to
use these methods. A simpler way to retrieve the same information
would be to use the at() method described in the next section.
Ace/Object.pm view on Meta::CPAN
asTable() returns the object as a tab-delimited text table.
=head2 asAce() method
$object->asAce;
asAce() returns the object as a tab-delimited text table in ".ace"
format.
=head2 asHTML() method
$object->asHTML;
$object->asHTML(\&tree_traversal_code);
asHTML() returns an HTML 3 table representing the object, suitable for
incorporation into a Web browser page. The callback routine, if
provided, will have a chance to modify the object representation
before it is incorporated into the table, for example by turning it
into an HREF link. The callback takes a single argument containing
the object, and must return a string-valued result. It may also
return a list as its result, in which case the first member of the
list is the string representation of the object, and the second
member is a boolean indicating whether to prune the table at this
level. For example, you can prune large repetitive lists.
Here's a complete example:
sub process_cell {
my $obj = shift;
return "$obj" unless $obj->isObject || $obj->isTag;
my @col = $obj->col;
my $cnt = scalar(@col);
return ("$obj -- $cnt members",1); # prune
if $cnt > 10 # if subtree to big
# tags are bold
return "<B>$obj</B>" if $obj->isTag;
# objects are blue
return qq{<FONT COLOR="blue">$obj</FONT>} if $obj->isObject;
}
$object->asHTML(\&process_cell);
=head2 asXML() method
$result = $object->asXML;
asXML() returns a well-formed XML representation of the object. The
particular representation is still under discussion, so this feature
is primarily for demonstration.
=head2 asGIF() method
($gif,$boxes) = $object->asGIF();
($gif,$boxes) = $object->asGIF(-clicks=>[[$x1,$y1],[$x2,$y2]...]
-dimensions=> [$width,$height],
-coords => [$top,$bottom],
-display => $display_type,
-view => $view_type,
-getcoords => $true_or_false
);
asGIF() returns the object as a GIF image. The contents of the GIF
will be whatever xace would ordinarily display in graphics mode, and
will vary for different object classes.
You can optionally provide asGIF with a B<-clicks> argument to
simulate the action of a user clicking on the image. The click
coordinates should be formatted as an array reference that contains a
series of two-element subarrays, each corresponding to the X and Y
coordinates of a single mouse click. There is currently no way to
pass information about middle or right mouse clicks, dragging
operations, or keystrokes. You may also specify a B<-dimensions> to
control the width and height of the returned GIF. Since there is no
way of obtaining the preferred size of the image in advance, this is
not usually useful.
The optional B<-display> argument allows you to specify an alternate
display for the object. For example, Clones can be displayed either
with the PMAP display or with the TREE display. If not specified, the
default display is used.
The optional B<-view> argument allows you to specify an alternative
view for MAP objects only. If not specified, you'll get the default
view.
The option B<-coords> argument allows you to provide the top and
bottom of the display for MAP objects only. These coordinates are in
the map's native coordinate system (cM, bp). By default, AceDB will
show most (but not necessarily all) of the map according to xace's
display rules. If you call this method with the B<-getcoords>
argument and a true value, it will return a two-element array
containing the coordinates of the top and bottom of the map.
asGIF() returns a two-element array. The first element is the GIF
data. The second element is an array reference that indicates special
areas of the image called "boxes." Boxes are rectangular areas that
surround buttons, and certain displayed objects. Using the contents
of the boxes array, you can turn the GIF image into a client-side
image map. Unfortunately, not everything that is clickable is
represented as a box. You still have to pass clicks on unknown image
areas back to the server for processing.
Each box in the array is a hash reference containing the following
keys:
'coordinates' => [$left,$top,$right,$bottom]
'class' => object class or "BUTTON"
'name' => object name, if any
'comment' => a text comment of some sort
I<coordinates> points to an array of points indicating the top-left and
bottom-right corners of the rectangle. I<class> indicates the class
of the object this rectangle surrounds. It may be a database object,
or the special word "BUTTON" for one of the display action buttons.
I<name> indicates the name of the object or the button. I<comment> is
some piece of information about the object in question. You can
display it in the status bar of the browser or in a popup window if
your browser provides that facility.
=head2 asDNA() and asPeptide() methods
$dna = $object->asDNA();
$peptide = $object->asPeptide();
If you are dealing with a sequence object of some sort, these methods
will return strings corresponding to the DNA or peptide sequence in
FASTA format.
=head2 add_row() method
$result_code = $object->add_row($tag=>$value);
$result_code = $object->add_row($tag=>[list,of,values]);
$result_code = $object->add(-path=>$tag,
-value=>$value);
add_row() updates the tree by adding data to the indicated tag path. The
example given below adds the value "555-1212" to a new Address entry
named "Pager". You may call add_row() a second time to add a new value
under this tag, creating multi-valued entries.
$object->add_row('Address.Pager'=>'555-1212');
You may provide a list of values to add an entire row of data. For
example:
$sequence->add_row('Assembly_tags'=>['Finished Left',38949,38952,'AC3']);
Actually, the array reference is not entirely necessary, and if you
prefer you can use this more concise notation:
$sequence->add_row('Assembly_tags','Finished Left',38949,38952,'AC3');
No check is done against the database model for the correct data type
or tag path. The update isn't actually performed until you call
commit(), at which time a result code indicates whether the database
update was successful.
You may create objects that reference other objects this way:
$lab = new Ace::Object('Laboratory','LM',$db);
$lab->add_row('Full_name','The Laboratory of Medicine');
$lab->add_row('City','Cincinatti');
$lab->add_row('Country','USA');
$author = new Ace::Object('Author','Smith J',$db);
$author->add_row('Full_name','Joseph M. Smith');
$author->add_row('Laboratory',$lab);
$lab->commit();
$author->commit();
The result code indicates whether the addition was syntactically
correct. add_row() will fail if you attempt to add a duplicate entry
(that is, one with exactly the same tag and value). In this case, use
replace() instead. Currently there is no checking for an attempt to
add multiple values to a single-valued (UNIQUE) tag. The error will
be detected and reported at commit() time however.
The add() method is an alias for add_row().
See also the Ace->new() method.
=head2 add_tree()
$result_code = $object->add_tree($tag=>$ace_object);
$result_code = $object->add_tree(-tag=>$tag,-tree=>$ace_object);
The add_tree() method will insert an entire Ace subtree into the object
to the right of the indicated tag. This can be used to build up
complex Ace objects, or to copy portions of objects from one database
to another. The first argument is a tag path, and the second is the
tree that you wish to insert. As with add_row() the database will
only be updated when you call commit().
When inserting a subtree, you must be careful to remember that
everything to the *right* of the node that you are pointing at will be
inserted; not the node itself. For example, given this Sequence
object:
Sequence AC3
DB_info Database EMBL
Assembly_tags Finished Left 1 4 AC3
Clone left end 1 4 AC3
Clone right end 5512 5515 K07C5
38949 38952 AC3
Finished Right 38949 38952 AC3
If we use at('Assembly_tags') to fetch the subtree rooted on the
"Assembly_tags" tag, it is the tree to the right of this tag,
beginning with "Finished Left", that will be inserted.
Here is an example of copying the "Assembly_tags" subtree
from one database object to another:
( run in 0.858 second using v1.01-cache-2.11-cpan-df04353d9ac )