epitools 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-