epitools 0.4.37 → 0.4.38

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.37
1
+ 0.4.38
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{epitools}
8
- s.version = "0.4.37"
8
+ s.version = "0.4.38"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["epitron"]
12
- s.date = %q{2011-05-29}
12
+ s.date = %q{2011-06-07}
13
13
  s.description = %q{Miscellaneous utility libraries to make my life easier.}
14
14
  s.email = %q{chris@ill-logic.com}
15
15
  s.extra_rdoc_files = [
@@ -2,6 +2,7 @@ require 'pp'
2
2
  require 'set'
3
3
 
4
4
  class Object
5
+
5
6
  unless defined?(__DIR__)
6
7
  #
7
8
  # This method is convenience for the `File.expand_path(File.dirname(__FILE__))` idiom.
@@ -13,8 +14,64 @@ class Object
13
14
  ::File.expand_path(::File.join(dir, *args.map{|a| a.to_s}))
14
15
  end
15
16
  end
17
+
18
+ #
19
+ # 'autoreq' is a replacement for autoload that can load gems.
20
+ #
21
+ # Usage:
22
+ # autoreq :Constant, 'thing-to-require'
23
+ # autoreq :Constant, 'thing-to-require'
24
+ # autoreq :OtherConstant do
25
+ # gem 'somegem', '~> 1.2'
26
+ # require 'somegem'
27
+ # end
28
+ #
29
+ def autoreq(const, path=nil, &block)
30
+ raise "Error: autoreq must be supplied with a file to load, or a block." unless !!path ^ block_given?
31
+
32
+ if block_given?
33
+ Module.autoreqs[const] = block
34
+ else
35
+ Module.autoreqs[const] = path
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ #
42
+ # Patch 'Module#const_missing' to support 'autoreq'
43
+ #
44
+ class Module
45
+
46
+ @@autoreq_searching_for = nil
47
+
48
+ alias const_missing_without_autoreq const_missing
49
+
50
+ def const_missing(const)
51
+ return if const == @@autoreq_searching_for
52
+
53
+ if thing = autoreqs[const]
54
+ case thing
55
+ when String, Symbol
56
+ require thing
57
+ when Proc
58
+ Object.class_eval(&thing)
59
+ else
60
+ raise "Error: Don't know how to autoload a #{thing.class}: #{thing.inspect}"
61
+ end
62
+ end
63
+
64
+ @@autoreq_searching_for = const
65
+ const_get(const) || const_missing_without_autoreq(const)
66
+ end
67
+
68
+ def autoreqs
69
+ @@autoreqs ||= {}
70
+ end
71
+
16
72
  end
17
73
 
74
+
18
75
  ## Pretty error messages
19
76
  require_wrapper = proc do |mod|
20
77
  #p [:loading, mod]
@@ -23,5 +23,6 @@ autoload :Ratio, 'epitools/ratio'
23
23
  autoload :Sys, 'epitools/sys'
24
24
  autoload :ProgressBar, 'epitools/progressbar'
25
25
 
26
-
26
+ ## Gems
27
+ autoreq :MimeMagic, 'mimemagic'
27
28
 
@@ -483,7 +483,7 @@ module Enumerable
483
483
  def foldl(methodname=nil, &block)
484
484
  result = nil
485
485
 
486
- raise "Error: pass a parameter OR a block, not both!" if methodname and block
486
+ raise "Error: pass a parameter OR a block, not both!" unless !!methodname ^ block_given?
487
487
 
488
488
  if methodname
489
489
 
@@ -842,6 +842,19 @@ class Object
842
842
  end
843
843
  end
844
844
 
845
+ unless IO.respond_to? :copy_stream
846
+
847
+ class IO
848
+
849
+ def self.copy_stream(input, output)
850
+ while chunk = input.read(8192)
851
+ output.write(chunk)
852
+ end
853
+ end
854
+
855
+ end
856
+
857
+ end
845
858
 
846
859
  #
847
860
  # Emit a quick debug message (only if $DEBUG is true)
@@ -856,3 +869,5 @@ def dmsg(msg)
856
869
  end
857
870
  end
858
871
  end
872
+
873
+
@@ -133,7 +133,7 @@ class Browser
133
133
  #end
134
134
 
135
135
  # Determine the cache setting
136
- use_cache = options[:use_cache] || options[:cache] || options[:cached] || @use_cache
136
+ use_cache = (options[:cached] == false) ? false : @use_cache
137
137
 
138
138
  cached_already = cache.include?(url)
139
139
 
@@ -67,6 +67,8 @@ def lesspipe(*args)
67
67
  yield less
68
68
  end
69
69
  end
70
+
71
+ rescue Errno::EPIPE
70
72
  end
71
73
 
72
74
 
@@ -22,6 +22,9 @@ class Path
22
22
  end
23
23
  end
24
24
 
25
+ #
26
+ # TODO: Remove the tempfile when the Path object is garbage collected or freed.
27
+ #
25
28
  def self.tmpfile(prefix="tmp")
26
29
  path = Path[ Tempfile.new(prefix).path ]
27
30
  yield path if block_given?
@@ -111,7 +114,6 @@ class Path
111
114
  end
112
115
  end
113
116
 
114
-
115
117
  ## getters
116
118
 
117
119
  # The directories in the path, split into an array. (eg: ['usr', 'src', 'linux'])
@@ -153,6 +155,11 @@ class Path
153
155
  end
154
156
  end
155
157
 
158
+ def exts
159
+ extensions = basename.split('.')[1..-1]
160
+ extensions += [@ext] if @ext
161
+ extensions
162
+ end
156
163
 
157
164
  ## fstat info
158
165
 
@@ -245,6 +252,8 @@ class Path
245
252
  File.open(path, mode)
246
253
  end
247
254
  end
255
+ alias_method :io, :open
256
+ alias_method :stream, :open
248
257
 
249
258
  def read(length=nil, offset=nil)
250
259
  File.read(path, length, offset)
@@ -373,10 +382,63 @@ class Path
373
382
  def md5
374
383
  Digest::MD5.file(self).hexdigest
375
384
  end
376
-
377
385
  alias_method :md5sum, :md5
378
386
 
379
387
 
388
+ # http://ruby-doc.org/stdlib/libdoc/zlib/rdoc/index.html
389
+
390
+ def gzip
391
+ gz_filename = self.with(:filename=>filename+".gz")
392
+
393
+ raise "#{gz_filename} already exists" if gz_filename.exists?
394
+
395
+ open("rb") do |input|
396
+ Zlib::GzipWriter.open(gz_filename) do |gzip|
397
+ IO.copy_stream(input, gzip)
398
+ end
399
+ end
400
+
401
+ gz_filename
402
+ end
403
+
404
+ def gzip!
405
+ gzipped = self.gzip
406
+ self.rm
407
+ self.path = gzipped.path
408
+ end
409
+
410
+ def gunzip
411
+ raise "Not a .gz file" unless ext == "gz"
412
+
413
+ gunzipped = self.with(:ext=>nil)
414
+
415
+ gunzipped.open("wb") do |out|
416
+ Zlib::GzipReader.open(self) do |gunzip|
417
+ IO.copy_stream(gunzip, out)
418
+ end
419
+ end
420
+
421
+ gunzipped
422
+ end
423
+
424
+ def gunzip!
425
+ gunzipped = self.gunzip
426
+ self.rm
427
+ self.path = gunzipped.path
428
+ end
429
+
430
+ #
431
+ # Return the IO object for this file.
432
+ #
433
+ def io
434
+ open
435
+ end
436
+ alias_method :stream, :io
437
+
438
+ def =~(pattern)
439
+ path =~ pattern
440
+ end
441
+
380
442
  ## Class method versions of FileUtils-like things
381
443
 
382
444
  %w[
@@ -394,9 +456,40 @@ class Path
394
456
  end
395
457
  }
396
458
  end
459
+
460
+
461
+ # Mimetype finding and magic (requires 'mimemagic' gem)
462
+
463
+ #
464
+ # Find the file's mimetype (first from file extension, then by magic)
465
+ #
466
+ def mimetype
467
+ mimetype_from_ext || magic
468
+ end
469
+ alias_method :identify, :mimetype
470
+
471
+ #
472
+ # Find the file's mimetype (only using the file extension)
473
+ #
474
+ def mimetype_from_ext
475
+ MimeMagic.by_extension(ext)
476
+ end
477
+
478
+ #
479
+ # Find the file's mimetype (by magic)
480
+ #
481
+ def magic
482
+ open { |io| MimeMagic.by_magic(io) }
483
+ end
484
+
485
+ def ext_by_magic
486
+ # TODO: return the extension for the mime type.
487
+ raise NotImplementedError
488
+ end
397
489
 
398
490
  end
399
491
 
492
+
400
493
  #
401
494
  # A wrapper for URL objects
402
495
  #
@@ -14,11 +14,12 @@ require 'epitools'
14
14
  # zopen("otherfile.gz", "w") #=> #<Zlib::GzipWriter:0x7fe30448>>
15
15
  # zopen("test.txt.gz") { |f| f.read } # read the contents of the .gz file, then close the file handle automatically.
16
16
  #
17
- def zopen(filename, mode="r")
17
+ def zopen(path, mode="r")
18
18
 
19
- file = open(filename, mode)
19
+ path = Path[path] unless path.is_a? Path
20
+ file = path.open(mode)
20
21
 
21
- if filename =~ /\.gz$/
22
+ if path.ext == "gz"
22
23
  case mode
23
24
  when "r", "rb"
24
25
  file = Zlib::GzipReader.new(file)
@@ -287,6 +287,8 @@ describe Enumerable do
287
287
  a = [1,2,3,4]
288
288
  a.foldl(:+).should == a.sum
289
289
  %w[hi there].foldl(:+).should == "hithere"
290
+
291
+ [ [1],[2],[3],[4] ].foldl(:+).should == [1,2,3,4]
290
292
  end
291
293
 
292
294
  it "powersets" do
@@ -1,5 +1,4 @@
1
- require 'epitools/permutations'
2
- require 'epitools/path'
1
+ require 'epitools'
3
2
 
4
3
  describe Path do
5
4
 
@@ -216,4 +215,38 @@ describe Path do
216
215
  path.sha1.should == Path.sha1(path)
217
216
  end
218
217
 
218
+ it "gzips and gunzips" do
219
+ path = Path.tmpfile
220
+ 500.times { path << "whee" }
221
+
222
+ path.ext.should_not == "gz"
223
+ gzipped = path.gzip
224
+
225
+ before = path.size
226
+ after = gzipped.size
227
+ before.should > after
228
+ gzipped.ext.should == "gz"
229
+
230
+ gunzipped = gzipped.gunzip
231
+ gunzipped.size.should == before
232
+ gunzipped.should == path
233
+ end
234
+
235
+ it "exts" do
236
+ path = Path["file.tar.gz"]
237
+ path.ext.should == "gz"
238
+ path.exts.should == ["tar", "gz"]
239
+ end
240
+
241
+ it "ios and streams" do
242
+ path = Path.tmpfile
243
+ f = open(path)
244
+ f.inspect.should == path.io.inspect
245
+ f.inspect.should == path.stream.inspect
246
+ end
247
+
248
+ it "mimes" do
249
+ Path[__FILE__].mimetype == "application/x-ruby"
250
+ end
251
+
219
252
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: epitools
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.4.37
5
+ version: 0.4.38
6
6
  platform: ruby
7
7
  authors:
8
8
  - epitron
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-29 00:00:00 -04:00
13
+ date: 2011-06-07 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency