cursor 0.5 → 0.6
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/cursor.rb +1257 -1138
- metadata +2 -2
data/cursor.rb
CHANGED
@@ -1,1138 +1,1257 @@
|
|
1
|
-
#!/bin/env ruby
|
2
|
-
# cursor.rb
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
class
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
#
|
23
|
-
|
24
|
-
#
|
25
|
-
|
26
|
-
#
|
27
|
-
|
28
|
-
#
|
29
|
-
|
30
|
-
#
|
31
|
-
|
32
|
-
#
|
33
|
-
|
34
|
-
# Operate on what follows the cursor and
|
35
|
-
|
36
|
-
# Operate on what precedes the cursor and
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
#
|
43
|
-
|
44
|
-
#
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
#
|
60
|
-
# is returned
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
flags
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
end
|
312
|
-
|
313
|
-
|
314
|
-
#
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
end
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
end
|
340
|
-
|
341
|
-
#
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
#
|
346
|
-
#
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
#
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
return(true) if
|
411
|
-
|
412
|
-
end
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
else
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
#
|
456
|
-
def
|
457
|
-
if other.respond_to?:pos
|
458
|
-
position?(other) or return(
|
459
|
-
other = other.pos
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
end
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
#
|
481
|
-
#
|
482
|
-
|
483
|
-
#
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
#
|
525
|
-
def
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
#
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
#
|
547
|
-
def
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
value
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
end
|
644
|
-
# Performs
|
645
|
-
# for index, len, and flags as #
|
646
|
-
#
|
647
|
-
#
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
class
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
@
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
def
|
709
|
-
@parent.pos
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
end
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
def
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
end
|
771
|
-
def
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
@
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
end
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
@data_class
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
)
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
@
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
#
|
863
|
-
#
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
@io.
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
@io.
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
end
|
976
|
-
|
977
|
-
|
978
|
-
@io.
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
def
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
end
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
end
|
1120
|
-
def
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1
|
+
#!/bin/env ruby
|
2
|
+
# = cursor.rb - external iterators with capabilities like a text editor cursor
|
3
|
+
# $Id: cursor.rb,v 1.8 2005/05/25 16:12:22 eric_mahurin Exp $
|
4
|
+
# Author:: Eric Mahurin (Eric under Mahurin at yahoo dot com)
|
5
|
+
# License:: Ruby license
|
6
|
+
# Home:: http://rubyforge.org/projects/cursor
|
7
|
+
|
8
|
+
# An object in this Cursor class can be best thought of as a cursor in a text
|
9
|
+
# editor. Many of the same operations apply - insert, delete, replace, copy,
|
10
|
+
# paste, move, goto begin/end, mark position, goto mark, etc. Unlike a
|
11
|
+
# text editor, this class can operate on variety of data, not just characters
|
12
|
+
# and strings. It is up to the derived classes to deal with what type of data
|
13
|
+
# is stored (i.e. characters, arbitrary array objects) and how it is stored (in
|
14
|
+
# an Array, String, IO, mapping to another Cursor, etc).
|
15
|
+
class Cursor
|
16
|
+
|
17
|
+
include Comparable
|
18
|
+
include Enumerable
|
19
|
+
|
20
|
+
# Operate on data before the cursor rather than after
|
21
|
+
Reverse = 1
|
22
|
+
# Hold position - do the operation and come back
|
23
|
+
Hold = 2
|
24
|
+
# Just count the elements from get/delete instead of returning their value
|
25
|
+
Ignore = 4
|
26
|
+
# Read the data being replaced using put and return it (instead of the count)
|
27
|
+
Read = 4
|
28
|
+
# Delete instead of retrieve elements (used with get)
|
29
|
+
Delete = 8
|
30
|
+
# Insert instead of replace elements (used with put)
|
31
|
+
Insert = 8
|
32
|
+
# Put a single element instead of a sequence (needed when it looks like a sequence)
|
33
|
+
Single = 16
|
34
|
+
# Operate on what follows the cursor and then move foward
|
35
|
+
Next = 0
|
36
|
+
# Operate on what precedes the cursor and then move backward
|
37
|
+
Prev = Reverse
|
38
|
+
# Operate on what follows the cursor and hold position
|
39
|
+
After = Hold
|
40
|
+
# Operate on what precedes the cursor and hold position
|
41
|
+
Before = Reverse|Hold
|
42
|
+
# #pos for the beginning (positive zero)
|
43
|
+
Begin = +0
|
44
|
+
# #pos for the end (negative zero)
|
45
|
+
End = -0.1
|
46
|
+
# #get +len+ for getting the rest of the elements
|
47
|
+
Rest = +1.0/0
|
48
|
+
|
49
|
+
protected
|
50
|
+
# Delete one element at the cursor and return it. The observed bits in +flags+
|
51
|
+
# are +Reverse+ (delete before the cursor instead of after) and +Ignore+
|
52
|
+
# (return true instead of the deleted element). When the cursor is at the end (or beginning),
|
53
|
+
# either nil or the code block result is returned (see #get).
|
54
|
+
# <b>This method must be overriden
|
55
|
+
# in a derived class</b>.
|
56
|
+
def _delete1(flags,&more) # :yield: l=1
|
57
|
+
raise(NotImplementedError)
|
58
|
+
end
|
59
|
+
# Insert one element at the cursor. Only the +Reverse+ bit
|
60
|
+
# is observed in +flags+. nil should be returned. <b>This method must be overriden
|
61
|
+
# in a derived class</b>.
|
62
|
+
def _insert1(value,flags)
|
63
|
+
raise(NotImplementedError)
|
64
|
+
end
|
65
|
+
# Get an element at the cursor. The observed bits in +flags+ are +Reverse+
|
66
|
+
# (read before instead of after the cursor), +Hold+ (don't move the
|
67
|
+
# cursor), and +Ignore+ (just return +true+ instead of the value). When the
|
68
|
+
# cursor is at the end (or beginning), either nil or the code block result
|
69
|
+
# is returned (see #get).
|
70
|
+
def _get1(flags,&more) # :yield: l=1
|
71
|
+
value = _delete1(flags&~Ignore) { |l| more&&more[l] || return }
|
72
|
+
if (flags&Hold).nonzero?
|
73
|
+
flags ^= Hold
|
74
|
+
flags ^= Reverse
|
75
|
+
end
|
76
|
+
_insert1(value,flags)
|
77
|
+
(flags&Ignore).nonzero? ? true : value
|
78
|
+
end
|
79
|
+
# Put an element at the cursor. The observed bits in +flags+ are +Reverse+
|
80
|
+
# (put before instead of after the cursor), +Hold+ (don't move the
|
81
|
+
# cursor), and +Read+ (read and return what is being replaced instead of
|
82
|
+
# just returning +true+). When the cursor is at the end (or beginning),
|
83
|
+
# either nil or the code block result is returned (see #get).
|
84
|
+
# The value is inserted at that point when that happens.
|
85
|
+
def _put1(value,flags,&more) # :yield: l=1
|
86
|
+
value0 = _delete1(flags^Read,&more)
|
87
|
+
if (flags&Hold).nonzero?
|
88
|
+
flags ^= Hold
|
89
|
+
flags ^= Reverse
|
90
|
+
end
|
91
|
+
_insert1(value,flags)
|
92
|
+
value0
|
93
|
+
end
|
94
|
+
|
95
|
+
public
|
96
|
+
# Create a cursor.
|
97
|
+
def initialize
|
98
|
+
@positions = []
|
99
|
+
end
|
100
|
+
# Return the class used for passing/returning a sequence of elements. This
|
101
|
+
# class must behave as a String or an Array ([], []=, slice, slice!, length).
|
102
|
+
# The default in the base class is Array.
|
103
|
+
def data_class
|
104
|
+
Array
|
105
|
+
end
|
106
|
+
# Get a single element or a sequence of them.
|
107
|
+
#
|
108
|
+
# +len+ can be +nil+ (get one element - like IO#getc), a non-negative number (get a
|
109
|
+
# sequence of that many elements - like IO#read), a negative number (get that many in reverse),
|
110
|
+
# or a termination sequence (get a sequence up until it finds a match to +len+ - like IO#gets).
|
111
|
+
#
|
112
|
+
# The observed bits in +flags+ are +Reverse+
|
113
|
+
# (read before instead of after the cursor), +Hold+ (don't move the
|
114
|
+
# cursor), +Ignore+ (just return +true+ or a count instead of the value),
|
115
|
+
# and +Delete+ (delete the element or sequence while retrieving it).
|
116
|
+
#
|
117
|
+
# If there is anything left, either nil (no code block) or the result from code block is
|
118
|
+
# returned. This code block could set some variable(s) to signify it
|
119
|
+
# is done or return data from some other source to make it look as though
|
120
|
+
# it is not done. When returning more data, it should return it in a
|
121
|
+
# String or Array of up to +l+ elements.
|
122
|
+
def get(len=nil,flags=Next,&more) # :yield: l
|
123
|
+
g = (flags&Delete).nonzero? ? :_delete1 : :_get1
|
124
|
+
return(__send__(g,flags,&more)) if not len
|
125
|
+
if (flags&Hold).nonzero? and (flags&Delete).zero?
|
126
|
+
flags ^= Hold
|
127
|
+
position { get(len,flags,&more) }
|
128
|
+
elsif len.respond_to?:zero?
|
129
|
+
if len<0
|
130
|
+
flags ^= Reverse
|
131
|
+
len = -len
|
132
|
+
end
|
133
|
+
len -= 1
|
134
|
+
if (flags&Ignore).nonzero?
|
135
|
+
len1 = 0
|
136
|
+
while len>=len1
|
137
|
+
__send__(g,flags) { |l|
|
138
|
+
more&&more[l] ||
|
139
|
+
(return(len1.zero? ? nil : len1))
|
140
|
+
}
|
141
|
+
len1 += 1
|
142
|
+
end
|
143
|
+
len1
|
144
|
+
else
|
145
|
+
value = data_class.new
|
146
|
+
while len>=value.size
|
147
|
+
v = __send__(g,flags&~Ignore) { |l|
|
148
|
+
more&&more[l] || (return(
|
149
|
+
value.size.zero? ? nil :
|
150
|
+
(flags&Reverse).nonzero? ? value.reverse : value
|
151
|
+
))
|
152
|
+
}
|
153
|
+
value << v
|
154
|
+
end
|
155
|
+
(flags&Reverse).nonzero? ? value.reverse : value
|
156
|
+
end
|
157
|
+
else
|
158
|
+
if (flags&Ignore).nonzero?
|
159
|
+
value = get(len,flags^Ignore,&more)
|
160
|
+
return(value&&value.size)
|
161
|
+
end
|
162
|
+
value = data_class.new
|
163
|
+
if (flags&Reverse).nonzero?
|
164
|
+
step = -1
|
165
|
+
start = len.size-1
|
166
|
+
finish = -1
|
167
|
+
else
|
168
|
+
step = +1
|
169
|
+
start = 0
|
170
|
+
finish = len.size
|
171
|
+
end
|
172
|
+
i = start
|
173
|
+
loop do
|
174
|
+
v = __send__(g,flags) { |l|
|
175
|
+
more&&more[l] || begin
|
176
|
+
value = value.reverse if (flags&Reverse).nonzero?
|
177
|
+
value = nil if value.size.zero?
|
178
|
+
return
|
179
|
+
end
|
180
|
+
}
|
181
|
+
value << v
|
182
|
+
if v==len[i]
|
183
|
+
i += step
|
184
|
+
if i==finish
|
185
|
+
value = value.reverse if (flags&Reverse).nonzero?
|
186
|
+
return(value)
|
187
|
+
end
|
188
|
+
else
|
189
|
+
i = start
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
# Put a single element or a sequence of them at the cursor.
|
195
|
+
#
|
196
|
+
# The observed bits in +flags+ are +Reverse+
|
197
|
+
# (read before instead of after the cursor), +Hold+ (don't move the
|
198
|
+
# cursor), +Read+ (return the what is overwritten instead of +true+ or a count),
|
199
|
+
# +Insert+ (insert rather than replace +value+), and +Single+ (force +value+
|
200
|
+
# to be treated as a single element rather than a sequence).
|
201
|
+
#
|
202
|
+
# When the cursor is at the end (or beginning),
|
203
|
+
# either nil or the code block result is returned (see #get).
|
204
|
+
# The value is inserted at that point when that happens.
|
205
|
+
def put(value,flags=Next,&more) # :yield: l
|
206
|
+
if (flags&Single).nonzero? or not data_class>=value.class
|
207
|
+
if (flags&Insert).nonzero?
|
208
|
+
if (flags&Hold).nonzero?
|
209
|
+
flags ^= Hold
|
210
|
+
flags ^= Reverse
|
211
|
+
end
|
212
|
+
return(_insert1(value,flags,&more))
|
213
|
+
else
|
214
|
+
return(_put1(value,flags,&more))
|
215
|
+
end
|
216
|
+
end
|
217
|
+
if (flags&Insert).nonzero?
|
218
|
+
flags |= Single
|
219
|
+
if (flags&Hold).nonzero?
|
220
|
+
flags ^= Hold
|
221
|
+
flags ^= Reverse
|
222
|
+
end
|
223
|
+
if (flags&Reverse).nonzero?
|
224
|
+
start = value.size-1
|
225
|
+
finish = 0
|
226
|
+
step = -1
|
227
|
+
else
|
228
|
+
start = 0
|
229
|
+
finish = value.size-1
|
230
|
+
step = +1
|
231
|
+
end
|
232
|
+
start.step(finish,step) do |i|
|
233
|
+
_insert1(value[i],flags)
|
234
|
+
end
|
235
|
+
nil
|
236
|
+
elsif (flags&Hold).nonzero?
|
237
|
+
flags ^= Hold
|
238
|
+
position { put(value,flags,&more) }
|
239
|
+
else
|
240
|
+
flags |= Single
|
241
|
+
if (flags&Reverse).nonzero?
|
242
|
+
start = value.size-1
|
243
|
+
finish = 0
|
244
|
+
step = -1
|
245
|
+
else
|
246
|
+
start = 0
|
247
|
+
finish = value.size-1
|
248
|
+
step = +1
|
249
|
+
end
|
250
|
+
if (flags&Read).nonzero?
|
251
|
+
value0 = data_class.new
|
252
|
+
replacing = true
|
253
|
+
start.step(finish,step) do |i|
|
254
|
+
v = _put1(value[i],flags) { |l|
|
255
|
+
replacing = more&&more[l]
|
256
|
+
}
|
257
|
+
value0 << v if replacing
|
258
|
+
end
|
259
|
+
if value0.size.zero?
|
260
|
+
nil
|
261
|
+
elsif step<0
|
262
|
+
value0.reverse
|
263
|
+
else
|
264
|
+
value0
|
265
|
+
end
|
266
|
+
else
|
267
|
+
len0 = 0
|
268
|
+
replacing = true
|
269
|
+
start.step(finish,step) do |i|
|
270
|
+
_put1(value[i],flags) { |l|
|
271
|
+
replacing = more&&more[l]
|
272
|
+
}
|
273
|
+
len0 += 1 if replacing
|
274
|
+
end
|
275
|
+
if len0.zero?
|
276
|
+
nil
|
277
|
+
else
|
278
|
+
len0
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
# This will return a numeric position. When not +reverse+,
|
284
|
+
# this numeric position is the number of elements from the beginning (0 is at the beginning). With
|
285
|
+
# +reverse+ it is negative and the number of elements from the end (-0.1 is at the end).
|
286
|
+
def pos(reverse=false,&code) # :yield:
|
287
|
+
flags = (reverse ? Prev : Next)|Ignore
|
288
|
+
ref = reverse ? End : Begin
|
289
|
+
p = get(Rest,flags^Reverse) or return(ref)
|
290
|
+
get(p,flags)==p or raise(IndexError,"couldn't get back to where we were: #{p}")
|
291
|
+
p = reverse ? -p : p
|
292
|
+
p+ref.to_i
|
293
|
+
end
|
294
|
+
# Returns #pos.to_i
|
295
|
+
def to_i
|
296
|
+
pos.to_i
|
297
|
+
end
|
298
|
+
# Returns "pos=#pos.to_s" followed by what's in prop in a reasonable format.
|
299
|
+
def to_s
|
300
|
+
s = "pos=#{pos.to_s}"
|
301
|
+
p = prop
|
302
|
+
if not p
|
303
|
+
elsif p.respond_to?:members
|
304
|
+
p.members.each { |m| s += " #{m}=#{p[m]}" }
|
305
|
+
elsif p.respond_to?:keys
|
306
|
+
p.keys.each { |k| s += " #{k}=#{p[k]}" }
|
307
|
+
elsif p.respond_to?:to_a
|
308
|
+
s += p.to_a.join(" ")
|
309
|
+
else
|
310
|
+
s += p.to_s
|
311
|
+
end
|
312
|
+
s
|
313
|
+
end
|
314
|
+
# Set #pos to be +p+. When +p+ is negative, it is set from the end.
|
315
|
+
def pos=(p)
|
316
|
+
reverse = p<Begin
|
317
|
+
flags = (reverse ? Prev : Next)|Ignore
|
318
|
+
ref = reverse ? End : Begin
|
319
|
+
p = (p-ref).round
|
320
|
+
p = reverse ? -p : p
|
321
|
+
get(Rest,flags^Reverse)
|
322
|
+
p.nonzero? or return(ref)
|
323
|
+
p = get(p,flags) or return(ref)
|
324
|
+
p = reverse ? -p : p
|
325
|
+
p+ref.to_i
|
326
|
+
end
|
327
|
+
# Get back what was stored by #prop=.
|
328
|
+
def prop
|
329
|
+
@prop
|
330
|
+
end
|
331
|
+
# Arbitrary data may be placed in here. It will be saved and restored by
|
332
|
+
# #position and friends.
|
333
|
+
def prop=(p)
|
334
|
+
@prop = p.clone if p
|
335
|
+
end
|
336
|
+
def _finalizer(id) # :nodoc:
|
337
|
+
i = @positions.index(id >> 1)
|
338
|
+
@positions.slice!(i) if i
|
339
|
+
end
|
340
|
+
protected :_finalizer
|
341
|
+
# These position* methods use a Cursor object (from Cursor::Position) to
|
342
|
+
# hold the #position rather than simply a numeric position that #pos and
|
343
|
+
# #pos= use. These Cursor::Position objects hold a #pos and whatever is
|
344
|
+
# in #prop. For now, the #pos in these objects do not adjust based on
|
345
|
+
# insertions and deletions, but that may change. So don't count
|
346
|
+
# Without +p+ or a code block, #position returns one of these objects to
|
347
|
+
# represent the current location of the cursor. With +p+ or a code block,
|
348
|
+
# the current #position is saved, the #position is set to +p+ using
|
349
|
+
# #position= (if +p+), the code block is executed (or the current #position
|
350
|
+
# is found with no code block), and the #position is returned to where it
|
351
|
+
# was saved (using #position=). The return value is the result of the code
|
352
|
+
# block or the #position if that was executed instead.
|
353
|
+
def position(p=nil,&code) # :yield:
|
354
|
+
if code or p
|
355
|
+
start = position
|
356
|
+
self.position = p if p
|
357
|
+
ret = code ? code[] : position
|
358
|
+
self.position = start
|
359
|
+
start.close
|
360
|
+
ret
|
361
|
+
else
|
362
|
+
p = Position.new(self,pos,prop)
|
363
|
+
@positions << (p.object_id >> 1)
|
364
|
+
ObjectSpace.define_finalizer(p,method(:_finalizer))
|
365
|
+
p
|
366
|
+
end
|
367
|
+
end
|
368
|
+
# Set the position to +p+. +p+ can be numeric (from #pos) or from #position.
|
369
|
+
def position=(p)
|
370
|
+
if p.respond_to?(:pos)
|
371
|
+
position?(p) or raise(TypeError,"invalid position #{p}")
|
372
|
+
self.pos = p.pos
|
373
|
+
self.prop = p.prop
|
374
|
+
else
|
375
|
+
self.pos = p
|
376
|
+
end
|
377
|
+
end
|
378
|
+
# Without a code block, this queries whether a particular #position +p+ is
|
379
|
+
# valid (is a child) or determines if there is any outstanding #position
|
380
|
+
# (when +p+=+nil+).
|
381
|
+
#
|
382
|
+
# With a code block, it sets optionally sets the #position= +p+ and
|
383
|
+
# and executes the code. If the result of the code is false/nil, it will
|
384
|
+
# return to the original #position (intially saved). Otherwise it will stay where the code
|
385
|
+
# left it. The result of the code block is returned. This is useful when
|
386
|
+
# you want the cursor to stay for a pass/match, and return to try something
|
387
|
+
# else for a fail/mismatch.
|
388
|
+
def position?(p=nil,&code) # :yield:
|
389
|
+
if code
|
390
|
+
start = position
|
391
|
+
self.position = p if p
|
392
|
+
ret = code[]
|
393
|
+
self.position = start if not ret
|
394
|
+
start.close
|
395
|
+
ret
|
396
|
+
elsif p
|
397
|
+
i = @positions.rindex(p.object_id >> 1)
|
398
|
+
if not i
|
399
|
+
return(true) if p.object_id==self.object_id
|
400
|
+
return(nil)
|
401
|
+
end
|
402
|
+
if p.closed?
|
403
|
+
@positions.slice!(i)
|
404
|
+
nil
|
405
|
+
else
|
406
|
+
true
|
407
|
+
end
|
408
|
+
else
|
409
|
+
while @positions.size>0
|
410
|
+
return(true) if not ObjectSpace._id2ref(@positions[0] << 1).closed?
|
411
|
+
@positions.shift
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
# Either discard/close the given #position +p+ or discard/close every child #position (+p+=+nil+).
|
416
|
+
def position!(p=nil)
|
417
|
+
if p
|
418
|
+
p.close
|
419
|
+
else
|
420
|
+
@positions.clone.each { |p| ObjectSpace._id2ref(p << 1).close }
|
421
|
+
end
|
422
|
+
self
|
423
|
+
end
|
424
|
+
# Close the cursor. This will also close every child #position.
|
425
|
+
def close
|
426
|
+
position!
|
427
|
+
# this should make just about any operation fail
|
428
|
+
instance_variables.each { |v| remove_instance_variable(v) }
|
429
|
+
nil
|
430
|
+
end
|
431
|
+
# Is the cursor closed?
|
432
|
+
def closed?
|
433
|
+
instance_variables.size.zero?
|
434
|
+
end
|
435
|
+
# Are we at the end? Or beginning if +reverse+.
|
436
|
+
def eof?(reverse=false)
|
437
|
+
not get(nil,(reverse ? Before : After)|Ignore)
|
438
|
+
end
|
439
|
+
alias eof eof?
|
440
|
+
# Compare +other+ (from #pos or #position) to the current position. +1
|
441
|
+
# for the self is after, -1 for self being before, and 0 for it being at
|
442
|
+
# same location.
|
443
|
+
def <=>(other)
|
444
|
+
if other.respond_to?:pos
|
445
|
+
position?(other) or return(nil)
|
446
|
+
other = other.pos
|
447
|
+
end
|
448
|
+
other.respond_to?:zero? or return(nil)
|
449
|
+
pos(other<0).to_i<=>other.to_i
|
450
|
+
end
|
451
|
+
alias === ==
|
452
|
+
# If +other+ is from #position, this will return the distance (number
|
453
|
+
# or elements) from +other+ to +self+. This can be +, -, or 0.
|
454
|
+
# Otherwise, a new #position is returned that is decreased by this amount
|
455
|
+
# (using #get).
|
456
|
+
def -(other)
|
457
|
+
if other.respond_to?:pos
|
458
|
+
position?(other) or return(nil)
|
459
|
+
other = other.pos
|
460
|
+
pos(other<0).to_i-other.to_i
|
461
|
+
elsif other.respond_to?:zero?
|
462
|
+
position { get(other,Prev|Ignore);position }
|
463
|
+
end
|
464
|
+
end
|
465
|
+
# Returns a new #position increased by +other+ (using #get).
|
466
|
+
def +(other)
|
467
|
+
position { get(other,Next|Ignore);position }
|
468
|
+
end
|
469
|
+
# Returns a Reversed cursor.
|
470
|
+
def reverse
|
471
|
+
Reversed.new(self)
|
472
|
+
end
|
473
|
+
alias -@ reverse
|
474
|
+
# Increments the cursor by +len+ (same +len+ of #get)
|
475
|
+
# Returns +nil+ at the end and self otherwise.
|
476
|
+
def succ!(len=nil); get(len,Next|Ignore) && self; end
|
477
|
+
# Decrements the cursor by +len+ (same +len+ of #get)
|
478
|
+
# Returns +nil+ at the beginning and self otherwise.
|
479
|
+
def pred!(len=nil); get(len,Prev|Ignore) && self; end
|
480
|
+
# Similar to #succ! except a new #position is returned instead of
|
481
|
+
# modifying the current.
|
482
|
+
def succ(len=nil); position { get(len,Next|Ignore) && position }; end
|
483
|
+
# Similar to #pred! except a new #position is returned instead of
|
484
|
+
# modifying the current.
|
485
|
+
def pred(len=nil); position { get(len,Prev|Ignore) && position }; end
|
486
|
+
# Go to the beginning
|
487
|
+
def begin!; get(Rest,Prev|Ignore); self; end
|
488
|
+
# Go to the end
|
489
|
+
def end!; get(Rest,Next|Ignore); self; end
|
490
|
+
# Similar to #first! except a new #position is returned instead of
|
491
|
+
# modifying the current.
|
492
|
+
def begin; position { get(Rest,Prev|Ignore);position }; end
|
493
|
+
# Similar to #last! except a new #position is returned instead of
|
494
|
+
# modifying the current.
|
495
|
+
def end; position { get(Rest,Next|Ignore);position }; end
|
496
|
+
# Returns the number of elements.
|
497
|
+
def size
|
498
|
+
l1 = position { get(Rest,Next|Ignore) } || 0
|
499
|
+
l0 = position { get(Rest,Prev|Ignore) } || 0
|
500
|
+
l0+l1
|
501
|
+
end
|
502
|
+
alias length size
|
503
|
+
# Determines whether there is anything before or after the cursor.
|
504
|
+
def empty?
|
505
|
+
get(nil,After |Ignore) and return(false)
|
506
|
+
get(nil,Before|Ignore) and return(false)
|
507
|
+
true
|
508
|
+
end
|
509
|
+
# Removes all elements and returns the number removed
|
510
|
+
def clear
|
511
|
+
(get(Rest,Next|Delete|Ignore)||0)+(get(Rest,Prev|Delete|Ignore)||0)
|
512
|
+
end
|
513
|
+
# If +obj+ is the #data_class, replace the all of the data with it. Otherwise
|
514
|
+
# use #position= +obj+. self is returned.
|
515
|
+
def replace(obj)
|
516
|
+
if data_class>=obj.class
|
517
|
+
clear
|
518
|
+
put(obj)
|
519
|
+
else
|
520
|
+
self.position = obj
|
521
|
+
end
|
522
|
+
self
|
523
|
+
end
|
524
|
+
# Get all of the data (beginning to the end)
|
525
|
+
def data
|
526
|
+
get(Rest,Prev|Ignore)
|
527
|
+
get(Rest,Next)
|
528
|
+
end
|
529
|
+
# Appends a single element at the end and returns self
|
530
|
+
def << (value)
|
531
|
+
get(Rest,Next|Ignore)
|
532
|
+
put(value,Next|Single)
|
533
|
+
self
|
534
|
+
end
|
535
|
+
# Prepends a single element at the beginning and returns self
|
536
|
+
def >> (value)
|
537
|
+
get(Rest,Prev|Ignore)
|
538
|
+
put(value,Prev|Single)
|
539
|
+
self
|
540
|
+
end
|
541
|
+
# like Array#first, except it takes a +len+
|
542
|
+
def first(len=nil)
|
543
|
+
get(Rest,Prev|Ignore)
|
544
|
+
get(len,Next)
|
545
|
+
end
|
546
|
+
# like Array#last, except it takes a +len+
|
547
|
+
def last(len=nil)
|
548
|
+
get(Rest,Next|Ignore)
|
549
|
+
get(len,Prev)
|
550
|
+
end
|
551
|
+
protected
|
552
|
+
def _index(index,len,flags) # :nodoc:
|
553
|
+
if index.respond_to?:exclude_end?
|
554
|
+
if index.first.respond_to?:zero? and (index.first<0)!=(index.last<0)
|
555
|
+
len = (size-index.last)-abs(index.first)
|
556
|
+
else
|
557
|
+
len = index.last-index.first
|
558
|
+
end
|
559
|
+
if index.exclude_end?
|
560
|
+
len = (len<0) ? len.floor : len.ceil
|
561
|
+
else
|
562
|
+
len = (len<0) ? len.to_i-1 : len.to_i+1
|
563
|
+
end
|
564
|
+
index = index.first
|
565
|
+
index += len if (flags&Reverse).nonzero?
|
566
|
+
end
|
567
|
+
self.position = index if index
|
568
|
+
[len,flags]
|
569
|
+
end
|
570
|
+
public
|
571
|
+
# Provides random access for the cursor like what is in Array/String.
|
572
|
+
# +index+ can be +nil+ (start at the current location), a numeric (possibly range)
|
573
|
+
# (just like Array/String), and even a range from start to end cursors.
|
574
|
+
# +len+ can be positive/0 (just like in Array/String), negative (goes
|
575
|
+
# in reverse), or even a matching sequence (passed to #get).
|
576
|
+
# +flags+ can take on the same things they can in get.
|
577
|
+
def slice(index=nil,len=nil,flags=After)
|
578
|
+
len,flags = _index(index,len,flags)
|
579
|
+
get(len,flags)
|
580
|
+
end
|
581
|
+
alias [] slice
|
582
|
+
alias at slice
|
583
|
+
# Random access slice! like in Array/String. Accepts the same enhancements
|
584
|
+
# for index, len, flags, and code block as #slice does (same except +Delete+
|
585
|
+
# bit is set).
|
586
|
+
def slice!(index=nil,len=nil,flags=After)
|
587
|
+
len,flags = _index(index,len,flags)
|
588
|
+
get(len,flags|Delete)
|
589
|
+
end
|
590
|
+
# Random access store like in Array/String. Accepts the same enhancements
|
591
|
+
# for index, len, and flags as #slice does.
|
592
|
+
def []=(*args) # :args: (index=nil,len=nil,flags=After,value)
|
593
|
+
value = args.slice!(-1)
|
594
|
+
index,len,flags = *args
|
595
|
+
flags ||= After
|
596
|
+
len,flags = _index(index,len,flags)
|
597
|
+
if not len
|
598
|
+
ret = put(value,flags|Single)
|
599
|
+
else
|
600
|
+
flags &= ~Single
|
601
|
+
ret = get(len,flags^Ignore|Delete)
|
602
|
+
put(value,flags|Insert)
|
603
|
+
end
|
604
|
+
if (flags&Read).nonzero?
|
605
|
+
ret
|
606
|
+
else
|
607
|
+
value
|
608
|
+
end
|
609
|
+
end
|
610
|
+
# copies data from one place to another. The default from and to indices are
|
611
|
+
# nil which is the current cursor location. All of the options of #slice
|
612
|
+
# are available for the indices, +len+, and flags.
|
613
|
+
def copy(from_index=nil,to_index=nil,len=nil,from_flags=After,to_flags=After)
|
614
|
+
if not to_index
|
615
|
+
value = position { self[from_index,len,from_flags] }
|
616
|
+
self[to_index,len,to_flags] = value
|
617
|
+
elsif not from_index
|
618
|
+
value = self[from_index,len,from_flags]
|
619
|
+
position { self[to_index,len,to_flags] = value }
|
620
|
+
else
|
621
|
+
self[to_index,len,to_flags] = self[from_index,len,from_flags]
|
622
|
+
end
|
623
|
+
end
|
624
|
+
# Performs each just to make this class Enumerable. Accepts the same enhancements
|
625
|
+
# for index, len, and flags as #slice does.
|
626
|
+
# The cursor will be left at the end (or beginning if the +Reverse+ flags bit is use).
|
627
|
+
# nil is returned (or the break value if the code does a break).
|
628
|
+
def each(index=Begin,len=nil,flags=Next,&code) # :yield: value
|
629
|
+
len,flags = _index(index,len,flags)
|
630
|
+
continue = true
|
631
|
+
loop do
|
632
|
+
value = get(len,flags) { continue = nil }
|
633
|
+
if not continue
|
634
|
+
code[value] if len and value
|
635
|
+
break
|
636
|
+
end
|
637
|
+
code[value]
|
638
|
+
end
|
639
|
+
end
|
640
|
+
# Same as #each except go in Reverse.
|
641
|
+
def reverse_each(index=End,len=nil,flags=Prev,&code) # :yield: value
|
642
|
+
each(index,len,flags,&code)
|
643
|
+
end
|
644
|
+
# Performs an in-place collect! (like Array#collect!). Accepts the same enhancements
|
645
|
+
# for index, len, and flags as #slice does.
|
646
|
+
# The cursor will be left at the end (or beginning if the +Reverse+ flags bit is use).
|
647
|
+
# nil is returned (or the break value if the code does a break).
|
648
|
+
def collect!(index=Begin,len=nil,flags=Next,&code) # :yield: value
|
649
|
+
len,flags = _index(index,len,flags)
|
650
|
+
continue = true
|
651
|
+
loop do
|
652
|
+
value = get(len,flags|Delete) { continue = nil }
|
653
|
+
if not continue
|
654
|
+
if len and value
|
655
|
+
value = code[value]
|
656
|
+
put(value,flags|Insert) if value
|
657
|
+
end
|
658
|
+
break
|
659
|
+
end
|
660
|
+
value = code[value]
|
661
|
+
put(value,flags|Insert|(len ? 0 : Single)) if value || !len
|
662
|
+
end
|
663
|
+
end
|
664
|
+
alias map! collect!
|
665
|
+
# Performs an in-place reject! (like Array#reject!). Accepts the same enhancements
|
666
|
+
# for index, len, and flags as #slice does.
|
667
|
+
# The cursor will be left at the end (or beginning if the +Reverse+ flags bit is use).
|
668
|
+
# nil is returned (or the break value if the code does a break).
|
669
|
+
def reject!(index=Begin,len=nil,flags=Next,&code) # :yield: value
|
670
|
+
len,flags = _index(index,len,flags)
|
671
|
+
continue = true
|
672
|
+
ret = nil
|
673
|
+
loop do
|
674
|
+
value = get(len,flags) { continue = nil }
|
675
|
+
if not continue
|
676
|
+
if len and value
|
677
|
+
if code[value]
|
678
|
+
get(len,flags^Reverse|Delete|Ignore)
|
679
|
+
ret = self
|
680
|
+
end
|
681
|
+
end
|
682
|
+
break
|
683
|
+
end
|
684
|
+
if code[value]
|
685
|
+
get(len,flags^Reverse|Delete|Ignore)
|
686
|
+
ret = self
|
687
|
+
end
|
688
|
+
end
|
689
|
+
ret
|
690
|
+
end
|
691
|
+
|
692
|
+
|
693
|
+
# Objects in this class are mainly used to simply mark/remember the location
|
694
|
+
# of a parent cursor. But, this class also has the fully functionality of the
|
695
|
+
# parent. When this child want to do an operation, it uses the parent to
|
696
|
+
# do it and returns the parent to where it was. Derived classes where the
|
697
|
+
# underlying data is random access may be able to implement this class to
|
698
|
+
# directly access the data rather than go through the parent.
|
699
|
+
class Position < Cursor
|
700
|
+
def initialize(parent,pos,prop)
|
701
|
+
@parent = parent
|
702
|
+
@pos,self.prop = pos,prop
|
703
|
+
end
|
704
|
+
def data_class
|
705
|
+
@parent.data_class
|
706
|
+
end
|
707
|
+
protected
|
708
|
+
def _pos(&code) # :nodoc:
|
709
|
+
start = @parent.pos,@parent.prop
|
710
|
+
@parent.pos,@parent.prop = @pos,self.prop
|
711
|
+
ret = code[]
|
712
|
+
@pos,self.prop = @parent.pos,@parent.prop
|
713
|
+
@parent.pos,@parent.prop = start
|
714
|
+
ret
|
715
|
+
end
|
716
|
+
public
|
717
|
+
def get(len=nil,flags=Next,&more) # :yield: l
|
718
|
+
_pos { @parent.get(len,flags,&more) }
|
719
|
+
end
|
720
|
+
def put(value,flags=Next,&more) # :yield: l
|
721
|
+
_pos { @parent.put(value,flags,&more) }
|
722
|
+
end
|
723
|
+
def pos(reverse=false)
|
724
|
+
if reverse
|
725
|
+
super(reverse)
|
726
|
+
else
|
727
|
+
@pos
|
728
|
+
end
|
729
|
+
end
|
730
|
+
def position(p=nil,&code) # :yield:
|
731
|
+
if p or code
|
732
|
+
super(p,&code)
|
733
|
+
else
|
734
|
+
_pos { @parent.position }
|
735
|
+
end
|
736
|
+
end
|
737
|
+
def position?(p=nil,&code) # :yield:
|
738
|
+
if code
|
739
|
+
super(p,&code)
|
740
|
+
else
|
741
|
+
@parent.position?(p)
|
742
|
+
end
|
743
|
+
end
|
744
|
+
def position!(p=nil)
|
745
|
+
if p
|
746
|
+
@parent.position!(p)
|
747
|
+
else
|
748
|
+
nil
|
749
|
+
end
|
750
|
+
end
|
751
|
+
def close
|
752
|
+
parent = @parent
|
753
|
+
super()
|
754
|
+
parent.position?(self)
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
# This class can be used to reverse the direction of operations on a given
|
759
|
+
# cursor. It operates on the given cursor directly moving it around.
|
760
|
+
class Reversed < Cursor
|
761
|
+
def initialize(cursor)
|
762
|
+
super()
|
763
|
+
@cursor = cursor
|
764
|
+
end
|
765
|
+
def data_class
|
766
|
+
@cursor.data_class
|
767
|
+
end
|
768
|
+
def get(len=nil,flags=Next,&more) # :yield: l
|
769
|
+
@cursor.get(len,flags^Reverse)
|
770
|
+
end
|
771
|
+
def put(value,flags=Next,&more) # :yield: l
|
772
|
+
@cursor.put(value,flags^Reverse,&more)
|
773
|
+
end
|
774
|
+
def pos(reverse=false,&code) # :yield:
|
775
|
+
if code
|
776
|
+
super(!reverse)
|
777
|
+
else
|
778
|
+
p = @cursor.pos(!reverse)
|
779
|
+
p = -p+Begin+End
|
780
|
+
end
|
781
|
+
end
|
782
|
+
def pos=(p)
|
783
|
+
reverse = p<Begin
|
784
|
+
p = -p+Begin+End
|
785
|
+
p = (@cursor.pos = p)
|
786
|
+
p = -p+Begin+End
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
# This class is used to test the base class by overriding as few methods
|
791
|
+
# as possible.
|
792
|
+
class Test < Cursor
|
793
|
+
def initialize(data=[],index=0)
|
794
|
+
super()
|
795
|
+
@data = data
|
796
|
+
@pos = index
|
797
|
+
@data_class = (@data.respond_to?:data_class) ?
|
798
|
+
@data.data_class : @data.class
|
799
|
+
end
|
800
|
+
def data_class
|
801
|
+
@data_class
|
802
|
+
end
|
803
|
+
def _delete1(flags,&more) # :yield: l=1
|
804
|
+
if (flags&Reverse).nonzero?
|
805
|
+
@pos>0 && (@pos -= 1)
|
806
|
+
else
|
807
|
+
@pos<@data.size
|
808
|
+
end or return(
|
809
|
+
if ret = more&&more[1]
|
810
|
+
(flags&Ignore).nonzero? ? true : ret[0]
|
811
|
+
end
|
812
|
+
)
|
813
|
+
if (flags&Ignore).nonzero?
|
814
|
+
@data[@pos,1] = @data_class.new
|
815
|
+
1
|
816
|
+
else
|
817
|
+
@data.slice!(@pos)
|
818
|
+
end
|
819
|
+
end
|
820
|
+
def _insert1(value,flags)
|
821
|
+
@data[@pos,0] = (@data_class.new << value)
|
822
|
+
@pos += 1 if (flags&Reverse).zero?
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
# This class puts a cursor on an Array or String.
|
827
|
+
class Indexed < Cursor
|
828
|
+
def initialize(data=[],index=0)
|
829
|
+
super()
|
830
|
+
@data = data
|
831
|
+
@pos = index
|
832
|
+
@data_class = (@data.respond_to?:data_class) ?
|
833
|
+
@data.data_class : @data.class
|
834
|
+
end
|
835
|
+
def data_class
|
836
|
+
@data_class
|
837
|
+
end
|
838
|
+
def _delete1(flags,&more) # :yield: l=1
|
839
|
+
if (flags&Reverse).nonzero?
|
840
|
+
@pos>0 && @pos -= 1
|
841
|
+
else
|
842
|
+
@pos<@data.size
|
843
|
+
end or return(
|
844
|
+
if ret = more&&more[1]
|
845
|
+
(flags&Ignore).nonzero? ? true : ret[0]
|
846
|
+
end
|
847
|
+
)
|
848
|
+
if (flags&Ignore).nonzero?
|
849
|
+
@data[@pos,1] = @data_class.new
|
850
|
+
true
|
851
|
+
else
|
852
|
+
@data.slice!(@pos)
|
853
|
+
end
|
854
|
+
end
|
855
|
+
def _insert1(value,flags)
|
856
|
+
@data[@pos,0] = (@data_class.new << value)
|
857
|
+
@pos += 1 if (flags&Reverse).zero?
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
861
|
+
# This class treats an IO (or StringIO) as a Cursor. An IO is already
|
862
|
+
# like a Cursor, but doesn't have as robust an interface. Deleting and
|
863
|
+
# inserting is a slow/painful process.
|
864
|
+
class IO < Cursor
|
865
|
+
def initialize(io=StringIO.new)
|
866
|
+
super()
|
867
|
+
@io = io
|
868
|
+
end
|
869
|
+
def data_class
|
870
|
+
String
|
871
|
+
end
|
872
|
+
def _delete1(flags,&more) # :yield: l=1
|
873
|
+
if (flags&Reverse).nonzero?
|
874
|
+
begin
|
875
|
+
@io.seek(-1,::IO::SEEK_CUR)
|
876
|
+
ret = @io.getc
|
877
|
+
rescue
|
878
|
+
ret = nil
|
879
|
+
end
|
880
|
+
else
|
881
|
+
ret = @io.getc
|
882
|
+
end or return(
|
883
|
+
if ret = more&&more[1]
|
884
|
+
(flags&Ignore).nonzero? ? true : ret[0]
|
885
|
+
end
|
886
|
+
)
|
887
|
+
ret = true if (flags&Ignore).nonzero?
|
888
|
+
after = 0
|
889
|
+
while c = @io.getc
|
890
|
+
after += 1
|
891
|
+
@io.seek(-2,::IO::SEEK_CUR)
|
892
|
+
@io.putc(c)
|
893
|
+
@io.seek(+1,::IO::SEEK_CUR)
|
894
|
+
end
|
895
|
+
@io.seek(-1,::IO::SEEK_CUR)
|
896
|
+
@io.truncate(@io.pos)
|
897
|
+
@io.seek(-after,::IO::SEEK_CUR) if after>0
|
898
|
+
ret
|
899
|
+
end
|
900
|
+
def _insert1(value,flags)
|
901
|
+
after = 0
|
902
|
+
while c = @io.getc
|
903
|
+
after += 1
|
904
|
+
@io.seek(-1,::IO::SEEK_CUR)
|
905
|
+
@io.putc(value)
|
906
|
+
value = c
|
907
|
+
end
|
908
|
+
@io.putc(value)
|
909
|
+
after += 1 if (flags&Reverse).nonzero?
|
910
|
+
@io.seek(-after,::IO::SEEK_CUR) if after>0
|
911
|
+
nil
|
912
|
+
end
|
913
|
+
def _get1(flags,&more) # :yield: l=1
|
914
|
+
if (flags&Reverse).nonzero?
|
915
|
+
begin
|
916
|
+
@io.seek(-1,::IO::SEEK_CUR)
|
917
|
+
rescue
|
918
|
+
return(
|
919
|
+
if ret = more&&more[1]
|
920
|
+
if (flags&Hold).nonzero?
|
921
|
+
flags ^= Hold
|
922
|
+
flags ^= Reverse
|
923
|
+
end
|
924
|
+
_insert(flags,ret=ret[0])
|
925
|
+
(flags&Ignore).nonzero? ? true : ret
|
926
|
+
end
|
927
|
+
)
|
928
|
+
end
|
929
|
+
if (flags&Ignore).nonzero?
|
930
|
+
@io.seek(+1,::IO::SEEK_CUR) if (flags&Hold).nonzero?
|
931
|
+
ret = true
|
932
|
+
else
|
933
|
+
ret = @io.getc
|
934
|
+
@io.seek(-1,::IO::SEEK_CUR) if (flags&Hold).zero?
|
935
|
+
end
|
936
|
+
else
|
937
|
+
if not ret = @io.getc
|
938
|
+
return(
|
939
|
+
if ret = more&&more[1]
|
940
|
+
@io.putc(ret=ret[0])
|
941
|
+
@io.seek(-1,::IO::SEEK_CUR) if (flags&Hold).nonzero?
|
942
|
+
(flags&Ignore).nonzero? ? true : ret
|
943
|
+
end
|
944
|
+
)
|
945
|
+
end
|
946
|
+
@io.ungetc(ret) if (flags&Hold).nonzero?
|
947
|
+
ret = true if (flags&Ignore).nonzero?
|
948
|
+
end
|
949
|
+
ret
|
950
|
+
end
|
951
|
+
def _put1(value,flags,&more) # :yield: l=1
|
952
|
+
if (flags&Reverse).nonzero?
|
953
|
+
begin
|
954
|
+
@io.seek(-1,::IO::SEEK_CUR)
|
955
|
+
rescue
|
956
|
+
if ret = more&&more[1]
|
957
|
+
ret = (flags&Read).zero? ? true : ret[0]
|
958
|
+
end
|
959
|
+
if (flags&Hold).nonzero?
|
960
|
+
flags ^= Hold
|
961
|
+
flags ^= Reverse
|
962
|
+
end
|
963
|
+
_insert1(value,flags)
|
964
|
+
return(ret)
|
965
|
+
end
|
966
|
+
if (flags&Read).nonzero?
|
967
|
+
ret = @io.getc
|
968
|
+
@io.ungetc(ret)
|
969
|
+
else
|
970
|
+
ret = true
|
971
|
+
end
|
972
|
+
@io.putc(value)
|
973
|
+
if (flags&Hold).zero?
|
974
|
+
@io.seek(-1,::IO::SEEK_CUR)
|
975
|
+
end
|
976
|
+
else
|
977
|
+
if (flags&Read).nonzero?
|
978
|
+
if not ret = @io.getc
|
979
|
+
if ret = more&&more[1]
|
980
|
+
ret = ret[0]
|
981
|
+
end
|
982
|
+
else
|
983
|
+
@io.ungetc(ret)
|
984
|
+
end
|
985
|
+
elsif @io.eof?
|
986
|
+
ret = more&&more[1]&&true
|
987
|
+
else
|
988
|
+
ret = true
|
989
|
+
end
|
990
|
+
@io.putc(value)
|
991
|
+
@io.seek(-1,::IO::SEEK_CUR) if (flags&Hold).nonzero?
|
992
|
+
end
|
993
|
+
ret
|
994
|
+
end
|
995
|
+
def close
|
996
|
+
@io.close
|
997
|
+
super()
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
|
1001
|
+
# This Cursor class uses an Array/String for data before the cursor
|
1002
|
+
# and another one for data after the cursor. The result of this is that
|
1003
|
+
# data is only deleted/inserted at the end of these 2. Because of that
|
1004
|
+
# most operations have similar expense and are linear with respect to the
|
1005
|
+
# number of elements being moved, inserted, deleted, replaced, etc.
|
1006
|
+
class Buffer < Cursor
|
1007
|
+
def initialize(before=[],after=before.class.new)
|
1008
|
+
super()
|
1009
|
+
@before = before
|
1010
|
+
@after = after
|
1011
|
+
@data_class = (@before.respond_to?:data_class) ?
|
1012
|
+
@before.data_class : @before.class
|
1013
|
+
end
|
1014
|
+
def data_class
|
1015
|
+
@data_class
|
1016
|
+
end
|
1017
|
+
def _delete1(flags,&more) # :yield: l=1
|
1018
|
+
data = (flags&Reverse).nonzero? ? @before : @after
|
1019
|
+
data.size>0 or return(
|
1020
|
+
if ret = more&&more[1]
|
1021
|
+
(flags&Ignore).nonzero? ? true : ret[0]
|
1022
|
+
end
|
1023
|
+
)
|
1024
|
+
if (flags&Ignore).nonzero?
|
1025
|
+
data[-1,1] = @data_class.new
|
1026
|
+
true
|
1027
|
+
else
|
1028
|
+
data.slice!(-1)
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
def _insert1(value,flags)
|
1032
|
+
data = (flags&Reverse).nonzero? ? @after : @before
|
1033
|
+
data << value
|
1034
|
+
end
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
# This Cursor class implements a circular buffer (not very efficient now). The beginning and end
|
1038
|
+
# are treated to be the current position. #pos/#position and friends really
|
1039
|
+
# don't make sense here (at least right now).
|
1040
|
+
class Circular < Cursor
|
1041
|
+
def initialize(data=[])
|
1042
|
+
super()
|
1043
|
+
@data = data
|
1044
|
+
@data_class = (@data.respond_to?:data_class) ?
|
1045
|
+
@data.data_class : @data.class
|
1046
|
+
end
|
1047
|
+
def data_class
|
1048
|
+
@data_class
|
1049
|
+
end
|
1050
|
+
def _delete1(flags,&more) # :yield: l=1
|
1051
|
+
@data.size>0 or return(
|
1052
|
+
if ret = more&&more[1]
|
1053
|
+
(flags&Ignore).nonzero? ? true : ret[0]
|
1054
|
+
end
|
1055
|
+
)
|
1056
|
+
index = (flags&Reverse).nonzero? ? -1 : 0
|
1057
|
+
if (flags&Ignore).nonzero?
|
1058
|
+
@data[index,1] = @data_class.new
|
1059
|
+
true
|
1060
|
+
else
|
1061
|
+
@data.slice!(index)
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
def _insert1(value,flags)
|
1065
|
+
if (flags&Reverse).nonzero?
|
1066
|
+
@data[0,0] = (@data_class.new << value)
|
1067
|
+
else
|
1068
|
+
@data << value
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
def get(len=nil,flags=Next,&more) # :yield: l
|
1072
|
+
if len==Rest
|
1073
|
+
nil
|
1074
|
+
else
|
1075
|
+
super(len,flags,&more)
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
def size
|
1079
|
+
@data.size
|
1080
|
+
end
|
1081
|
+
alias length size
|
1082
|
+
def clear
|
1083
|
+
@data.replace(@data_class.new)
|
1084
|
+
end
|
1085
|
+
def data
|
1086
|
+
@data.clone()
|
1087
|
+
end
|
1088
|
+
def replace(obj)
|
1089
|
+
if @data_class>=obj.class
|
1090
|
+
@data.replace(obj)
|
1091
|
+
else
|
1092
|
+
super(obj)
|
1093
|
+
end
|
1094
|
+
self
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
# This class gives unidirectional cursors (i.e. IO pipes) some
|
1100
|
+
# bidirectional capabilities. An input cursor and/or an output cursor
|
1101
|
+
# can be specified. The #position, #position?, and #position! methods are
|
1102
|
+
# used to control buffering. Full cursor capability (limited by the buffer
|
1103
|
+
# cursor) is accessible starting from the first #position. When the end of
|
1104
|
+
# the buffer is reached more data is read from the input cursor (if not nil) using #get . When no
|
1105
|
+
# #position is outstanding, everything before the buffer cursor is written
|
1106
|
+
# to the output cursor (if not nil) using #put. If the cursor is attempted
|
1107
|
+
# to be moved before the buffer, the output cursor is read in reverse (which
|
1108
|
+
# the output cursor may not like).
|
1109
|
+
class Buffered < Cursor
|
1110
|
+
def initialize(input,output=nil,buffer=Buffer.new((input||output).data_class.new))
|
1111
|
+
@input = input
|
1112
|
+
@output = output
|
1113
|
+
@buffer = buffer
|
1114
|
+
@offset = 0
|
1115
|
+
super()
|
1116
|
+
end
|
1117
|
+
def data_class
|
1118
|
+
@buffer.data_class
|
1119
|
+
end
|
1120
|
+
def get(len=nil,flags=Next,&more) # :yield: l
|
1121
|
+
value = @buffer.get(len,flags) { |l|
|
1122
|
+
if (flags&Reverse).nonzero?
|
1123
|
+
if @offset.zero?
|
1124
|
+
more&&more[l]
|
1125
|
+
else
|
1126
|
+
v = @output.get(l,Prev,&more)
|
1127
|
+
@offset -= v.size if v
|
1128
|
+
v
|
1129
|
+
end
|
1130
|
+
elsif @input
|
1131
|
+
@input.get(l,Next,&more)
|
1132
|
+
else
|
1133
|
+
more&&more[l]
|
1134
|
+
end
|
1135
|
+
}
|
1136
|
+
if not position?
|
1137
|
+
@offset = @buffer.pos+@offset
|
1138
|
+
if output_value = @buffer.get(Rest,Prev|Delete)
|
1139
|
+
@output.put(output_value,Next) if @output
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
value
|
1143
|
+
end
|
1144
|
+
def put(value,flags=Next,&more) # :yield: l
|
1145
|
+
value0 = @buffer.put(value,flags) { |l|
|
1146
|
+
if (flags&Reverse).nonzero?
|
1147
|
+
if @offset.zero?
|
1148
|
+
more&&more[l]
|
1149
|
+
else
|
1150
|
+
v = @output.get(l,Prev,&more)
|
1151
|
+
@offset -= v.size if v
|
1152
|
+
v
|
1153
|
+
end
|
1154
|
+
elsif @input
|
1155
|
+
@input.get(l,Next,&more)
|
1156
|
+
else
|
1157
|
+
more&&more[l]
|
1158
|
+
end
|
1159
|
+
}
|
1160
|
+
if not position?
|
1161
|
+
@offset = @buffer.pos+@offset
|
1162
|
+
if output_value = @buffer.get(Rest,Prev|Delete)
|
1163
|
+
@output.put(output_value,Next) if @output
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
value0
|
1167
|
+
end
|
1168
|
+
def pos(reverse=false,&code) # :yield:
|
1169
|
+
if code or reverse
|
1170
|
+
super(reverse,&code)
|
1171
|
+
else
|
1172
|
+
@buffer.pos+@offset
|
1173
|
+
end
|
1174
|
+
end
|
1175
|
+
def pos=(p)
|
1176
|
+
if p<Begin
|
1177
|
+
super(p)
|
1178
|
+
else
|
1179
|
+
p = p-@offset
|
1180
|
+
if p<Begin
|
1181
|
+
@buffer.pos = Begin
|
1182
|
+
get(-p,Prev|Ignore)
|
1183
|
+
@offset
|
1184
|
+
else
|
1185
|
+
(@buffer.pos = p)+@offset
|
1186
|
+
end
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
def close
|
1190
|
+
value = @buffer.get(Rest,Prev|Delete) and @output and
|
1191
|
+
@output.put(value,Next)
|
1192
|
+
value = @buffer.get(Rest,Next|Delete) and @output and
|
1193
|
+
@output.put(value,Next)
|
1194
|
+
super()
|
1195
|
+
end
|
1196
|
+
end
|
1197
|
+
|
1198
|
+
# This class tracks the current line and column. Both line and column
|
1199
|
+
# start at 0. When a newline is found, the line is incremented and the
|
1200
|
+
# column is reset. With other characters, the column is incremented.
|
1201
|
+
# The line and column numbers are only tracked when reading forward, but
|
1202
|
+
# using #position (and friends) will hold the line and column.
|
1203
|
+
class LineColumnNumbered < Cursor
|
1204
|
+
# Structure stored in the #prop attribute. line and column numbers
|
1205
|
+
# are accessed through #prop.line and #prop.column.
|
1206
|
+
LineColumn = Struct.new("LineColumn",:line,:column)
|
1207
|
+
# Create a new Cursor from another that tracks line and column.
|
1208
|
+
# +newline+ can be any valid argument for String#index (or the
|
1209
|
+
# index method for whatever the underlying #data_class is). For example,
|
1210
|
+
# +newline+=+/\n|\r(?!\n)/+ could be used for unix, mac, dos/cpm style
|
1211
|
+
# newlines.
|
1212
|
+
def initialize(cursor,newline="\n"[0])
|
1213
|
+
@cursor = cursor
|
1214
|
+
@newline = newline
|
1215
|
+
self.prop = LineColumn.new(0,0)
|
1216
|
+
super()
|
1217
|
+
end
|
1218
|
+
def get(len=nil,flags=Next,&more) # :yield: l
|
1219
|
+
ret = @cursor.get(len,flags,&more)
|
1220
|
+
if (flags&Ignore).zero? and (flags&Reverse).zero? and ret
|
1221
|
+
if not len
|
1222
|
+
if ret==@newline
|
1223
|
+
prop.line += 1
|
1224
|
+
prop.column = 0
|
1225
|
+
else
|
1226
|
+
prop.column += 1
|
1227
|
+
end
|
1228
|
+
else
|
1229
|
+
i0 = 0
|
1230
|
+
begin
|
1231
|
+
while i = index(@newline,i0)
|
1232
|
+
prop.line += 1
|
1233
|
+
prop.column = 0
|
1234
|
+
i0 = i+1
|
1235
|
+
end
|
1236
|
+
rescue
|
1237
|
+
#index with 2 args not supported
|
1238
|
+
i = i0
|
1239
|
+
while i<ret.size
|
1240
|
+
if @newline==ret[i]
|
1241
|
+
prop.line += 1
|
1242
|
+
prop.column = 0
|
1243
|
+
i0 = i+1
|
1244
|
+
end
|
1245
|
+
i += 1
|
1246
|
+
end
|
1247
|
+
end
|
1248
|
+
prop.column += ret.size-i0
|
1249
|
+
end
|
1250
|
+
end
|
1251
|
+
ret
|
1252
|
+
end
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
|