cursor 0.8 → 0.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/bin/env ruby
2
2
  # = cursor.rb - external iterators with capabilities like a text editor cursor
3
- # $Id: cursor.rb,v 1.53 2005/07/21 15:15:38 eric_mahurin Exp $
3
+ # $Id: cursor.rb,v 1.58 2005/10/14 00:22:58 eric_mahurin Exp $
4
4
  # Author:: Eric Mahurin (Eric under Mahurin at yahoo dot com)
5
5
  # License:: Ruby license
6
6
  # Home:: http://rubyforge.org/projects/cursor
@@ -50,7 +50,8 @@ to #==).
50
50
 
51
51
  #read, #read!, #skip, #skip!,
52
52
  #write, #write?,
53
- #scan, #scan_until, #scan_partial,
53
+ #scan, #scan_until
54
+ #scan_pattern, #scan_pattern_while, #scan_pattern_until
54
55
  #modify
55
56
 
56
57
  The methods below deal with numeric positions (a pos) to represent the cursor location.
@@ -60,22 +61,13 @@ end. Also included in this list below is #prop for manipulating properities
60
61
  for the current cursor location. One typical use is for tracking line and
61
62
  column numbers.
62
63
 
63
- #pos, #pos=, #to_i, #prop, #to_s,
64
+ #pos, #pos=, #pos?, #to_i, #prop, #to_s,
64
65
 
65
66
  The position methods below use a Cursor object (Cursor::Position in the base class) to
66
67
  hold the position rather than simply a numeric position. These
67
68
  position objects hold a #pos and whatever is
68
69
  in #prop. Also, the #pos in these objects adjust based on
69
- insertions and deletions. It is preferrable to use these position objects
70
- over numeric positions because
71
- a) derived classes may have a more efficient means of holding a position (i.e. linked list could hold a node reference),
72
- b) they may trigger things like buffering in derived classes,
73
- c) they hold what's in #prop,
74
- d) they adjust with insert/delete,
75
- e) when the numeric positions can't be implemented these methods still may, and
76
- f) the covenience of saving and possibly restoring position
77
- before/after executing a code block is available (should be implementable before
78
- any of the others).
70
+ insertions and deletions.
79
71
 
80
72
  #position, #position=, #position?, #position!,
81
73
  #close, #closed?
@@ -86,7 +78,7 @@ Return a remote #position: #+, #succ, #pred, #begin, #end
86
78
 
87
79
  Access the entire collection: #empty?, #length/#size, #data, #replace
88
80
 
89
- Random access: #[]/#slice, #slice!, #[]=, #<<, #>>
81
+ Random access: #[]/#slice, #slice!, #[]=, #<<, #>>, #concat, #prepend
90
82
 
91
83
  Enumerable: #each, #collect!/#map!
92
84
 
@@ -272,9 +264,12 @@ class Cursor
272
264
  def new_data
273
265
  @cursor.new_data
274
266
  end
275
- # read +len+ elements. A negative +len+ will go in reverse. +hold+ will
276
- # hold the cursor in place. +hold+==+nil+ (not false) will make it delete.
277
- def read(len,hold=false,buffer=new_data)
267
+ # read +len+ elements.
268
+ # A negative +len+ will go in reverse.
269
+ # +hold+ will hold the cursor in place.
270
+ # +hold+.nil? will make it delete.
271
+ def read(len,hold=false,buffer=nil)
272
+ buffer0 = buffer or buffer = new_data
278
273
  reverse = len<0
279
274
  len = len.abs
280
275
  meth = method(hold.nil? ?
@@ -282,35 +277,39 @@ class Cursor
282
277
  (reverse ? :read1prev : :read1next) )
283
278
  len0 = 0
284
279
  while len>len0
