@ -33,68 +33,74 @@ class Glitch::KeywordMute < ApplicationRecord
Rails . cache . delete ( TagMatcher . cache_key ( account_id ) )
end
class RegexpMatcher
class CachedKeywordMute
attr_reader :keyword
attr_reader :whole_word
def initialize ( keyword , whole_word )
@keyword = keyword
@whole_word = whole_word
end
def boundary_regex_for_keyword
sb = keyword =~ / \ A[[:word:]] / ? '\b' : ''
eb = keyword =~ / [[:word:]] \ Z / ? '\b' : ''
/ (?mix: #{ sb } #{ Regexp . escape ( keyword ) } #{ eb } ) /
end
def matches? ( str )
str =~ ( whole_word ? boundary_regex_for_keyword : / #{ keyword } /i )
end
end
class Matcher
attr_reader :account_id
attr_reader :regex
attr_reader :words
def initialize ( account_id )
@account_id = account_id
regex_text = Rails . cache . fetch ( self . class . cache_key ( account_id ) ) { make_regex_text }
@regex = / #{ regex_text } /
@words = Rails . cache . fetch ( self . class . cache_key ( account_id ) ) { fetch_keywords }
end
protected
def keywords
Glitch :: KeywordMute . where ( account_id : account_id ) . pluck ( :whole_word , :keyword )
def fetch_keywords
Glitch :: KeywordMute . where ( account_id : account_id ) . pluck ( :whole_word , :keyword ) . map do | whole_word , keyword |
CachedKeywordMute . new ( transform_keyword ( keyword ) , whole_word )
end
end
def boundary_regex_for_keyword ( keyword )
sb = keyword =~ / \ A[[:word:]] / ? '\b' : ''
eb = keyword =~ / [[:word:]] \ Z / ? '\b' : ''
/ (?mix: #{ sb } #{ Regexp . escape ( keyword ) } #{ eb } ) /
def transform_keyword ( keyword )
keyword
end
end
class TextMatcher < Regexp Matcher
class TextMatcher < Matcher
def self . cache_key ( account_id )
format ( 'keyword_mutes:regex:text:%s' , account_id )
end
def matches? ( str )
! ! ( regex =~ str )
end
private
def make_regex_text
kws = keywords . map! do | whole_word , keyword |
whole_word ? boundary_regex_for_keyword ( keyword ) : / (?i: #{ Regexp . escape ( keyword ) } ) /
end
Regexp . union ( kws ) . source
words . any? { | w | w . matches? ( str ) }
end
end
class TagMatcher < Regexp Matcher
class TagMatcher < Matcher
def self . cache_key ( account_id )
format ( 'keyword_mutes:regex:tag:%s' , account_id )
end
def matches? ( tags )
tags . pluck ( :name ) . any? { | n | regex =~ n }
tags . pluck ( :name ) . any? do | n |
words . any? { | w | w . matches? ( n ) }
end
private
def make_regex_text
kws = keywords . map! do | whole_word , keyword |
term = ( Tag :: HASHTAG_RE =~ keyword ) ? $1 : keyword
whole_word ? boundary_regex_for_keyword ( term ) : term
end
Regexp . union ( kws ) . source
protected
def transform_keyword ( kw )
Tag :: HASHTAG_RE =~ kw ? $1 : kw
end
end
end