Metastatic.Analysis.Encapsulation
(Metastatic v0.10.4)
View Source
Encapsulation analysis for containers (modules/classes).
Detects violations of encapsulation principles - the practice of hiding internal state and requiring all interaction to go through well-defined interfaces.
Principles Checked
- Information Hiding: Internal state should be private
- Controlled Access: State access should go through methods
- Interface Segregation: Public interface should be minimal and focused
- Implementation Hiding: Internal details should not leak
Detected Violations
Public State (Critical)
Instance variables that are publicly accessible without getters/setters. Breaks encapsulation by allowing uncontrolled state modification.
Missing Accessors (High)
Direct state access/modification without using accessor methods. Bypasses potential validation and business logic.
Excessive Accessors (Medium)
Too many getter/setter pairs relative to behavior methods. May indicate a "data class" that lacks encapsulation of behavior.
Leaky Abstraction (Medium)
Methods that expose internal implementation details. Makes refactoring difficult and couples clients to implementation.
Examples
# Good encapsulation
ast = {:container, :class, "BankAccount", %{}, [
{:function_def, :public, "deposit", ["amount"], %{},
{:augmented_assignment, :+,
{:attribute_access, {:variable, "self"}, "balance"}, {:variable, "amount"}}},
{:function_def, :public, "get_balance", [], %{},
{:attribute_access, {:variable, "self"}, "balance"}}
]}
doc = Document.new(ast, :python)
{:ok, result} = Encapsulation.analyze(doc)
result.violations # => []
result.score # => 100
result.assessment # => :excellent
# Poor encapsulation - direct state access
ast = {:container, :class, "User", %{}, [
{:function_def, :public, "process", [], %{},
{:assignment, {:attribute_access, {:variable, "self"}, "status"}, {:literal, :string, "done"}}}
]}
{:ok, result} = Encapsulation.analyze(doc)
result.violations # => [%{type: :missing_accessor, ...}]
result.assessment # => :poor
Summary
Functions
Analyze encapsulation of a container (module/class/namespace).
Analyze encapsulation of a container (module/class/namespace).
Functions
@spec analyze(Metastatic.language(), term(), keyword()) :: {:ok, map()} | {:error, term()}
Analyze encapsulation of a container (module/class/namespace).
Returns {:ok, result} if the AST contains a container, or {:error, reason} otherwise.
Examples
iex> ast = {:container, :class, "Example", %{}, [
...> {:function_def, :public, "get_value", [], %{},
...> {:attribute_access, {:variable, "self"}, "value"}}
...> ]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Encapsulation.analyze(doc)
iex> result.score
100
iex> result.assessment
:excellent
@spec analyze!(Metastatic.language(), term(), keyword()) :: map()
Analyze encapsulation of a container (module/class/namespace).
Returns {:ok, result} if the AST contains a container, or {:error, reason} otherwise.
Examples
iex> ast = {:container, :class, "Example", %{}, [
...> {:function_def, :public, "get_value", [], %{},
...> {:attribute_access, {:variable, "self"}, "value"}}
...> ]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Encapsulation.analyze(doc)
iex> result.score
100
iex> result.assessment
:excellentUnlike not-banged version, this one either returns a result or raises