epitools 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+
2
+ class Object
3
+
4
+ #
5
+ # Default "integer?" behaviour.
6
+ #
7
+ def integer?; false; end
8
+
9
+ #
10
+ # `truthy?` means `not blank?`
11
+ #
12
+ def truthy?
13
+ if respond_to? :blank?
14
+ not blank?
15
+ else
16
+ not nil?
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+
23
+ class TrueClass
24
+
25
+ def truthy?; true; end
26
+
27
+ end
28
+
29
+
30
+ class FalseClass
31
+
32
+ def truthy?; false; end
33
+
34
+ end
35
+
36
+
37
+ class Float
38
+
39
+ #
40
+ # 'true' if the float is 0.0
41
+ #
42
+ def blank?; self == 0.0; end
43
+
44
+ end
45
+
46
+
47
+ class NilClass
48
+
49
+ #
50
+ # Always 'true'; nil is considered blank.
51
+ #
52
+ def blank?; true; end
53
+
54
+ end
55
+
56
+
57
+ class Symbol
58
+
59
+ #
60
+ # Symbols are never blank.
61
+ #
62
+ def blank?; false; end
63
+
64
+ end
@@ -12,11 +12,16 @@ class Iter
12
12
  attr_accessor :container
13
13
 
14
14
  def initialize(vals)
15
- @container = vals.map{|val| Elem.new(self, val)}
15
+ @container = vals.map { |val| elem(val) }
16
16
  end
17
17
 
18
+ # Wrap a value in an Elem container
19
+ def elem(val)
20
+ Elem.new(self, val)
21
+ end
22
+
18
23
  def self.from_elems(elems)
19
- new([]).tap{|i| i.container = elems}
24
+ new([]).tap { |i| i.container = elems }
20
25
  end
21
26
 
22
27
  def ==(other)
@@ -31,12 +36,14 @@ class Iter
31
36
  def each
32
37
  @container.each do |elem|
33
38
  yield elem
39
+ elem.visited = true
34
40
  end
35
41
  end
36
42
 
37
43
  def each_cons(num=1)
38
44
  @container.each_cons(num) do |(*elems)|
39
45
  yield *elems
46
+ elems.each { |e| e.visited = true }
40
47
  end
41
48
  end
42
49
 
@@ -59,11 +66,16 @@ class Iter
59
66
 
60
67
  class Elem < BasicObject
61
68
 
62
- attr_accessor :val
63
-
69
+ attr_accessor :val, :visited
70
+
64
71
  def initialize(iter, val)
65
72
  @iter = iter
66
- @val = val
73
+ @val = val.is_a?(Elem) ? val.value : val
74
+ @visited = false
75
+ end
76
+
77
+ def elem?
78
+ true
67
79
  end
68
80
 
69
81
  def ==(other)
@@ -78,6 +90,10 @@ class Iter
78
90
  self
79
91
  end
80
92
 
93
+ def visited?
94
+ @visited
95
+ end
96
+
81
97
  def next
82
98
  p = pos+1
83
99
  if p >= container.size
@@ -143,7 +159,5 @@ class Iter
143
159
  "<Elem: #{@val.inspect}>"
144
160
  end
145
161
  end
146
-
147
162
 
148
- end
149
-
163
+ end
@@ -16,7 +16,6 @@
16
16
  # Daniel Mendler
17
17
  #
18
18
  require 'epitools/mimemagic_tables'
19
- require 'stringio'
20
19
 
21
20
  # Mime type detection
22
21
  class MimeMagic
@@ -8,14 +8,13 @@
8
8
  require 'epitools'
9
9
 
10
10
  #
11
- # Path: An object-oriented wrapper for files.
12
- # (Combines useful methods from FileUtils, File, Dir, and more!)
11
+ # Path: An object-oriented wrapper for files. (Combines useful methods from FileUtils, File, Dir, and more!)
13
12
  #
14
13
  # Each Path object has the following attributes:
15
14
  #
16
15
  # path => the entire path
17
16
  # filename => just the name and extension
18
- # basename => just the filename
17
+ # basename => just the filename (without extension)
19
18
  # ext => just the extension
20
19
  # dir => just the directory
21
20
  # dirs => an array of directories
@@ -33,25 +32,27 @@ require 'epitools'
33
32
  # false
