epitools 0.5.14 → 0.5.15

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.5.14
1
+ 0.5.15
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "epitools"
8
- s.version = "0.5.14"
8
+ s.version = "0.5.15"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["epitron"]
@@ -19,8 +19,8 @@ module Enumerable
19
19
  #
20
20
  alias_method :includes?, :include?
21
21
 
22
-
23
- #
22
+
23
+ #
24
24
  # Skip the first n elements and return an Enumerator for the rest, or pass them
25
25
  # in succession to the block, if given. This is like "drop", but returns an enumerator
26
26
  # instead of converting the whole thing to an array.
@@ -38,32 +38,32 @@ module Enumerable
38
38
  enum_for :skip, n
39
39
  end
40
40
  end
41
-
41
+
42
42
  #
43
43
  # Split this enumerable into chunks, given some boundary condition. (Returns an array of arrays.)
44
44
  #
45
45
  # Options:
46
- # :include_boundary => true #=> include the element that you're splitting at in the results
46
+ # :include_boundary => true #=> include the element that you're splitting at in the results
47
47
  # (default: false)
48
- # :after => true #=> split after the matched element (only has an effect when used with :include_boundary)
48
+ # :after => true #=> split after the matched element (only has an effect when used with :include_boundary)
49
49
  # (default: false)
50
50
  # :once => flase #=> only perform one split (default: false)
51
51
  #
52
- # Examples:
53
- # [1,2,3,4,5].split{ |e| e == 3 }
52
+ # Examples:
53
+ # [1,2,3,4,5].split{ |e| e == 3 }
54
54
  # #=> [ [1,2], [4,5] ]
55
55
  #
56
- # [1,2,3,4,5].split(:include_boundary=>true) { |e| e == 3 }
57
- # #=> [ [1,2], [3,4,5] ]
56
+ # [1,2,3,4,5].split(:include_boundary=>true) { |e| e == 3 }
57
+ # #=> [ [1,2], [3,4,5] ]
58
58
  #
59
59
  # chapters = File.read("ebook.txt").split(/Chapter \d+/, :include_boundary=>true)
60
60
  # #=> [ ["Chapter 1", ...], ["Chapter 2", ...], etc. ]
61
61
  #
62
62
  def split_at(matcher=nil, options={}, &block)
63
63
  # TODO: Ruby 1.9 returns Enumerators for everything now. Maybe use that?
64
-
64
+
65
65
  return self unless self.any?
66
-
66
+
67
67
  include_boundary = options[:include_boundary] || false
68
68
 
69
69
  if matcher.nil?
@@ -79,18 +79,18 @@ module Enumerable
79
79
 
80
80
  chunks = []
81
81
  current_chunk = []
82
-
82
+
83
83
  splits = 0
84
- max_splits = options[:once] == true ? 1 : options[:max_splits]
84
+ max_splits = options[:once] == true ? 1 : options[:max_splits]
85
85
 
86
86
  each do |e|
87
87
 
88
88
  if boundary_test_proc.call(e) and (max_splits == nil or splits < max_splits)
89
-
90
- if current_chunk.empty? and not include_boundary
89
+
90
+ if current_chunk.empty? and not include_boundary
91
91
  next # hit 2 boundaries in a row... just keep moving, people!
92
92
  end
93
-
93
+
94
94
  if options[:after]
95
95
  # split after boundary
96
96
  current_chunk << e if include_boundary # include the boundary, if necessary
@@ -104,13 +104,13 @@ module Enumerable
104
104
  end
105
105
 
106
106
  splits += 1
107
-
107
+
108
108
  else
109
109
  current_chunk << e
110
110
  end
111
111
 
112
112
  end
113
-
113
+
114
114
  chunks << current_chunk if current_chunk.any?
115
115
 
116
116
  chunks # resultset
@@ -141,15 +141,15 @@ module Enumerable
141
141
 
142
142
  #
143
143
  # Sum the elements
144
- #
144
+ #
145
145
  def sum
146
146
  if block_given?
147
- inject(0) { |total,elem| total + yield(elem) }
147
+ inject(0) { |total,elem| total + yield(elem) }
148
148
  else
149
149
  inject(0) { |total,elem| total + elem }
150
150
  end
151
151
  end
152
-
152
+
153
153
  #
154
154
  # Average the elements
155
155
  #
@@ -164,7 +164,7 @@ module Enumerable
164
164
  # recursively on that element.
165
165
  #
166
166
  # Example:
167
- # [ [1,2], [3,4] ].deep_map{|e| e ** 2 } #=> [ [1,4], [9,16] ]
167
+ # [ [1,2], [3,4] ].deep_map{|e| e ** 2 } #=> [ [1,4], [9,16] ]
168
168
  #