285
- (v0 = meth.call).nil? and return(
280
+ (v0 = meth.call).nil? and (
286
281
  skip(reverse ? len0 : -len0) if hold
287
- len0.nonzero?&&buffer
282
+ return len0.nonzero?&&(buffer0 ? len0 : buffer)
288
283
  )
289
284
  buffer << v0
290
285
  len0 += 1
291
286
  end
292
287
  skip(reverse ? len0 : -len0) if hold
293
- buffer
288
+ buffer0 ? len0 : buffer
294
289
  end
295
- # read the remaining elements. +hold+ will
296
- # hold the cursor in place. +hold+==+nil+ (not false) will make it delete.
297
- def read!(reverse=false,hold=false,buffer=new_data)
290
+ # read the remaining elements.
291
+ # +hold+ will hold the cursor in place.
292
+ # +hold+.nil? will make it delete.
293
+ def read!(reverse=false,hold=false,buffer=nil)
294
+ buffer0 = buffer or buffer = new_data
298
295
  meth = method(hold.nil? ?
299
296
  (reverse ? :delete1before? : :delete1after?) :
300
297
  (reverse ? :read1prev : :read1next) )
301
298
  len0 = 0
302
299
  loop do
303
- (v0 = meth.call).nil? and return(
300
+ (v0 = meth.call).nil? and (
304
301
  skip(reverse ? len0 : -len0) if hold
305
- len0.nonzero?&&buffer
302
+ return len0.nonzero? && (buffer0 ? len0 : buffer)
306
303
  )
307
304
  buffer << v0
308
305
  len0 += 1
309
306
  end
310
307
  end
311
- # skip +len+ elements and return the count. A negative +len+ will go in
312
- # reverse. +hold+ will
313
- # hold the cursor in place. +hold+==+nil+ (not false) will make it delete.
308
+ # skip +len+ elements.
309
+ # A negative +len+ will go in reverse.
310
+ # +hold+ will hold the cursor in place.
311
+ # +hold+.nil? will make it delete.
312
+ # The amount skipped is returned (<+len+ if reached beginning/end).
314
313
  def skip(len,hold=false)
315
314
  reverse = len<0
316
315
  len = len.abs
@@ -319,34 +318,41 @@ class Cursor
319
318
  (reverse ? :skip1prev : :skip1next) )
320
319
  len0 = 0
321
320
  while len>len0
322
- meth.call or return(
321
+ meth.call or (
323
322
  skip(reverse ? len0 : -len0) if hold
324
- len0.nonzero?
323
+ return len0.nonzero?
325
324
  )
326
325
  len0 += 1
327
326
  end
328
327
  skip(reverse ? len0 : -len0) if hold
329
328
  len0
330
329
  end
331
- # skip the remaining elements and return the count. A negative +len+ will go in
332
- # reverse. +hold+ will hold the cursor in place. +hold+==+nil+ (not false)
333
- # will make it delete.
330
+ # skip the remaining elements.
331
+ # A negative +len+ will go in reverse.
332
+ # +hold+ will hold the cursor in place.
333
+ # +hold+.nil? will make it delete.
334
+ # The amount skipped is returned.
334
335
  def skip!(reverse=false,hold=false)
335
336
  meth = method(hold.nil? ?
336
337
  (reverse ? :delete1before : :delete1after) :
337
338
  (reverse ? :skip1prev : :skip1next) )
338
339
  len0 = 0
339
340
  loop do
340
- meth.call or return(
341
+ meth.call or (
341
342
  skip(reverse ? len0 : -len0) if hold
342
- len0.nonzero?
343
+ return len0.nonzero?
343
344
  )
344
345
  len0 += 1
345
346
  end
346
347
  end
347
- # write a sequence of elements and return the overwrite count. +hold+ will
348
- # hold the cursor in place. +hold+==+nil+ (not false) will make it insert.
348
+ # write a sequence of elements (+value+).
349
+ # +hold+ will hold the cursor in place.
350
+ # +hold+.nil? will make it insert.
349
351
  # +overwrite_only+ will prevent insertion when the cursor is at the beginning/end.
352
+ # When the entire +value+ is written, the length is returned.
353
+ # When nothing of the +value+ could be written, +nil+ is returned.
354
+ # When a portion of +value+ is written, the negative of the length written
355
+ # is returned.
350
356
  def write(value,reverse=false,hold=false,overwrite_only=false)
351
357
  meth = method(
352
358
  hold.nil? ? (reverse ? :insert1after : :insert1before) :
@@ -354,53 +360,68 @@ class Cursor
354
360
  (reverse ? :write1prev! : :write1next!) )
355
361
  i = 0
356
362
  until (v = value[i]).nil?
357
- meth.call(v) or return(
363
+ meth.call(v) or (
358
364
  skip(reverse ? i : -i) if hold
359
- i.nonzero?
365
+ return (-i).nonzero?
360
366
  )
361
367
  i += 1
362
368
  end
363
369
  skip(reverse ? i : -i) if hold
364
370
  i
365
371
  end
366
- # overwrite a sequence of elements and return the sequence overwritten.
372
+ # overwrite a sequence of elements while reading what is overwritten.
373
+ # and return the sequence overwritten.
367
374
  # +hold+ will hold the cursor in place.
368
- def write?(value,reverse=false,hold=false,buffer=value.class.new)
375
+ def write?(value,reverse=false,hold=false,buffer=nil)
376
+ buffer0 = buffer or buffer = new_data
369
377
  meth = method(reverse ? :write1prev? : :write1next?)
370
378
  i = 0
371
379
  until (v = value[i]).nil?
372
- (v0 = meth.call(v)).nil? and return(
380
+ (v0 = meth.call(v)).nil? and (
373
381
  skip(reverse ? i : -i) if hold
374
- i.nonzero? && buffer
382
+ return i.nonzero? && (buffer0 ? -i : buffer)
375
383
  )
376
384
  buffer << v0
377
385
  i += 1
378
386
  end
379
387
  skip(reverse ? i : -i) if hold
380
- buffer
381
- end
382
- # scan for +value+ at the cursor. When there is a mismatch, +nil+ is returned
383
- # and the cursor is move back to where it started (unless hold==+nil+:
384
- # cursor position will indeterminate).
385
- # +hold+ will hold the cursor in place even on a match.
386
- def scan(value,reverse=false,hold=false,buffer=value.class.new)
387
- meth = method(reverse ? :read1prev : :read1next)
388
+ buffer0 ? i : buffer
389
+ end
390
+ # scan for the sequence +value+. Will terminate on the first mismatching
391
+ # element and leave the cursor at that mismatched element.
392
+ # Without +buffer+, the matching sequence found will be returned.
393
+ # With +buffer+, an integer will be returned where its absolute value is the
394
+ # number of elements matched. Positive means the entire sequence matched
395
+ # and negative means only part of the sequence matched.
396
+ # If there is a mismatch on the very first element, +nil+ is returned
397
+ # (regardless of +buffer+).
398
+ def scan(value,reverse=false,hold=false,buffer=nil)
399
+ buffer0 = buffer or buffer = new_data
400
+ meth = method(reverse ? :scan1prev : :scan1next)
388
401
  i = 0
389
402
  until (v = value[i]).nil?
390
- v0 = meth.call
391
- (!v0.nil? and i += 1 and v==v0) or return(
392
- skip(reverse ? i : -i) if !hold.nil?
393
- nil
403
+ v0 = meth.call(v)
404
+ !v0.nil? or (
405
+ skip(reverse ? i : -i) if hold
406
+ return i.nonzero? && (buffer0 ? -i : buffer)
394
407
  )
395
408
  buffer << v0
409
+ i += 1
396
410
  end
397
411
  skip(reverse ? i : -i) if hold
398
- buffer
399
- end
400
- # scan for +value+ until it is found (or the end is reached) and
401
- # return that entire sequence. +hold+ will
402
- # hold the cursor in place. +hold+==+nil+ (not false) will make it delete.
403
- def scan_until(value,reverse=false,hold=false,buffer=value.class.new)
412
+ buffer0 ? i : buffer
413
+ end
414
+ # scan for +value+ until it is found (or the beginning/end is reached).
415
+ # +hold+.nil? will make it delete instead of read.
416
+ # Without +buffer+, sequence (including what +value+ matched) will be
417
+ # returned (or +nil+ if started at the beginning/end).
418
+ # With +buffer+, the length of the sequence scanned and the final index of
419
+ # +value+ is returned. If the cursor started at the beginnning/end,
420
+ # +nil+ will be returned in place of the sequence length. If the entire
421
+ # +value+ is not found (beginning/end reached), the index will be <=0 and
422
+ # its absolute value is the index of the mismatch.
423
+ def scan_until(value,reverse=false,hold=false,buffer=nil)
424
+ buffer0 = buffer or buffer = new_data
404
425
  meth = method(hold.nil? ?
405
426
  (reverse ? :delete1before? : :delete1after?) :
406
427
  (reverse ? :read1prev : :read1next) )
@@ -408,9 +429,13 @@ class Cursor
408
429
  len0 = 0
409
430
  i = 0
410
431
  until (v = value[i]).nil?
411
- (v0 = meth.call).nil? and return(
432
+ (v0 = meth.call).nil? and (
412
433
  skip(reverse ? len0 : -len0) if hold
413
- len0.nonzero?&&buffer
434
+ if buffer0
435
+ return len0.nonzero?,-i
436
+ else
437
+ return len0.nonzero? && buffer
438
+ end
414
439
  )
415
440
  buffer << v0
416
441
  buffer2 << v0
@@ -426,41 +451,166 @@ class Cursor
426
451
  end
427
452
  end
428
453
  skip(reverse ? len0 : -len0) if hold
429
- buffer
454
+ if buffer0
455
+ return len0,i
456
+ else
457
+ return buffer
458
+ end
430
459
  end
431
- # scan for +value+ and return as much of the sequence that matched
432
- def scan_partial(value,reverse=false,hold=false,buffer=value.class.new)
433
- meth = method(reverse ? :scan1prev : :scan1next)
434
- i = 0
435
- until (v = value[i]).nil?
436
- v0 = meth.call(v)
437
- !v0.nil? or return(
438
- skip(reverse ? i : -i) if hold
439
- i.nonzero?&&buffer
460
+ # scan for +pattern+ at the cursor.
461
+ # +pattern+ should #match no more than than +len+ (< 0 goes in reverse) elements.
462
+ # Although +pattern+ is implicitly anchored to the current cursor location
463
+ # (\A) the current implementation is more efficient with the anchor explicit.
464
+ # +pattern+ should not use any end anchors (\Z or $).
465
+ # +pattern+.match should return a MatchData like object that needs
466
+ # to respond to #offset(0).
467
+ # An array of the what matched and this MatchData object is returned
468
+ # (or nil upon mismatch).
469
+ # #post_match isn't valid in this MatchData object.
470
+ # The cursor is advanced to right after the match unless there is mismatch or
471
+ # the cursor is requested to +hold+ position.
472
+ def scan_pattern(pattern,len=1,hold=false,buffer=nil)
473
+ reverse = len<0
474
+ matchbuffer = new_data
475
+ matchbuffer_len = read(len,false,matchbuffer) or return
476
+ (matchdata = pattern.match(matchbuffer) and
477
+ (b,e = matchdata.offset(0);b.zero?)) or (
478
+ skip(reverse ? +matchbuffer_len : -matchbuffer_len)
479
+ return
480
+ )
481
+ back_len = matchbuffer_len-e
482
+ matchbuffer.slice!(e,back_len)
483
+ back_len += e if hold
484
+ skip(reverse ? +back_len : -back_len)
485
+ if buffer
486
+ buffer.concat(matchbuffer)
487
+ matchdata
488
+ else
489
+ matchbuffer
490
+ end
491
+ end
492
+ # scan until +pattern+ is found.
493
+ # +pattern+ should need no more than +len+ (<0 goes in reverse) elements
494
+ # to determine a match.
495
+ # Initially, a sequence of +init+*+len+ elements is read to be matched.
496
+ # Until the +pattern+ matches the buffer, more data is read and tried to be
497
+ # matched with +pattern+.
498
+ # +pattern+.match should return a MatchData like object that needs
499
+ # to respond to #offset(0).
500
+ # An array of the prematch, what matched, and this
501
+ # MatchData object is returned (or nil upon mismatch).
502
+ # #post_match and #pre_match aren't valid in this MatchData object.
503
+ # The cursor is advanced to right after the match unless there is mismatch or
504
+ # the cursor is requested to +hold+ position.
505
+ def scan_pattern_until(pattern,len=1,hold=false,buffer=nil,init=16)
506
+ buffer0 = buffer or buffer = new_data
507
+ reverse = len<0
508
+ read_len = len*init
509
+ len = -len if reverse
510
+ matchbuffer = new_data
511
+ buffer_len = 0
512
+ matchbuffer_len = 0
513
+ read_len1 = read(read_len,false,matchbuffer) or (
514
+ if buffer0
515
+ return nil,nil,nil
516
+ else
517
+ return nil
518
+ end
519
+ )
520
+ matchbuffer_len += read_len1
521
+ until matchdata = pattern.match(matchbuffer)
522
+ matchbuffer_len>=len and (
523
+ buffer.concat(matchbuffer.slice!(0,matchbuffer_len-len+1))
524
+ buffer_len += matchbuffer_len-len+1
525
+ matchbuffer_len = len-1
526
+ read_len *= 2
527
+ read_len1 = read(read_len,false,matchbuffer)) or (
528
+ buffer.concat(matchbuffer)
529
+ buffer_len += matchbuffer_len
530
+ skip(reverse ? +buffer_len : -buffer_len) if hold
531
+ if buffer0
532
+ return buffer_len,nil,nil
533
+ else
534
+ return buffer
535
+ end
440
536
  )
441
- buffer << v0
442
- i += 1
537
+ p self
538
+ matchbuffer_len += read_len1
539
+ end
540
+ b,e = matchdata.offset(0)
541
+ back_len = matchbuffer_len-e
542
+ matchbuffer.slice!(e,back_len)
543
+ buffer.concat(matchbuffer)
544
+ buffer_len += e
545
+ back_len += buffer_len if hold
546
+ skip(reverse ? +back_len : -back_len)
547
+ if buffer0
548
+ return buffer_len-(e-b),buffer_len,matchdata
549
+ else
550
+ return buffer
443
551
  end
444
- skip(reverse ? i : -i) if hold
445
- buffer
446
552
  end
447
- # modify elements using +lookup+[orignalElement] until that returns nil
448
- def modify(lookup,reverse=false,hold=false,buffer=new_data)
449
- meth = method(reverse ? :modify1prev : :modify1next)
450
- len0 = 0
451
- until (v0 = meth.call(lookup)).nil?
452
- buffer << v0
453
- len0 += 1
553
+ # scan while +pattern+ matches more data.
554
+ # +pattern+ should be a zero or more ("*") loop with the maximum match
555
+ # length per iteration being +len+ (< 0 goes in reverse).
556
+ # +pattern+ should not use any anchors (\A, \Z, or $).
557
+ # Initially, a sequence of +init+*+len+ elements is read to be matched.
558
+ # As long as the pattern matches more data, more data is read to be matched
559
+ # with the pattern.
560
+ # +pattern+.match should return a MatchData like object that needs
561
+ # to respond to #offset(0).
562
+ # An array of the what matched and this
563
+ # MatchData object is returned (or nil for a mismatch or empty match).
564
+ # #post_match, #pre_match, everything related to #[0] aren't valid in this
565
+ # MatchData object.
566
+ # The cursor is advanced to right after the match unless there is mismatch or
567
+ # the cursor is requested to +hold+ position.
568
+ def scan_pattern_while(pattern,len=1,hold=false,buffer=nil,init=16)
569
+ buffer0 = buffer or buffer = new_data
570
+ reverse = len<0
571
+ read_len = len*init
572
+ len = -len if reverse
573
+ matchbuffer = new_data
574
+ buffer_len = 0
575
+ matchbuffer_len = 0
576
+ while matchbuffer_len<len and
577
+ read_len1 = read(read_len,false,matchbuffer) and
578
+ matchbuffer_len += read_len1 and
579
+ matchdata = pattern.match(matchbuffer) and
580
+ (b,e = matchdata.offset(0);b.zero? and e.nonzero?)
581
+ buffer.concat(matchbuffer.slice!(0,e))
582
+ buffer_len += e
583
+ matchbuffer_len -= e
584
+ read_len *= 2
585
+ end
586
+ back_len = matchbuffer_len+(hold ? buffer_len : 0)
587
+ skip(reverse ? +back_len : -back_len)
588
+ if buffer0
589
+ buffer_len.nonzero?
590
+ else
591
+ buffer_len.nonzero? and buffer
454
592
  end
455
- skip(reverse ? len0 : -len0) if hold
456
- buffer
457
593
  end
458
594
 
459
- # This will return a numeric position. When not +reverse+,
595
+ # Without a block, this will return a numeric position. When not +reverse+,
460
596
  # this numeric position is the number of elements from the beginning (0 is at the beginning). With
461
597
  # +reverse+ it is negative and the number of elements from the end (-0.0 is at the end).
462
- def pos(reverse=false)
463
- reverse ? -(skip!(false,true)||0.0) : (skip!(true,true)||0)
598
+ # With a code block, it will execute some code and come back to where the
599
+ # cursor started. The result of the block will be returned.
600
+ # Within the block, no operations that insert or delete elements
601
+ # before (or after if +reverse+) the starting cursor location should be executed.
602
+ # The cursor will be left in an unknown location if that happens.
603
+ def pos(reverse=false,&code) # :yield:
604
+ p = reverse ? -(skip!(false,true)||0.0) : (skip!(true,true)||0)
605
+ if code
606
+ begin
607
+ code[]
608
+ ensure
609
+ self.pos = p
610
+ end
611
+ else
612
+ p
613
+ end
464
614
  end
465
615
  # Returns #pos.to_i
466
616
  def to_i
@@ -474,6 +624,23 @@ class Cursor
474
624
  len.to_i.abs==skip(len) or raise(IndexError,"invalid pos=#{p}")
475
625
  p
476
626
  end
627
+ # Without a block, this checks to see if p is a valid numeric position.
628
+ # With a block, it will execute the block and come back to where the cursor
629
+ # started if the result of the block was +false+/+nil+. The result of the
630
+ # block will be returned. The restrictions on the #pos block also apply here.
631
+ def pos?(p=false,&code) # :yield:
632
+ if code
633
+ p = pos(p)
634
+ begin
635
+ ret = code[]
636
+ ensure
637
+ self.pos = p if !ret
638
+ end
639
+ else
640
+ len = p-pos((p.nonzero?||1.0/p)<0)
641
+ len.to_i.abs==skip(len,true)
642
+ end
643
+ end
477
644
  # Get (no +value+) and set cursor properties. Normally, +name+
478
645
  # should be a symbol. If +name+ is +nil+, it wil get/set using a hash
479
646
  # representing all of the properties.
@@ -506,7 +673,9 @@ class Cursor
506
673
  # represent the current location of the cursor. When +reverse+, it will
507
674
  # anchor the #position to the element after. Otherwise it will anchor it
508
675
  # to the element before. This anchoring is used when an insertion occurs at
509
- # that point affecting how this position is adjusted.
676
+ # that point affecting how this position is adjusted. If the element that a
677
+ # #position is anchored to is deleted, that #position may become invalid
678
+ # or have an unknown behavior.
510
679
  #
511
680
  # With a code block, it saves the #position (also using +reverse+),
512
681
  # executes the code block, and returns the #position to where it
@@ -544,7 +713,7 @@ class Cursor
544
713
  # left it. The result of the code block is returned. This is useful when
545
714
  # you want the cursor to stay for a pass/match, and return to try something
546
715
  # else for a fail/mismatch.
547
- def position?(p=nil,&code) # :yield:
716
+ def position?(p=false,&code) # :yield:
548
717
  if code
549
718
  start = position(p)
550
719
  begin
@@ -556,26 +725,19 @@ class Cursor
556
725
  start.close
557
726
  end
558
727
  end
559
- elsif p
560
- @positions && @positions.include?(p) || equal?(p) || nil
561
728
  else
562
- @positions && (!@positions.empty? || nil)
729
+ @positions && @positions.include?(p) || equal?(p) || false
563
730
  end
564
731
  end
565
- # Discard/close every child #position (+p+=+nil+) or discard (not close)
566
- # the give +p+ (you probably want +p+.close instead).
567
- def position!(p=nil)
568
- if p
569
- @positions.delete(p)
570
- elsif @positions
571
- @positions.each { |p| p.close }
572
- remove_instance_variable(:@positions)
573
- end
732
+ # Delete +p+ from the list of children (from #position).
733
+ # Should only be used by child #position.
734
+ def _delete_position(p) # :nodoc:
735
+ @positions.delete(p)
574
736
  self
575
737
  end
576
- # Close the cursor. This will also close every child #position.
738
+ # Close the cursor. This will also close/invalidate every child #position.
577
739
  def close
578
- position!
740
+ @positions and @positions.each { |p| p.close }
579
741
  # this should make just about any operation fail
580
742
  instance_variables.each { |v| instance_variable_set(v,nil) }
581
743
  nil
@@ -598,24 +760,24 @@ class Cursor
598
760
  end
599
761
  # Returns a new #position increased by +len+ (positive or negative).
600
762
  def +(len)
601
- position { skip(len);position((len.nonzero?||1.0/len)<0) }
763
+ pos { skip(len);position((len.nonzero?||1.0/len)<0) }
602
764
  end
603
765
 
604
766
  # Return a new #position for next cursor location or +nil+ if we are at the end.
605
767
  def succ
606
- position { skip1next && position(false) }
768
+ pos(false) { skip1next && position(false) }
607
769
  end
608
770
  # Return a new #position for previous cursor location or +nil+ if we are at the beginning.
609
771
  def pred
610
- position { skip1prev && position(true) }
772
+ pos(true) { skip1prev && position(true) }
611
773
  end
612
774
  # Return a new #position for the beginning.
613
775
  def begin
614
- position { skip!(true);position(false) }
776
+ pos(false) { skip!(true);position(false) }
615
777
  end
616
778
  # Return a new #position for the end.
617
779
  def end
618
- position { skip!(false);position(true) }
780
+ pos(true) { skip!(false);position(true) }
619
781
  end
620
782
  # Returns the number of elements.
621
783
  def size
@@ -631,55 +793,83 @@ class Cursor
631
793
  (skip!(false,nil)||0)+(skip!(true,nil)||0)
632
794
  end
633
795
  # Replace the all of the data and return self.
634
- def replace(obj)
796
+ def replace(value,reverse=false)
635
797
  clear
636
- write(obj,false,nil)
798
+ write(value,reverse,nil)
637
799
  self
638
800
  end
639
- # Get all of the data and leave the cursor at the end.
640
- def data
641
- skip!(true)
642
- read!(false)
801
+ # Get all of the data.
802
+ def data(reverse=false)
803
+ pos { skip!(!reverse);read!(reverse) }
643
804
  end
644
805
  # Appends a single element at the end and returns self.
645
806
  def << (v)
646
- skip!(false)
647
- insert1before(v)
807
+ pos(false) { skip!(false);write1next!(v) }
648
808
  self
649
809
  end
650
810
  # Prepends a single element at the beginning and returns self.
651
811
  def >> (v)
652
- skip!(true)
653
- insert1after(v)
812
+ pos(true) { skip!(true);write1prev!(v) }
813
+ self
814
+ end
815
+ # Appends a sequence to the end and returns self.
816
+ def concat(value)
817
+ pos(false) { skip!(false);write(value,false) }
818
+ self
819
+ end
820
+ # Prepends a sequence to the beginning and returns self.
821
+ def prepend(value)
822
+ pos(true) { skip!(true);write(value,true) }
823
+ self
824
+ end
825
+ def push(v)
826
+ pos(false) { skip!(false);write1next!(v) }
827
+ self
828
+ end
829
+ def unshift(v)
830
+ pos(true) { skip!(true);write1prev!(v) }
654
831
  self
655
832
  end
833
+ def pop
834
+ pos(false) { skip!(false);delete1before? }
835
+ end
836
+ def shift
837
+ pos(true) { skip!(true);delete1after? }
838
+ end
839
+ def first
840
+ pos(true) { skip!(true);read1next }
841
+ end
842
+ def last
843
+ pos(false) { skip!(false);read1prev }
844
+ end
656
845
 
657
846
  # Provides random access for the cursor like what is in Array/String.
658
847
  # +index+ can be +nil+ (start at the current location) or a numeric (for #pos=).
659
848
  # +len+ can be +nil+ (get a single element) or the number of elements to
660
- # #read (positive or negative). The cursor is left at +index+ (or not
661
- # moved if +nil+).
849
+ # #read (positive or negative). The cursor is left at where the access
850
+ # started (+index+==nil : no chnage, or +index).
662
851
  def slice(index=nil,len=nil)
663
852
  self.pos = index if index
664
- len.nil? ? read1after : read(len,true)
853
+ len ? read(len,true) : read1after
665
854
  end
666
855
  alias [] slice
667
856
  # Like #slice except the element(s) are deleted.
668
857
  def slice!(index=nil,len=nil)
669
858
  self.pos = index if index
670
- len.nil? ? delete1after? : read(len,nil)
859
+ len ? read(len,nil) : delete1after?
671
860
  end
672
861
  # Similar to #slice except data is written. +index+ and +len+ have the
673
- # same meaning as they do in #slice. +value+ is written using #write.
862
+ # same meaning as they do in #slice. +len+ elements are deleted and +value+
863
+ # is inserted.
674
864
  def []=(*args) # :args: (index=nil,len=nil,value)
675
865
  value = args.slice!(-1)
676
866
  index,len = *args
677
867
  self.pos = index if index
678
- if len.nil?
679
- write1after!(value)
680
- else
868
+ if len
681
869
  skip(len,nil)
682
- write(value,(len.nonzero?||1.0/len)>=0,nil)
870
+ write(value,(len.nonzero?||1.0/len)<0,nil)
871
+ else
872
+ write1after!(value)
683
873
  end
684
874
  value
685
875
  end
@@ -690,7 +880,7 @@ class Cursor
690
880
  # #scan_until(+terminator+) instead of using a single element.
691
881
  # The cursor will be left at the end (or beginning if +reverse+).
692
882
  # nil is returned (or the break value if the code does a break).
693
- def each(index=+0.0,reverse=false,terminator=nil,&code) # :yield: value
883
+ def each(index=0,reverse=false,terminator=nil,&code) # :yield: value
694
884
  self.pos = index if index
695
885
  continue = true
696
886
  if terminator.nil?
@@ -713,7 +903,7 @@ class Cursor
713
903
  # When the code returns +nil+ the element/sequence will be deleted.
714
904
  # Accepts the same enhancements as #each does.
715
905
  # nil is returned (or the break value if the code does a break).
716
- def collect!(index=+0.0,reverse=false,terminator=nil,&code) # :yield: value
906
+ def collect!(index=0,reverse=false,terminator=nil,&code) # :yield: value
717
907
  self.pos = index if index
718
908
  continue = true
719
909
  if terminator.nil?