Boulder
view release on metacpan or search on metacpan
# insert a tag/value pair
$stone->insert(Martha => { First_name => 'Martha', Last_name => 'Steward'} );
# find the first Address
$stone->search('Address');
# change an existing subtree
$martha = $stone->Martha;
$martha->replace(Last_name => 'Stewart'); # replace a value
# iterate over the tree with a cursor
$cursor = $stone->cursor;
while (my ($key,$value) = $cursor->each) {
print "$value: Go Bluejays!\n" if $key eq 'State' and $value eq 'Katonah';
}
# various format conversions
print $stone->asTable;
print $stone->asString;
print $stone->asHTML;
print $stone->asXML('Person');
=head1 DESCRIPTION
person[0].name[0]=Fred
person[0].pets[0]=Fido
person[0].pets[1]=Rex
person[0].pets[2]=Lassie
person[0].age[0]=30
person[1].name[0]=Harry
person[1].pets[0]=Rover
person[1].pets[1]=Spot
person[1].age[0]=23
=head2 $cursor = $stone->cursor()
Retrieves an iterator over the object. You can call this several
times in order to return independent iterators. The following brief
example is described in more detail in L<Stone::Cursor>.
my $curs = $stone->cursor;
while (my($tag,$value) = $curs->next_pair) {
print "$tag => $value\n";
}
# yields:
Sally[0].Address[0].Zip[0] => 10578
Sally[0].Address[0].City[0] => Katonah
Sally[0].Address[0].Street[0] => Hickory Street
Sally[0].Address[0].State[0] => NY
Sally[0].Last_name[0] => James
Sally[0].Age[0] => 30
# Equivalent to $stone->{'tag'}
sub at {
my $self = shift;
return $self->{$_[0]};
}
#
# Delete the indicated key entirely.
sub delete {
my($self,$key) = @_;
delete $self->{$key};
$self->_fix_cursors;
}
# Return all the tags in the stone.
sub tags {
my $self = shift;
return grep (!/^\./,keys %{$self});
}
# Return attributes as a hash reference
# (only used by asXML)
if (defined $tag) {
return $self->{'.att'} = $tag if ref $tag eq 'HASH';
return $self->{'.att'}{$tag} = $value if defined $value;
return $self->{'.att'}{$tag};
}
return $self->{'.att'} ||= {};
}
# Fetch an Iterator on the Stone.
sub cursor {
my $self = shift;
return new Stone::Cursor($self);
}
# Convert a stone into a straight hash
sub to_hash {
my ($self) = shift;
my ($key,%result);
foreach $key (keys %$self) {
next if substr($key,0,1) eq '.';
my ($tag,$value) = @_;
$value =~ s/&/&/g;
$value =~ s/>/>/g;
$value =~ s/</</g;
($tag,$value);
}
# Dump the entire data structure, for debugging purposes
sub dump {
my($self) = shift;
my $i = $self->cursor;
my ($key,$value);
while (($key,$value)=$i->each) {
print "$key=$value\n";
}
# this has to be done explicitly here or it won't happen.
$i->DESTROY;
}
# return the name of the Stone
sub name {
if ($ref eq 'HASH') { # Insert a record, potentially recursively
$self->insert_hash($key,%{$_});
next;
}
warn "Attempting to insert a $ref into a Stone. Be alert.\n";
push(@{$self->{$key}},$_);
}
$self->_fix_cursors;
}
# Put the values into the key, replacing
# whatever was there before.
sub replace_list {
my($self,$key,@values) = @_;
$self->{$key}=[]; # clear it out
$self->insert_list($key,@values); # append the values
}
my($self,$key) = @_;
return $self->{$key}->[0];
}
sub get_last {
my($self,$key) = @_;
return $self->{$key}->[$#{$self->{$key}}];
}
# This is a private subroutine used for registering
# and unregistering cursors
sub _register_cursor {
my($self,$cursor,$register) = @_;
if ($register) {
$self->{'.cursors'}->{$cursor}=$cursor;
} else {
delete $self->{'.cursors'}->{$cursor};
delete $self->{'.cursors'} unless %{$self->{'.cursors'}};
}
}
# This is a private subroutine used to alert cursors that
# our contents have changed.
sub _fix_cursors {
my($self) = @_;
return unless $self->{'.cursors'};
my($cursor);
foreach $cursor (values %{$self->{'.cursors'}}) {
$cursor->reset;
}
}
# This is a private subroutine. It indexes
# all the way into the structure.
#sub _index {
# my($self,@indices) = @_;
# my $stone = $self;
# my($key,$index,@h);
# while (($key,$index) = splice(@indices,0,2)) {
# $stone= ($index eq "\#") ? $stone->get_last($key):
# $stone->get($key,$index);
# last unless ref($stone)=~/Stone/;
# }
# }
# return $stone;
#}
sub DESTROY {
my $self = shift;
undef %{$self->{'.cursor'}}; # not really necessary ?
}
1;
Stone/Cursor.pm view on Meta::CPAN
=head1 NAME
Stone::Cursor - Traverse tags and values of a Stone
=head1 SYNOPSIS
use Boulder::Store;
$store = Boulder::Store->new('./soccer_teams');
my $stone = $store->get(28);
$cursor = $stone->cursor;
while (my ($key,$value) = $cursor->each) {
print "$value: Go Bluejays!\n" if $key eq 'State' and $value eq 'Katonah';
}
=head1 DESCRIPTION
Boulder::Cursor is a utility class that allows you to create one or
more iterators across a L<Stone> object. This is used for traversing
large Stone objects in order to identify or modify portions of the
record.
=head2 CLASS METHODS
=item Boulder::Cursor->new($stone)
Return a new Boulder::Cursor over the specified L<Stone> object. This
will return an error if the object is not a L<Stone> or a
descendent. This method is usually not called directly, but rather
indirectly via the L<Stone> cursor() method:
my $cursor = $stone->cursor;
=head2 OBJECT METHODS
=item $cursor->each()
Iterate over the attached B<Stone>. Each iteration will return a
two-valued list consisting of a tag path and a value. The tag path is
of a form that can be used with B<Stone::index()> (in fact, a cursor
is used internally to implement the B<Stone::dump()> method. When the
end of the B<Stone> is reached, C<each()> will return an empty list,
after which it will start over again from the beginning. If you
attempt to insert or delete from the stone while iterating over it,
all attached cursors will reset to the beginnning.
For example:
$cursor = $s->cursor;
while (($key,$value) = $cursor->each) {
print "$value: BOW WOW!\n" if $key=~/pet/;
}
=item $cursor->reset()
This resets the cursor back to the beginning of the associated
B<Stone>.
=head1 AUTHOR
Lincoln D. Stein <lstein@cshl.org>.
=head1 COPYRIGHT
Copyright 1997-1999, Cold Spring Harbor Laboratory, Cold Spring Harbor
NY. This module can be used and distributed on the same terms as Perl
Stone/Cursor.pm view on Meta::CPAN
# New expects a Stone object as its single
# parameter.
sub new {
my($package,$stone) = @_;
die "Boulder::Cursor: expect a Stone object parameter"
unless ref($stone);
my $self = bless {'stone'=>$stone},$package;
$self->reset;
$stone->_register_cursor($self,'true');
return $self;
}
# This procedure does a breadth-first search
# over the entire structure. It returns an array that looks like this
# (key1[index1].key2[index2].key3[index3],value)
sub each {
my $self = shift;
my $short_keys = shift;
Stone/Cursor.pm view on Meta::CPAN
while ($top && !$found) {
$found++ if ($key,$value) = $top->next;
if (!$found) { # this iterator is done
pop @{$stack};
$top = $stack->[$#{$stack}];
next;
}
if ( ref $value && !exists $value->{'.name'} ) { # found another record to begin iterating on
if (%{$value}) {
undef $found;
$top = $value->cursor;
push @{$stack},$top;
next;
} else {
undef $value;
}
}
}
unless ($found) {
$self->reset;
return ();
Stone/Cursor.pm view on Meta::CPAN
my $self = shift;
$self->{'arrayindex'} = 0;
$self->{'hashindex'} = 0;
$self->{'keys'}=[$self->{'stone'}->tags];
$self->{'stack'}=[$self];
}
sub DESTROY {
my $self = shift;
if (ref $self->{'stone'}) {
$self->{'stone'}->_register_cursor($self,undef);
}
}
# Next will return the next index in its Stone object,
# indexing first through the members of the array, and then through
# the individual keys. When iteration is finished, it resets itself
# and returns an empty array.
sub next {
my $self = shift;
my($arrayi,$hashi,$stone,$keys) = ($self->{'arrayindex'},
docs/javaboulder.txt view on Meta::CPAN
[0-9]+ index leftward from first value
-[0-9]+ index rightward from last value
# last item
\? random item (question mark)
*public Stone[] path(String index_string)
This is a better name for index(), but unfortunately not part of the
Perl Boulder API. Maybe index() should be phased out.
*public Enumeration cursor()
Return an Enumeration over the Stone object. Each call to
nextElement() takes a step in a breadth-first traversal of the Stone.
The elements of the Enumeration are Stones with three tags:
tag name interpretation
-------- --------------
"tag" String representing the name of the current
element's tag
"path" String representing full path to current element
docs/javaboulder.txt view on Meta::CPAN
Return True if this Stone should be passed up to higher layers.
===========================================================================
public interface Boulder.IO;
This interface defines everything that a generic Boulder IO class
should be able to do. Both Boulder.Stream (serial input/output) and
Boulder.Store (record-oriented input/output) implement this interface.
Note that Boulder.IO has an intrinsic cursor behavior, in that it
returns Stones in some defined order.
* public abstract Stone read_record() throws IOException
Reads a new Stone from input and returns it. If no further stones can
be read returns NULL. If an I/O error occurs returns IOException.
Returns EOFException if the caller makes additional calls to
read_record() after it has returned NULL.
* public abstract Stone read_record(String[] f) throws IOException
( run in 0.305 second using v1.01-cache-2.11-cpan-4d50c553e7e )