class Goodcheck::Pattern::Token

Constants

AUTO_EMAIL_LOCAL_RE

github.com/tenderlove/rails_autolink/blob/master/lib/rails_autolink/helpers.rb#L81-L82

AUTO_EMAIL_RE

From rails_autolink gem github.com/tenderlove/rails_autolink/blob/master/lib/rails_autolink/helpers.rb#L73 With ')' support, which should be frequently used for markdown or CSS `url(…)`

WORD_RE

Attributes

case_sensitive[R]
source[R]
variables[R]

Public Class Methods

compile_tokens(source, variables, case_sensitive:) click to toggle source
# File lib/goodcheck/pattern.rb, line 207
def self.compile_tokens(source, variables, case_sensitive:)
  tokens = []
  s = StringScanner.new(source)

  until s.eos?
    case
    when s.scan(/\${(?<name>[a-zA-Z_]\w*)(?::(?<type>#{::Regexp.union(*@@TYPES.keys.map(&:to_s))}))?}/)
      name = s[:name].to_sym
      type = s[:type] ? s[:type].to_sym : :__

      if variables.key?(name)
        if !s[:type] && s.pre_match == ""
          Goodcheck.logger.error "Variable binding ${#{name}} at the beginning of pattern would cause an unexpected match"
        end
        if !s[:type] && s.peek(1) == ""
          Goodcheck.logger.error "Variable binding ${#{name}} at the end of pattern would cause an unexpected match"
        end

        tokens << :nobr
        variables[name].type = type
        regexp = regexp_for_type(name: name, type: type, scanner: s).to_s
        if tokens.empty? && (type == :word || type == :identifier)
          regexp = /\b#{regexp.to_s}/
        end
        tokens << regexp.to_s
        tokens << :nobr
      else
        tokens << ::Regexp.escape("${")
        tokens << ::Regexp.escape(name.to_s)
        tokens << ::Regexp.escape("}")
      end
    when s.scan(/\(|\)|\{|\}|\[|\]|\<|\>/)
      tokens << ::Regexp.escape(s.matched)
    when s.scan(/\s+/)
      tokens << '\s+'
    when s.scan(WORD_RE)
      tokens << ::Regexp.escape(s.matched)
    when s.scan(%r{[!"#%&'=\-^~¥\\|`@*:+;/?.,]+})
      tokens << ::Regexp.escape(s.matched.rstrip)
    when s.scan(/./)
      tokens << ::Regexp.escape(s.matched)
    end
  end

  if source[0] =~ /\p{L}/
    tokens.first.prepend('\b')
  end

  if source[-1] =~ /\p{L}/
    tokens.last << '\b'
  end

  options = ::Regexp::MULTILINE
  options |= ::Regexp::IGNORECASE unless case_sensitive

  buf, skip = tokens[0].is_a?(String) ? [tokens[0], false] : ["", true]
  tokens.drop(1).each do |tok|
    if tok == :nobr
      skip = true
    else
      buf << '\s*' unless skip
      skip = false
      buf << tok
    end
  end

  ::Regexp.new(buf.
    gsub(/\\s\*(\\s\+\\s\*)+/, '\s+').
    gsub(/#{::Regexp.escape('\s+\s*')}/, '\s+').
    gsub(/#{::Regexp.escape('\s*\s+')}/, '\s+'), options)
end
expand(prefix, suffix, depth: 5) click to toggle source
# File lib/goodcheck/pattern.rb, line 165
def self.expand(prefix, suffix, depth: 5)
  if depth == 0
    [
      /[^#{suffix}]*/
    ]
  else
    expandeds = expand(prefix, suffix, depth: depth - 1)
    [/[^#{prefix}#{suffix}]*#{prefix}#{expandeds.first}#{suffix}[^#{prefix}#{suffix}]*/] + expandeds
  end
end
new(source:, variables:, case_sensitive:) click to toggle source
# File lib/goodcheck/pattern.rb, line 42
def initialize(source:, variables:, case_sensitive:)
  @source = source
  @variables = variables
  @case_sensitive = case_sensitive
end
regexp_for_type(name:, type:, scanner:) click to toggle source
# File lib/goodcheck/pattern.rb, line 176
def self.regexp_for_type(name:, type:, scanner:)
  prefix = scanner.pre_match[-1]
  suffix = scanner.check(WORD_RE) || scanner.peek(1)

  case
  when type == :__
    body = case
           when prefix == "{" && suffix == "}"
             ::Regexp.union(expand(prefix, suffix))
           when prefix == "(" && suffix == ")"
             ::Regexp.union(expand(prefix, suffix))
           when prefix == "[" && suffix == "]"
             ::Regexp.union(expand(prefix, suffix))
           when prefix == "<" && suffix == ">"
             ::Regexp.union(expand(prefix, suffix))
           else
             unless suffix.empty?
               /(?~#{::Regexp.escape(suffix)})/
             else
               /.*/
             end
           end
    /(?<#{name}>#{body})/

  when @@TYPES.key?(type)
    @@TYPES[type][name]
  end
end

Public Instance Methods

regexp() click to toggle source
# File lib/goodcheck/pattern.rb, line 48
def regexp
  @regexp ||= Token.compile_tokens(source, variables, case_sensitive: case_sensitive)
end
test_variables(match) click to toggle source
# File lib/goodcheck/pattern.rb, line 97
def test_variables(match)
  variables.all? do |name, var|
    str = match[name]
    str && var.test(str)
  end
end