rupat 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/bin/rupat +183 -0
- data/doc/Rupat.html +973 -0
- data/doc/RupatAlias.html +191 -0
- data/doc/RupatMod/RupatError.html +138 -0
- data/doc/RupatMod/RupatInvalidLineError.html +142 -0
- data/doc/RupatMod/RupatPasteError.html +142 -0
- data/doc/RupatMod/RupatSearchError.html +142 -0
- data/doc/RupatMod/RupatTypeError.html +142 -0
- data/doc/RupatMod.html +5150 -0
- data/doc/_index.html +158 -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 +89 -0
- data/doc/file_list.html +63 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +89 -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 +399 -0
- data/doc/top-level-namespace.html +114 -0
- data/lib/rupat.rb +912 -0
- data/lib/version.rb +6 -0
- data/test/input/diff_test1.txt +10 -0
- data/test/input/diff_test2.txt +13 -0
- data/test/input/test_file1.txt +10 -0
- data/test/test_rupat.rb +213 -0
- data/test/test_rupat_bin.rb +27 -0
- metadata +96 -0
data/lib/rupat.rb
ADDED
@@ -0,0 +1,912 @@
|
|
1
|
+
# {RupatMod} contains the core functionality of {Rupat}.
|
2
|
+
module RupatMod
|
3
|
+
|
4
|
+
|
5
|
+
# {Rupat} exception base class.
|
6
|
+
class RupatError < RuntimeError; end
|
7
|
+
|
8
|
+
# {Rupat} type error.
|
9
|
+
class RupatTypeError < RupatError; end
|
10
|
+
|
11
|
+
# {Rupat} searching error (for find functions).
|
12
|
+
class RupatSearchError < RupatError; end
|
13
|
+
|
14
|
+
# {Rupat} invalid line number error (for goto functions).
|
15
|
+
class RupatInvalidLineError < RupatError; end
|
16
|
+
|
17
|
+
# {Rupat} paste error.
|
18
|
+
class RupatPasteError < RupatError; end
|
19
|
+
|
20
|
+
|
21
|
+
# Array of lines including current content.
|
22
|
+
attr_reader :lines
|
23
|
+
|
24
|
+
# Copy buffer.
|
25
|
+
attr_reader :copybuf
|
26
|
+
|
27
|
+
# Original file reference.
|
28
|
+
attr_accessor :orgFile
|
29
|
+
|
30
|
+
# Created file reference.
|
31
|
+
attr_accessor :newFile
|
32
|
+
|
33
|
+
|
34
|
+
# Create new file based on given name (or IO stream).
|
35
|
+
#
|
36
|
+
# @param orgFile [String,File] Source file.
|
37
|
+
# @param newFile [String] Destination file.
|
38
|
+
def create( orgFile, newFile = nil )
|
39
|
+
|
40
|
+
@orgFile = orgFile
|
41
|
+
@newFile = newFile
|
42
|
+
|
43
|
+
if @orgFile.class == String
|
44
|
+
@lines = cleanlines( File.open( @orgFile ) )
|
45
|
+
else
|
46
|
+
@lines = cleanlines( @orgFile )
|
47
|
+
end
|
48
|
+
|
49
|
+
@curline = 0
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Create new file based on old. Original file is backupped.
|
54
|
+
#
|
55
|
+
# @param file [String,File] Source file.
|
56
|
+
# @param backup [Boolean] Create backup from the source (original)
|
57
|
+
# file.
|
58
|
+
def edit( file, backup = true )
|
59
|
+
@backup = backup
|
60
|
+
create( file, file )
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# Open a file in source mode (read only).
|
65
|
+
#
|
66
|
+
# @param file [String,File] Source file.
|
67
|
+
def open( file )
|
68
|
+
create( file, nil )
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Use set of lines for editing.
|
73
|
+
#
|
74
|
+
# @param lines [Array<String>] Lines to use.
|
75
|
+
def use( lines )
|
76
|
+
@lines = lines
|
77
|
+
@curline = 0
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# Update the content using proc block.
|
82
|
+
#
|
83
|
+
# @yield blk Proc to execute on file content.
|
84
|
+
def update( &blk )
|
85
|
+
instance_eval &blk
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# Perform operations in block, but revert back to original
|
90
|
+
# position after block completion.
|
91
|
+
#
|
92
|
+
# @yield blk Proc to execute on file content.
|
93
|
+
# @return [Object] Value of the block.
|
94
|
+
def excursion( &blk )
|
95
|
+
startline = @curline
|
96
|
+
ret = instance_eval( &blk )
|
97
|
+
@curline = startline
|
98
|
+
ret
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# Goto line.
|
103
|
+
#
|
104
|
+
# @param line [Integer] Line to access.
|
105
|
+
# @return [Object] Self.
|
106
|
+
def goto( line = 0 )
|
107
|
+
@curline = line
|
108
|
+
normalizeCurline
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# Goto (text editor) line.
|
114
|
+
#
|
115
|
+
# @param line [Integer] Line to access (updated to <line>-1).
|
116
|
+
# @return [Object] Self.
|
117
|
+
def goto1( line = 1 )
|
118
|
+
@curline = line-1
|
119
|
+
normalizeCurline
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# Goto line without checking for line number validity.
|
125
|
+
#
|
126
|
+
# NOTE: User has to be aware of out-of-bound indexing issues.
|
127
|
+
#
|
128
|
+
# @param line [Integer] Line to access.
|
129
|
+
# @return [Object] Self.
|
130
|
+
def gotoForce( line = 0 )
|
131
|
+
@curline = line
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
# Goto first line.
|
137
|
+
#
|
138
|
+
# @return [Object] Self.
|
139
|
+
def gotoFirst
|
140
|
+
goto
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# Goto last line.
|
145
|
+
#
|
146
|
+
# @return [Object] Self.
|
147
|
+
def gotoLast
|
148
|
+
@curline = @lines.length-1
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Goto line after last line. User can append content starting with
|
154
|
+
# this line.
|
155
|
+
#
|
156
|
+
# @return [Object] Self.
|
157
|
+
def gotoEnd
|
158
|
+
@curline = @lines.length
|
159
|
+
self
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
alias jump goto
|
164
|
+
alias jumpFirst gotoFirst
|
165
|
+
alias jumpLast gotoLast
|
166
|
+
alias jumpEnd gotoEnd
|
167
|
+
|
168
|
+
|
169
|
+
# Forward line (or more).
|
170
|
+
#
|
171
|
+
# @param count [Integer] Number of lines to step forwards.
|
172
|
+
# @return [Object] Self.
|
173
|
+
def forward( count = 1 )
|
174
|
+
@curline += count
|
175
|
+
normalizeCurline
|
176
|
+
self
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
# Backwards line (or more).
|
181
|
+
#
|
182
|
+
# @param count [Integer] Number of lines to step backwards.
|
183
|
+
# @return [Object] Self.
|
184
|
+
def backward( count = 1 )
|
185
|
+
@curline -= count
|
186
|
+
normalizeCurline
|
187
|
+
self
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
# Goto next line.
|
192
|
+
alias step forward
|
193
|
+
alias down forward
|
194
|
+
alias inc forward
|
195
|
+
|
196
|
+
|
197
|
+
# Goto previous line.
|
198
|
+
alias up backward
|
199
|
+
alias back backward
|
200
|
+
alias dec backward
|
201
|
+
|
202
|
+
|
203
|
+
# Return next line number from current. Current line is not
|
204
|
+
# changed.
|
205
|
+
def next
|
206
|
+
@curline+1
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
# Return prev line number from current. Current line is not
|
211
|
+
# changed.
|
212
|
+
def prev
|
213
|
+
@curline-1
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
# Return current line number. First line is 0.
|
218
|
+
def line
|
219
|
+
@curline
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
# Return current line number + one, i.e. matches what for example an text
|
224
|
+
# editor would show. First line is 1.
|
225
|
+
def line1
|
226
|
+
@curline + 1
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
# Return last line number.
|
231
|
+
def last
|
232
|
+
length-1
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
# Find regexp forwards. Exception is generated, if pattern is not
|
237
|
+
# found.
|
238
|
+
#
|
239
|
+
# @param re [Regexp] Search pattern regexp.
|
240
|
+
# @return Self if found.
|
241
|
+
def findForward( re )
|
242
|
+
findCommon( re, true )
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
# Find regexp forward.
|
247
|
+
#
|
248
|
+
# @param re [Regexp] Search pattern regexp.
|
249
|
+
# @return Self if pattern found, nil otherwise.
|
250
|
+
def findForward?( re )
|
251
|
+
findCommon( re, true, false )
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
alias find findForward
|
256
|
+
alias find? findForward?
|
257
|
+
|
258
|
+
alias ffind findForward
|
259
|
+
alias ffind? findForward?
|
260
|
+
|
261
|
+
|
262
|
+
# Find regexp backwards. Exception is generated, if pattern is not
|
263
|
+
# found.
|
264
|
+
#
|
265
|
+
# @param re [Regexp] Search pattern regexp.
|
266
|
+
# @return Self if found.
|
267
|
+
def findBackward( re )
|
268
|
+
findCommon( re, false )
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
# Find regexp backward.
|
273
|
+
#
|
274
|
+
# @param re [Regexp] Search pattern regexp.
|
275
|
+
# @return Self if pattern found, nil otherwise.
|
276
|
+
def findBackward?( re )
|
277
|
+
findCommon( re, false, false )
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
alias bfind findBackward
|
282
|
+
alias bfind? findBackward?
|
283
|
+
|
284
|
+
|
285
|
+
# Return pair of line numbers that match the start/end
|
286
|
+
# regexps.
|
287
|
+
#
|
288
|
+
# @param re1 [Regexp] Range start marking Regexp.
|
289
|
+
# @param re2 [Regexp] Range end marking Regexp.
|
290
|
+
# @return [Integer,Integer] Range start/end tuplet.
|
291
|
+
def findBlock( re1, re2 )
|
292
|
+
findCommon( re1, true )
|
293
|
+
l1 = line
|
294
|
+
findCommon( re2, true )
|
295
|
+
l2 = line
|
296
|
+
[ l1, l2 ]
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
# Return lines content.
|
301
|
+
def []( range )
|
302
|
+
@lines[ range ]
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
# Return line content.
|
307
|
+
#
|
308
|
+
# @param line [Integer,NilClass] Indexed or current line.
|
309
|
+
# @return [String] Line content.
|
310
|
+
def get( line = nil )
|
311
|
+
@lines[ lineRef( line ) ]
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
# Return content of lines bounded by start/end markers
|
316
|
+
# (inclusive).
|
317
|
+
#
|
318
|
+
# @param l1 [Integer] Line marker 1 (See: {#linePairRef}).
|
319
|
+
# @param l2 [Integer] Line marker 2 (See: {#linePairRef}).
|
320
|
+
# @return [Array<String>] Line(s) content.
|
321
|
+
def getMany( l1 = nil, l2 = nil )
|
322
|
+
l1, l2 = linePairRef( l1, l2 )
|
323
|
+
@lines[ lineRef( l1 )..lineRef( l2 ) ]
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
# Store content of lines bounded by start/end markers
|
328
|
+
# (inclusive) to copy-buffer.
|
329
|
+
#
|
330
|
+
# @param l1 [Integer] Line marker 1 (See: {#linePairRef}).
|
331
|
+
# @param l2 [Integer] Line marker 2 (See: {#linePairRef}).
|
332
|
+
# @return [Array<String>] Line(s) content.
|
333
|
+
def copy( l1 = nil, l2 = nil )
|
334
|
+
l1, l2 = linePairRef( l1, l2 )
|
335
|
+
@copybuf = @lines[ lineRef( l1 )..lineRef( l2 ) ]
|
336
|
+
self
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
# Insert content from {#copybuf} (i.e. from {#copy}) to current
|
341
|
+
# position.
|
342
|
+
#
|
343
|
+
# @param err [Boolean] Generated exception for empty copybuf if
|
344
|
+
# true.
|
345
|
+
def paste( err = true )
|
346
|
+
if err
|
347
|
+
unless @copybuf
|
348
|
+
raise RupatPasteError, "Copy buffer was empty!"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
insertMany( @copybuf ) if @copybuf
|
352
|
+
self
|
353
|
+
end
|
354
|
+
|
355
|
+
|
356
|
+
# Set line content.
|
357
|
+
#
|
358
|
+
# @param str [String] New content for line.
|
359
|
+
# @param line [Integer] Index to modified line.
|
360
|
+
# @return [Object] Self.
|
361
|
+
def set( str, line = nil )
|
362
|
+
@lines[ lineRef( line ) ] = str
|
363
|
+
self
|
364
|
+
end
|
365
|
+
|
366
|
+
|
367
|
+
# Replace the current line content (i.e. get&set).
|
368
|
+
#
|
369
|
+
# @example
|
370
|
+
# r.replace do |c|
|
371
|
+
# c.gsub( /foo/, 'bar'
|
372
|
+
# end
|
373
|
+
#
|
374
|
+
# @yield [get] Actions to perform for the content. Current content
|
375
|
+
# is given as argument for the block.
|
376
|
+
# @return [Object] Self.
|
377
|
+
def replace( &action )
|
378
|
+
set( yield( get ) )
|
379
|
+
self
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
alias subs replace
|
384
|
+
|
385
|
+
|
386
|
+
# Insert a line at current position.
|
387
|
+
#
|
388
|
+
# @param str [String] Content for the inserted line.
|
389
|
+
# @return [Object] Self.
|
390
|
+
def insert( str = "" )
|
391
|
+
@lines.insert( @curline, str )
|
392
|
+
self
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
# Insert multiple lines at current position.
|
397
|
+
#
|
398
|
+
# @param content [Object] Content (See: {#manyLineContent}).
|
399
|
+
# @return [Object] Self.
|
400
|
+
def insertMany( content )
|
401
|
+
lines = manyLineContent( content )
|
402
|
+
excursion do
|
403
|
+
insert( lines[0] )
|
404
|
+
lines[1..-1].each do |s|
|
405
|
+
append( s )
|
406
|
+
end
|
407
|
+
end
|
408
|
+
self
|
409
|
+
end
|
410
|
+
|
411
|
+
|
412
|
+
# Append line to current position.
|
413
|
+
#
|
414
|
+
# @param str [String] Content for the appended line.
|
415
|
+
# @return [Object] Self.
|
416
|
+
def append( str = "" )
|
417
|
+
forward
|
418
|
+
@lines.insert( @curline, str )
|
419
|
+
self
|
420
|
+
end
|
421
|
+
|
422
|
+
|
423
|
+
# Append lines to current position.
|
424
|
+
#
|
425
|
+
# @param content [Object] Content (See: {#manyLineContent}).
|
426
|
+
# @return [Object] Self.
|
427
|
+
def appendMany( content )
|
428
|
+
lines = manyLineContent( content )
|
429
|
+
lines.each do |s|
|
430
|
+
append( s )
|
431
|
+
end
|
432
|
+
self
|
433
|
+
end
|
434
|
+
|
435
|
+
|
436
|
+
# Delete current line.
|
437
|
+
#
|
438
|
+
# @return [Object] Self.
|
439
|
+
def delete
|
440
|
+
@lines.delete_at( @curline )
|
441
|
+
self
|
442
|
+
end
|
443
|
+
|
444
|
+
|
445
|
+
# Delete current line N times.
|
446
|
+
#
|
447
|
+
# @param cnt [Integer] Number of lines to delete.
|
448
|
+
# @return [Object] Self.
|
449
|
+
def deleteMany( cnt = length )
|
450
|
+
cnt.times do
|
451
|
+
@lines.delete_at( @curline )
|
452
|
+
end
|
453
|
+
self
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
# Delete specified lines (inclusive). Save content to copy-buffer.
|
458
|
+
#
|
459
|
+
# @param l1 [Integer] Line marker 1 (See: {#linePairRef}).
|
460
|
+
# @param l2 [Integer] Line marker 2 (See: {#linePairRef}).
|
461
|
+
# @return [Object] Self.
|
462
|
+
def cut( l1 = nil, l2 = nil )
|
463
|
+
l1, l2 = linePairRef( l1, l2 )
|
464
|
+
@copybuf = []
|
465
|
+
cnt = l2-l1+1
|
466
|
+
cnt.times do
|
467
|
+
@copybuf.push @lines.delete_at( l1 )
|
468
|
+
end
|
469
|
+
self
|
470
|
+
end
|
471
|
+
|
472
|
+
|
473
|
+
# Insert file content to current position.
|
474
|
+
#
|
475
|
+
# @param file [String] Name of file to insert.
|
476
|
+
# @return [Object] Self.
|
477
|
+
def insertFile( file )
|
478
|
+
excursion do
|
479
|
+
lines = cleanlines( File.open( file ) )
|
480
|
+
insertMany( lines )
|
481
|
+
end
|
482
|
+
self
|
483
|
+
end
|
484
|
+
|
485
|
+
|
486
|
+
# Replace all occurance of re with str.
|
487
|
+
#
|
488
|
+
# @param re [Regexp] Regexp to match replace lines to.
|
489
|
+
# @param str [String] New content.
|
490
|
+
# @return [Object] Self.
|
491
|
+
def replaceAll( re, str )
|
492
|
+
@lines.each_index do |idx|
|
493
|
+
@lines[idx].gsub!( re, str )
|
494
|
+
end
|
495
|
+
self
|
496
|
+
end
|
497
|
+
|
498
|
+
|
499
|
+
# Replace all occurance of re with str within given range.
|
500
|
+
#
|
501
|
+
# @param re [Regexp] Regexp to match replace lines to.
|
502
|
+
# @param str [String] New content.
|
503
|
+
# @param l1 [Integer] Line marker 1 (See: {#linePairRef}).
|
504
|
+
# @param l2 [Integer] Line marker 2 (See: {#linePairRef}).
|
505
|
+
# @return [Object] Self.
|
506
|
+
def replaceWithin( re, str, l1 = nil, l2 = nil )
|
507
|
+
l1, l2 = linePairRef( l1, l2 )
|
508
|
+
@lines[l1..l2].each_index do |idx|
|
509
|
+
@lines[idx].gsub!( re, str )
|
510
|
+
end
|
511
|
+
self
|
512
|
+
end
|
513
|
+
|
514
|
+
|
515
|
+
# Return lines length.
|
516
|
+
def length
|
517
|
+
@lines.length
|
518
|
+
end
|
519
|
+
|
520
|
+
|
521
|
+
# Save edits and close file.
|
522
|
+
#
|
523
|
+
# @param file [String] File to save edits to.
|
524
|
+
# @return [String,NilClass] Backup file name if backup made,
|
525
|
+
# otherwise nil.
|
526
|
+
def close( file = @newFile )
|
527
|
+
|
528
|
+
# Backup original file:
|
529
|
+
if @backup
|
530
|
+
time = Time.now.strftime( "%y%m%d_%H%M_%S" )
|
531
|
+
|
532
|
+
p = @orgFile.split( '/' )
|
533
|
+
backupFile = "#{p[0..-2].join('/')}/rupat_#{time}_#{p[-1]}"
|
534
|
+
|
535
|
+
File.rename( @orgFile, backupFile )
|
536
|
+
@orgFile = backupFile
|
537
|
+
end
|
538
|
+
|
539
|
+
save( file )
|
540
|
+
|
541
|
+
file.close if file.class == File
|
542
|
+
|
543
|
+
if @backup
|
544
|
+
backupFile
|
545
|
+
else
|
546
|
+
nil
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
|
551
|
+
# Save edits. File handle is not closed. Use {#close} for complete
|
552
|
+
# file closing.
|
553
|
+
#
|
554
|
+
# @param file [String,File] File to save edits to. If type is
|
555
|
+
# File, stream is not closed.
|
556
|
+
def save( file = @newFile )
|
557
|
+
|
558
|
+
raise RupatTypeError, "Can't use \"nil\" for file save!" unless file
|
559
|
+
|
560
|
+
close = true
|
561
|
+
|
562
|
+
case file
|
563
|
+
when String
|
564
|
+
if @orgFile.class == String
|
565
|
+
# Open with original file permissions.
|
566
|
+
fh = File.open( file, "w", File.stat( @orgFile ).mode )
|
567
|
+
else
|
568
|
+
# Open with default file permissions.
|
569
|
+
fh = File.open( file, "w" )
|
570
|
+
end
|
571
|
+
when File
|
572
|
+
fh = file
|
573
|
+
close = false
|
574
|
+
else
|
575
|
+
raise RupatTypeError, "Can't use \"#{file.class}\" type for file save!"
|
576
|
+
end
|
577
|
+
|
578
|
+
@lines.each do |l|
|
579
|
+
fh.syswrite( l + "\n" )
|
580
|
+
end
|
581
|
+
|
582
|
+
fh.close if close
|
583
|
+
end
|
584
|
+
|
585
|
+
|
586
|
+
# Print file content.
|
587
|
+
#
|
588
|
+
# @param fh [IO] IO stream for printout.
|
589
|
+
def print( fh = STDOUT )
|
590
|
+
@lines.each do |l|
|
591
|
+
fh.puts l
|
592
|
+
end
|
593
|
+
self
|
594
|
+
end
|
595
|
+
|
596
|
+
|
597
|
+
|
598
|
+
private
|
599
|
+
|
600
|
+
# RupatMod Internal methods:
|
601
|
+
|
602
|
+
# Return non-newline lines from IO.
|
603
|
+
def cleanlines( io ) # :nodoc
|
604
|
+
lines = []
|
605
|
+
io.each_line do |line|
|
606
|
+
lines.push line.chomp
|
607
|
+
end
|
608
|
+
lines
|
609
|
+
end
|
610
|
+
|
611
|
+
|
612
|
+
# Find regular expression to selected direction.
|
613
|
+
def findCommon( re, forward = true, err = true ) # :nodoc:
|
614
|
+
|
615
|
+
tline = @curline
|
616
|
+
len = @lines.length
|
617
|
+
|
618
|
+
while forward ? tline < len : tline >= 0
|
619
|
+
|
620
|
+
if re =~ @lines[ tline ]
|
621
|
+
@curline = tline
|
622
|
+
return self
|
623
|
+
end
|
624
|
+
|
625
|
+
forward ? tline += 1 : tline -= 1
|
626
|
+
end
|
627
|
+
|
628
|
+
raise RupatSearchError, "#{@file}: Didn't find \"#{re}\"..." if err
|
629
|
+
|
630
|
+
nil
|
631
|
+
end
|
632
|
+
|
633
|
+
|
634
|
+
# Transform line reference.
|
635
|
+
#
|
636
|
+
# @param line [Integer] Line reference.
|
637
|
+
# @return [Integer] Current line if line is nil, otherwise line.
|
638
|
+
def lineRef( line )
|
639
|
+
if !line
|
640
|
+
@curline
|
641
|
+
else
|
642
|
+
line
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
|
647
|
+
# Fix a pair of line markers according to rules:
|
648
|
+
# * If both are nil, then pair is <current,current>.
|
649
|
+
# * If line2 is nil and line1 is positive, then pair is
|
650
|
+
# <current,current+line1>, i.e. line1 is offset from current
|
651
|
+
# line.
|
652
|
+
# * If line2 is nil and line1 is negative, then pair is
|
653
|
+
# <current-line1,current>, i.e. line1 is offset from current
|
654
|
+
# line for first marker.
|
655
|
+
# * If line1 and line2 are valid, then pair is <line1,line2>.
|
656
|
+
#
|
657
|
+
# @param line1 [Integer] First line reference.
|
658
|
+
# @param line2 [Integer] Second line reference.
|
659
|
+
# @return [Array<Integer>] Pair of valid line references.
|
660
|
+
def linePairRef( line1, line2 )
|
661
|
+
if !line1 && !line2
|
662
|
+
[ @curline, @curline ]
|
663
|
+
elsif line1 && !line2
|
664
|
+
if line1 >= 0
|
665
|
+
[ @curline, @curline+line1 ]
|
666
|
+
else
|
667
|
+
[ @curline+line1, @curline ]
|
668
|
+
end
|
669
|
+
else
|
670
|
+
[ line1, line2 ]
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
|
675
|
+
# Fix "many" content, i.e. if String, split it with "\n". If
|
676
|
+
# Array, pass it as it is (except chomp).
|
677
|
+
def manyLineContent( content )
|
678
|
+
case content
|
679
|
+
when String; content.split("\n")
|
680
|
+
when Array; content.collect{|i| i.chomp}
|
681
|
+
else raise RupatTypeError, "Unknown \"many\" line content!"
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
|
686
|
+
# Normalize curline. Raise exception if needed.
|
687
|
+
def normalizeCurline( err = true )
|
688
|
+
if @curline < 0
|
689
|
+
@curline = 0
|
690
|
+
raise RupatInvalidLineError, "Current line underflow..." if err
|
691
|
+
elsif @curline > @lines.length
|
692
|
+
@curline = @lines.length
|
693
|
+
raise RupatInvalidLineError, "Current line overflow..." if err
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
end
|
698
|
+
|
699
|
+
|
700
|
+
# Set of aliases to enable a very compact {Rupat} program.
|
701
|
+
#
|
702
|
+
# Aliases:
|
703
|
+
# * l -> {RupatMod#line}
|
704
|
+
# * n -> {RupatMod#forward}
|
705
|
+
# * p -> {RupatMod#backward}
|
706
|
+
# * j -> {RupatMod#goto}
|
707
|
+
# * j1 -> {RupatMod#goto1}
|
708
|
+
# * jl -> {RupatMod#gotoLast}
|
709
|
+
# * je -> {RupatMod#gotoEnd}
|
710
|
+
# * f -> {RupatMod#find?}
|
711
|
+
# * ff -> {RupatMod#findForward?}
|
712
|
+
# * fb -> {RupatMod#findBackward?}
|
713
|
+
# * s -> {RupatMod#set}
|
714
|
+
# * g -> {RupatMod#get}
|
715
|
+
# * gm -> {RupatMod#getMany}
|
716
|
+
# * cp -> {RupatMod#copy}
|
717
|
+
# * pt -> {RupatMod#paste}
|
718
|
+
# * r -> {RupatMod#replace}
|
719
|
+
# * i -> {RupatMod#insert}
|
720
|
+
# * im -> {RupatMod#insertMany}
|
721
|
+
# * a -> {RupatMod#append}
|
722
|
+
# * am -> {RupatMod#appendMany}
|
723
|
+
# * d -> {RupatMod#delete}
|
724
|
+
# * dm -> {RupatMod#deleteMany}
|
725
|
+
# * ct -> {RupatMod#cut}
|
726
|
+
# * ifi -> {RupatMod#insertFile}
|
727
|
+
# * cl -> {RupatMod#close}
|
728
|
+
# * sv -> {RupatMod#save}
|
729
|
+
module RupatAlias
|
730
|
+
|
731
|
+
include RupatMod
|
732
|
+
|
733
|
+
alias l line
|
734
|
+
alias n forward
|
735
|
+
alias p backward
|
736
|
+
alias j goto
|
737
|
+
alias j1 goto1
|
738
|
+
alias jl gotoLast
|
739
|
+
alias je gotoEnd
|
740
|
+
alias f find?
|
741
|
+
alias ff findForward?
|
742
|
+
alias fb findBackward?
|
743
|
+
alias s set
|
744
|
+
alias g get
|
745
|
+
alias gm getMany
|
746
|
+
alias cp copy
|
747
|
+
alias pt paste
|
748
|
+
alias r replace
|
749
|
+
alias i insert
|
750
|
+
alias im insertMany
|
751
|
+
alias a append
|
752
|
+
alias am appendMany
|
753
|
+
alias d delete
|
754
|
+
alias dm deleteMany
|
755
|
+
alias ct cut
|
756
|
+
alias ifi insertFile
|
757
|
+
alias cl close
|
758
|
+
alias sv save
|
759
|
+
end
|
760
|
+
|
761
|
+
|
762
|
+
|
763
|
+
# = Rupat
|
764
|
+
#
|
765
|
+
# == Introduction
|
766
|
+
#
|
767
|
+
# {Rupat} is a Ruby Patching utility. It can be used to patch files or
|
768
|
+
# for extracting information from files.
|
769
|
+
#
|
770
|
+
# {Rupat} includes:
|
771
|
+
# [{RupatMod}] File content manipulation methods.
|
772
|
+
# [{Rupat}] Class methods for Rupat script creation.
|
773
|
+
# [Rupat command] Shell command for creating Rupat patch files.
|
774
|
+
#
|
775
|
+
# Typical {Rupat} script opens a file for editing, uses Regexp
|
776
|
+
# searches to find the file position(s) to change, and adds/replaces
|
777
|
+
# the content. File positions can be referred also line numbers.
|
778
|
+
#
|
779
|
+
# Rupat command can be used to create a patch script from diff
|
780
|
+
# output. The generated script includes {RupatMod} commands which
|
781
|
+
# implement the transformation.
|
782
|
+
#
|
783
|
+
# {Rupat} includes lines of the file in a line Array. {Rupat} keeps
|
784
|
+
# track of the current line. Many editing commands use the current
|
785
|
+
# line to specify the context for editing.
|
786
|
+
#
|
787
|
+
# {Rupat} has two parts: {Rupat} class and {RupatMod}. {Rupat} class
|
788
|
+
# is a front end class to create {Rupat} instance for editing. {Rupat}
|
789
|
+
# includes {RupatMod}. {RupatMod} can be used for other user classes
|
790
|
+
# that benefit from lines editing.
|
791
|
+
#
|
792
|
+
# The basic flow is:
|
793
|
+
# [open file] Source file can be opened in multiple editing modes.
|
794
|
+
# [line manipulation] Search/jump to lines, extract and edit content
|
795
|
+
# (See: {RupatMod} for all access/editing methods).
|
796
|
+
# [save file] Save the editing results to the source file or to a
|
797
|
+
# newly created file.
|
798
|
+
#
|
799
|
+
#
|
800
|
+
# == Rupat class
|
801
|
+
#
|
802
|
+
# {Rupat} is a class that provides the default entry point to the
|
803
|
+
# {RupatMod} module.
|
804
|
+
#
|
805
|
+
# The user can modify, duplicate, or just read file(s).
|
806
|
+
# [update] Perform content update for a file, but without any backups.
|
807
|
+
# [edit] Inplace editing with possibility to backup the original.
|
808
|
+
# [open] Open file in read-only mode. Possibility to save the changes
|
809
|
+
# later exist.
|
810
|
+
# [create] A named file is to be created from source file.
|
811
|
+
#
|
812
|
+
#
|
813
|
+
# === Example usage:
|
814
|
+
#
|
815
|
+
# # Open file for reading.
|
816
|
+
# r = Rupat.update( "report.txt" )
|
817
|
+
#
|
818
|
+
# # Find line.
|
819
|
+
# r.find /cpp/
|
820
|
+
#
|
821
|
+
# # Collect some lines.
|
822
|
+
# line = r.line
|
823
|
+
# data = 4.times.collect do |i|
|
824
|
+
# r.get( line + i )
|
825
|
+
# end
|
826
|
+
#
|
827
|
+
# # Duplicate the lines collected.
|
828
|
+
# insertMany( data )
|
829
|
+
#
|
830
|
+
# # Save changes.
|
831
|
+
# r.close
|
832
|
+
#
|
833
|
+
#
|
834
|
+
# == Rupat command
|
835
|
+
#
|
836
|
+
# Rupat command is a simple shell command using {Rupat}. Main purpose
|
837
|
+
# is to execute Rupat programs. It can also be used to generate a
|
838
|
+
# {Rupat} patch from files with different content. When applied, the
|
839
|
+
# patch transforms file1 to file2.
|
840
|
+
class Rupat
|
841
|
+
|
842
|
+
include RupatMod
|
843
|
+
|
844
|
+
|
845
|
+
# Edit existing file inplace without backups.
|
846
|
+
#
|
847
|
+
# @param file [String,File] Source file.
|
848
|
+
def Rupat.update( file )
|
849
|
+
Rupat.edit( file, false )
|
850
|
+
end
|
851
|
+
|
852
|
+
|
853
|
+
# Open existing file for reading.
|
854
|
+
#
|
855
|
+
# @param file [String,File] Source file.
|
856
|
+
def Rupat.open( file )
|
857
|
+
r = Rupat.new
|
858
|
+
r.open( file )
|
859
|
+
r
|
860
|
+
end
|
861
|
+
|
862
|
+
|
863
|
+
# Open existing file for reading.
|
864
|
+
#
|
865
|
+
# @param file [String,File] Source file.
|
866
|
+
def Rupat.readonly( file )
|
867
|
+
Rupat.open( file )
|
868
|
+
end
|
869
|
+
|
870
|
+
|
871
|
+
# Edit existing file and by default make backup.
|
872
|
+
#
|
873
|
+
# @param file [String,File] Source file.
|
874
|
+
# @param backup [Boolean] Create backup from the source (original)
|
875
|
+
# file.
|
876
|
+
def Rupat.edit( file, backup = true )
|
877
|
+
r = Rupat.new
|
878
|
+
r.edit( file, backup )
|
879
|
+
r
|
880
|
+
end
|
881
|
+
|
882
|
+
|
883
|
+
# Create new file based on old file.
|
884
|
+
#
|
885
|
+
# @param orgFile [String,File] Source file.
|
886
|
+
# @param newFile [String] Destination file.
|
887
|
+
def Rupat.create( orgFile, newFile )
|
888
|
+
r = Rupat.new
|
889
|
+
r.create( orgFile, newFile )
|
890
|
+
r
|
891
|
+
end
|
892
|
+
|
893
|
+
|
894
|
+
# Use set of lines for editing.
|
895
|
+
#
|
896
|
+
# @param lines [Array<String>] Lines to edit.
|
897
|
+
def Rupat.lines( lines )
|
898
|
+
r = Rupat.new
|
899
|
+
r.use( lines )
|
900
|
+
r
|
901
|
+
end
|
902
|
+
|
903
|
+
|
904
|
+
# Use short aliases from {RupatAlias} module.
|
905
|
+
def useAlias
|
906
|
+
Rupat.send( :include, RupatAlias )
|
907
|
+
self
|
908
|
+
end
|
909
|
+
|
910
|
+
end
|
911
|
+
|
912
|
+
require_relative 'version'
|