Class: List::Matcher::Sequence

Inherits:
Node
  • Object
show all
Defined in:
lib/list_matcher.rb

Instance Attribute Summary

Attributes inherited from Node

#engine, #optional, #root, #symbols

Instance Method Summary collapse

Methods inherited from Node

#atomic?, #bound, #children, #finalize, #optional?, #pfx, #qmark, #quote, #root?, #wrap

Constructor Details

#initialize(engine, *constituents) ⇒ Sequence

Returns a new instance of Sequence.



508
509
510
511
# File 'lib/list_matcher.rb', line 508

def initialize(engine, *constituents)
  super(engine, nil)
  @children = constituents
end

Instance Method Details

#atomy?(s) ⇒ Boolean

infer atomic patterns

Returns:

  • (Boolean)


568
569
570
# File 'lib/list_matcher.rb', line 568

def atomy?(s)
  s.size == 1 || /\A(?>\\\w|\[(?>[^\[\]\\]|\\.)++\])\z/ === s
end

#condense(elements) ⇒ Object

iterated repeat condensation



573
574
575
576
577
578
579
580
# File 'lib/list_matcher.rb', line 573

def condense(elements)
  while elements.size > 1
    condensate = condense_repeats elements
    break if condensate == elements
    elements = condensate
  end
  elements.join
end

#condense_repeats(elements) ⇒ Object

looks for repeating subsequences, as in ababababab, and condenses them to (?>ab)5 condensation is only done when it results in a more compact regex



531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'lib/list_matcher.rb', line 531

def condense_repeats(elements)
  (1..(elements.size/2)).each do |l|            # length of subsequence considered
    (0...l).each do |o|                         # offset from the start of the sequence
      dup_count = []
      (1...(elements.size - o)/l).each do |s|   # the sub-sequence number
        s2 = s * l + o
        s1 = s2 - l
        seq1 = elements[s1...s1 + l]
        seq2 = elements[s2...s2 + l]
        if seq1 == seq2
          s0 = s - 1
          counts = dup_count[s] = dup_count[s0] || [ 1, seq1.join, s1, nil ]
          counts[0] += 1
          counts[3]  = s2 + l
          dup_count[s0] = nil
        end
      end
      dup_count.compact!
      if dup_count.any?
        copy = elements.dup
        changed = false
        dup_count.reverse.each do |repeats, seq, start, finish|
          a  = atomy? seq
          sl = seq.length
          if ( a ? 0 : engine.wrap_size ) + 2 + repeats.to_s.length + sl < sl * repeats
            changed = true
            copy[start...finish] = ( a ? seq : wrap(seq) ) + "{#{repeats}}"
          end
        end
        return copy if changed
      end
    end
  end
  elements
end

#convertObject



513
514
515
516
# File 'lib/list_matcher.rb', line 513

def convert
  rx = condense children.map(&:convert)
  finalize rx
end

#flattenObject



518
519
520
521
522
523
524
525
526
527
# File 'lib/list_matcher.rb', line 518

def flatten
  super
  (0...children.size).to_a.reverse.each do |i|
    c = children[i]
    if c.is_a?(Sequence) && !c.optional?
      children.delete_at i
      children.insert i, *c.children
    end
  end
end