169
169
  def deep_map(depth=nil, &block)
170
170
  map do |obj|
@@ -181,14 +181,14 @@ module Enumerable
181
181
 
182
182
  alias_method :recursive_map, :deep_map
183
183
  alias_method :map_recursively, :deep_map
184
- alias_method :map_recursive, :deep_map
184
+ alias_method :map_recursive, :deep_map
185
185
 
186
186
  #
187
187
  # The same as "select", except that if an element is an Array or Enumerable, select is called
188
188
  # recursively on that element.
189
189
  #
190
190
  # Example:
191
- # [ [1,2], [3,4] ].deep_select{|e| e % 2 == 0 } #=> [ [2], [4] ]
191
+ # [ [1,2], [3,4] ].deep_select{|e| e % 2 == 0 } #=> [ [2], [4] ]
192
192
  #
193
193
  def deep_select(depth=nil, &block)
194
194
  map do |*args|
@@ -211,9 +211,9 @@ module Enumerable
211
211
 
212
212
  end.compact
213
213
  end
214
-
214
+
215
215
  alias_method :recursive_select, :deep_select
216
-
216
+
217
217
 
218
218
  #
219
219
  # Identical to "reduce" in ruby1.9 (or foldl in haskell.)
@@ -225,31 +225,31 @@ module Enumerable
225
225
  result = nil
226
226
 
227
227
  raise "Error: pass a parameter OR a block, not both!" unless !!methodname ^ block_given?
228
-
228
+
229
229
  if methodname
230
-
230
+
231
231
  each_with_index do |e,i|
232
232
  if i == 0
233
- result = e
233
+ result = e
234
234
  next
235
235
  end
236
-
237
- result = result.send(methodname, e)
236
+
237
+ result = result.send(methodname, e)
238
238
  end
239
-
239
+
240
240
  else
241
-
241
+
242
242
  each_with_index do |e,i|
243
243
  if i == 0
244
- result = e
244
+ result = e
245
245
  next
246
246
  end
247
-
248
- result = block.call(result, e)
247
+
248
+ result = block.call(result, e)
249
249
  end
250
-
250
+
251
251
  end
252
-
252
+
253
253
  result
254
254
  end
255
255
 
@@ -269,16 +269,16 @@ module Enumerable
269
269
 
270
270
  #
271
271
  # Does the opposite of #zip -- converts [ [:a, 1], [:b, 2] ] to [ [:a, :b], [1, 2] ]
272
- #
272
+ #
273
273
  def unzip
274
274
  # TODO: make it work for arrays containing uneven-length contents
275
275
  to_a.transpose
276
276
  end
277
-
277
+
278
278
  #
279
279
  # Associative grouping; groups all elements who share something in common with each other.
280
280
  # You supply a block which takes two elements, and have it return true if they are "neighbours"
281
- # (eg: belong in the same group).
281
+ # (eg: belong in the same group).
282
282
  #
283
283
  # Example:
284
284
  # [1,2,5,6].group_neighbours_by { |a,b| b-a <= 1 } #=> [ [1,2], [5,6] ]
@@ -296,13 +296,13 @@ module Enumerable
296
296
  cluster = [b]
297
297
  end
298
298
  end
299
-
299
+
300
300
  result << cluster if cluster.any?
301
-
302
- result
301
+
302
+ result
303
303
  end
304
- alias_method :group_neighbors_by, :group_neighbours_by
305
-
304
+ alias_method :group_neighbors_by, :group_neighbours_by
305
+
306
306
 
307
307
  #
308
308
  # Convert the array into a stable iterator (Iter) object.
@@ -67,6 +67,7 @@ class Path
67
67
  # The file extension, including the . (eg: ".mp3")
68
68
  attr_reader :ext
69
69
 
70
+
70
71
  ## initializers
71
72
 
72
73
  def initialize(newpath, hints={})
@@ -74,13 +75,13 @@ class Path
74
75
  end
75
76
 
76
77
  def initialize_copy(other)
77
- @dirs = other.dirs.dup
78
- @base = other.base.dup
79
- @ext = other.ext.dup
78
+ @dirs = other.dirs && other.dirs.dup
79
+ @base = other.base && other.base.dup
80
+ @ext = other.ext && other.ext.dup
80
81
  end
81
82
 
82
- def self.glob(str)
83
- Dir[str].map { |entry| new(entry) }
83
+ def self.glob(str, hints={})
84
+ Dir[str].map { |entry| new(entry, hints) }
84
85
  end
