patman 0.0.1
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 +7 -0
- data/CHANGELOG.rdoc +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +14 -0
- data/doc/Patman/PatmanError.html +138 -0
- data/doc/Patman/PatmanFileError.html +142 -0
- data/doc/Patman/PatmanSearchError.html +142 -0
- data/doc/Patman.html +3313 -0
- data/doc/_index.html +134 -0
- data/doc/class_list.html +58 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +339 -0
- data/doc/file.CHANGELOG.html +79 -0
- data/doc/file.README.html +87 -0
- data/doc/file_list.html +63 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +87 -0
- data/doc/js/app.js +219 -0
- data/doc/js/full_list.js +181 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +309 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/patman.rb +525 -0
- data/lib/version.rb +6 -0
- data/test/input/test_file1.txt +10 -0
- data/test/test_patman.rb +175 -0
- metadata +72 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.8.7.6
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
hasFrames = window.top.frames.main ? true : false;
|
19
|
+
relpath = '';
|
20
|
+
framesUrl = "frames.html#!top-level-namespace.html";
|
21
|
+
</script>
|
22
|
+
|
23
|
+
|
24
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
25
|
+
|
26
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
27
|
+
|
28
|
+
|
29
|
+
</head>
|
30
|
+
<body>
|
31
|
+
<div id="header">
|
32
|
+
<div id="menu">
|
33
|
+
|
34
|
+
<a href="_index.html">Index</a> »
|
35
|
+
|
36
|
+
|
37
|
+
<span class="title">Top Level Namespace</span>
|
38
|
+
|
39
|
+
|
40
|
+
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<div id="search">
|
44
|
+
|
45
|
+
<a class="full_list_link" id="class_list_link"
|
46
|
+
href="class_list.html">
|
47
|
+
Class List
|
48
|
+
</a>
|
49
|
+
|
50
|
+
<a class="full_list_link" id="method_list_link"
|
51
|
+
href="method_list.html">
|
52
|
+
Method List
|
53
|
+
</a>
|
54
|
+
|
55
|
+
<a class="full_list_link" id="file_list_link"
|
56
|
+
href="file_list.html">
|
57
|
+
File List
|
58
|
+
</a>
|
59
|
+
|
60
|
+
</div>
|
61
|
+
<div class="clear"></div>
|
62
|
+
</div>
|
63
|
+
|
64
|
+
<iframe id="search_frame"></iframe>
|
65
|
+
|
66
|
+
<div id="content"><h1>Top Level Namespace
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
</h1>
|
71
|
+
|
72
|
+
<dl class="box">
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
</dl>
|
82
|
+
<div class="clear"></div>
|
83
|
+
|
84
|
+
<h2>Defined Under Namespace</h2>
|
85
|
+
<p class="children">
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
<strong class="classes">Classes:</strong> <span class='object_link'><a href="Patman.html" title="Patman (class)">Patman</a></span>
|
91
|
+
|
92
|
+
|
93
|
+
</p>
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
</div>
|
104
|
+
|
105
|
+
<div id="footer">
|
106
|
+
Generated on Sat Dec 16 23:10:27 2017 by
|
107
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
108
|
+
0.8.7.6 (ruby-2.3.3).
|
109
|
+
</div>
|
110
|
+
|
111
|
+
</body>
|
112
|
+
</html>
|
data/lib/patman.rb
ADDED
@@ -0,0 +1,525 @@
|
|
1
|
+
# = Patman
|
2
|
+
#
|
3
|
+
# == Introduction
|
4
|
+
#
|
5
|
+
# {Patman} (Patch Manipulator) is a library for text file patching. It
|
6
|
+
# can also be used to extract information from files.
|
7
|
+
#
|
8
|
+
# Typical {Patman} script opens a file for editing. The file is read
|
9
|
+
# into the library. User finds the place for editing either with
|
10
|
+
# Regexp searches or with direct line numbers. The file content is
|
11
|
+
# edited by adding, removing, or replacing lines. When all edits are
|
12
|
+
# done, the updated file content is written to disk.
|
13
|
+
#
|
14
|
+
# All editing commands refer to the "current position". Current
|
15
|
+
# position is returned by "line" method. Positions refer to lines that
|
16
|
+
# have content. If user wants append to the end of file, then user
|
17
|
+
# should jump to last line, with "lastline" method, and then issue
|
18
|
+
# "append". It is also possible to jump to arbitrary lines, {Patman}
|
19
|
+
# does not prevent this. The line positions are just used as an index
|
20
|
+
# to Array. For example negative line number will refer from end
|
21
|
+
# towards beginning in content.
|
22
|
+
#
|
23
|
+
# Position can be explicitly changed with "step", "firstline", or
|
24
|
+
# "lastline" methods (commands). "find" changes position if the
|
25
|
+
# pattern is found in selected direction. "append" changes position
|
26
|
+
# implicitly with every call.
|
27
|
+
#
|
28
|
+
# Current line content is returned by "get" and it can be set with
|
29
|
+
# "set" method. Current line content can be replaced with "sub".
|
30
|
+
#
|
31
|
+
# {Patman} includes many query commands: line, lines, [], get, find,
|
32
|
+
# get_range, get_for. They all return the queried item. All other
|
33
|
+
# methods return {Patman} object itself, hence many {Patman} methods
|
34
|
+
# can be "chained".
|
35
|
+
#
|
36
|
+
# Block commands perform commands over a range of lines. Block
|
37
|
+
# commands are: do_all, do_range, and do_for. These retain the
|
38
|
+
# original position, but the final position is stored (actually one
|
39
|
+
# after) and it can be activated by calling "blockline" method.
|
40
|
+
#
|
41
|
+
# Block commands take a pre-defined number of lines to process. Note
|
42
|
+
# that, if user deletes lines in block action, the outcome is most
|
43
|
+
# likely not what the user expects.
|
44
|
+
#
|
45
|
+
# Mark feature can be used if user wants to return back to original
|
46
|
+
# position after changes. Mark features includes a "default mark" and
|
47
|
+
# "named marks".
|
48
|
+
#
|
49
|
+
# For debugging purposes it is good to see line content. "view" and
|
50
|
+
# "view_ln" can be used to view line content either without or with
|
51
|
+
# line numbers respectively.
|
52
|
+
#
|
53
|
+
# No changes are stored to disk unless "write" is called. If user want
|
54
|
+
# to create a "backup" of the edited file, the "copy" method can be
|
55
|
+
# used before any editing commands have been applied.
|
56
|
+
#
|
57
|
+
# == Example session
|
58
|
+
#
|
59
|
+
# # Open file for reading.
|
60
|
+
# r = Patman.read( "report.txt" )
|
61
|
+
#
|
62
|
+
# # Backup file and find next line with "cpp", method chaining.
|
63
|
+
# r.copy( "report.txt.org" ).find( /cpp/ )
|
64
|
+
#
|
65
|
+
# # Collect some lines.
|
66
|
+
# data = 4.times.collect do |i|
|
67
|
+
# r.ref( r.line + i )
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# # Duplicate the lines collected.
|
71
|
+
# r.insert( data )
|
72
|
+
#
|
73
|
+
# # Move to line 9.
|
74
|
+
# r.line 9
|
75
|
+
#
|
76
|
+
# # Append " Hello" to the end of current line.
|
77
|
+
# r.set( r.get + " Hello" )
|
78
|
+
#
|
79
|
+
# # Save changes.
|
80
|
+
# r.write
|
81
|
+
#
|
82
|
+
|
83
|
+
class Patman
|
84
|
+
|
85
|
+
# {Patman} exception base class.
|
86
|
+
class PatmanError < RuntimeError; end
|
87
|
+
|
88
|
+
# {Patman} searching error (for find functions).
|
89
|
+
class PatmanSearchError < PatmanError; end
|
90
|
+
|
91
|
+
# {Patman} file error.
|
92
|
+
class PatmanFileError < PatmanError; end
|
93
|
+
|
94
|
+
|
95
|
+
attr_accessor :marks
|
96
|
+
|
97
|
+
|
98
|
+
# Create editing session with file.
|
99
|
+
def Patman.read( file )
|
100
|
+
p = Patman.new( file )
|
101
|
+
p.read
|
102
|
+
p
|
103
|
+
end
|
104
|
+
|
105
|
+
# Create {Patman} object.
|
106
|
+
def initialize( file )
|
107
|
+
@file = file
|
108
|
+
@lines = []
|
109
|
+
@line = 0
|
110
|
+
@mark = nil
|
111
|
+
@marks = {}
|
112
|
+
@blockline = nil
|
113
|
+
@edited = false
|
114
|
+
end
|
115
|
+
|
116
|
+
# Read file in.
|
117
|
+
def read
|
118
|
+
if File.exist?( @file )
|
119
|
+
@lines = read_clean( @file )
|
120
|
+
else
|
121
|
+
raise PatmanFileError
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Write {Patman} content to disk.
|
126
|
+
def write( file = @file )
|
127
|
+
return unless @edited
|
128
|
+
fh = File.open( file, 'w' )
|
129
|
+
@lines.each do |line|
|
130
|
+
if line
|
131
|
+
fh.puts line
|
132
|
+
else
|
133
|
+
fh.puts ""
|
134
|
+
end
|
135
|
+
end
|
136
|
+
fh.close
|
137
|
+
@edited = false
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
# Copy {Patman} content to file.
|
142
|
+
def copy( file )
|
143
|
+
write( file )
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
# Return or set line.
|
148
|
+
def line( arg = nil )
|
149
|
+
if arg
|
150
|
+
@line = (arg-1)
|
151
|
+
self
|
152
|
+
else
|
153
|
+
@line+1
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Step forward or backward current position.
|
158
|
+
def step( dir = 1 )
|
159
|
+
@line = @line + dir
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
# Jump to first line.
|
164
|
+
def firstline
|
165
|
+
@line = 0
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# Jump to last line.
|
170
|
+
def lastline
|
171
|
+
@line = @lines.length-1
|
172
|
+
self
|
173
|
+
end
|
174
|
+
|
175
|
+
# Jump to line after block.
|
176
|
+
def blockline
|
177
|
+
if @blockline
|
178
|
+
@line = @blockline
|
179
|
+
end
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
# Get or set all {Patman} content.
|
184
|
+
def lines( arg = nil )
|
185
|
+
if arg
|
186
|
+
@edited = true
|
187
|
+
@lines = arg
|
188
|
+
else
|
189
|
+
@lines
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Reference {Patman} content by range.
|
194
|
+
def []( range )
|
195
|
+
@lines[ range ]
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get current line or lines by count.
|
199
|
+
def get( count = 1 )
|
200
|
+
if count == 1
|
201
|
+
@lines[ @line ]
|
202
|
+
else
|
203
|
+
@lines[ @line .. (@line+count-1) ]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Get current line or any line.
|
208
|
+
def ref( line = nil )
|
209
|
+
if line
|
210
|
+
@lines[ line-1 ]
|
211
|
+
else
|
212
|
+
@lines[ @line ]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Set current line.
|
217
|
+
def set( text )
|
218
|
+
@edited = true
|
219
|
+
@lines[ @line ] = text
|
220
|
+
self
|
221
|
+
end
|
222
|
+
|
223
|
+
# Substitution in current line.
|
224
|
+
def sub( from, to )
|
225
|
+
@edited = true
|
226
|
+
@lines[ @line ] = @lines[ @line ].sub( from, to )
|
227
|
+
self
|
228
|
+
end
|
229
|
+
|
230
|
+
# Update current line content (i.e. get&set) with the return value
|
231
|
+
# of the given block. Hence last stmt should include the new line
|
232
|
+
# content.
|
233
|
+
#
|
234
|
+
# @example
|
235
|
+
# r.update do |c|
|
236
|
+
# c.sub!( /foo/, 'bar' )
|
237
|
+
# c
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
def update( &blk )
|
241
|
+
@edited = true
|
242
|
+
set( yield( get ) )
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
# Insert line or lines (Array) to current position.
|
247
|
+
def insert( text = nil )
|
248
|
+
@edited = true
|
249
|
+
if text.kind_of? Array
|
250
|
+
line = @line
|
251
|
+
step -1
|
252
|
+
text.each do |txt|
|
253
|
+
append( txt )
|
254
|
+
end
|
255
|
+
@line = line
|
256
|
+
else
|
257
|
+
@lines.insert( @line, text )
|
258
|
+
end
|
259
|
+
self
|
260
|
+
end
|
261
|
+
|
262
|
+
# Append after current position.
|
263
|
+
def append( text = nil )
|
264
|
+
@edited = true
|
265
|
+
if text.kind_of? Array
|
266
|
+
text.each do |txt|
|
267
|
+
append( txt )
|
268
|
+
end
|
269
|
+
else
|
270
|
+
step
|
271
|
+
@lines.insert( @line, text )
|
272
|
+
end
|
273
|
+
self
|
274
|
+
end
|
275
|
+
|
276
|
+
# Delete current line.
|
277
|
+
def delete( count = 1 )
|
278
|
+
@edited = true
|
279
|
+
count.times do |i|
|
280
|
+
@lines.delete_at( @line )
|
281
|
+
end
|
282
|
+
self
|
283
|
+
end
|
284
|
+
|
285
|
+
# Insert file to current position.
|
286
|
+
def insertfile( file )
|
287
|
+
@edited = true
|
288
|
+
step -1
|
289
|
+
read_clean( file ).each do |line|
|
290
|
+
append line
|
291
|
+
end
|
292
|
+
self
|
293
|
+
end
|
294
|
+
|
295
|
+
# Clear {Patman} content and reset current line.
|
296
|
+
def clear
|
297
|
+
@edited = true
|
298
|
+
@lines = []
|
299
|
+
@line = 0
|
300
|
+
self
|
301
|
+
end
|
302
|
+
|
303
|
+
# Find Regexp or literal string forwards or backwards. Return true
|
304
|
+
# on success.
|
305
|
+
def find( re_or_str, forward = true )
|
306
|
+
begin
|
307
|
+
@line = search_with_exception( re_or_str, forward )
|
308
|
+
true
|
309
|
+
rescue
|
310
|
+
false
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
# Search Regexp or literal string forwards or backwards. Fail with
|
315
|
+
# expection (PatmanSearchError) if not found.
|
316
|
+
def search( re_or_str, forward = true )
|
317
|
+
@line = search_with_exception( re_or_str, forward )
|
318
|
+
self
|
319
|
+
end
|
320
|
+
|
321
|
+
# Return line count of {Patman} content.
|
322
|
+
def length
|
323
|
+
@lines.length
|
324
|
+
end
|
325
|
+
|
326
|
+
# Return {Patman} file name.
|
327
|
+
def filename
|
328
|
+
@file
|
329
|
+
end
|
330
|
+
|
331
|
+
# Mark content modified (explicit).
|
332
|
+
def edit
|
333
|
+
@edited = true
|
334
|
+
end
|
335
|
+
|
336
|
+
# Return true if content is modified.
|
337
|
+
def edited?
|
338
|
+
@edited
|
339
|
+
end
|
340
|
+
|
341
|
+
# Execute block, retain current position, and return block value.
|
342
|
+
def excursion( &blk )
|
343
|
+
line = @line
|
344
|
+
ret = instance_eval( &blk )
|
345
|
+
@line = line
|
346
|
+
ret
|
347
|
+
end
|
348
|
+
|
349
|
+
# Mark (store) current position to default or to named mark.
|
350
|
+
def mark( tag = nil )
|
351
|
+
if tag
|
352
|
+
@marks[ tag ] = @line+1
|
353
|
+
self
|
354
|
+
else
|
355
|
+
@mark = @line+1
|
356
|
+
self
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
# Unmark (restore) current position from default or from named
|
361
|
+
# mark.
|
362
|
+
def unmark( tag = nil )
|
363
|
+
if tag && @marks[ tag ]
|
364
|
+
@line = @marks[ tag ]-1
|
365
|
+
self
|
366
|
+
elsif @mark
|
367
|
+
@line = @mark-1
|
368
|
+
@mark = nil
|
369
|
+
self
|
370
|
+
else
|
371
|
+
self
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
# Execute given block for all lines, i.e. all positions. Block
|
376
|
+
# parameter is {Patman}.
|
377
|
+
def do_all( &blk )
|
378
|
+
do_for( 1, length-1, &blk )
|
379
|
+
end
|
380
|
+
|
381
|
+
# Execute given block between start and stop positions, and update
|
382
|
+
# position.
|
383
|
+
def do_range( start, stop, &blk )
|
384
|
+
do_for( start, (stop-start+1), &blk )
|
385
|
+
end
|
386
|
+
|
387
|
+
# Execute given block starting from start by count, and update
|
388
|
+
# position.
|
389
|
+
def do_for( start, count, &blk )
|
390
|
+
line = @line
|
391
|
+
@line = start-1
|
392
|
+
count.times do
|
393
|
+
yield self
|
394
|
+
@line += 1
|
395
|
+
end
|
396
|
+
@blockline = @line
|
397
|
+
@line = line
|
398
|
+
self
|
399
|
+
end
|
400
|
+
|
401
|
+
# Get lines between start and stop positions inclusive.
|
402
|
+
def get_range( start, stop )
|
403
|
+
@lines[ (start-1) .. (stop-1) ]
|
404
|
+
end
|
405
|
+
|
406
|
+
# Get lines starting from start by count.
|
407
|
+
def get_for( start, count )
|
408
|
+
@lines[ (start-1) ... (start-1+count) ]
|
409
|
+
end
|
410
|
+
|
411
|
+
# View line content around current position (by count).
|
412
|
+
def peek( count = 0 )
|
413
|
+
view_range( @line-count, @line+count+1 )
|
414
|
+
nil
|
415
|
+
end
|
416
|
+
|
417
|
+
# View line content with line numbers around current position (by
|
418
|
+
# count).
|
419
|
+
def peek_ln( count = 0 )
|
420
|
+
view_range( @line-count, @line+count+1, true )
|
421
|
+
nil
|
422
|
+
end
|
423
|
+
|
424
|
+
# View line content.
|
425
|
+
#
|
426
|
+
# * no args: view all
|
427
|
+
# * one arg: view from current onwards by count
|
428
|
+
# * two args: view given range
|
429
|
+
def view( arg1 = nil, arg2 = nil )
|
430
|
+
if !arg1 && !arg2
|
431
|
+
view_range( 0, length )
|
432
|
+
elsif arg1 && !arg2
|
433
|
+
view_range( @line, @line+arg1 )
|
434
|
+
elsif arg1 && arg2
|
435
|
+
view_range( arg1-1, arg1-1+arg2 )
|
436
|
+
end
|
437
|
+
nil
|
438
|
+
end
|
439
|
+
|
440
|
+
# View line content with line numbers.
|
441
|
+
#
|
442
|
+
# * no args: view all
|
443
|
+
# * one arg: view from current onwards by count
|
444
|
+
# * two args: view given range
|
445
|
+
def view_ln( arg1 = nil, arg2 = nil )
|
446
|
+
if !arg1 && !arg2
|
447
|
+
view_range( 0, length, true )
|
448
|
+
elsif arg1 && !arg2
|
449
|
+
view_range( @line, @line+arg1, true )
|
450
|
+
elsif arg1 && arg2
|
451
|
+
view_range( arg1-1, arg1-1+arg2, true )
|
452
|
+
end
|
453
|
+
nil
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
|
458
|
+
private
|
459
|
+
|
460
|
+
def read_clean( file ) # :nodoc:
|
461
|
+
File.readlines( file ).map{|line| line.chomp}.map{|line| line.empty? ? nil : line}
|
462
|
+
end
|
463
|
+
|
464
|
+
def view_range( first, last, ln = false ) # :nodoc:
|
465
|
+
if ln
|
466
|
+
ln = first+1
|
467
|
+
@lines[first...last].each do |line|
|
468
|
+
puts format( "%-4s #{line}", "#{ln.to_s}:" )
|
469
|
+
ln += 1
|
470
|
+
end
|
471
|
+
else
|
472
|
+
@lines[first...last].each do |line|
|
473
|
+
puts line
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
def search_with_exception( re_or_str, forward ) # :nodoc:
|
479
|
+
|
480
|
+
line = @line
|
481
|
+
len = @lines.length
|
482
|
+
|
483
|
+
if re_or_str.kind_of? String
|
484
|
+
|
485
|
+
if forward
|
486
|
+
while line < len
|
487
|
+
if @lines[line] && @lines[line].include?( re_or_str )
|
488
|
+
return line
|
489
|
+
end
|
490
|
+
line += 1
|
491
|
+
end
|
492
|
+
else
|
493
|
+
while line >= 0
|
494
|
+
if @lines[line] && @lines[line].include?( re_or_str )
|
495
|
+
return line
|
496
|
+
end
|
497
|
+
line -= 1
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
else
|
502
|
+
|
503
|
+
if forward
|
504
|
+
while line < len
|
505
|
+
if @lines[line] && re_or_str.match( @lines[line] )
|
506
|
+
return line
|
507
|
+
end
|
508
|
+
line += 1
|
509
|
+
end
|
510
|
+
else
|
511
|
+
while line >= 0
|
512
|
+
if @lines[line] && re_or_str.match( @lines[line] )
|
513
|
+
return line
|
514
|
+
end
|
515
|
+
line -= 1
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
raise PatmanSearchError, "#{@file}: Could not find \"#{re_or_str}\"..."
|
521
|
+
end
|
522
|
+
|
523
|
+
end
|
524
|
+
|
525
|
+
require_relative 'version'
|
data/lib/version.rb
ADDED