34
33
  # end
35
34
  #
36
- #
37
- # Examples:
35
+ # More examples:
38
36
  #
39
37
  # Path["*.jpeg"].each { |path| path.rename(:ext=>"jpg") }
40
- #
41
38
  # Path["filename.txt"] << "Append data!"
42
- #
43
- # entries = Path["/etc"].ls
44
- #
45
- # Path
39
+ # etcfiles = Path["/etc"].ls
40
+ # Path["*.txt"].each(&:gzip)
46
41
  #
47
42
  # Swap two files:
48
43
  #
49
44
  # a, b = Path["file_a", "file_b"]
50
- # temp = a.with(:ext=>a.ext+".swapping")
45
+ # temp = a.with(:ext=>a.ext+".swapping") # return a modified version of this object
51
46
  # a.mv(temp)
52
47
  # b.mv(a)
53
48
  # temp.mv(b)
54
- #
49
+ #
50
+ # Paths can be created for existant and non-existant files. If you want to create a nonexistant
51
+ # directory, just add a '/' at the end, so Path knows. (eg: Path["/etc/nonexistant/"]).
52
+ #
53
+ # Performance has been an important factor in Path's design, so doing crazy things with Path
54
+ # usually doesn't kill your machine. Go nuts!
55
+ #
55
56
  #
56
57
  class Path
57
58
 
@@ -170,8 +171,27 @@ class Path
170
171
  ""
171
172
  end
172
173
  end
174
+
175
+ #
176
+ # Path relative to current directory (Path.pwd)
177
+ #
178
+ def relative
179
+ relative_to(pwd)
180
+ end
181
+
182
+ def relative_to(to)
183
+ from = path.split(File::SEPARATOR)
184
+ to = Path[to].path.split(File::SEPARATOR)
185
+ p [from, to]
186
+ from.length.times do
187
+ break if from[0] != to[0]
188
+ from.shift; to.shift
189
+ end
190
+ fname = from.pop
191
+ join(*(from.map { RELATIVE_PARENTDIR } + to))
192
+ end
173
193
 
174
- def relative_to(anchor=nil)
194
+ def relative_to2(anchor=nil)
175
195
  anchor ||= Path.pwd
176
196
 
177
197
  # operations to transform anchor into self
@@ -231,15 +251,15 @@ class Path
231
251
  end
232
252
 
233
253
  def mtime
234
- File.mtime path
254
+ lstat.mtime
235
255
  end
236
256
 
237
257
  def ctime
238
- File.ctime path
258
+ lstat.ctime path
239
259
  end
240
260
 
241
261
  def atime
242
- File.atime path
262
+ lstat.atime path
243
263
  end
244
264
 
245
265
  def dir?
@@ -258,6 +278,11 @@ class Path
258
278
  File.symlink?(path) and not File.exists?(path)
259
279
  end
260
280
 
281
+ def symlink_target
282
+ Path.new File.readlink(path)
283
+ end
284
+ alias_method :readlink, :symlink_target
285
+
261
286
  def uri?
262
287
  false
263
288
  end
@@ -322,7 +347,7 @@ class Path
322
347
  def read(length=nil, offset=nil)
323
348
  File.read(path, length, offset)
324
349
  end
325
-
350
+
326
351
  #
327
352
  # All the lines in this file, chomped.
328
353
  #
@@ -386,6 +411,79 @@ class Path
386
411
  end
387
412
  end
388
413
  end