85
86
 
86
87
  def self.[](path)
@@ -114,26 +115,6 @@ class Path
114
115
  attr_writer :base
115
116
  attr_writer :dirs
116
117
 
117
- #
118
- # Clear out the internal state of this object, so that it can be reinitialized.
119
- #
120
- def reset!
121
- [:@dirs, :@base, :@ext].each { |var| remove_instance_variable var }
122
- self
123
- end
124
-
125
-
126
- #
127
- # Reload this path (update cached values.)
128
- #
129
- def reload!
130
- temp = path
131
- reset!
132
- self.path = temp
133
- self
134
- end
135
-
136
-
137
118
  #
138
119
  # This is the core that initializes the whole class.
139
120
  #
@@ -153,6 +134,13 @@ class Path
153
134
  self.dir, self.filename = File.split(newpath)
154
135
  end
155
136
  end
137
+
138
+ # FIXME: Make this work with globs.
139
+ if hints[:relative]
140
+ update(relative_to(Path.pwd))
141
+ elsif hints[:relative_to]
142
+ update(relative_to(hints[:relative_to]))
143
+ end
156
144
  end
157
145
 
158
146
  def filename=(newfilename)
@@ -192,6 +180,30 @@ class Path
192
180
  end
193
181
  end
194
182
 
183
+ #
184
+ # Clear out the internal state of this object, so that it can be reinitialized.
185
+ #
186
+ def reset!
187
+ [:@dirs, :@base, :@ext].each { |var| remove_instance_variable var }
188
+ self
189
+ end
190
+
191
+ #
192
+ # Reload this path (update cached values.)
193
+ #
194
+ def reload!
195
+ temp = path
196
+ reset!
197
+ self.path = temp
198
+ self
199
+ end
200
+
201
+ def update(other)
202
+ @dirs = other.dirs
203
+ @base = other.base
204
+ @ext = other.ext
205
+ end
206
+
195
207
  ## getters
196
208
 
197
209
  # Joins and returns the full path
@@ -203,6 +215,15 @@ class Path
203
215
  end
204
216
  end
205
217
 
218
+ #
219
+ # Is this a relative path?
220
+ #
221
+ def relative?
222
+ # FIXME: Need a Path::Relative subclass, so that "dir/filename" can be valid.
223
+ # (If the user changes dirs, the relative path should change too.)
224
+ dirs.first == ".."
225
+ end
226
+
206
227
  #
207
228
  # Path relative to current directory (Path.pwd)
208
229
  #
@@ -210,44 +231,29 @@ class Path
210
231
  relative_to(pwd)
211
232
  end
212
233
 
213
- def relative_to(to)
214
- from = path.split(File::SEPARATOR)
215
- to = Path[to].path.split(File::SEPARATOR)
216
- p [from, to]
217
- from.length.times do
218
- break if from[0] != to[0]
219
- from.shift; to.shift
220
- end
221
- fname = from.pop
222
- join(*(from.map { RELATIVE_PARENTDIR } + to))
223
- end
224
-
225
- def relative_to2(anchor=nil)
226
- anchor ||= Path.pwd
227
-
228
- # operations to transform anchor into self
229
-
234
+ def relative_to(anchor)
230
235
  # stage 1: go ".." until we find a common dir prefix
231
236
  # (discard everything and go '/' if there's no common dir)
232
237
  # stage 2: append the rest of the other path
233
238
 
234
- # find common prefix
235
- smaller, bigger = [ anchor.dirs, self.dirs ].sort_by(&:size)
236
- common_prefix_end = bigger.zip(smaller).index { |a,b | a != b }
237
- common_prefix = bigger[0...common_prefix_end]
239
+ first_mismatch = dirs.zip(anchor.dirs).index { |a,b| a != b }
238
240
 
239
- if common_prefix.any?
240
- dots = nil
241
- end
241
+ num_dots = anchor.dirs.size - first_mismatch
242
242
 
243
- self.dirs & anchor.dirs
243
+ result = self.dup
244
+ result.dirs = ([".."] * num_dots) + dirs[first_mismatch..-1]
244
245
 
246
+ result
245
247
  end
246
248
 
247
249
  # The current directory (with a trailing /)
248
250
  def dir
249
251
  if dirs
250
- File::SEPARATOR + File.join(*dirs)
252
+ if relative?
253
+ File.join(*dirs)
254
+ else
255
+ File::SEPARATOR + File.join(*dirs)
256
+ end
251
257
  else
252
258
  nil
253
259
  end
@@ -356,8 +362,7 @@ class Path
356
362
  end
357
363
 
