class List::Matcher::Special

Attributes

engine[R]
left[RW]
list[RW]
right[RW]
special_map[R]
specials[RW]

Public Class Methods

new( engine, specials, list ) click to toggle source
# File lib/list_matcher.rb, line 336
def initialize( engine, specials, list )
  @engine = engine
  @list = list
  max = 0
  list.each do |w|
    w.chars.each{ |c| i = c.ord; max = i if i > max }
  end
  @specials = [].tap do |ar|
    specials.sort do |a, b|
      a = a.first
      b = b.first
      s1 = a.is_a?(String) || a.is_a?(Symbol)
      s2 = b.is_a?(String) || b.is_a?(Symbol)
      if s1 && s2
        b.to_s <=> a.to_s
      elsif s1
        -1
      elsif s2
        1
      else
        s = a.to_s.length - b.to_s.length
        s == 0 ? a.to_s <=> b.to_s : s
      end
    end.each do |var, opts|
      c = ( max += 1 ).chr(engine.encoding)
      sp = if opts.is_a? Hash
        pat = opts.delete :pattern
        raise Error, "symbol #{var} requires a pattern" unless pat || var.is_a?(Regexp)
        pat ||= var.to_s
        SymbolPattern.new engine, c, var, pat, **opts
      elsif opts.is_a? String
        SymbolPattern.new engine, c, var, opts
      elsif var.is_a?(Regexp) && opts.nil?
        SymbolPattern.new engine, c, var, nil
      else
        raise Error, "symbol #{var} requires a pattern"
      end
      ar << sp
    end
  end
  if engine.bound
    if engine.left_bound
      c = ( max += 1 ).chr(engine.encoding)
      @left = SymbolPattern.new engine, c, c, engine.left_bound
      @specials << @left
    end
    if engine.right_bound
      c = ( max += 1 ).chr(engine.encoding)
      @right = SymbolPattern.new engine, c, c, engine.right_bound
      @specials << @right
    end
  end
  @special_map = Hash[@specials.map{ |s| [ s.char, s ] }]
end

Public Instance Methods

[](s) click to toggle source

maps a symbol character back to the symbol object

# File lib/list_matcher.rb, line 403
def [](s)
  special_map[s]
end
normalize() click to toggle source

reduce the list to a version ready for pattern generation

# File lib/list_matcher.rb, line 408
def normalize
  rx = if specials.empty?
    /(?!)/
  else
    Regexp.new '(' + specials.map(&:var).map(&:to_s).join('|') + ')'
  end
  list = self.list.uniq.map do |w|
    parts = w.split(rx).select{ |p| p.length > 0 }
    e = parts.size - 1
    (0..e).map do |i|
      p = parts[i]
      if rx === p
        p = specials.detect{ |sp| sp.var === p }
        if engine.bound
          s = p
          if i == 0 && engine.left_bound && engine.word_test === p.left
            s = "#{left}#{s}"
          end
          if i == e && engine.right_bound && engine.word_test === p.right
            s = "#{s}#{right}"
          end
          p = s
        end
      else
        p = p.downcase if engine.case_insensitive
        if engine.bound
          s = p
          if i == 0 && engine.left_bound && engine.word_test === p[0]
            s = "#{left}#{s}"
          end
          if i == e && engine.right_bound && engine.word_test === p[-1]
            s = "#{s}#{right}"
          end
          p = s
        end
      end
      p
    end.join
  end.uniq.sort
  list
end
verify() click to toggle source

confirm that all special patterns are legitimate regexen

# File lib/list_matcher.rb, line 392
def verify
  specials.each do |s|
    begin
      Regexp.new s.pat
    rescue
      raise Error, "the symbol #{s.symbol} has an ill-formed pattern: #{s.pat}"
    end
  end
end