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.
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'