epitools 0.5.14 → 0.5.15

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