Module: Moult::FlagScanner
- Defined in:
- lib/moult/flag_scanner.rb
Overview
The OpenFeature flag-evaluation SCANNER — the only file that knows the OpenFeature client call shape, so a future SDK or provider shift is a swap, not a rewrite (the same isolation Clones gives flay and Boundaries::Packwerk gives packwerk). It is a pure Prism scan over source, shaped like SymbolScanner: there is no external-tool output to ingest here.
OpenFeature (github.com/open-feature/ruby-sdk, gem openfeature-sdk) is the
provider-agnostic feature-flag standard: a client is built via
OpenFeature::SDK.build_client and flags are evaluated with
client.fetch_<type>_value(flag_key:, default_value:, evaluation_context:)
(and the fetch_<type>_details variants). Scanning that client surface catches
flag usage behind any provider (flagd, LaunchDarkly, GO Feature Flag, ...).
We detect by AST only and take NO dependency on the openfeature-sdk gem — we
read the call shape, we never call the SDK. A call is an OpenFeature evaluation
when its method name is one of the known fetch_* names AND it passes a
flag_key: keyword argument (the keyword uniquely disambiguates it from any
unrelated same-named method, since the receiver is a runtime value).
Defined Under Namespace
Constant Summary collapse
- TARGET =
Provenance recorded in the report's
analysis.scannerblock. The swap point: retarget these (and METHOD_VALUE_TYPES) for a different SDK/standard. "openfeature"- SDK_GEM =
"openfeature-sdk"- CLIENT_BUILDER =
"OpenFeature::SDK.build_client"- FETCH_TYPES =
The fetch_
_(value|details) method names mapped to the contract's value_type. integer/float collapse to "number" (the value_type enum is coarser than the SDK's fetch types); the precise method name is kept on each call site so nothing is lost. { "boolean" => "boolean", "string" => "string", "number" => "number", "integer" => "number", "float" => "number", "object" => "object" }.freeze
- METHOD_VALUE_TYPES =
FETCH_TYPES.each_with_object({}) do |(fetch_type, value_type), acc| acc["fetch_#{fetch_type}_value"] = value_type acc["fetch_#{fetch_type}_details"] = value_type end.freeze
- LITERAL_NODES =
The literal default_value node types we render. A non-literal default (a variable, method call, array/hash) renders to nil — recorded as "no observed literal default" rather than guessed.
[ Prism::StringNode, Prism::SymbolNode, Prism::IntegerNode, Prism::FloatNode, Prism::TrueNode, Prism::FalseNode, Prism::NilNode ].freeze
Class Method Summary collapse
Class Method Details
.scan_file(path, rel_path) ⇒ Array<CallSite>
67 68 69 |
# File 'lib/moult/flag_scanner.rb', line 67 def scan_file(path, rel_path) scan_source(File.read(path), rel_path) end |