epitools 0.5.7 → 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/epitools/iter.rb CHANGED
@@ -160,4 +160,4 @@ class Iter
160
160
  end
161
161
  end
162
162
 
163
- end
163
+ end
@@ -1,4 +1,4 @@
1
- require 'epitools'
1
+ #require 'epitools'
2
2
 
3
3
  #
4
4
  # Allow numbers to be converted into words, or exprssed more easily with words.
data/lib/epitools/path.rb CHANGED
@@ -21,7 +21,7 @@ require 'epitools'
21
21
  #
22
22
  # Note: all of the above attributes can be modified to produce new paths!
23
23
  # Here's a useful example:
24
- #
24
+ #
25
25
  # # Check if there's a '.git' directory in the current or parent directories.
26
26
  # def inside_a_git_repository?
27
27
  # path = Path.pwd # get the current directory
@@ -31,7 +31,7 @@ require 'epitools'
31
31
  # end
32
32
  # false
33
33
  # end
34
- #
34
+ #
35
35
  # More examples:
36
36
  #
37
37
  # Path["*.jpeg"].each { |path| path.rename(:ext=>"jpg") }
@@ -55,7 +55,7 @@ require 'epitools'
55
55
  #
56
56
  #
57
57
  class Path
58
-
58
+
59
59
  ## initializers
60
60
 
61
61
  def initialize(newpath, hints={})
@@ -65,13 +65,13 @@ class Path
65
65
  def self.glob(str)
66
66
  Dir[str].map { |entry| new(entry) }
67
67
  end
68
-
68
+
69
69
  def self.[](path)
70
70
  case path
71
71
  when Path
72
72
  path
73
73
  when String
