Merged
Conversation
This commit introduces a new guard system for Servus that provides
self-contained validation objects with rich error responses.
Key features:
- Servus::Guard base class with declarative DSL
- Automatic registration via Guards::Registry
- Integration with Servus::Base via throw/catch for performance
- Support for localized messages (I18n, inline translations)
- Method signature-based parameter contracts
- Backward compatible with existing raise-based error handling
Core guards included:
- EnsurePresent: validates values are not nil/empty
- EnsurePositive: validates numeric values are > 0
The guard system uses throw/catch instead of exceptions for control
flow, providing ~4x better performance than raise-based approaches
while maintaining clean syntax at any nesting level.
Usage example:
class TransferService < Servus::Base
def call
# ... perform transfer ...
success(result)
end
end
All changes include comprehensive test coverage following existing
Servus testing patterns.
- Removed the Guards registry and integrated guard method definitions directly into the Servus::Guards module. - Updated the Guard class to provide bang (!) and predicate (?) methods for guard execution. - Introduced configuration options for guards directory and inclusion of default guards. - Modified ensure_positive and ensure_present guards to use new message formatting. - Updated tests to reflect changes in guard method definitions and removed references to the old registry. - Added new tests for predicate guard methods to ensure correct behavior.
- Removed the existing event bus specification document. - Updated configuration documentation to include guards directory and settings. - Refactored the Servus::Guard class to remove severity level declaration. - Implemented auto-loading for custom guards in Rails. - Created built-in guards: EnsurePresent and EnsurePositive. - Added comprehensive documentation for guards, including usage, creation, and testing. - Updated tests to reflect changes in guard implementation and error handling.
- Change class names from Ensure* to *Guard (e.g., EnsurePresent -> PresenceGuard) - Update method generation to use enforce_*! and check_*? prefixes - Rename guard files: ensure_present.rb -> presence.rb, ensure_positive.rb -> positive.rb - Update all documentation and examples to reflect new naming - Add comprehensive naming convention documentation The new pattern: - Guard classes describe WHAT is checked, not HOW (e.g., SufficientBalanceGuard) - Framework adds action verbs: enforce_*! (throws) and check_*? (boolean) - Example: SufficientBalanceGuard generates enforce_sufficient_balance! and check_sufficient_balance? This makes guard names cleaner and more semantic, avoiding redundant action verbs.
- Updated guard class naming to strip both "Ensure" prefix and "Guard" suffix for cleaner method names. - Modified `derive_method_name` to reflect new naming conventions. - Enhanced error handling in `ControllerHelpers` to use `error.http_status` and `error.api_error` for rendering. - Refactored error classes to provide consistent HTTP status and API error responses. - Created a dummy Rails application for testing and development purposes.
- Implemented PresenceGuard to ensure all provided values are present (not nil or empty). - Created StateGuard to validate that an attribute matches an expected value or one of several allowed values. - Developed TruthyGuard to check that specified attributes on an object are truthy. - Introduced MessageResolver for resolving message templates with interpolation support, handling strings, symbols, hashes, and procs. - Added comprehensive specs for each guard and the message resolver to ensure functionality and error handling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces a comprehensive Guards system for declarative precondition validation in services. Guards halt execution when conditions aren't met, returning
structured error responses.
New Built-in Guards
PresenceGuardenforce_presence!(user: user)TruthyGuardenforce_truthy!(on: user, check: :active)FalseyGuardenforce_falsey!(on: user, check: :banned)StateGuardenforce_state!(on: order, check: :status, is: :pending)Features
Two method styles per guard:
enforce_*!- halts execution on failure, returns failure responsecheck_*?- returns boolean for conditional logicRich error responses:
Multiple attribute support:
enforce_truthy!(on: user, check: [:active, :verified, :confirmed])
enforce_state!(on: account, check: :status, is: [:active, :trial])
Rails generator:
rails g servus:guard sufficient_balance
Breaking Changes
Files Changed
New Files
Modified Files
Deleted Files
Test Plan