Module: Moderate::Filters

Defined in:
lib/moderate/filters/base.rb,
lib/moderate/filters/wordlist.rb

Overview

The built-in filter adapters live under Moderate::Filters. They're the gem's own implementations of the ONE adapter contract the whole filtering design hinges on:

adapter.classify(value) -> Moderate::Result

...where value is a piece of user content (a String of text, or an image reference) and the returned Moderate::Result answers "is this allowed?" and, if not, "why?" (the per-Moderate::Label detail, mapped onto the gem's single canonical taxonomy — see Moderate::Label).

── How adapters are invoked ──────────────────────────────────────────────── The configuration registry (Moderate::Configuration#adapters) stores each adapter as EITHER a live object the host registered, OR a class-NAME String the gem constantizes lazily. The one built-in is seeded as the string "Moderate::Filters::Wordlist", and Configuration#resolve_adapter returns the CLASS itself for a String/Class entry. That means the gem calls SomeAdapterClass.classify(value) and SomeAdapterClass.synchronous? — i.e. the built-in exposes CLASS methods, not instance methods. (A host's own adapter registered as an instance — including the reference adapters in examples/ — exposes the same #classify/#synchronous? on that instance — same duck type, both work.)

Base gives the built-in both halves of that duck type from a single source: subclasses implement the work as an INSTANCE method (#classify), and Base provides the CLASS-level classify/synchronous?/async? that the registry resolution path calls, delegating the class call to a fresh instance. So one implementation satisfies both call styles and there's no copy-paste. (It's the base for the bundled wordlist; the examples/ reference adapters don't need it — any object answering #classify is a valid adapter.)

── Sync vs. async (why it matters for :block) ────────────────────────────── Configuration#validate! enforces the README's rule: a :block-mode filter MUST use a synchronous adapter, because you can't reject a save on a result that's still computing in a background job. The validator probes the adapter with synchronous? and treats anything that doesn't answer, or answers truthy, as synchronous (the safe default that keeps simple adapters working); only an adapter that explicitly returns synchronous? == false is rejected for :block.

We model this once here as async? (default false — the built-in wordlist is sync) and derive synchronous? from it, so a subclass flips ONE flag (def self.async? = true) to declare itself background-only. The wordlist leaves the default; a network-backed reference adapter (see examples/) declares itself async via its own synchronous? == false, which the spine honors regardless of whether the adapter inherits from Base.

Defined Under Namespace

Classes: Base, Wordlist