74
-
74
+
75
75
  if path =~ %r{^[a-z\-]+://}i # URL?
76
76
  Path::URL.new(path)
77
77
 
@@ -81,27 +81,27 @@ class Path
81
81
  else
82
82
  # todo: highlight backgrounds of codeblocks to show indent level & put boxes (or rules?) around (between?) double-spaced regions
83
83
  path = Path.expand_path(path)
84
- if path =~ /(^|[^\\])[\?\*\{\}]/ # contains unescaped glob chars?
84
+ if path =~ /(^|[^\\])[\?\*\{\}]/ # contains unescaped glob chars?
85
85
  glob(path)
86
86
  else
87
87
  new(path)
88
88
  end
89
-
89
+
90
90
  end
91
-
91
+
92
92
  end
93
93
  end
94
94
 
95
95
  ## setters
96
-
96
+
97
97
  attr_writer :base
98
98
  attr_writer :dirs
99
-
99
+
100
100
  #
101
101
  # This is the core that initializes the whole class.
102
102
  #
103
103
  # Note: The `hints` parameter contains options so `path=` doesn't have to touch the filesytem as much.
104
- #
104
+ #
105
105
  def path=(newpath, hints={})
106
106
  if hints[:type] or File.exists? newpath
107
107
  if hints[:type] == :dir or File.directory? newpath
@@ -112,18 +112,18 @@ class Path
112
112
  else
113
113
  if newpath.endswith(File::SEPARATOR) # ends in '/'
114
114
  self.dir = newpath
115
- else
115
+ else
116
116
  self.dir, self.filename = File.split(newpath)
117
117
  end
118
118
  end
119
119
  end
120
-
120
+
121
121
  def filename=(newfilename)
122
122
  if newfilename.nil?
123
123
  @ext, @base = nil, nil
124
124
  else
125
125
  ext = File.extname(newfilename)
126
-
126
+
127
127
  if ext.blank?
128
128
  @ext = nil
129
129
  @base = newfilename
@@ -135,16 +135,16 @@ class Path
135
135
  end
136
136
  end
137
137
  end
138
-
138
+
139
139
  def dir=(newdir)
140
140
  dirs = File.expand_path(newdir).split(File::SEPARATOR)
141
141
  dirs = dirs[1..-1] if dirs.size > 0
142
-
142
+
143
143
  @dirs = dirs
144
144
  end
145
-
145
+
146
146
  # TODO: Figure out how to fix the 'path.with(:ext=>ext+".other")' problem (when 'ext == nil')...
147
-
147
+
148
148
  def ext=(newext)
149
149
  if newext.blank?
150
150
  @ext = nil
@@ -156,17 +156,17 @@ class Path
156
156
  end
157
157
 
158
158
  ## getters
159
-
159
+
160
160
  # The directories in the path, split into an array. (eg: ['usr', 'src', 'linux'])
161
- attr_reader :dirs
162
-
163
- # The filename without an extension
161
+ attr_reader :dirs
162
+
163
+ # The filename without an extension
164
164
  attr_reader :base
165
-
166
- # The file extension, including the . (eg: ".mp3")
165
+
166
+ # The file extension, including the . (eg: ".mp3")
167
167
  attr_reader :ext
168
168
 
169
- # Joins and returns the full path
169
+ # Joins and returns the full path
170
170
  def path
171
171
  if d = dir
172
172
  File.join(d, (filename || "") )
@@ -193,38 +193,38 @@ class Path
193
193
  fname = from.pop
194
194
  join(*(from.map { RELATIVE_PARENTDIR } + to))
195
195
  end
196
-
196
+
197
197
  def relative_to2(anchor=nil)
198
- anchor ||= Path.pwd
199
-
198
+ anchor ||= Path.pwd
199
+
200
200
  # operations to transform anchor into self
201
-
201
+
202
202
  # stage 1: go ".." until we find a common dir prefix
203
203
  # (discard everything and go '/' if there's no common dir)
204
- # stage 2: append the rest of the other path
205
-
204
+ # stage 2: append the rest of the other path
205
+
206
206
  # find common prefix
207
207
  smaller, bigger = [ anchor.dirs, self.dirs ].sort_by(&:size)
208
208
  common_prefix_end = bigger.zip(smaller).index { |a,b | a != b }
209
- common_prefix = bigger[0...common_prefix_end]
210
-
209
+ common_prefix = bigger[0...common_prefix_end]
210
+
211
211
  if common_prefix.any?
212
212
  dots = nil
213
213
  end
214
-
214
+
215
215
  self.dirs & anchor.dirs
216
-
216
+
217
217
  end
218
-
218
+
219
219
  # The current directory (with a trailing /)
220
220
  def dir
221
- if dirs
221
+ if dirs
222
222
  File::SEPARATOR + File.join(*dirs)
223
223
  else
224
224
  nil
225
225
  end
226
226
  end
227
-
227
+
228
228
  def filename
229
229
  if base
230
230
  if ext
@@ -237,14 +237,16 @@ class Path
237
237
  end
238
238
  end
239
239
 
240
+ alias_method :name, :filename
241
+
240
242
  def exts
241
243
  extensions = basename.split('.')[1..-1]
242
244
  extensions += [@ext] if @ext
243
245
  extensions
244
246
  end
245
-
247
+
246
248
  ## fstat info
247
-
249
+
248
250
  def exists?
249
251
  File.exists? path
250
252
  end
@@ -252,61 +254,88 @@ class Path
252
254
  def size
253
255
  File.size path
254
256
  end
255
-
257
+
258
+ def lstat
259
+ @lstat ||= File.lstat self # to cache or not to cache -- that is the question.
260
+ #File.lstat self
261
+ end
262
+
263
+ def mode
264
+ lstat.mode
265
+ end
266
+
256
267
  def mtime
257
268
  lstat.mtime
258
269
  end
259
-
270
+
260
271
  def ctime
261
- lstat.ctime path
272
+ lstat.ctime
262
273
  end
263
-
274
+
264
275
  def atime
265
- lstat.atime path
276
+ lstat.atime
266
277
  end
267
-
278
+
279
+ # FIXME: Does the current user own this file?
280
+ def owner?
281
+ raise "STUB"
282
+ end
283
+
284
+ def executable?
285
+ mode & 0o111 > 0
286
+ end
287
+ alias_method :exe?, :executable?
288
+
289
+ def writable?
290
+ mode & 0o222 > 0
291
+ end
292
+
293
+ def readable?
294
+ mode & 0o444 > 0
295
+ end
296
+
268
297
  def dir?
269
298
  File.directory? path
270
299
  end
271
-
300
+
272
301
  def file?
273
302
  File.file? path
274
303
  end
275
-
304
+
276
305
  def symlink?
277
306
  File.symlink? path
278
307
  end
279
-
308
+
280
309
  def broken_symlink?
281
310
  File.symlink?(path) and not File.exists?(path)
282
311
  end
283
-
312
+
284
313
  def symlink_target
285
- Path.new File.readlink(path)
314
+ Path.new File.readlink(path)
286
315
  end
287
316
  alias_method :readlink, :symlink_target
288
-
317
+
289
318
  def uri?
290
319
  false
291
320
  end
292
-
321
+
293
322
  def url?
294
323
  uri?
295
324
  end
296
-
325
+
297
326
  def child_of?(parent)
298
327
  parent.parent_of? self
299
328
  end
300
-
329
+
301
330
  def parent_of?(child)
302
331
  # If `self` is a parent of `child`, it's a prefix.
303
332
  child.path[/^#{Regexp.escape self.path}\/.+/] != nil
304
333
  end
305
-
334
+
306
335
  ## comparisons
307
336
 
308
337
  include Comparable
309
-
338
+
310
339
  def <=>(other)
311
340
  case other
312
341
  when Path
@@ -317,26 +346,33 @@ class Path
317
346
  raise "Invalid comparison: Path to #{other.class}"
318
347
  end
319
348
  end
320
-
349
+
321
350
  def ==(other)
322
351
  self.path == other.to_s
323
352
  end
324
353
 
325
-
354
+
326
355
  ## appending
327
-
356
+
357
+ #
358
+ # Path["/etc"].join("anything{}").path == "/etc/anything{}"
359
+ #
360
+ def join(other)
361
+ Path.new File.join(self, other)
362
+ end
363
+
328
364
  #
329
365
  # Path["/etc"]/"passwd" == Path["/etc/passwd"]
330
366
  #
331
367
  def /(other)
332
368
  # / <- fixes jedit syntax highlighting bug.
333
- # TODO: make it work for "/dir/dir"/"/dir/file"
369
+ # TODO: make it work for "/dir/dir"/"/dir/file"
334
370
  #Path.new( File.join(self, other) )
335
371
  Path[ File.join(self, other) ]
336
- end
337
-
372
+ end
373
+
338
374
  ## opening/reading files
339
-
375
+
340
376
  def open(mode="rb", &block)
341
377
  if block_given?
342
378
  File.open(path, mode, &block)
@@ -346,31 +382,31 @@ class Path
346
382
  end
347
383
  alias_method :io, :open
348
384
  alias_method :stream, :open
349
-
385
+
350
386
  def read(length=nil, offset=nil)
351
387
  File.read(path, length, offset)
352
388
  end
353
-
389
+
354
390
  #
355
391
  # All the lines in this file, chomped.
356
- #
392
+ #
357
393
  def lines
358
394
  io.lines.map(&:chomp)
359
395
  end
360
-
396
+
361
397
  def unmarshal
362
398
  read.unmarshal
363
399
  end
364
-
400
+
365
401
  def ls; Path[File.join(path, "*")]; end
366
402
 
367
403
  def ls_r; Path[File.join(path, "**/*")]; end
368
-
404
+
369
405
  def ls_dirs
370
406
  ls.select(&:dir?)
371
407
  #Dir.glob("#{path}*/", File::FNM_DOTMATCH).map { |s| Path.new(s, :type=>:dir) }
372
408
  end
373
-
409
+
374
410
  def ls_files
375
411
  ls.select(&:file?)
376
412
  #Dir.glob("#{path}*", File::FNM_DOTMATCH).map { |s| Path.new(s, :type=>:file) }
@@ -379,12 +415,12 @@ class Path
379
415
  def siblings
380
416
  ls - [self]
381
417
  end
382
-
418
+
383
419
  def touch
384
420
  open("a") { }
385
421
  self
386
422
  end
387
-
423
+
388
424
  ## modifying files
389
425
 
390
426
  #
@@ -405,7 +441,7 @@ class Path
405
441
  self
406
442
  end
407
443
  alias_method :<<, :append
408
-
444
+
409
445
  #
410
446
  # Overwrite the data in this file (accepts a string, an IO, or it can yield the file handle to a block.)
411
447
  #
@@ -420,7 +456,7 @@ class Path
420
456
  else
421
457
  yield f
422
458
  end
423
- end
459
+ end
424
460
  end
425
461
 
426
462
  #
@@ -450,7 +486,7 @@ class Path
450
486
  def read_json
451
487
  JSON.load(io)
452
488
  end
453
-
489
+
454
490
  # Convert the object to JSON and write it to the file (overwriting the existing file).
455
491
  def write_json(object)
456
492
  write object.to_json
@@ -490,64 +526,64 @@ class Path
490
526
  def read_bson
491
527
  BSON.deserialize(read)
492
528
  end
493
-
529
+
494
530
  def write_bson(object)
495
531
  write BSON.serialize(object)
496
532
  end
497
533
 
498
-
534
+
499
535
  #
500
536
  # Examples:
501
537
  # Path["SongySong.mp3"].rename(:basename=>"Songy Song")
502
538
  # Path["Songy Song.mp3"].rename(:ext=>"aac")
503
539
  # Path["Songy Song.aac"].rename(:dir=>"/music2")
504
540
  # Path["/music2/Songy Song.aac"].exists? #=> true
505
- #
541
+ #
506
542
  def rename!(options)
507
543
  raise "Broken!"
508
-
544
+
509
545
  dest = rename(options)
510
546
  self.path = dest.path # become dest
511
547
  self
512
548
  end
513
-
549
+
514
550
  def rename(options)
515
551
  raise "Broken!"
516
-
552
+
517
553
  raise "Options must be a Hash" unless options.is_a? Hash
518
554
  dest = self.with(options)
519
-
555
+
520
556
  raise "Error: destination (#{dest.inspect}) already exists" if dest.exists?
521
557
  File.rename(path, dest)
522
-
558
+
523
559
  dest
524
560
  end
525
561
 
526
562
  #
527
563
  # Renames the file the specified full path (like Dir.rename.)
528
- #
564
+ #
529
565
  def rename_to(path)
530
566
  raise "Broken!"
531
-
567
+
532
568
  rename :path=>path.to_s
533
569
  end
534
570
  alias_method :mv, :rename_to
535
-
571
+
536
572
  def rename_to!(path)
537
573
  raise "Broken!"
538
574
  rename! :path=>path.to_s
539
575
  end
540
576
  alias_method :mv!, :rename_to!
541
-
577
+
542
578
  def reload!
543
579
  self.path = to_s
544
580
  end
545
-
581
+
546
582
  #
547
- # Generate two almost identical methods: mkdir and mkdir_p
583
+ # Generate two almost identical methods: mkdir and mkdir_p
548
584
  #
549
585
  {
550
- :mkdir => "Dir.mkdir",
586
+ :mkdir => "Dir.mkdir",
551
587
  :mkdir_p =>"FileUtils.mkdir_p"
552
588
  }.each do |method, command|
553
589
  class_eval %{
@@ -573,7 +609,7 @@ raise "Broken!"
573
609
  def cp_r(dest)
574
610
  FileUtils.cp_r(path, dest) #if Path[dest].exists?
575
611
  end
576
-
612
+
577
613
  def mv(dest)
578
614
  FileUtils.mv(path, dest)
579
615
  end
@@ -588,22 +624,22 @@ raise "Broken!"
588
624
 
589
625
  def ln_s(dest)
590
626
  dest = Path[dest]
591
- FileUtils.ln_s self, dest
627
+ FileUtils.ln_s self, dest
592
628
  end
593
629
 
594
630
  ## Owners and permissions
595
-
631
+
596
632
  def chmod(mode)
597
633
  FileUtils.chmod(mode, self)
598
634
  self
599
635
  end
600
-
636
+
601
637
  def chown(usergroup)
602
638
  user, group = usergroup.split(":")
603
639
  FileUtils.chown(user, group, self)
604
640
  self
605
641
  end
606
-
642
+
607
643
  def chmod_R(mode)
608
644
  if directory?
609
645
  FileUtils.chmod_R(mode, self)
@@ -612,7 +648,7 @@ raise "Broken!"
612
648
  raise "Not a directory."
613
649
  end
614
650
  end
615
-
651
+
616
652
  def chown_R(usergroup)
617
653
  user, group = usergroup.split(":")
618
654
  if directory?
@@ -622,36 +658,9 @@ raise "Broken!"
622
658
  raise "Not a directory."
623
659
  end
624
660
  end
625
-
626
- def lstat
627
- @lstat ||= File.lstat self # to cache or not to cache -- that is the question.
628
- #File.lstat self
629
- end
630
-
631
- def mode
632
- lstat.mode
633
- end
634
-
635
- # TODO: Unstub
636
- def owner?
637
- raise "STUB"
638
- end
639
-
640
- def executable?
641
- mode & 0o111 > 0
642
- end
643
- alias_method :exe?, :executable?
644
-
645
- def writable?
646
- mode & 0o222 > 0
647
- end
648
-
649
- def readable?
650
- mode & 0o444 > 0
651
- end
652
661
 
653
662
  ## Dangerous methods.
654
-
663
+
655
664
  def rm
656
665
  if directory? and not symlink?
657
666
  Dir.rmdir(self) == 0
@@ -662,61 +671,61 @@ raise "Broken!"
662
671
  alias_method :"delete!", :rm
663
672
  alias_method :"unlink!", :rm
664
673
  alias_method :"remove!", :rm
665
-
674
+
666
675
  def truncate(offset=0)
667
676
  File.truncate(self, offset) if exists?
668
677
  end
669
678
 
670
-
679
+
671
680
  ## Checksums
672
-
681
+
673
682
  def sha1
674
683
  Digest::SHA1.file(self).hexdigest
675
684
  end
676
-
685
+
677
686
  def sha2
678
687
  Digest::SHA2.file(self).hexdigest
679
688
  end
680
-
689
+
681
690
  def md5
682
691
  Digest::MD5.file(self).hexdigest
683
692
  end
684
693
  alias_method :md5sum, :md5
685
694
 
686
-
695
+
687
696
  # http://ruby-doc.org/stdlib/libdoc/zlib/rdoc/index.html
688
-
697
+
689
698
  def gzip(level=nil)
690
699
  gz_filename = self.with(:filename=>filename+".gz")
691
-
692
- raise "#{gz_filename} already exists" if gz_filename.exists?
693
-
694
- open("rb") do |input|
700
+
701
+ raise "#{gz_filename} already exists" if gz_filename.exists?
702
+
703
+ open("rb") do |input|
695
704
  Zlib::GzipWriter.open(gz_filename) do |gzip|
696
705
  IO.copy_stream(input, gzip)
697
706
  end
698
707
  end
699
-
708
+
700
709
  gz_filename
701
710
  end
702
-
711
+
703
712
  def gzip!(level=nil)
704
713
  gzipped = self.gzip(level)
705
714
  self.rm
706
715
  self.path = gzipped.path
707
716
  end
708
-
717
+
709
718
  def gunzip
710
719
  raise "Not a .gz file" unless ext == "gz"
711
720
 
712
721
  gunzipped = self.with(:ext=>nil)
713
-
722
+
714
723
  gunzipped.open("wb") do |out|
715
724
  Zlib::GzipReader.open(self) do |gunzip|
716
725
  IO.copy_stream(gunzip, out)
717
726
  end
718
727
  end
719
-
728
+
720
729
  gunzipped
721
730
  end
722
731
 
@@ -740,7 +749,7 @@ raise "Broken!"
740
749
  with(:dirs=>dirs[0...-1])
741
750
  end
742
751
  end
743
-
752
+
744
753
  #
745
754
  # Follows all symlinks to give the true location of a path.
746
755
  #
@@ -755,29 +764,29 @@ raise "Broken!"
755
764
  end
756
765
  end
757
766
 
758
-
767
+
759
768
  #
760
769
  # Find the file's mimetype (first from file extension, then by magic)
761
- #
770
+ #
762
771
  def mimetype
763
772
  mimetype_from_ext || magic
764
773
  end
765
774
  alias_method :identify, :mimetype
766
-
775
+
767
776
  #
768
777
  # Find the file's mimetype (only using the file extension)
769
- #
778
+ #
770
779
  def mimetype_from_ext
771
780
  MimeMagic.by_extension(ext)
772
781
  end
773
782
 
774
783
  #
775
784
  # Find the file's mimetype (by magic)
776
- #
785
+ #
777
786
  def magic
778
787
  open { |io| MimeMagic.by_magic(io) }
779
788
  end
780
-
789
+
781
790
  #
782
791
  # Returns the filetype (as a standard file extension), verified with Magic.
783
792
  #
@@ -787,15 +796,15 @@ raise "Broken!"
787
796
  # Note: Prefers long extensions (eg: jpeg over jpg)
788
797
  #
789
798
  # TODO: rename type => magicext?
790
- #
799
+ #
791
800
  def type
792
801
  @cached_type ||= begin
793
-
802
+
794
803
  if file? or symlink?
795
-
804
+
796
805
  ext = self.ext
797
806
  magic = self.magic
798
-
807
+
799
808
  if ext and magic
800
809
  if magic.extensions.include? ext
801
810
  ext
@@ -809,17 +818,17 @@ raise "Broken!"
809
818
  else # !ext and !magic
810
819
  :unknown
811
820
  end
812
-
821
+
813
822
  elsif dir?
814
823
  :directory
815
824
  end
816
-
825
+
817
826
  end
818
827
  end
819
828
 
820
829
 
821
830
  ## aliases
822
-
831
+
823
832
  alias_method :to_path, :path
824
833
  alias_method :to_str, :path
825
834
  alias_method :to_s, :path
@@ -837,9 +846,9 @@ raise "Broken!"
837
846
  alias_method :directory=, :dir=
838
847
 
839
848
  alias_method :directory?, :dir?
840
-
849
+
841
850
  alias_method :exist?, :exists?
842
-
851
+
843
852
  ############################################################################
844
853
  ## Class Methods
845
854
 
@@ -852,9 +861,9 @@ raise "Broken!"
852
861
  #
853
862
  AUTOGENERATED_CLASS_METHODS = %w[
854
863
  mkdir
855
- mkdir_p
856
- sha1
857
- sha2
864
+ mkdir_p
865
+ sha1
866
+ sha2
858
867
  md5
859
868
  rm
860
869
  truncate
@@ -868,7 +877,7 @@ raise "Broken!"
868
877
  ].each do |spec|
869
878
  method, cardinality = spec.split("/")
870
879
  cardinality = cardinality.to_i
871
-
880
+
872
881
  class_eval %{
873
882
  def self.#{method}(path#{", *args" if cardinality > 0})
874
883
  Path[path].#{method}#{"(*args)" if cardinality > 0}
@@ -885,7 +894,7 @@ raise "Broken!"
885
894
  new_path << "/" if orig_path.endswith "/"
886
895
  new_path
887
896
  end
888
-
897
+
889
898
  #
890
899
  # TODO: Remove the tempfile when the Path object is garbage collected or freed.
891
900
  #
@@ -894,39 +903,39 @@ raise "Broken!"
894
903
  yield path if block_given?
895
904
  path
896
905
  end
897
- alias_class_method :tempfile, :tmpfile
898
- alias_class_method :tmp, :tmpfile
899
-
906
+ alias_class_method :tempfile, :tmpfile
907
+ alias_class_method :tmp, :tmpfile
908
+
900
909
  def self.home
901
910
  Path[ENV['HOME']]
902
911
  end
903
-
912
+
904
913
  def self.pwd
905
914
  Path.new expand_path(Dir.pwd)
906
915
  end
907
-
916
+
908
917
  def self.pushd
909
918
  @@dir_stack ||= []
910
919
  @@dir_stack.push pwd
911
920
  end
912
-
921
+
913
922
  def self.popd
914
923
  @@dir_stack ||= [pwd]
915
924
  @@dir_stack.pop
916
925
  end
917
-
926
+
918
927
  def self.cd(dest); Dir.chdir(dest); end
919
-
928
+
920
929
  def self.ls(path); Path[path].ls end
921
-
930
+
922
931
  def self.ls_r(path); Path[path].ls_r; end
923
-
932
+
924
933
  def self.ln_s(src, dest); Path[src].ln_s(dest); end
925
934
 
926
935
  ## TODO: Verbose mode
927
936
  #def self.verbose=(value); @@verbose = value; end
928
937
  #def self.verbose; @@verbose ||= false; end
929
-
938
+
930
939
  if Sys.windows?
931
940
  PATH_SEPARATOR = ";"
932
941
  BINARY_EXTENSION = ".exe"
@@ -941,7 +950,7 @@ raise "Broken!"
941
950
  #
942
951
  # (Note: If you pass more than one argument, it'll return an array of `Path`s instead of
943
952
  # a single path.)
944
- #
953
+ #
945
954
  def self.which(bin, *extras)
946
955
  if extras.empty?
947
956
  ENV["PATH"].split(PATH_SEPARATOR).find do |path|
@@ -952,8 +961,8 @@ raise "Broken!"
952
961
  else
953
962
  ([bin] + extras).map { |bin| which(bin) }
954
963
  end
955
- end
956
-
964
+ end
965
+
957
966
  end
958
967
 
959
968
 
@@ -967,12 +976,12 @@ class Path::URL < Path
967
976
  #
968
977
  # TODO: only include certain methods from Path (delegate style)
969
978
  # (eg: remove commands that write)
970
-
979
+
971
980
  def initialize(uri, hints={})
972
981
  @uri = URI.parse(uri)
973
982
  self.path = @uri.path
974
983
  end
975
-
984
+
976
985
  def uri?
977
986
  true
978
987
  end
@@ -985,30 +994,30 @@ class Path::URL < Path
985
994
  def to_s
986
995
  uri.to_s
987
996
  end
988
-
997
+
989
998
 
990
999
  #
991
1000
  # ...this is: 'http'
992
- #
1001
+ #
993
1002
  def scheme
994
1003
  uri.scheme
995
1004
  end
996
1005
  alias_method :protocol, :scheme
997
-
1006
+
998
1007
  #
999
1008
  # ...and this is: 'host.com'
1000
1009
  #
1001
1010
  def host
1002
1011
  uri.host
1003
1012
  end
1004
-
1013
+
1005
1014
  #
1006
1015
  # ...and this is: 80
1007
1016
  #
1008
1017
  def port
1009
1018
  uri.port
1010
1019
  end
1011
-
1020
+
1012
1021
  #
1013
1022
  # ...and this is: {param1: value1, param2: value2, ...etc... }
1014
1023
  #
@@ -1019,8 +1028,29 @@ class Path::URL < Path
1019
1028
  nil
1020
1029
  end
1021
1030
  end
1022
-
1031
+
1023
1032
  # ...and `path` is /path/filename.ext
1033
+
1034
+ def open(mode="r", &block)
1035
+ require 'open-uri'
1036
+ if block_given?
1037
+ open(to_s, mode, &block)
1038
+ else
1039
+ open(to_s, mode)
1040
+ end
1041
+ end
1042
+
1043
+ # Note: open is already aliased to io in parent class.
1044
+ def read(*args)
1045
+ require 'open-uri'
1046
+ case scheme
1047
+ when /https?/i
1048
+ io.read(*args)
1049
+ else
1050
+ raise "No connector for #{scheme} yet. Please fix!"
1051
+ end
1052
+ end
1053
+
1024
1054
  end
1025
1055
 
1026
1056
 
@@ -1035,6 +1065,6 @@ class String
1035
1065
  def to_Path
1036
1066
  Path.new self
1037
1067
  end
1038
-
1068
+
1039
1069
  alias_method :to_P, :to_Path
1040
1070
  end