414
+
415
+ #
416
+ # Parse the file based on the file extension.
417
+ # (Handles json, html, yaml, marshal.)
418
+ #
419
+ def parse
420
+ case ext.downcase
421
+ when 'json'
422
+ read_json
423
+ when 'html', 'htm'
424
+ read_html
425
+ when 'xml', 'rdf', 'rss'
426
+ read_xml
427
+ when 'yaml', 'yml'
428
+ read_yaml
429
+ when 'marshal'
430
+ read_marshal
431
+ when 'bson'
432
+ read_bson
433
+ else
434
+ raise "Unrecognized format: #{ext}"
435
+ end
436
+ end
437
+
438
+ # Parse the file as JSON
439
+ def read_json
440
+ JSON.load(io)
441
+ end
442
+
443
+ # Convert the object to JSON and write it to the file (overwriting the existing file).
444
+ def write_json(object)
445
+ write object.to_json
446
+ end
447
+
448
+
449
+ def read_html
450
+ Nokogiri::HTML(io)
451
+ end
452
+
453
+
454
+ # Convert the object to YAML and write it to the file (overwriting the existing file).
455
+ def write_yaml(object)
456
+ write object.to_yaml
457
+ end
458
+
459
+ # Parse the file as YAML
460
+ def read_yaml
461
+ YAML.load(io)
462
+ end
463
+
464
+
465
+ def read_xml
466
+ Nokogiri::XML(io)
467
+ end
468
+
469
+
470
+ def read_marshal
471
+ Marshal.load(io)
472
+ end
473
+
474
+ def write_marshal(object)
475
+ write object.marshal
476
+ end
477
+
478
+
479
+ def read_bson
480
+ BSON.deserialize(read)
481
+ end
482
+
483
+ def write_bson(object)
484
+ write BSON.serialize(object)
485
+ end
486
+
389
487
 
390
488
  #
391
489
  # Examples:
@@ -514,6 +612,33 @@ raise "Broken!"
514
612
  end
515
613
  end
516
614
 
615
+ def lstat
616
+ @lstat ||= File.lstat self # to cache or not to cache -- that is the question.
617
+ #File.lstat self
618
+ end
619
+
620
+ def mode
621
+ lstat.mode
622
+ end
623
+
624
+ # TODO: Unstub
625
+ def owner?
626
+ raise "STUB"
627
+ end
628
+
629
+ def executable?
630
+ mode & 0o111 > 0
631
+ end
632
+ alias_method :exe?, :executable?
633
+
634
+ def writable?
635
+ mode & 0o222 > 0
636
+ end
637
+
638
+ def readable?
639
+ mode & 0o444 > 0
640
+ end
641
+
517
642
  ## Dangerous methods.
518
643
 
519
644
  def rm
@@ -602,15 +727,6 @@ raise "Broken!"
602
727
  to_s =~ pattern
603
728
  end
604
729
 
605
- def lstat
606
- #@lstat ||= File.lstat self # to cache or not to cache -- that is the question.
607
- File.lstat self
608
- end
609
-
610
- def mode
611
- lstat.mode
612
- end
613
-
614
730
  #
615
731
  # Find the parent directory. If the `Path` is a filename, it returns the containing directory.
616
732
  #
@@ -637,8 +753,6 @@ raise "Broken!"
637
753
  end
638
754
 
639
755
 
640
- # Mimetype finding and magic (requires 'mimemagic' gem)
641
-
642
756
  #
643
757
  # Find the file's mimetype (first from file extension, then by magic)
644
758
  #
@@ -661,16 +775,16 @@ raise "Broken!"
661
775
  open { |io| MimeMagic.by_magic(io) }
662
776
  end
663
777
 
664
- # TODO: rename type => magicext
665
-
666
778
  #
667
- # The filetype (as a standard file extension), verified with Magic.
779
+ # Returns the filetype (as a standard file extension), verified with Magic.
668
780
  #
669
781
  # (In other words, this will give you the *true* extension, even if the file's
670
782
  # extension is wrong.)
671
783
  #
672
784
  # Note: Prefers long extensions (eg: jpeg over jpg)
673
785
  #
786
+ # TODO: rename type => magicext?
787
+ #
674
788
  def type
675
789
  @cached_type ||= begin
676
790
 
@@ -699,7 +813,8 @@ raise "Broken!"
699
813
 
700
814
  end
701
815
  end
702
-
816
+
817
+
703
818
  ## aliases
704
819
 
705
820
  alias_method :to_path, :path
@@ -903,15 +1018,14 @@ class Path::URL < Path
903
1018
  end
904
1019
 
905
1020
  # ...and `path` is /path/filename.ext
906
-
907
1021
  end
908
1022
 
909
1023
 
910
1024
  #
911
1025
  # Path("/some/path") is an alias for Path["/some/path"]
912
1026
  #
913
- def Path(*args)
914
- Path[*args]
1027
+ def Path(arg)
1028
+ Path[arg]
915
1029
  end
916
1030
 
917
1031
  class String
@@ -921,4 +1035,3 @@ class String
921
1035
 
922
1036
  alias_method :to_P, :to_Path
923
1037
  end
924
-