Index: trunk/Nebulous-Server/lib/Nebulous/Keys.pm
===================================================================
--- trunk/Nebulous-Server/lib/Nebulous/Keys.pm	(revision 17072)
+++ trunk/Nebulous-Server/lib/Nebulous/Keys.pm	(revision 18451)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: Keys.pm,v 1.1 2008-03-20 21:13:28 jhoblitt Exp $
+# $Id: Keys.pm,v 1.2 2008-07-09 23:32:35 jhoblitt Exp $
 
 package Nebulous::Keys;
@@ -10,27 +10,34 @@
 our $VERSION = '0.01';
 
-use base qw( Exporter );
-
-use File::Spec::Functions;
+use base qw( Exporter Class::Accessor::Fast );
+
+use File::Spec;
 use URI::file;
 use URI;
-
-our @EXPORT_OK      = qw( parse_neb_key );
+use overload '""' => \&_stringify_key;
+
+our @EXPORT_OK = qw(
+    parse_neb_key
+    parse_neb_volume
+);
+
+__PACKAGE__->mk_ro_accessors(qw( path volume soft_volume ));
 
 sub parse_neb_key
 {
-    my $text = shift;
-    return unless defined $text;
+    my ($key, $volume) = @_;
+    return unless defined $key;
 
     # white space is not allowed
-    if ($text =~ qr/\s+/) {
+    if ($key =~ qr/\s+/) {
         die "keys and URIs may not contain whitespace";
     }
 
-    my $uri = URI->new($text);
+    my $uri = URI->new($key);
     my $scheme = $uri->scheme;
     my $path = $uri->opaque;
     
-    my $volume;
+    my $volume_name;
+    my $soft_volume;
     # if this is a valid uri 
     if (defined $scheme) {
@@ -47,10 +54,27 @@
         # strip off volume component if it exists
         $path =~ s|^//([^/]+)||;
-        $volume = $1;
+        
+        # ignore key supplied volume name if one is passed as a parameter
+        $volume ||= $1;
+        my $volume_info = parse_neb_volume($volume);
+
+        # magically eat the "any" volume
+        if (defined $volume_info->{volume} and $volume_info->{volume} ne 'any') {
+            $volume_name = $volume_info->{volume};
+            $soft_volume = $volume_info->{soft_volume};
+        }
 
         # require a leading slash if there is no volume name
-        if ((not defined $volume) and (not $path =~ m|^/|)) {
+        if ((not defined $volume_name) and (not $path =~ m|^/|)) {
             die "neb URI scheme requires a leading slash, eg. neb:/";
         }
+    } else {
+        my $volume_info = parse_neb_volume($volume);
+
+        # magically eat the "any" volume
+        if (defined $volume_info->{volume} and $volume_info->{volume} ne 'any') {
+            $volume_name = $volume_info->{volume};
+            $soft_volume = $volume_info->{soft_volume};
+        }
     }
 
@@ -59,7 +83,36 @@
 
     # remove multiple /'s and trailing slashes
-    $path = canonpath($path);
-
-    return ($volume, $path);
+    $path = File::Spec->canonpath($path);
+
+    return __PACKAGE__->new({
+        volume      => $volume_name,
+        soft_volume => $soft_volume,
+        path        => $path,
+    });
+}
+
+sub parse_neb_volume
+{
+    my $volume = shift;
+    return unless defined $volume;
+
+    my $soft_volume;
+    # check to see if there is a tilde and remove it if found
+    if (defined $volume and $volume =~ s/^~//) {
+        $soft_volume = 1;
+    }
+
+    return({ volume => $volume, soft_volume => $soft_volume });
+}
+
+sub _stringify_key
+{
+    my $self = shift;
+
+    my $path        = $self->path;
+    my $volume      = $self->volume || "";
+    my $soft_volume = $self->soft_volume ? '~' : "";
+
+    return "neb://${soft_volume}${volume}/$path";
 }
 
