some more progress. All the initialization routines run and I can get some of the...
[kakapo:kakapo.git] / src / Path.nqp
1 # Copyright (C) 2010, Austin Hastings. See accompanying LICENSE file, or
2 # http://www.opensource.org/licenses/artistic-license-2.0.php for license.
3
4 # Abstract representation of filesystem entries.
5 class Path;
6
7 INIT {
8         our %_Osname_class_map := Hash.new(
9                 :DEFAULT(       Path::Unix),
10                 :linux( Path::Unix),
11         );
12 }
13
14 method get_osname_map() {
15         our %_Osname_class_map;
16 }
17
18 method _init_obj(*@pos, *%named) {
19         my %map := self.get_osname_map();
20         my $osname := 'DEFAULT';
21         try {
22             my $tmp := %*VM<osname>;
23             $osname := $tmp if %map.contains: $tmp;
24
25             # if not, whatever. Keep it at DEFAULT
26             CATCH { }
27         }
28
29         my $class := %map{$osname};
30         my $obj := $class.new( |@pos, |%named );        # NB: Returns a different type than Path.
31         $obj;
32 }
33
34 class Path::Unix
35         is Path;
36
37 has     @!elements;
38 has     $!filesystem;
39 has     $!volume;
40 has     $!is_relative;
41 has     $!initialized;
42
43 INIT {
44         #Parrot::define_multisub( <append>, :method, :starting_with( <append> ));
45         #Parrot::define_multisub( <append>, [ Path::Unix::append__String ], :method, :signatures( [ < _ string > ]));
46 }
47
48 our method absolute($bool = 1)          { $!is_relative := ! $bool; }
49
50 my method append__ANY($element, :$dynamic) {
51         die( "Can't use a ", pir::typeof__SP($element), " as part of a Path - use a String or Path instead.");
52 }
53
54 my method append__Path($element, :$dynamic = 0) {
55
56         unless $!initialized {
57                 $!initialized := $element.initialized;
58                 $!is_relative := $element.is_relative;
59                 $!volume := $element.volume;
60         }
61
62         $dynamic
63                 ?? @!elements.push: $element
64                 !! @!elements.append( $element.elements );
65
66         self;
67 }
68
69 # Scenario:  "x" -> [ 'x' ], :relative
70 # Scenario: "/x" -> [ '', 'x' ] -> ['x'] :absolute
71 # Scenario: "x/" -> [ 'x', '' ] -> [ 'x' ] :relative
72 # Scenario: "" -> [ '' ] -> [ ] :absolute (confused with /)
73
74 my method append__String($element, :$dynamic = 0) {
75         die( "Cannot use :dynamic with a String, only a Path argument" )
76                 if $dynamic;
77
78         my @parts := $element.split: self.directory_separator;
79
80         # If this $element is first one, it determines $!is_relative.
81         unless $!initialized {
82                 $!initialized := 1;
83                 if @parts[0] eq '' {
84                         @parts.shift;
85                         $!is_relative := 0;
86                 }
87                 else {
88                         $!is_relative := 1;
89                 }
90         }
91
92         # Take care of trailing /:  "foo/" -> [ 'foo', '' ]
93         my $last := @parts.pop;
94
95         @parts.push: $last
96                 unless $last eq '';
97
98         @!elements.append: @parts;
99
100         self;
101 }
102
103 our method directory_separator()        { '/'; }
104
105 our method elements() {
106         my @result := [ ];
107
108         for @!elements -> $elt {
109                 if $elt.isa: <String> {
110                         @result.push: $elt;
111                 }
112                 else {
113                         @result.append: $elt.elements;
114                 }
115         }
116
117         @result;
118 }
119
120 our method exists()                     { $!filesystem.exists(self); }
121
122 # NB: This is called by the 'get_string' vtable provided by P6object
123 method get_string() {
124         my $slash := self.directory_separator;
125
126         self.is_absolute
127                 ?? $!volume ~ $slash ~ self.elements.join: $slash
128                 !! self.elements.join: $slash;
129 }
130
131 my method _init_obj(*@parts, :$dynamic = 0, *%named) {
132         @!elements := @!elements;
133         $!filesystem := $*FileSystem;
134         $!initialized := 0;
135         $!is_relative := 1;
136         $!volume := '';
137
138         self._init_args(|%named);
139
140         for @parts -> $part {
141                 self.append($part, :dynamic($dynamic && $part.isa: 'Path'));
142         }
143
144         self;
145 }
146
147 our method is_absolute() {
148         if @!elements.elems == 0 || @!elements[0].isa('String') {
149                 ! $!is_relative;
150         }
151         else {
152                 @!elements[0].is_absolute;
153         }
154 }
155
156 our method is_relative() {
157         if @!elements.elems == 0 || @!elements[0].isa('String') {
158                 $!is_relative;
159         }
160         else {
161                 @!elements[0].is_relative;
162         }
163 }
164
165 our method relative($bool = 1)          { $!is_relative := $bool; }
166
167 ############## Stuff that is delegated to filesystem
168 #~ our method is_directory()    { self.exists && self._stat_query(2); }
169 #~ our method is_device()       { self.exists && self._stat_query(3); }
170 #~ our method is_file()         { self.exists && get_file().is_file(self._complete); }
171 #~ our method is_link()         { self.exists && get_file.is_link(self._complete); }
172 #~ our method modify_time()     { self._stat_query(6); }
173 #~ our method size()            { self._stat_query(1); }
174 #~ our method access_time()     { self._stat_query(5); }
175 #~ our method backup_time()     { self._stat_query(8); }
176 #~ our method change_time()     { self._stat_query(7); }
177 #~ our method create_time()     { self._stat_query(4); }
178 #~ my method _stat_query($index) {      # $index
179         #~ pir::stat__ISI(self._complete, $index);
180 #~ }
181 #~ our method gid()             { self._stat_query(10); }
182 #~ our method uid()             { self._stat_query(9); }
183 our method open(*%named) {
184         $!filesystem.open(self, |%named);
185 }
186
187 our method slurp(*%named) {
188         $!filesystem.slurp(self, |%named);
189 }
190
191
192
193 #~ class Path::Cwd;
194
195 #~ my method _complete() {
196         #~ '.';
197 #~ }