358
364
  def parent_of?(child)
359
- # If `self` is a parent of `child`, it's a prefix.
360
- child.path[/^#{Regexp.escape self.path}\/.+/] != nil
365
+ dirs == child.dirs[0...dirs.size]
361
366
  end
362
367
 
363
368
  ## comparisons
@@ -384,6 +389,7 @@ class Path
384
389
 
385
390
  #
386
391
  # Path["/etc"].join("anything{}").path == "/etc/anything{}"
392
+ # (globs ignored)
387
393
  #
388
394
  def join(other)
389
395
  Path.new File.join(self, other)
@@ -391,6 +397,7 @@ class Path
391
397
 
392
398
  #
393
399
  # Path["/etc"]/"passwd" == Path["/etc/passwd"]
400
+ # (globs permitted)
394
401
  #
395
402
  def /(other)
396
403
  # / <- fixes jedit syntax highlighting bug.
@@ -578,41 +585,28 @@ class Path
578
585
  # Path["Songy Song.aac"].rename(:dir=>"/music2")
579
586
  # Path["/music2/Songy Song.aac"].exists? #=> true
580
587
  #
581
- def rename!(options)
582
- raise "Broken!"
583
-
584
- dest = rename(options)
585
- self.path = dest.path # become dest
586
- self
587
- end
588
-
589
588
  def rename(options)
590
- raise "Broken!"
591
-
592
589
  raise "Options must be a Hash" unless options.is_a? Hash
593
590
  dest = self.with(options)
594
591
 
595
592
  raise "Error: destination (#{dest.inspect}) already exists" if dest.exists?
596
593
  File.rename(path, dest)
597
594
 
598
- dest
595
+ update(dest)
596
+
597
+ self
599
598
  end
600
599
 
601
600
  #
602
601
  # Renames the file the specified full path (like Dir.rename.)
603
602
  #
604
603
  def rename_to(path)
605
- raise "Broken!"
606
-
607
604
  rename :path=>path.to_s
608
605
  end
609
- alias_method :mv, :rename_to
610
606
 
611
607
  def rename_to!(path)
612
- raise "Broken!"
613
608
  rename! :path=>path.to_s
614
609
  end
615
- alias_method :mv!, :rename_to!
616
610
 
617
611
  #
618
612
  # Generate two almost identical methods: mkdir and mkdir_p
@@ -646,17 +640,9 @@ raise "Broken!"
646
640
  FileUtils.mv(path, dest)
647
641
  end
648
642
 
649
- def join(other)
650
- if uri?
651
- Path[URI.join(path, other).to_s]
652
- else
653
- Path[File.join(path, other)]
654
- end
655
- end
656
-
657
643
  def ln_s(dest)
658
644
  dest = Path[dest]
659
- FileUtils.ln_s self, dest
645
+ FileUtils.ln_s(self, dest)
660
646
  end
661
647
 
662
648
  ## Owners and permissions
@@ -1017,6 +1003,10 @@ raise "Broken!"
1017
1003
  end
1018
1004
 
1019
1005
 
1006
+ class Path::Relative < Path
1007
+ # FIXME: Implement this.
1008
+ end
1009
+
1020
1010
  #
1021
1011
  # A wrapper for URL objects.
1022
1012
  #
@@ -1042,32 +1032,24 @@ class Path::URL < Path
1042
1032
  #
1043
1033
  # When this is: http://host.com:port/path/filename.ext?param1=value1&param2=value2&...
1044
1034
  #
1045
- def to_s
1046
- uri.to_s
1047
- end
1035
+ def to_s; uri.to_s; end
1048
1036
 
1049
1037
 
1050
1038
  #
1051
1039
  # ...this is: 'http'
1052
1040
  #
1053
- def scheme
1054
- uri.scheme
1055
- end
1041
+ def scheme; uri.scheme; end
1056
1042
  alias_method :protocol, :scheme
1057
1043
 
1058
1044
  #
1059
1045
  # ...and this is: 'host.com'
1060
1046
  #
1061
- def host
1062
- uri.host
1063
- end
1047
+ def host; uri.host; end
1064
1048
 
1065
1049
  #
1066
1050
  # ...and this is: 80
1067
1051
  #
1068
- def port
1069
- uri.port
1070
- end
1052
+ def port; uri.port; end
1071
1053
 
1072
1054
  #
1073
1055
  # ...and this is: {param1: value1, param2: value2, ...etc... }
@@ -1080,6 +1062,11 @@ class Path::URL < Path
1080
1062
  end
1081
1063
  end
1082
1064
 
1065
+ def join(other)
1066
+ Path.new URI.join(path, other).to_s
1067
+ end
1068
+
1069
+
1083
1070
  # ...and `path` is /path/filename.ext
1084
1071
 
1085
1072
  def open(mode="r", &block)
@@ -1,4 +1,5 @@
1
1
  require 'epitools'
2
+ require 'epitools/permutations'
2
3
 
3
4
  describe Path do
4
5
 
@@ -31,7 +32,11 @@ describe Path do
31
32
  end
32
33
 
33
34
  it "'relative_to's" do
34
- Path["/etc"].relative_to(Path["/tmp"]).should == "../tmp"
35
+ Path["/etc"].relative_to(Path["/tmp"]).should == "../etc/"
36
+ end
37
+
38
+ it "should glob with relative paths" do
39
+ raise "not implemented"
35
40
  end
36
41
 
37
42
  it "handles directories" do
@@ -204,14 +209,19 @@ describe Path do
204
209
  end
205
210
 
206
211
  it "renames" do
207
- path = Path.tmpfile
212
+ path = Path.tmp
208
213
 
209
- str = path.to_s
214
+ path.rm
215
+ path.touch
216
+
217
+ path.exists?.should == true
218
+
219
+ old_name = path.to_s
210
220
 
211
221
  path.rename(:ext=>".dat")
212
222
 
213
- path.to_s.should_not == str
214
- path.to_s.should == str+".dat"
223
+ path.to_s.should == old_name+".dat"
224
+ path.to_s.should_not == old_name
215
225
  end
216
226
 
217
227
  it "rms" do
@@ -236,7 +246,7 @@ describe Path do
236
246
  end
237
247
 
238
248
  it "checksums" do
239
- a, b = Path["*.rb"].take(2)
249
+ a, b = Path["**/*.rb"].take(2)
240
250
  [:sha1, :sha2, :md5].each do |meth|
241
251
  sum1 = a.send(meth)
242
252
  sum2 = b.send(meth)
@@ -333,7 +343,8 @@ describe Path do
333
343
  tmp.touch
334
344
  tmp2.touch
335
345
 
336
- newmode = tmp.mode
346
+ tmp.mode.should == tmp2.mode
347
+
337
348
  tmp.chmod("+x")
338
349
  system("chmod", "+x", tmp2)
339
350
  tmp.mode.should == tmp2.mode
@@ -350,14 +361,13 @@ describe Path do
350
361
  tmp = Path.tmpfile
351
362
  tmp.rm if tmp.exists?
352
363
  tmp.mkdir
353
- p tmp
354
- p tmp.dirs
364
+
355
365
  #tmp.to_s.endswith('/').should == true
356
366
  file = tmp/"file"
357
367
  file.touch
358
- p file
368
+
359
369
  file.dirs.should == tmp.dirs
360
- file.filename.should != tmp.filename
370
+ file.filename.should_not == tmp.filename
361
371
  end
362
372
 
363
373
  it 'parents and childs properly' do
@@ -372,12 +382,12 @@ describe Path do
372
382
  root => parent,
373
383
  root => child,
374
384
  root => neither,
375
- }.each do |p, c|
376
- p.parent_of?(c).should == true
377
- c.parent_of?(p).should == false
385
+ }.each do |parent, child|
386
+ parent.should be_parent_of child
387
+ child.should_not be_parent_of parent
378
388
 
379
- c.child_of?(p).should == true
380
- p.child_of?(c).should == false
389
+ child.should be_child_of parent
390
+ parent.should_not be_child_of child
381
391
  end
382
392
 
383
393
  neither.parent_of?(child).should == false
@@ -388,7 +398,7 @@ describe Path do
388
398
  path = Path.tmpfile
389
399
  path.exe?.should == false
390
400
  path.chmod(0o666)
391
- p path.mode
401
+
392
402
  (path.mode & 0o666).should > 0
393
403
  end
394
404
 
@@ -407,8 +417,9 @@ describe Path do
407
417
  end
408
418
 
409
419
  it 'swaps two files' do
410
- raise "errorn!"
411
420
  # swap two regular files
421
+
422
+
412
423
  # swap a symlink and a regular file
413
424
  # swap two symlinks
414
425
  end
@@ -426,7 +437,7 @@ describe Path do
426
437
 
427
438
  it "shouldn't glob with Path#join" do
428
439
  path = Path["/etc"].join("blah{}")
429
- path.should == "/etc/blah{}"
440
+ path.path.should == "/etc/blah{}"
430
441
  end
431
442
 
432
443
  it "should glob with Path#/" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epitools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.14
4
+ version: 0.5.15
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: