/
Path.pod6
973 lines (649 loc) · 32.7 KB
/
Path.pod6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
=begin pod
=TITLE class IO::Path
=SUBTITLE File or directory path
=for code :skip-test
class IO::Path is Cool does IO { }
The workhorse of IO operations.
Conceptually, an C<IO::Path> object consists of a volume, a directory, and a
basename. It supports both purely textual operations, and operations that access
the file system, e.g. to resolve a path, or to read all content of a file.
At creation, each C<IO::Path> object is given information about the current
working directory the path might be relative to using the C<$.CWD> attribute
(defaults to L«C<$*CWD>|/language/variables#Dynamic_variables»), as well as
what operating system semantics should be used for path manipulation using
the special L«C<IO::Spec>|/type/IO::Spec» type given in the C<$.SPEC> attribute.
The C<$.SPEC> defaults to the value of
L«C<$*SPEC>|/language/variables#Dynamic_variables», which uses the object
suitable for the operating system the code is currently running on. This is
the default most code will be comfortable with.
In certain situations, e.g. testing, you may wish to force C<$*SPEC> to use one
of the specific SPEC modules: L«C<IO::Spec::Unix>|/type/IO::Spec::Unix»,
L«C<IO::Spec::Win32>|/type/IO::Spec::Win32»,
L«C<IO::Spec::Cygwin>|/type/IO::Spec::Cygwin», and
L«C<IO::Spec::QNX>|/type/IO::Spec::QNX», or to create C<IO::Path> objects via
shortcut subclasses L«C<IO::Path::Unix>|/type/IO::Path::Unix»,
L«C<IO::Path::Win32>|/type/IO::Path::Win32»,
L«C<IO::Path::Cygwin>|/type/IO::Path::Cygwin», and
L«C<IO::Path::QNX>|/type/IO::Path::QNX» that pre-set the C<$.SPEC> attribute
for you.
The rest of this document silently assumes Unix semantics in its examples,
unless stated otherwise.
=head1 Methods
=head2 method new
Defined as:
=for code :skip-test
multi method new(Str:D $path, IO::Spec :$SPEC = $*SPEC, Str() :$CWD = $*CWD)
multi method new(
:$basename!, :$dirname = '.', :$volume = ''
IO::Spec :$SPEC = $*SPEC, Str() :$CWD = $*CWD
)
Creates a new C<IO::Path> object from a path string (which is being parsed for
volume, directory name and basename), or from volume, directory name and
basename passed as named arguments.
The path's operation will be performed using C<:$SPEC> semantics (defaults to
current L«C<$*SPEC>|/language/variables#Dynamic_variables») and will use
C<:$CWD> as the directory the path is relative to (defaults to
L«C<$*CWD>|/language/variables#Dynamic_variables»).
=head2 attribute CWD
IO::Path.new("foo", :CWD</home/camelia>)
.IO.CWD.say; # OUTPUT: «/home/camelia»
Read-only. Contains implicit or explicit value of C<:$CWD> argument to C<.new>.
=head2 attribute SPEC
IO::Path.new("foo", :SPEC(IO::Spec::Unix.new))\
.IO.SPEC.^name.say; # OUTPUT: «IO::Spec::Unix»
Read-only. Contains implicit or explicit value of C<:$SPEC> argument to C<.new>.
=head2 attribute path
IO::Path.new("foo").path.say; # OUTPUT: «foo»
Read-only. Returns the string the object was constructed from or the value of
C<$SPEC.join($volume, $dirname, $basename)> if multi-part version of C<.new>
was used. B<NOTE:> this does not include the C<$.CWD>; see
L«C<IO::Path.absolute>|/routine/absolute»
and L«C<IO::Path.relative>|/routine/relative» for
stringification options that include C<$.CWD>.
B<NOTE:> Implementations may cache operations done with this attribute, so
modifying its value (via cloning or Proxy) is NOT recommended and may result
in broken C<IO::Path> objects. Create a new C<IO::Path> object instead.
=head2 method ACCEPTS
Defined as:
multi method ACCEPTS(IO::Path:D: Cool:D $other --> Bool:D)
Coerces the argument to C<IO::Path>, if necessary. Returns C<True> if
L«C<.absolute>|/routine/absolute» method on both paths returns the same string.
B<NOTE:> it's possible for two paths that superficially point to the same
resource to NOT smartmatch as C<True>, if they were constructed differently and
were never fully resolved:
say "foo/../bar".IO ~~ "bar".IO # False
The reason is the two paths above may point to different resources when fully
resolved (e.g. if C<foo> is a symlink). Resolve the paths before smartmatching
to check they point to same resource:
say "foo/../bar".IO.resolve(:completely) ~~ "bar".IO.resolve(:completely) # True
=head2 method basename
Defined as:
method basename(IO::Path:D:)
Returns the basename part of the path object, which is the name of the
filesystem object itself that is referenced by the path.
"docs/README.pod".IO.basename.say; # OUTPUT: «README.pod»
"/tmp/".IO.basename.say; # OUTPUT: «tmp»
Note that in L«C<IO::Spec::Win32>|/type/IO::Spec::Win32» semantics, the
C<basename> of a Windows share is C<\>, not the name of the share itself:
IO::Path::Win32.new('//server/share').basename.say; # OUTPUT: «\»
=head2 method add
Defined as:
method add(IO::Path:D: Str() $what --> IO::Path:D)
Concatenates a path fragment to the invocant and returns the resultant
C<IO::Path>.
"foo/bar".IO.add("meow") .resolve.relative.say; # OUTPUT: «foo/bar/meow»
"foo/bar".IO.add("/meow") .resolve.relative.say; # OUTPUT: «foo/bar/meow»
"foo/bar".IO.add("meow.txt").resolve.relative.say; # OUTPUT: «foo/bar/meow.txt»
"foo/bar".IO.add("../meow") .resolve.relative.say; # OUTPUT: «foo/meow»
"foo/bar".IO.add("../../") .resolve.relative.say; # OUTPUT: «.»
=head2 method child
Defined as:
method child(IO::Path:D: Str() $childname --> IO::Path:D)
Alias for L«C<.add>|/routine/add». B<NOTE:> C<.child> will be switched to
secure version around 6.d release time, which will C<fail()> with non-child
paths and is also slower, since it has to do more work. Use
L«C<.add>|/routine/add» if your code does not need to guarantee the added
path is in fact a child path.
=head2 method cleanup
Defined as:
method cleanup(IO::Path:D: --> IO::Path:D)
Returns a new path that is a canonical representation of the invocant path,
cleaning up any extraneous path parts:
"foo/./././..////bar".IO.cleanup.say; # OUTPUT: «"foo/../bar".IO»
IO::Path::Win32.new("foo/./././..////bar")
.cleanup.say; "foo\..\bar".IO; # OUTPUT: «"foo\..\bar".IO»
Note that no file system access is made. See also
L«C<resolve>|/routine/resolve».
=head2 method comb
Defined as:
method comb(IO::Path:D: |args --> Seq:D)
Opens the file and processes its contents the same way
L«C<Str.comb>|/type/Str» does, taking the same arguments. Implementations may
slurp the file in its entirety when this method is called.
=head2 method extension
Defined as:
multi method extension(IO::Path:D: --> Str:D)
multi method extension(IO::Path:D: Int :$parts --> Str:D)
multi method extension(IO::Path:D: Range :$parts --> Str:D)
multi method extension(IO::Path:D: Str $subst, Int :$parts, Str :$joiner --> IO::Path:D)
multi method extension(IO::Path:D: Str $subst, Range :$parts, Str :$joiner --> IO::Path:D)
Returns the extension consisting of C<$parts> parts (defaults to C<1>),
where a "part" is defined
as a dot followed by possibly-empty string up to the end of the string, or
previous part. That is C<"foo.tar.gz"> has an extension of two parts: first part
is C<"gz"> and second part is C<"tar"> and calling
C<"foo.tar.gz".IO.extension: :2parts> gives C<"tar.gz">. If an extension with
the specified number of C<$parts> is not found, returns an empty string.
C<$parts> can be a L«C<Range>|/type/Range», specifying the minimum number of
parts and maximum number of parts the extension should have. The routine will
attempt to much the most parts it can. If C<$parts> range's endpoints that are
smaller than C<0> they'll be treated as C<0>; implementations may treat
endpoints larger than C<2⁶³-1> as C<2⁶³-1>. Ranges with C<NaN> or
L«C<Str>|/type/Str» endpoints will cause an exception to be thrown.
If C<$subst> is provided, the extension will be instead replaced with C<$subst>
and a new C<IO::Path> object will be returned. It will be joined to the file's
name with C<$joiner>, which defaults to an empty string when C<$subst> is
an empty string and to C<"."> when C<$subst> is not empty. B<Note:> if as
the result of replacement the L«C<basename>|/routine/basename» of the path
ends up being empty, it will be assumed to be C<.> (a single dot).
# Getting an extension:
say "foo.tar.gz".IO.extension; # OUTPUT: «gz»
say "foo.tar.gz".IO.extension: :2parts; # OUTPUT: «tar.gz»
say "foo.tar.gz".IO.extension: :parts(^5); # OUTPUT: «tar.gz»
say "foo.tar.gz".IO.extension: :parts(0..1); # OUTPUT: «gz»
# Replacing an extension
say "foo.tar.gz".IO.extension: ''; # OUTPUT: «"foo.tar".IO»
say "foo.tar.gz".IO.extension: 'ZIP'; # OUTPUT: «"foo.tar.ZIP".IO»
say "foo.tar.gz".IO.extension: 'ZIP', :0parts; # OUTPUT: «"foo.tar.gz.ZIP".IO»
say "foo.tar.gz".IO.extension: 'ZIP', :2parts; # OUTPUT: «"foo.ZIP".IO»
say "foo.tar.gz".IO.extension: 'ZIP', :parts(^5); # OUTPUT: «"foo.ZIP".IO»
# Replacing an extension using non-standard joiner:
say "foo.tar.gz".IO.extension: '', :joiner<_>; # OUTPUT: «"foo.tar_".IO»
say "foo.tar.gz".IO.extension: 'ZIP', :joiner<_>; # OUTPUT: «"foo.tar_ZIP".IO»
say "foo.tar.gz".IO.extension: 'ZIP', :joiner<_>,
:2parts; # OUTPUT: «"foo_ZIP".IO»
say "foo.tar.gz".IO.extension: 'ZIP', :joiner<_>,
:parts(^5); # OUTPUT: «"foo_ZIP".IO»
# EDGE CASES:
# There is no 5-part extension, so returned value is an empty string
say "foo.tar.gz".IO.extension: :5parts; # OUTPUT: «»
# There is no 5-part extension, so we replaced nothing:
say "foo.tar.gz".IO.extension: 'ZIP', :5parts; # OUTPUT: «"foo.tar.gz".IO»
# Replacing a 0-part extension is just appending:
say "foo.tar.gz".IO.extension: 'ZIP', :0parts; # OUTPUT: «"foo.tar.gz.ZIP".IO»
# Replace 1-part of the extension, using '.' joiner
say "...".IO.extension: 'tar'; # OUTPUT: «"....tar".IO»
# Replace 1-part of the extension, using empty string joiner
say "...".IO.extension: 'tar', :joiner(''); # OUTPUT: «"...tar".IO»
# Remove 1-part extension; results in empty basename, so result is ".".IO
say ".".IO.extension: ''; # OUTPUT: «".".IO»
=head2 method dirname
Defined as:
method dirname(IO::Path:D:)
Returns the directory name portion of the path object. That is, it returns
the path excluding the L<volume|/routine/volume> and the
L<base name|/routine/basename>.
say IO::Path.new("/home/camelia/myfile.p6").dirname; # OUTPUT: «/home/camelia»
say IO::Path::Win32.new("C:/home/camelia").dirname; # OUTPUT: «/home»
say IO::Path.new("/home").dirname; # OUTPUT: «/»
=head2 method volume
Defined as:
method volume(IO::Path:D:)
Returns the volume portion of the path object. On Unix system, this is always
the empty string.
say IO::Path::Win32.new("C:\\Windows\\registry.ini").volume; # OUTPUT: «C:»
=head2 method parts
Defined as:
method parts(IO::Path:D: --> Hash)
Returns a hash with the keys C<dirname>, C<path> and C<volume>, and as
values the return values of the methods with the same names.
say IO::Path.new("/etc/passwd").parts.perl;
# OUTPUT: «{:basename("passwd"), :directory("/etc"), :dirname("/etc"), :volume("")}»
=head method gist
Defined as:
method gist(IO::Path:D: --> Str:D)
Returns a string, part of which contains either the value of
L«C<.absolute>|/type/IO::Path#method_absolute» (if path is absolute) or
L«C<.path>|/type/IO::Path#attribute_path». Note that no escaping
of special characters is made, so e.g. C<"\b"> means a path contains a backslash
and letter "b", not a backspace.
say "foo/bar".IO; # OUTPUT: «"foo/bar".IO»
say IO::Path::Win32.new: 「C:\foo/bar\」; # OUTPUT: «"C:\foo/bar\".IO»
=head2 method Str
Defined as:
method Str(IO::Path:D: --> Str)
Alias for L«C<IO::Path.path>|/routine/path». In particular, note that default
stringification of an C<IO::Path> does B<NOT> use the value of
L«C<$.CWD> attribute|type/IO::Path#attribute_CWD». To stringify while
retaining full path information use L«C<.absolute>|/routine/absolute» or
L«C<.relative>|/routine/relative» methods.
=head2 method succ
Defined as:
method succ(IO::Path:D: --> IO::Path:D)
Returns a new L<IO::Path> constructed from the invocant, with
L«C<.basename>|/routine/basename» changed by calling
L«C<Str.succ>|/type/Str#method_succ» on it.
"foo/file02.txt".IO.succ.say; # OUTPUT: «"foo/file03.txt".IO»
=head2 method open
Defined as:
method open(IO::Path:D: *%opts)
Opens the path as a file; the named options control the mode, and are the
same as the L<open> function accepts.
=head2 method pred
Defined as:
method pred(IO::Path:D: --> IO::Path:D)
Returns a new L<IO::Path> constructed from the invocant, with
L«C<.basename>|/routine/basename» changed by calling
L«C<Str.pred>|/type/Str#method_pred» on it.
"foo/file02.txt".IO.pred.say; # OUTPUT: «"foo/file01.txt".IO»
=head2 method watch
Defined as:
method watch(IO::Path:D: --> Supply)
Watches the path for modifications. Only implemented in Rakudo with the
MoarVM backend at the moment.
=head2 method is-absolute
Defined as:
method is-absolute(IO::Path:D: --> Bool)
Returns C<True> if the path is an absolute path, and C<False> otherwise.
"/foo".IO.is-absolute.say; # OUTPUT: «True»
"bars".IO.is-absolute.say; # OUTPUT: «False»
Note that on Windows a path that starts with a slash or backslash is still
considered absolute even if no volume was given, as it is absolute for that
particular volume:
IO::Path::Win32.new("/foo" ).is-absolute.say; # OUTPUT: «True»
IO::Path::Win32.new("C:/foo").is-absolute.say; # OUTPUT: «True»
IO::Path::Win32.new("C:foo" ).is-absolute.say; # OUTPUT: «False»
=head2 method is-relative
Defined as:
method is-relative(IO::Path:D: --> Bool)
Returns C<True> if the path is a relative path, and C<False> otherwise.
Windows caveats for L«C<.is-absolute>|/type/IO::Path#method_is-absolute»
apply.
=head2 method absolute
Defined as:
multi method absolute(IO::Path:D: --> Str)
multi method absolute(IO::Path:D: $base --> Str)
Returns a new C<Str> object that is an absolute path. If the invocant
is not already an absolute path, it is first made absolute using C<$base>
as base, if it is provided, or the C<.CWD> attribute the object was
created with if it is not.
=head2 method relative
Defined as:
method relative(IO::Path:D: $base = $*CWD --> Str)
Returns a new C<Str> object with the path relative to the C<$base>. If C<$base>
is not provided, C<$*CWD> is used in its place. If the invocant is not
an absolute path, it's first made to be absolute using the C<.CWD>
attribute the object was created with, and then is made relative to C<$base>.
=head2 method parent
Defined as:
method parent(IO::Path:D: --> IO::Path)
Removes the last portion of the path and returns the result as a new C<IO::Path>.
my $io = IO::Path.new( "/etc/passwd" );
say $io.parent; # OUTPUT: «"/etc".IO»
=head2 method resolve
Defined as:
method resolve(IO::Path:D: :$completely --> IO::Path)
Returns a new C<IO::Path> object with all symbolic links and references to the
parent directory (C<..>) resolved. This means that the filesystem is examined
for each directory in the path, and any symlinks found are followed.
# bar is a symlink pointing to "/baz"
my $io = "foo/./bar/..".IO.resolve; # now "/" (the parent of "/baz")
If C<:$completely>, which defaults to C<False>, is set to a true value, the
method will L«C<fail>|/routine/fail» with C<X::IO::Resolve>
if it cannot completely resolve the path,
otherwise, it will resolve as much as possible, and will merely perform
L«C<cleanup>|/routine/cleanup» of the rest of the path. The last part of the
path does B<NOT> have to exist to C<:$completely> resolve the path.
NOTE: Currently (April 2017) this method doesn't work correctly on all
platforms, e.g. Windows, since it assumes POSIX semantics.
=head2 routine dir
Defined as:
sub dir(Cool $path = '.', Mu :$test = none('.', '..'))
method dir(IO::Path:D: Mu :$test = none('.', '..'))
Returns the contents of a directory as a lazy list of C<IO::Path> objects
representing relative paths, filtered by L<smart-matching|
/language/operators#infix_~~> their names (as strings) against the C<:test>
parameter.
B<NOTE:> a C<dir> call opens a directory for reading, which counts towards
maximum per-process open files for your program. Be sure to exhaust returned
L<Seq> before doing something like recursively performing more C<dir> calls.
You can exhaust it by assigning to a C<@->sigiled variable or simply looping
over it. Note how examples below push further dirs to look through into
an L<Array>, rather than immediately calling C<dir> on them. See also
L«C<IO::Dir> module|https://modules.perl6.org/dist/IO::Dir» that gives you finer
control over closing dir handles.
Examples:
=begin code :skip-test
# To iterate over the contents of the current directory:
for dir() -> $file {
say $file;
}
# As before, but include even '.' and '..' which are filtered out by
# the default :test matcher:
for dir(test => *) -> $file {
say $file;
}
# To get the names of all .jpg and .jpeg files in ~/Downloads:
my @jpegs = $*HOME.dir: test => /:i '.' jpe?g $/;
=end code
=comment TODO: Turn the following into a FAQ entry, and link to it from here.
An example program that lists all files and directories recursively:
sub MAIN($dir = '.') {
my @todo = $dir.IO;
while @todo {
for @todo.pop.dir -> $path {
say $path.Str;
@todo.push: $path if $path.d;
}
}
}
A lazy way to find the first three files ending in ".p6" recursively starting from the current directory:
=for code :skip-test
my @stack = '.'.IO;
my $perl-files = gather while @stack {
with @stack.pop {
when :d { @stack.append: .dir }
.take when .extension.lc eq 'p6'
}
}
.put for $perl-files[^3];
=head2 method e
Defined as:
method e(--> Bool:D)
Returns C<True> if the invocant is a path that exists.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method d
Defined as:
method d(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is a directory.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method f
Defined as:
method f(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is a file.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method s
Defined as:
method s(--> Int:D)
Returns the file size in bytes. May be called on paths that are directories, in
which case the reported size is dependent on the operating system.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method l
Defined as:
method l(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is a symlink.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method r
Defined as:
method r(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is accessible.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method w
Defined as:
method w(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is writable.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method rw
Defined as:
method rw(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is readable and
writable. The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist>
if the path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method x
Defined as:
method x(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is executable.
The method will L«C<fail>|/routine/fail» with C<X::IO::DoesNotExist> if the
path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method rwx
Defined as:
method rwx(--> Bool:D)
Returns C<True> if the invocant is a path that exists and is executable,
readable, and writable. The method will L«C<fail>|/routine/fail» with
C<X::IO::DoesNotExist> if the path points to a non-existent filesystem entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method z
Defined as:
method z(--> Bool:D)
Returns C<True> if the invocant is a path that exists and has size of C<0>.
May be called on paths that are directories, in
which case the reported file size (and thus the result of this method)
is dependent on the operating system. The method will L«C<fail>|/routine/fail»
with C<X::IO::DoesNotExist> if the path points to a non-existent filesystem
entity.
TIP: use L«smartmatch with Pairs|/type/Pair#method_ACCEPTS» to perform multiple
file tests.
=head2 method sibling
Defined as:
method sibling(IO::Path:D: Str() $sibling --> IO::Path:D)
Allows to reference a sibling file or directory. Returns a new
L«C<IO::Path>|/type/IO::Path» based on the invocant, with the
# L«C<.basename>|/type/IO::Path#method_basename» changed to C<$sibling>. The
C<$sibling> is allowed to be a multi-part path fragment, although
# L«C<.add>|/type/IO::Path#method_add» is a better choice for such use.
say '.bashrc'.IO.sibling: '.bash_aliases'; # OUTPUT: «.bash_aliases".IO»
say '/home/camelia/.bashrc'.IO.sibling: '.bash_aliases';
# OUTPUT: «/home/camelia/.bash_aliases".IO»
say '/foo/' .IO.sibling: 'bar'; # OUTPUT: «/bar".IO»
say '/foo/.'.IO.sibling: 'bar'; # OUTPUT: «/foo/bar".IO»
=head2 routine slurp
Defined as:
multi method slurp(IO::Path:D: :$bin, :$enc)
Read all of the file's content and return it as either L<Buf>, if C<:$bin>
is C<True>, or if not, as L<Str> decoded with C<:$enc> encoding, which defaults
to C<utf8>. See L«C<&open>|/routine/open» for valid values for C<:$enc>.
=head2 method spurt
Defined as:
method spurt(IO::Path:D: $data, :$enc, :$append, :$createonly)
Opens the file path for writing, and writes all of the C<$data> into it.
Will L«C<fail>|/routine/fail» if it cannot succeed for any reason.
The C<$data> can be any L«C<Cool>|/type/Cool» type or any L«C<Blob>|/type/Blob»
type. Arguments are as follows:
=item C<:$enc> — character encoding of the data. Takes same values as C<:$enc>
in L«C<IO::Handle.open>|/routine/open». Defaults to C<utf8>. Ignored if C<$data>
is a L«C<Blob>|/type/Blob».
=item C<:$append> — open the file in C<append> mode, preserving existing
contents, and appending data to the end of the file.
=item C<:$createonly> — L«C<fail>|/routine/fail» if the file already exists.
=head2 method chdir
Defined as:
multi method chdir(IO::Path:D: Str() $path, :$d = True, :$r, :$w, :$x)
B<DEPRECATION NOTICE:> this method will be deprecated in C<6.d> language. Do
not use it for new code. Instead, create a new path or use
L«C<add>|/routine/add» method. For altering current working
directory see L«C<&chdir>|/routine/chdir» and L«C<&*chdir>|/routine/&*chdir»
subroutines.
Contrary to the name, the C<.chdir> method does not change any directories,
but merely concatenates the given C<$path> to the invocant and returns the
resultant C<IO::Path>. Optional file tests can be performed by providing
C<:d>, C<:r>, C<:w>, or C<:x> L«C<Bool>|/type/Bool» named arguments; when
set to C<True>, they'll perform L«C<.d>|/routine/d», L«C<.r>|/routine/r»,
L«C<.w>|/routine/w», and L«C<.x>|/routine/x» tests respectively. By default,
only C<:d> is set to C<True>.
=head2 routine mkdir
Defined as:
method mkdir(IO::Path:D: Int() $mode = 0o777 --> IO::Path:D)
sub mkdir( IO() $path, Int() $mode = 0o777 --> IO::Path:D)
Creates a new directory. See L«C<mode>|/routine/mode» for explanation and
valid values for C<$mode>. Returns the L<IO::Path> object pointing to
the newly created directory on success;
L<fails|/routine/fail> with L<X::IO::Mkdir> if directory cannot be created.
Creates parent directories, as needed. That is, C<mkdir "foo/bar"> will
create C<foo> if it does not exist.
=head2 routine rmdir
Defined as:
sub rmdir(IO $dir --> Bool)
method rmdir(IO::Path:D: --> Bool)
Remove the given directory if it is empty.
Returns C<True> on success. Throws an exception of type
L<X::IO::Rmdir> if the directory cannot be removed (e.g.
the directory is not empty, or the path is not a directory).
Since this only works on an empty directory, to remove a directory and its
contents you will have to do something more complex.
# When we have a directory first recurse, then remove it
multi sub rm-all(IO::Path $path where :d) {
.&rm-all for $path.dir;
rmdir($path)
}
# Otherwise just remove the thing directly
multi sub rm-all(IO::Path $path) { $path.unlink }
See also L<rmtree in File::Directory::Tree|https://github.com/labster/p6-file-directory-tree>.
=head2 method chmod
Defined as:
method chmod(IO::Path:D: Int() $mode --> Bool)
Changes the POSIX permissions of a file or directory to C<$mode>.
Returns C<True> on success; on failure,
L<fails|/routine/fail> with L<X::IO::Chmod>.
The mode is expected as an integer following the L<standard numeric notation|
https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation>, and is
best written as an octal number:
=for code :skip-test
'myfile'.IO.chmod(0o444); # make a file read-only
'somedir'.IO.chmod(0o777); # set 0777 permissions on a directory
Make sure you I<don't> accidentally pass the intended octal digits as a decimal
number (or string containing a decimal number):
=for code :skip-test
'myfile'.IO.chmod: '0444'; # BAD!!! (interpreted as mode 0o674)
'myfile'.IO.chmod: '0o444'; # OK (an octal in a string)
'myfile'.IO.chmod: 0o444; # Also OK (an octal literal)
=head2 routine rename
Defined as:
method rename(IO::Path:D: IO() $to, :$createonly = False --> Bool:D)
sub rename(IO() $from, IO() $to, :$createonly = False --> Bool:D)
Renames a file or directory. Returns C<True> on success; L<fails|/routine/fail>
with L<X::IO::Rename> if C<:$createonly> is C<True> and the C<$to> path already
exists or if the operation failed for some other reason.
B<Note:> some renames will always fail, such as when the new name is on a
different storage device. See also: L«C<move>|/routine/move».
=head2 routine copy
Defined as:
method copy(IO::Path:D: IO() $to, :$createonly --> Bool:D)
sub copy(IO() $from, IO() $to, :$createonly --> Bool:D)
Copies a file. Returns C<True> on success; L<fails|/routine/fail>
with L<X::IO::Copy> if C<:$createonly> is C<True> and the C<$to> path already
exists or if the operation failed for some other reason, such as when
C<$to> and C<$from> are the same file.
=head2 routine move
Defined as:
method move(IO::Path:D: IO() $to, :$createonly --> Bool:D)
sub move(IO() $from, IO() $to, :$createonly --> Bool:D)
Copies a file and then removes the original. If removal fails, it's possible
to end up with two copies of the file. Returns C<True> on success;
L<fails|/routine/fail> with L<X::IO::Move> if C<:$createonly> is C<True> and
the C<$to> path already exists or if the operation failed for some other reason,
such as when C<$to> and C<$from> are the same file.
To avoid copying, you can use L«C<rename>|/routine/rename», if the files are on
the same storage device. It also works with directories, while C<move> does not.
=head2 method Numeric
Defined as:
method Numeric(IO::Path:D: --> Numeric:D)
Coerces L«C<.basename>|/routine/basename» to L<Numeric>. L<Fails|/routine/fail>
with C<X::Str::Numeric> if base name is not numerical.
=head2 method Int
Defined as:
method Int(IO::Path:D: --> Int:D)
Coerces L«C<.basename>|/routine/basename» to L<Int>. L<Fails|/routine/fail>
with C<X::Str::Numeric> if base name is not numerical.
=head2 routine symlink
Defined as:
method symlink(IO::Path:D $target: IO() $link --> Bool:D)
sub symlink( IO() $target, IO() $link --> Bool:D)
Create a new I<symbolic> link C<$link> to existing C<$target>.
Returns C<True> on success; L<fails|/routine/fail> with
L<X::IO::Symlink> if the symbolic link could not be created. If C<$target>
does not exist, creates a dangling symbolic link.
To create a hard link, see L«C<link>|/routine/link».
B<Note:> on Windows, creation of symbolic links may require escalated
privileges.
=head2 routine link
Defined as:
method link(IO::Path:D $target: IO() $link --> Bool:D)
sub link( IO() $target, IO() $link --> Bool:D)
Create a new I<hard> link C<$link> to existing C<$target>.
Returns C<True> on success; L<fails|/routine/fail> with
L<X::IO::Link> if the symbolic link could not be created.
To create a symbolic link, see L«C<symlink>|/routine/symlink».
=head2 routine unlink
Defined as:
method unlink(IO::Path:D: --> Bool)
sub unlink(*@filenames --> List)
Delete all specified ordinary files, links, or symbolic links.
The subroutine form returns the names of the files that were successfully
deleted. The method form returns C<True> on success, or
L<fails|/routine/fail> with L<X::IO::Unlink> if the operation could not be
completed.
=head2 method IO
Defined as:
method IO(IO::Path:D: --> IO::Path)
Returns the invocant.
=head2 method SPEC
Defined as:
method SPEC(IO::Path:D: --> IO::Spec)
Returns the L<IO::Spec|/type/IO::Spec> object that was (implicitly) specified at object
creation time.
my $io = IO::Path.new("/bin/bash");
say $io.SPEC; # OUTPUT: «(Unix)»
say $io.SPEC.dir-sep; # OUTPUT: «/»
=head1 File timestamp retrieval
There are also 3 methods for fetching the 3 timestamps of a file (inode),
on Operating Systems where these are available:
=head2 method modified
Returns an L«C<Instant>|/type/Instant» object indicating when the file was
last modified.
=for code :skip-test
say "path/to/file".IO.modified; # Instant:1424089165
say "path/to/file".IO.modified.DateTime; # 2015-02-16T12:18:50Z
=head2 method accessed
Return an L<Instant> object representing the timestamp when the file was
last accessed. B<Note:> depending on how the filesystem was mounted, the
last accessed time may not update on I<each access> to the file, but only
on the first access after modifications.
=for code :skip-test
say "path/to/file".IO.accessed; # Instant:1424353577
say "path/to/file".IO.accessed.DateTime; # 2015-02-19T13:45:42Z
=head2 method changed
Returns an L«C<Instant>|/type/Instant» object indicating the file or directory
was last changed.
=for code :skip-test
say "path/to/file".IO.changed; # Instant:1424089165
say "path/to/file".IO.changed.DateTime; # 2015-02-16T12:18:50Z
=head1 File permissions retrieval
=head2 method mode
Return an L<IntStr> object representing the POSIX permissions of a file. The
Str part of the result is the octal representation of the file permission, like
the form accepted by the chmod(1) utility.
=for code :skip-test
say ~"path/to/file".IO.mode; # e.g. '0644'
say +"path/to/file".IO.mode; # e.g. 420, where sprintf('%04o', 420) eq '0644'
The result of this can be used in the other methods that take a mode as an
argument.
=for code :skip-test
"path/to/file1".IO.chmod("path/to/file2".IO.mode); # will change the
# permissions of file1
# to be the same as file2
=end pod
# vim: expandtab shiftwidth=4 ft=perl6