rupat 0.0.1

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