epitools 0.5.37 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 74b5a665bc66555050576a5aa863b79017d10e90
4
- data.tar.gz: a860badfc15c9f1f44f7d8db7aa4f47d2ef32bd4
3
+ metadata.gz: 22d5dfb7f91836122b2c98f3699a61a95e564f93
4
+ data.tar.gz: e948af15b3b59d8c1d6fdb8d6077fb83abdcddf0
5
5
  SHA512:
6
- metadata.gz: 1d19c2fd984f89485d8a00f7c2f8c5fb0cdeff916b1bf7fa8ea4a5922c447258a56ea21b610ae20e6c5e0b27d5e4679a4d9617b7263d9dbe1b36eaefff4a8f8e
7
- data.tar.gz: db684ad10202d61c32167346cf6e3032316041308a0914bd3be5ac5b3ef535a687362966be703778f573686180c526ea3d4525957b9042669bb1cbd9d497e888
6
+ metadata.gz: a457026eed7f6db059cdf1638a63515034fec427e3fb61b5eed17f18bd163863175297eab9400bd0a91b030e0893da94173d94dad738df58b5be6eea1c5cb092
7
+ data.tar.gz: e5fe8275dfc204ca5772b33fd3ceae35735a398a073f7201f022a6fcff8c014190a25dd3d0bc39cd54dc1e52c2bc0761cc056a1fe80e00bd11e82d71449d78d3
data/README.rdoc CHANGED
@@ -8,7 +8,7 @@ All epitools modules (and a bunch of Ruby's stdlib) are
8
8
  {loaded on demand with "autoload"}[https://github.com/epitron/epitools/blob/master/lib/epitools/autoloads.rb],
9
9
  so it's really fast. (Require this in your .irbrc or .pryrc, and you'll never have to require another Ruby stdlib module again!)
10
10
 
11
- Enhanced base classes: {Enumerable}[http://rdoc.info/github/epitron/epitools/master/Enumerable], {Hash}[http://rdoc.info/github/epitron/epitools/master/Hash], {String}[http://rdoc.info/github/epitron/epitools/master/String], {Array}[http://rdoc.info/github/epitron/epitools/master/Array], {Object}[http://rdoc.info/github/epitron/epitools/master/Object], {Integer}[http://rdoc.info/github/epitron/epitools/master/Integer], etc.
11
+ Enhanced base classes: {Enumerable}[http://rdoc.info/github/epitron/epitools/master/Enumerable], {Hash}[http://rdoc.info/github/epitron/epitools/master/Hash], {String}[http://rdoc.info/github/epitron/epitools/master/String], {Array}[http://rdoc.info/github/epitron/epitools/master/Array], {File}[http://rdoc.info/github/epitron/epitools/master/File], {Object}[http://rdoc.info/github/epitron/epitools/master/Object], {Integer}[http://rdoc.info/github/epitron/epitools/master/Integer], etc.
12
12
 
13
13
  Extras:
14
14
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.37
1
+ 0.5.38
@@ -8,7 +8,7 @@ class BOFError < Exception; end
8
8
  class File
9
9
 
10
10
  #
11
- # A much faster `reverse_each` implementation.
11
+ # A streaming `reverse_each` implementation. (For large files, it's faster and uses less memory.)
12
12
  #
13
13
  def reverse_each(&block)
14
14
  return to_enum(:reverse_each) unless block_given?
@@ -18,20 +18,33 @@ class File
18
18
  end
19
19
 
20
20
  #
21
- # Read the previous +length+ bytes. After the read, +pos+ will be at the beginning of the region that you just read.
21
+ # Read the previous `length` bytes. After the read, `pos` will be at the beginning of the region that you just read.
22
+ # Returns `nil` when the beginning of the file is reached.
22
23
  #
23
- def read_backwards(length)
24
- old_pos = pos
24
+ # If the `block_aligned` argument is `true`, reads will always be aligned to file positions which are multiples of 512 bytes.
25
+ # (This should increase performance slightly.)
26
+ #
27
+ def reverse_read(length, block_aligned=false)
28
+ raise "length must be a multiple of 512" if block_aligned and length % 512 != 0
29
+
30
+ end_pos = pos
31
+
32
+ if block_aligned
33
+ misalignment = end_pos % length
34
+ length += misalignment
35
+ end
25
36
 
26
- if length > pos
37
+ return nil if end_pos == 0
38
+
39
+ if length >= end_pos # this read will take us to the beginning of the file
27
40
  seek(0)
28
41
  else
29
42
  seek(-length, IO::SEEK_CUR)
30
43
  end
31
44
 
32
- new_pos = pos
33
- data = read(old_pos - new_pos)
34
- seek(new_pos)
45
+ start_pos = pos
46
+ data = read(end_pos - start_pos)
47
+ seek(start_pos)
35
48
 
36
49
  data
37
50
  end
@@ -42,22 +55,17 @@ class File
42
55
  def reverse_each_from_current_pos
43
56
  return to_enum(:reverse_each_from_current_pos) unless block_given?
44
57
 
58
+ # read the rest of the current line, in case we started in the middle of a line
59
+ start_pos = pos
45
60
  fragment = readline rescue ""
61
+ seek(start_pos)
46
62
 
47
- loop do
48
- data = read_backwards(4096) + fragment
49
- loc = data.size-1
50
-
51
- # NOTE: `rindex(str, loc)` includes the character at `loc`
52
- while index = data.rindex("\n", loc-1)
53
- line = data[index+1..loc]
54
- yield line
55
- loc = index
56
- end
63
+ while data = reverse_read(4096)
64
+ data += fragment
65
+ lines = data.lines
66
+ fragment = lines.shift
57
67
 
58
- fragment = data[0..loc]
59
-
60
- break if pos == 0 # we're done reading!
68
+ lines.reverse_each { |line| yield line }
61
69
  end
62
70
 
63
71
  yield fragment
@@ -70,6 +78,13 @@ class File
70
78
  seek(0, IO::SEEK_END)
71
79
  end
72
80
 
81
+ #
82
+ # Seek to `BOF`
83
+ #
84
+ def seek_start
85
+ seek(0)
86
+ end
87
+
73
88
  #
74
89
  # Read the previous line (leaving `pos` at the beginning of the string that was read.)
75
90
  #
@@ -88,7 +103,7 @@ class File
88
103
  #
89
104
  def seek_backwards_to(string, blocksize=512, rindex_end=-1)
90
105
  loop do
91
- data = read_backwards(blocksize)
106
+ data = reverse_read(blocksize)
92
107
 
93
108
  if index = data.rindex(string, rindex_end)
94
109
  seek(index+string.size, IO::SEEK_CUR)
@@ -101,21 +101,32 @@ class String
101
101
  def wrap(width=nil, ignore=nil)
102
102
  if width.nil?
103
103
  require 'io/console'
104
- height, width = STDIN.winsize
104
+ _, width = STDIN.winsize
105
+ width -= 1
105
106
  end
106
107
 
107
- wrap_re = /(?:.{1,#{width}}[ \t]+|.{1,#{width}})/
108
+ return self if size <= width
108
109
 
109
- # TODO: 'ignore' ignores characters matching some regexp
110
- #
111
- # if ignore
112
- # stripped = gsub(ignore, '') # remove whatever we're ignoring
113
- # lines = stripped.scan(wrap_re) # wrap the lines
114
- # lines.each do |line|
115
- # line.
116
- # end
117
-
118
- scan(wrap_re).map(&:rstrip).join("\n")
110
+ strings = []
111
+ start_pos = 0
112
+ end_pos = width
113
+
114
+ loop do
115
+ split_pos = rindex(/\s/, end_pos) || end_pos
116
+
117
+ strings << self[start_pos...split_pos]
118
+
119
+ start_pos = index(/\S/, split_pos)
120
+ break if start_pos == nil
121
+ end_pos = start_pos + width
122
+
123
+ if end_pos > size
124
+ strings << self[start_pos..-1]
125
+ break
126
+ end
127
+ end
128
+
129
+ strings.join("\n")
119
130
  end
120
131
 
121
132
  #
@@ -216,8 +216,10 @@ describe String do
216
216
  it "wraps" do
217
217
  s1 = "Hello there, I am a sentence or series of words."
218
218
  s2 = "012345678901234567890123456789012345678901234567"
219
+ s3 = "hello there"
219
220
  s1.wrap(14).should == "Hello there, I\nam a sentence\nor series of\nwords."
220
221
  s2.wrap(14).should == "01234567890123\n45678901234567\n89012345678901\n234567"
222
+ s3.wrap(80).should == "hello there"
221
223
  end
222
224
 
223
225
  it "indents" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epitools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.37
4
+ version: 0.5.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - epitron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-23 00:00:00.000000000 Z
11
+ date: 2013-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec