rupat 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 +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'
|