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?, #optionalize, #pfx, #qmark, #quote, #root?, #wrap

Constructor Details

#initialize(engine, *constituents) ⇒ Sequence

Returns a new instance of Sequence.



563
564
565
566
# File 'lib/list_matcher.rb', line 563

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

Instance Method Details

#atomy?(s) ⇒ Boolean

infer atomic patterns

Returns:

  • (Boolean)


621
622
623
# File 'lib/list_matcher.rb', line 621

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

#condense(elements) ⇒ Object

iterated repeat condensation



626
627
628
629
630
631
632
633
# File 'lib/list_matcher.rb', line 626

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



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
# File 'lib/list_matcher.rb', line 586

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
        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
            copy[start...finish] = ( a ? seq : wrap(seq) ) + "{#{repeats}}"
            return copy;
          end
        end
      end
    end
  end
  elements
end

#convertObject



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

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

#flattenObject



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

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